diff --git a/frontend/src/components/BackstoryQuery.tsx b/frontend/src/components/BackstoryQuery.tsx
index 074495b..692ffac 100644
--- a/frontend/src/components/BackstoryQuery.tsx
+++ b/frontend/src/components/BackstoryQuery.tsx
@@ -1,20 +1,20 @@
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
-import { ChatQuery } from "types/types";
+import { CandidateQuestion } from "types/types";
-type ChatSubmitQueryInterface = (query: ChatQuery) => void;
+type ChatSubmitQueryInterface = (query: CandidateQuestion) => void;
interface BackstoryQueryInterface {
- query: ChatQuery,
+ question: CandidateQuestion,
submitQuery?: ChatSubmitQueryInterface
}
const BackstoryQuery = (props : BackstoryQueryInterface) => {
- const { query, submitQuery } = props;
+ const { question, submitQuery } = props;
if (submitQuery === undefined) {
- return ({query.prompt});
+ return ({question.question});
}
return (
);
}
diff --git a/frontend/src/components/DeleteConfirmation.tsx b/frontend/src/components/DeleteConfirmation.tsx
index f87d959..643d15b 100644
--- a/frontend/src/components/DeleteConfirmation.tsx
+++ b/frontend/src/components/DeleteConfirmation.tsx
@@ -9,6 +9,7 @@ import {
Button,
useMediaQuery,
Tooltip,
+ SxProps,
} from '@mui/material';
import { useTheme } from '@mui/material/styles';
import ResetIcon from '@mui/icons-material/History';
@@ -20,7 +21,7 @@ interface DeleteConfirmationProps {
label?: string;
action?: "delete" | "reset";
color?: "inherit" | "default" | "primary" | "secondary" | "error" | "info" | "success" | "warning" | undefined;
-
+ sx?: SxProps;
// New props for controlled mode
open?: boolean;
onClose?: () => void;
@@ -54,7 +55,8 @@ const DeleteConfirmation = (props: DeleteConfirmationProps) => {
message,
hideButton = false,
confirmButtonText,
- cancelButtonText = "Cancel"
+ cancelButtonText = "Cancel",
+ sx
} = props;
// Internal state for uncontrolled mode
@@ -104,7 +106,7 @@ const DeleteConfirmation = (props: DeleteConfirmationProps) => {
aria-label={action}
onClick={handleClickOpen}
color={color || "inherit"}
- sx={{ display: "flex", margin: 'auto 0px' }}
+ sx={{ display: "flex", margin: 'auto 0px', ...sx }}
size="large"
edge="start"
disabled={disabled}
diff --git a/frontend/src/components/StyledMarkdown.tsx b/frontend/src/components/StyledMarkdown.tsx
index 2a740de..cf24b57 100644
--- a/frontend/src/components/StyledMarkdown.tsx
+++ b/frontend/src/components/StyledMarkdown.tsx
@@ -13,7 +13,7 @@ import { GenerateImage } from 'components/GenerateImage';
import './StyledMarkdown.css';
import { BackstoryElementProps } from './BackstoryTab';
-import { ChatSession } from 'types/types';
+import { CandidateQuestion, ChatSession } from 'types/types';
interface StyledMarkdownProps extends BackstoryElementProps {
className?: string,
@@ -106,8 +106,11 @@ const StyledMarkdown: React.FC = (props: StyledMarkdownProp
const queryString = props.query.replace(/(\w+):/g, '"$1":');
try {
const query = JSON.parse(queryString);
+ const backstoryQuestion: CandidateQuestion = {
+ question: queryString
+ }
- return
+ return
} catch (e) {
console.log("StyledMarkdown error:", queryString, e);
return props.query;
diff --git a/frontend/src/components/layout/BackstoryLayout.tsx b/frontend/src/components/layout/BackstoryLayout.tsx
index 936c3de..c3dfb4d 100644
--- a/frontend/src/components/layout/BackstoryLayout.tsx
+++ b/frontend/src/components/layout/BackstoryLayout.tsx
@@ -44,7 +44,7 @@ const ViewerNavItems: NavigationLinkType[] = [
const CandidateNavItems : NavigationLinkType[]= [
{ name: 'Chat', path: '/chat', icon: },
- // { name: 'Job Analysis', path: '/candidate/job-analysis', icon: },
+ { name: 'Job Analysis', path: '/candidate/job-analysis', icon: },
{ name: 'Resume Builder', path: '/candidate/resume-builder', icon: },
// { name: 'Knowledge Explorer', path: '/candidate/knowledge-explorer', icon: },
// { name: 'Dashboard', icon: , path: '/candidate/dashboard' },
diff --git a/frontend/src/components/layout/BackstoryRoutes.tsx b/frontend/src/components/layout/BackstoryRoutes.tsx
index d2941da..660ba15 100644
--- a/frontend/src/components/layout/BackstoryRoutes.tsx
+++ b/frontend/src/components/layout/BackstoryRoutes.tsx
@@ -21,6 +21,7 @@ import { LoginPage } from "pages/LoginPage";
import { CandidateDashboardPage } from "pages/CandidateDashboardPage"
import { EmailVerificationPage } from "components/EmailVerificationComponents";
import { CandidateProfilePage } from "pages/candidate/Profile";
+import { JobMatchAnalysis } from "components/JobMatchAnalysis";
const BackstoryPage = () => (Backstory);
const ResumesPage = () => (Resumes);
@@ -70,6 +71,7 @@ const getBackstoryDynamicRoutes = (props: BackstoryDynamicRoutesProps): ReactNod
routes.splice(-1, 0, ...[
} />,
} />,
+ } />,
} />,
} />,
} />,
diff --git a/frontend/src/pages/CandidateChatPage.tsx b/frontend/src/pages/CandidateChatPage.tsx
index 207c627..7b0703f 100644
--- a/frontend/src/pages/CandidateChatPage.tsx
+++ b/frontend/src/pages/CandidateChatPage.tsx
@@ -6,6 +6,7 @@ import {
Divider,
useTheme,
useMediaQuery,
+ Tooltip,
} from '@mui/material';
import {
Send as SendIcon
@@ -21,6 +22,7 @@ import { useNavigate } from 'react-router-dom';
import { useSelectedCandidate } from 'hooks/GlobalContext';
import PropagateLoader from 'react-spinners/PropagateLoader';
import { BackstoryTextField, BackstoryTextFieldRef } from 'components/BackstoryTextField';
+import { BackstoryQuery } from 'components/BackstoryQuery';
const defaultMessage: ChatMessage = {
type: "preparing", status: "done", sender: "system", sessionId: "", timestamp: new Date(), content: ""
@@ -279,12 +281,13 @@ const CandidateChatPage = forwardRef((pr
>}
-
+ {selectedCandidate.questions?.length !== 0 && selectedCandidate.questions?.map(q => )}
{/* Fixed Message Input */}
{ chatSession && onDelete(chatSession); }}
disabled={!chatSession}
+ sx={{ minWidth: 'auto', px: 2, maxHeight: "min-content" }}
action="reset"
label="chat session"
title="Reset Chat Session"
@@ -296,14 +299,19 @@ const CandidateChatPage = forwardRef((pr
onEnter={sendMessage}
disabled={streaming || loading}
/>
+
+
+
+
);
diff --git a/frontend/src/pages/DocsPage.tsx b/frontend/src/pages/DocsPage.tsx
index d4514de..2d3e96f 100644
--- a/frontend/src/pages/DocsPage.tsx
+++ b/frontend/src/pages/DocsPage.tsx
@@ -145,7 +145,6 @@ const documents : DocType[] = [
{ title: "Authentication Architecture", route: "authentication.md", description: "Complete authentication architecture", icon: },
{ title: "UI Overview", route: "ui-overview", description: "Guide to the user interface components and interactions", icon: },
{ title: "UI Mockup", route: "ui-mockup", description: "Visual previews of interfaces and layout concepts", icon: },
- { title: "Chat Mockup", route: "mockup-chat-system", description: "Mockup of chat system", icon: },
{ title: "Theme Visualizer", route: "theme-visualizer", description: "Explore and customize application themes and visual styles", icon: },
{ title: "App Analysis", route: "app-analysis", description: "Statistics and performance metrics of the application", icon: },
{ title: 'Text Mockups', route: "backstory-ui-mockups", description: "Early text mockups of many of the interaction points." },
diff --git a/frontend/src/pages/FindCandidatePage.tsx b/frontend/src/pages/FindCandidatePage.tsx
index 6072baf..5487e0f 100644
--- a/frontend/src/pages/FindCandidatePage.tsx
+++ b/frontend/src/pages/FindCandidatePage.tsx
@@ -55,7 +55,7 @@ const CandidateListingPage = (props: BackstoryPageProps) => {
Generate your own perfect AI candidate!
-
+
{candidates?.map((u, i) =>
{ setSelectedCandidate(u); navigate("/chat"); }}
diff --git a/frontend/src/pages/JobAnalysisPage.tsx b/frontend/src/pages/JobAnalysisPage.tsx
index bf4a945..5291721 100644
--- a/frontend/src/pages/JobAnalysisPage.tsx
+++ b/frontend/src/pages/JobAnalysisPage.tsx
@@ -38,15 +38,16 @@ import { Candidate } from "types/types";
import { useNavigate } from 'react-router-dom';
import { BackstoryPageProps } from 'components/BackstoryTab';
import { useAuth } from 'hooks/AuthContext';
+import { useSelectedCandidate } from 'hooks/GlobalContext';
// Main component
const JobAnalysisPage: React.FC = (props: BackstoryPageProps) => {
const theme = useTheme();
const { user } = useAuth();
+ const { selectedCandidate, setSelectedCandidate } = useSelectedCandidate()
// State management
const [activeStep, setActiveStep] = useState(0);
- const [selectedCandidate, setSelectedCandidate] = useState(null);
const [jobDescription, setJobDescription] = useState('');
const [jobTitle, setJobTitle] = useState('');
const [jobLocation, setJobLocation] = useState('');
@@ -58,7 +59,7 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
const [candidates, setCandidates] = useState(null);
useEffect(() => {
- if (candidates !== null) {
+ if (candidates !== null || selectedCandidate) {
return;
}
const getCandidates = async () => {
@@ -85,11 +86,20 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
getCandidates();
}, [candidates, setSnack]);
+ useEffect(() => {
+ if (selectedCandidate && activeStep === 0) {
+ setActiveStep(1);
+ }
+ }, [selectedCandidate, activeStep]);
+
// Steps in our process
- const steps = [
- { label: 'Select Candidate', icon: },
- { label: 'Job Description', icon: },
- { label: 'View Analysis', icon: }
+ const steps = selectedCandidate === null ? [
+ { index: 0, label: 'Select Candidate', icon: },
+ { index: 1, label: 'Job Description', icon: },
+ { index: 2, label: 'View Analysis', icon: }
+ ] : [
+ { index: 1, label: 'Job Description', icon: },
+ { index: 2, label: 'View Analysis', icon: }
];
// Mock handlers for our analysis APIs
@@ -235,7 +245,7 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
return;
}
- if (activeStep === 1 && (!jobTitle || !jobDescription)) {
+ if (activeStep === 1 && (/*(extraInfo && !jobTitle) || */!jobDescription)) {
setError('Please provide both job title and description before continuing.');
return;
}
@@ -252,11 +262,12 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
};
const handleReset = () => {
- setActiveStep(0);
- setSelectedCandidate(null);
+ // setActiveStep(0);
+ setActiveStep(1);
+ // setSelectedCandidate(null);
setJobDescription('');
- setJobTitle('');
- setJobLocation('');
+ // setJobTitle('');
+ // setJobLocation('');
setAnalysisStarted(false);
};
@@ -341,50 +352,56 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
);
+ const extraInfo = false;
+
// Render function for the job description step
const renderJobDescription = () => (
-
- Enter Job Details
-
-
-
-
- setJobTitle(e.target.value)}
- required
- margin="normal"
- />
+ {extraInfo && <>
+
+ Enter Job Details
+
+
+
+
+ setJobTitle(e.target.value)}
+ required
+ margin="normal"
+ />
+
+
+
+ setJobLocation(e.target.value)}
+ margin="normal"
+ />
+
-
-
- setJobLocation(e.target.value)}
- margin="normal"
- />
-
-
+ >
+ }
+
Job Description
- }
size="small"
onClick={() => setOpenUploadDialog(true)}
>
Upload
-
+ }
= (props: BackstoryPageProps
/>
The job description will be used to extract requirements for candidate matching.
-
-
+
);
@@ -455,13 +471,13 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
- {steps.map((step, index) => (
-
+ {steps.map(step => (
+
(
= index ? theme.palette.primary.main : theme.palette.grey[300],
+ bgcolor: activeStep >= step.index ? theme.palette.primary.main : theme.palette.grey[300],
color: 'white'
}}
>
@@ -484,7 +500,7 @@ const JobAnalysisPage: React.FC = (props: BackstoryPageProps
- {activeStep === steps.length - 1 ? (
+ {activeStep === steps[steps.length - 1].index ? (
) : (
)}
diff --git a/frontend/src/pages/OldChatPage.tsx b/frontend/src/pages/OldChatPage.tsx
index a346b73..c58f549 100644
--- a/frontend/src/pages/OldChatPage.tsx
+++ b/frontend/src/pages/OldChatPage.tsx
@@ -27,8 +27,8 @@ const ChatPage = forwardRef((props: Back
setQuestions([
- {candidate.questions?.map(({ question, tunables }, i: number) =>
-
+ {candidate.questions?.map((q, i: number) =>
+
)}
,
diff --git a/frontend/src/types/types.ts b/frontend/src/types/types.ts
index 9dde1b7..9dcf9ab 100644
--- a/frontend/src/types/types.ts
+++ b/frontend/src/types/types.ts
@@ -1,6 +1,6 @@
// Generated TypeScript types from Pydantic models
// Source: src/backend/models.py
-// Generated on: 2025-06-02T23:24:36.213957
+// Generated on: 2025-06-03T02:54:38.566349
// DO NOT EDIT MANUALLY - This file is auto-generated
// ============================
@@ -367,7 +367,6 @@ export interface ChatSession {
lastActivity?: Date;
title?: string;
context: ChatContext;
- messages?: Array;
isArchived: boolean;
systemPrompt?: string;
}
diff --git a/src/backend/main.py b/src/backend/main.py
index fd4ce61..e2a3b84 100644
--- a/src/backend/main.py
+++ b/src/backend/main.py
@@ -3032,15 +3032,9 @@ async def delete_chat_session(
# Delete all messages associated with this session
try:
+ await database.delete_chat_messages(session_id)
chat_messages = await database.get_chat_messages(session_id)
- message_count = len(chat_messages)
-
- # Delete each message
- for message_data in chat_messages:
- message_id = message_data.get("id")
- if message_id:
- await database.delete_chat_message(session_id, message_id)
-
+ message_count = len(chat_messages)
logger.info(f"🗑️ Deleted {message_count} messages from session {session_id}")
except Exception as e:
@@ -3092,15 +3086,9 @@ async def reset_chat_session(
# Delete all messages associated with this session
try:
+ await database.delete_chat_messages(session_id)
chat_messages = await database.get_chat_messages(session_id)
- message_count = len(chat_messages)
-
- # Delete each message
- for message_data in chat_messages:
- message_id = message_data.get("id")
- if message_id:
- await database.delete_chat_message(session_id, message_id)
-
+ message_count = len(chat_messages)
logger.info(f"🗑️ Deleted {message_count} messages from session {session_id}")
except Exception as e:
diff --git a/src/backend/models.py b/src/backend/models.py
index 2bb4517..b3cab3d 100644
--- a/src/backend/models.py
+++ b/src/backend/models.py
@@ -774,7 +774,7 @@ class ChatSession(BaseModel):
last_activity: datetime = Field(default_factory=lambda: datetime.now(UTC), alias="lastActivity")
title: Optional[str] = None
context: ChatContext
- messages: Optional[List[ChatMessage]] = None
+ # messages: Optional[List[ChatMessage]] = None
is_archived: bool = Field(False, alias="isArchived")
system_prompt: Optional[str] = Field(None, alias="systemPrompt")
model_config = {