import React, { useState, useCallback, useRef } from 'react'; import { Tabs, Tab, Box, } from '@mui/material'; import { SxProps } from '@mui/material'; import { BackstoryQuery } from 'components/BackstoryQuery'; import { Conversation } from 'components/Conversation'; import { BackstoryPageProps } from 'components/BackstoryTab'; import { ChatQuery, ChatMessage } from "types/types"; import './ResumeBuilderPage.css'; /** * ResumeBuilder component * * A responsive component that displays job descriptions, generated resumes and fact checks * with different layouts for mobile and desktop views. */ const ResumeBuilderPage: React.FC = (props: BackstoryPageProps) => { const { sx, setSnack, submitQuery, } = props // State for editing job description const [hasJobDescription, setHasJobDescription] = useState(false); const [hasResume, setHasResume] = useState(false); const [hasFacts, setHasFacts] = useState(false); const jobConversationRef = useRef(null); const resumeConversationRef = useRef(null); const factsConversationRef = useRef(null); const [activeTab, setActiveTab] = useState(0); /** * Handle tab change for mobile view */ const handleTabChange = (_event: React.SyntheticEvent, newValue: number): void => { setActiveTab(newValue); }; const handleJobQuery = (query: ChatQuery) => { console.log(`handleJobQuery: ${query.prompt} -- `, jobConversationRef.current ? ' sending' : 'no handler'); jobConversationRef.current?.submitQuery(query); }; const handleResumeQuery = (query: ChatQuery) => { console.log(`handleResumeQuery: ${query.prompt} -- `, resumeConversationRef.current ? ' sending' : 'no handler'); resumeConversationRef.current?.submitQuery(query); }; const handleFactsQuery = (query: ChatQuery) => { console.log(`handleFactsQuery: ${query.prompt} -- `, factsConversationRef.current ? ' sending' : 'no handler'); factsConversationRef.current?.submitQuery(query); }; const filterJobDescriptionMessages = useCallback((messages: ChatMessage[]): ChatMessage[] => { if (messages === undefined || messages.length === 0) { return []; } if (messages.length > 0) { // messages[0].role = 'content'; // messages[0].title = 'Job Description'; // messages[0].disableCopy = false; // messages[0].expandable = true; } if (-1 !== messages.findIndex(m => m.status === 'done')) { // || (m.actions && m.actions.includes("resume_generated")))) { setHasResume(true); setHasFacts(true); } return messages; if (messages.length > 1) { setHasResume(true); setHasFacts(true); } if (messages.length > 3) { // messages[2] is Show job requirements // messages[3].role = 'job-requirements'; // messages[3].title = 'Job Requirements'; // messages[3].disableCopy = false; // messages[3].expanded = false; // messages[3].expandable = true; } /* Filter out the 2nd and 3rd (0-based) */ const filtered = messages;//.filter((m, i) => i !== 1 && i !== 2); console.warn("Set filtering back on"); return filtered; }, [setHasResume, setHasFacts]); const filterResumeMessages = useCallback((messages: ChatMessage[]): ChatMessage[] => { if (messages === undefined || messages.length === 0) { return []; } return messages; if (messages.length > 1) { // messages[0] is Show Qualifications // messages[1].role = 'qualifications'; // messages[1].title = 'Candidate qualifications'; // messages[1].disableCopy = false; // messages[1].expanded = false; // messages[1].expandable = true; } if (messages.length > 3) { // messages[2] is Show Resume // messages[3].role = 'resume'; // messages[3].title = 'Generated Resume'; // messages[3].disableCopy = false; // messages[3].expanded = true; // messages[3].expandable = true; } /* Filter out the 1st and 3rd messages (0-based) */ const filtered = messages.filter((m, i) => i !== 0 && i !== 2); return filtered; }, []); const filterFactsMessages = useCallback((messages: ChatMessage[]): ChatMessage[] => { if (messages === undefined || messages.length === 0) { return []; } if (messages.length > 1) { // messages[0] is Show verification // messages[1].role = 'fact-check'; // messages[1].title = 'Fact Check'; // messages[1].disableCopy = false; // messages[1].expanded = true; // messages[1].expandable = true; } /* Filter out the 1st (0-based) */ const filtered = messages.filter((m, i) => i !== 0); return filtered; }, []); const jobResponse = useCallback(async (message: ChatMessage) => { // if (message.actions && message.actions.includes("job_description")) { // if (jobConversationRef.current) { // await jobConversationRef.current.fetchHistory(); // } // } // if (message.actions && message.actions.includes("resume_generated")) { // if (resumeConversationRef.current) { // await resumeConversationRef.current.fetchHistory(); // } // setHasResume(true); // setActiveTab(1); // Switch to Resume tab // } // if (message.actions && message.actions.includes("facts_checked")) { // if (factsConversationRef.current) { // await factsConversationRef.current.fetchHistory(); // } // setHasFacts(true); // } }, [setHasFacts, setHasResume, setActiveTab]); const resumeResponse = useCallback((message: ChatMessage): void => { console.log('onResumeResponse', message); setHasFacts(true); }, [setHasFacts]); const factsResponse = useCallback((message: ChatMessage): void => { console.log('onFactsResponse', message); }, []); const resetJobDescription = useCallback(() => { setHasJobDescription(false); setHasResume(false); setHasFacts(false); }, [setHasJobDescription, setHasResume, setHasFacts]); const resetResume = useCallback(() => { setHasResume(false); setHasFacts(false); }, [setHasResume, setHasFacts]); const resetFacts = useCallback(() => { setHasFacts(false); }, [setHasFacts]); return (Not re-implmented yet); // const renderJobDescriptionView = useCallback((sx?: SxProps) => { // console.log('renderJobDescriptionView'); // const jobDescriptionQuestions = [ // // // // , // ]; // const jobDescriptionPreamble: ChatMessage[] = [{ // role: 'info', // content: `Once you paste a job description and press **Generate Resume**, Backstory will perform the following actions: // 1. **Job Analysis**: LLM extracts requirements from '\`Job Description\`' to generate a list of desired '\`Skills\`'. // 2. **Candidate Analysis**: LLM determines candidate qualifications by performing skill assessments. // For each '\`Skill\`' from **Job Analysis** phase: // 1. **RAG**: Retrieval Augmented Generation collection is queried for context related content for each '\`Skill\`'. // 2. **Evidence Creation**: LLM is queried to generate supporting evidence of '\`Skill\`' from the '\`RAG\`' and '\`Candidate Resume\`'. // 3. **Resume Generation**: LLM is provided the output from the **Candidate Analysis:Evidence Creation** phase and asked to generate a professional resume. // See [About > Resume Generation Architecture](/about/resume-generation) for more details. // `, // disableCopy: true // }]; // if (!hasJobDescription) { // return // } else { // return // } // }, [filterJobDescriptionMessages, hasJobDescription, sessionId, setSnack, jobResponse, resetJobDescription, hasFacts, hasResume, submitQuery]); // /** // * Renders the resume view with loading indicator // */ // const renderResumeView = useCallback((sx?: SxProps) => { // const resumeQuestions = [ // // // // , // ]; // if (!hasFacts) { // return // } else { // return // } // }, [filterResumeMessages, hasFacts, sessionId, setSnack, resumeResponse, resetResume, hasResume, submitQuery]); // /** // * Renders the fact check view // */ // const renderFactCheckView = useCallback((sx?: SxProps) => { // const factsQuestions = [ // // // , // ]; // return // }, [ sessionId, setSnack, factsResponse, filterFactsMessages, resetFacts, hasResume, hasFacts, submitQuery]); // return ( // // {/* Tabs */} // // // {hasResume && } // {hasFacts && } // // {/* Document display area */} // // {renderJobDescriptionView(/*{ height: "calc(100% - 72px - 48px)" }*/)} // {renderResumeView(/*{ height: "calc(100% - 72px - 48px)" }*/)} // {renderFactCheckView(/*{ height: "calc(100% - 72px - 48px)" }*/)} // // // ); }; export { ResumeBuilderPage };