Restructured

This commit is contained in:
James Ketr 2025-05-28 09:32:36 -07:00
parent 179a3dcc43
commit 5720c51f15
71 changed files with 378 additions and 690 deletions

View File

@ -2,15 +2,15 @@ import React, { useEffect, useState, useRef, useCallback } from 'react';
import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
import { ThemeProvider } from '@mui/material/styles';
import { backstoryTheme } from '../BackstoryTheme';
import { backstoryTheme } from './BackstoryTheme';
import { SeverityType } from '../Components/Snack';
import { Query } from '../types/types';
import { ConversationHandle } from './Components/Conversation';
import { UserProvider } from './Components/UserContext';
import { BetaPage } from './Pages/BetaPage';
import { SeverityType } from './components/Snack';
import { Query } from './types/types';
import { ConversationHandle } from './components/Conversation';
import { UserProvider } from './components/UserContext';
import { BetaPage } from './pages/BetaPage';
import { UserRoute } from './routes/UserRoute';
import { BackstoryLayout } from './Components/BackstoryLayout';
import { BackstoryLayout } from './components/BackstoryLayout';
import './BackstoryApp.css';
import '@fontsource/roboto/300.css';
@ -18,7 +18,7 @@ import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import { connectionBase } from '../Global';
import { connectionBase } from './Global';
// Cookie handling functions
const getCookie = (name: string) => {

View File

@ -12,7 +12,7 @@ const backstoryTheme = createTheme({
},
text: {
primary: '#2E2E2E', // Charcoal Black
secondary: '#1A2536',//D3CDBF', // Warm Gray
secondary: '#1A2536', // Midnight Blue
},
background: {
default: '#D3CDBF', // Warm Gray
@ -34,9 +34,32 @@ const backstoryTheme = createTheme({
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
},
h2: {
fontSize: '1.75rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '1rem',
},
h3: {
fontSize: '1.5rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.75rem',
},
h4: {
fontSize: '1.25rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.5rem',
},
body1: {
fontSize: '1rem',
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.5rem',
},
body2: {
fontSize: '0.875rem',
color: '#2E2E2E', // Charcoal Black
},
},
components: {
@ -69,6 +92,31 @@ const backstoryTheme = createTheme({
},
},
},
MuiPaper: {
styleOverrides: {
root: {
padding: '2rem',
borderRadius: '8px',
},
},
},
MuiList: {
styleOverrides: {
root: {
padding: '0.5rem',
},
},
},
MuiListItem: {
styleOverrides: {
root: {
borderRadius: '4px',
'&:hover': {
backgroundColor: 'rgba(212, 160, 23, 0.1)', // Golden Ochre with opacity
},
},
},
},
},
});

View File

@ -1,227 +0,0 @@
import React from 'react';
import { Box } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { SxProps, Theme } from '@mui/material';
import Accordion from '@mui/material/Accordion';
import AccordionSummary from '@mui/material/AccordionSummary';
import AccordionDetails from '@mui/material/AccordionDetails';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import LocationSearchingIcon from '@mui/icons-material/LocationSearching';
import { MessageRoles } from './Message';
import { ErrorOutline, InfoOutline, Memory, Psychology, /* Stream, */ } from '@mui/icons-material';
interface ChatBubbleProps {
role: MessageRoles,
isInfo?: boolean;
children: React.ReactNode;
sx?: SxProps<Theme>;
className?: string;
title?: string;
expanded?: boolean;
expandable?: boolean;
onExpand?: (open: boolean) => void;
}
function ChatBubble(props: ChatBubbleProps) {
const { role, children, sx, className, title, onExpand, expandable, expanded } = props;
const theme = useTheme();
const defaultRadius = '16px';
const defaultStyle = {
padding: theme.spacing(1, 2),
fontSize: '0.875rem',
alignSelf: 'flex-start',
maxWidth: '100%',
minWidth: '100%',
height: 'fit-content',
'& > *': {
color: 'inherit',
overflow: 'hidden',
m: 0,
},
'& > :last-child': {
mb: 0,
m: 0,
p: 0,
},
};
const styles: any = {
assistant: {
...defaultStyle,
backgroundColor: theme.palette.primary.main,
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`,
color: theme.palette.primary.contrastText,
},
content: {
...defaultStyle,
backgroundColor: '#F5F2EA',
border: `1px solid ${theme.palette.custom.highlight}`,
borderRadius: 0,
alignSelf: 'center',
color: theme.palette.text.primary,
padding: '8px 8px',
marginBottom: '0px',
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.05)',
fontSize: '0.9rem',
lineHeight: '1.3',
fontFamily: theme.typography.fontFamily,
},
error: {
...defaultStyle,
backgroundColor: '#F8E7E7',
border: `1px solid #D83A3A`,
borderRadius: defaultRadius,
maxWidth: '90%',
minWidth: '90%',
alignSelf: 'center',
color: '#8B2525',
padding: '10px 16px',
boxShadow: '0 1px 3px rgba(216, 58, 58, 0.15)',
},
'fact-check': 'qualifications',
'job-description': 'content',
'job-requirements': 'qualifications',
info: {
...defaultStyle,
backgroundColor: '#BFD8D8',
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: defaultRadius,
color: theme.palette.text.primary,
opacity: 0.95,
},
processing: 'status',
qualifications: {
...defaultStyle,
backgroundColor: theme.palette.primary.light,
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`,
color: theme.palette.primary.contrastText,
},
resume: 'content',
searching: 'status',
status: {
...defaultStyle,
backgroundColor: 'rgba(74, 122, 125, 0.15)',
border: `1px solid ${theme.palette.secondary.light}`,
borderRadius: '4px',
maxWidth: '75%',
minWidth: '75%',
alignSelf: 'center',
color: theme.palette.secondary.dark,
fontWeight: 500,
fontSize: '0.95rem',
padding: '8px 12px',
opacity: 0.9,
transition: 'opacity 0.3s ease-in-out',
},
streaming: 'assistant',
system: {
...defaultStyle,
backgroundColor: '#EDEAE0',
border: `1px dashed ${theme.palette.custom.highlight}`,
borderRadius: defaultRadius,
maxWidth: '90%',
minWidth: '90%',
alignSelf: 'center',
color: theme.palette.text.primary,
fontStyle: 'italic',
},
thinking: 'status',
user: {
...defaultStyle,
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.custom.highlight}`,
borderRadius: `${defaultRadius} ${defaultRadius} 0 ${defaultRadius}`,
alignSelf: 'flex-end',
color: theme.palette.primary.main,
},
};
// Resolve string references in styles
for (const [key, value] of Object.entries(styles)) {
if (typeof value === 'string') {
styles[key] = styles[value];
}
}
const icons: any = {
error: <ErrorOutline color="error" />,
info: <InfoOutline color="info" />,
processing: <LocationSearchingIcon />,
searching: <Memory />,
thinking: <Psychology />,
tooling: <LocationSearchingIcon />,
};
// Render Accordion for expandable content
if (expandable || title) {
// Determine if Accordion is controlled
const isControlled = typeof expanded === 'boolean' && typeof onExpand === 'function';
return (
<Accordion
expanded={isControlled ? expanded : undefined} // Omit expanded prop for uncontrolled
defaultExpanded={expanded} // Default to collapsed for uncontrolled Accordion
className={className}
onChange={(_event, newExpanded) => {
if (isControlled && onExpand) {
onExpand(newExpanded); // Call onExpand with new state
}
}}
sx={{ ...styles[role], ...sx }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
slotProps={{
content: {
sx: {
fontWeight: 'bold',
fontSize: '1.1rem',
m: 0,
p: 0,
display: 'flex',
justifyItems: 'center',
},
},
}}
>
{title || ''}
</AccordionSummary>
<AccordionDetails sx={{ mt: 0, mb: 0, p: 0, pl: 2, pr: 2 }}>
{children}
</AccordionDetails>
</Accordion>
);
}
// Render non-expandable content
return (
<Box
className={className}
sx={{
...(role in styles ? styles[role] : styles['status']),
gap: 1,
display: 'flex',
...sx,
flexDirection: 'row',
}}
>
{icons[role] !== undefined && icons[role]}
<Box sx={{ p: 0, m: 0, gap: 0, display: 'flex', flexGrow: 1, flexDirection: 'column' }}>
{children}
</Box>
</Box>
);
}
export type {
ChatBubbleProps
};
export {
ChatBubble
};

View File

@ -1,8 +0,0 @@
type ContextStatus = {
context_used: number,
max_context: number
};
export type {
ContextStatus
};

View File

@ -1,99 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Box } from '@mui/material';
import { Message } from './Message';
import { ChatBubble } from '../Components/ChatBubble';
import { BackstoryElementProps } from './BackstoryTab';
interface DocumentProps extends BackstoryElementProps {
title: string;
expanded?: boolean;
filepath?: string;
content?: string;
disableCopy?: boolean;
children?: React.ReactNode;
onExpand?: (open: boolean) => void;
}
const Document = (props: DocumentProps) => {
const { sessionId, setSnack, submitQuery, filepath, content, title, expanded, disableCopy, onExpand, children } = props;
const backstoryProps = {
submitQuery,
setSnack,
sessionId
}
const [document, setDocument] = useState<string>("");
// Get the markdown
useEffect(() => {
if (document !== "" || !filepath) {
return;
}
const fetchDocument = async () => {
try {
const response = await fetch(filepath, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw Error(`${filepath} not found.`);
}
const data = await response.text();
setDocument(data);
} catch (error: any) {
console.error('Error obtaining About content information:', error);
setDocument(`${filepath} not found.`);
};
};
fetchDocument();
}, [document, setDocument, filepath])
return (
<Box>
{children !== undefined && <ChatBubble
{...{
sx: {
mt: 1,
p: 1,
flexGrow: 0,
display: "flex",
flexDirection: "column",
pt: "8px",
pb: "8px",
marginTop: "8px !important", // Remove whitespace from expanded Accordion
marginBottom: "0px !important", // Remove whitespace from expanded Accordion
},
role: "content",
title,
expanded,
disableCopy,
onExpand
}}>{children}</ChatBubble>}
{children === undefined && <Message
{...{
sx: {
display: 'flex',
flexDirection: 'column',
p: 1,
m: 0,
flexGrow: 0,
marginTop: "8px !important", // Remove whitespace from expanded Accordion
},
message: { role: 'content', title: title, content: document || content || "" },
expanded,
disableCopy,
onExpand,
}}
{...backstoryProps} />
}
</Box>
);
};
export {
Document
};

View File

@ -1,123 +0,0 @@
import { createTheme } from '@mui/material/styles';
const backstoryTheme = createTheme({
palette: {
primary: {
main: '#1A2536', // Midnight Blue
contrastText: '#D3CDBF', // Warm Gray
},
secondary: {
main: '#4A7A7D', // Dusty Teal
contrastText: '#FFFFFF', // White
},
text: {
primary: '#2E2E2E', // Charcoal Black
secondary: '#1A2536', // Midnight Blue
},
background: {
default: '#D3CDBF', // Warm Gray
paper: '#FFFFFF', // White
},
action: {
active: '#D4A017', // Golden Ochre
hover: 'rgba(212, 160, 23, 0.1)', // Golden Ochre with opacity
},
custom: {
highlight: '#D4A017', // Golden Ochre
contrast: '#2E2E2E', // Charcoal Black
},
},
typography: {
fontFamily: "'Roboto', sans-serif",
h1: {
fontSize: '2rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
},
h2: {
fontSize: '1.75rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '1rem',
},
h3: {
fontSize: '1.5rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.75rem',
},
h4: {
fontSize: '1.25rem',
fontWeight: 500,
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.5rem',
},
body1: {
fontSize: '1rem',
color: '#2E2E2E', // Charcoal Black
marginBottom: '0.5rem',
},
body2: {
fontSize: '0.875rem',
color: '#2E2E2E', // Charcoal Black
},
},
components: {
MuiLink: {
styleOverrides: {
root: {
color: '#4A7A7D', // Dusty Teal (your secondary color)
textDecoration: 'none',
'&:hover': {
color: '#D4A017', // Golden Ochre on hover
textDecoration: 'underline',
},
},
},
},
MuiButton: {
styleOverrides: {
root: {
textTransform: 'none',
'&:hover': {
backgroundColor: 'rgba(212, 160, 23, 0.2)', // Golden Ochre hover
},
},
},
},
MuiAppBar: {
styleOverrides: {
root: {
backgroundColor: '#1A2536', // Midnight Blue
},
},
},
MuiPaper: {
styleOverrides: {
root: {
padding: '2rem',
borderRadius: '8px',
},
},
},
MuiList: {
styleOverrides: {
root: {
padding: '0.5rem',
},
},
},
MuiListItem: {
styleOverrides: {
root: {
borderRadius: '4px',
'&:hover': {
backgroundColor: 'rgba(212, 160, 23, 0.1)', // Golden Ochre with opacity
},
},
},
},
},
});
export { backstoryTheme };

View File

@ -1,111 +0,0 @@
import React, { useState, useEffect } from 'react';
import { Scrollable } from '../Components/Scrollable';
import { BackstoryPageProps } from '../Components/BackstoryTab';
import { Document } from '../Components/Document';
const AboutPage = (props: BackstoryPageProps) => {
const { sessionId, submitQuery, setSnack, route, setRoute } = props;
const [subRoute, setSubRoute] = useState<string>("");
const [page, setPage] = useState<string>("");
useEffect(() => {
if (route === undefined) { return; }
const parts = route.split("/");
setPage(parts[0]);
parts.shift();
setSubRoute(parts.join("/"));
}, [route]);
useEffect(() => {
console.log(`AboutPage: ${page} - sub-route - ${subRoute}`);
}, [page, subRoute]);
useEffect(() => {
if (route) {
const parts = route.split("/");
if (parts[0] !== page) {
parts.shift();
const incomingSubRoute = parts.join("/");
if (incomingSubRoute !== subRoute) {
setSubRoute(incomingSubRoute);
}
}
} else if (subRoute) {
setRoute && setRoute(subRoute);
}
}, [page, route, setRoute, subRoute]);
useEffect(() => {
let newRoute = page;
if (subRoute) {
newRoute += '/' + subRoute;
}
if (route !== newRoute && setRoute) {
setRoute(newRoute);
}
}, [route, page, subRoute, setRoute]);
const onDocumentExpand = (document: string, open: boolean) => {
console.log("Document expanded:", document, open);
if (open) {
setSubRoute("");
setPage(document);
} else {
setSubRoute("");
setPage("");
}
}
return <Scrollable
autoscroll={false}
sx={{
maxWidth: "1024px",
height: "100%",
flexDirection: "column",
margin: "0 auto",
p: 1,
}}
>
<Document {...{
title: "About",
filepath: "/docs/about.md",
onExpand: (open: boolean) => { onDocumentExpand('about', open); },
expanded: page === 'about',
sessionId,
submitQuery: submitQuery,
setSnack,
}} />
<Document {...{
title: "BETA",
filepath: "/docs/beta.md",
onExpand: (open: boolean) => { onDocumentExpand('beta', open); },
expanded: page === 'beta',
sessionId,
submitQuery: submitQuery,
setSnack,
}} />
<Document {...{
title: "Resume Generation Architecture",
filepath: "/docs/resume-generation.md",
onExpand: (open: boolean) => { onDocumentExpand('resume-generation', open); },
expanded: page === 'resume-generation',
sessionId,
submitQuery: submitQuery,
setSnack,
}} />
<Document {...{
title: "Application Architecture",
filepath: "/docs/about-app.md",
onExpand: (open: boolean) => { onDocumentExpand('about-app', open); },
expanded: page === 'about-app',
sessionId,
submitQuery: submitQuery,
setSnack,
}} />
</Scrollable>;
};
export {
AboutPage
};

View File

@ -33,12 +33,12 @@ import {
isSuccessResponse,
debugConversion,
type ApiResponse
} from '../types/conversion';
} from './types/conversion';
import {
AuthResponse, BaseUser, Guest
} from '../types/types'
} from './types/types'
import { connectionBase } from 'Global';
interface LoginRequest {
login: string;
@ -54,7 +54,7 @@ interface RegisterRequest {
phone?: string;
}
const API_BASE_URL = 'https://backstory-beta.ketrenos.com/api/1.0';
const API_BASE_URL = `${connectionBase}/api/1.0`;
const BackstoryTestApp: React.FC = () => {
const [currentUser, setCurrentUser] = useState<BaseUser | null>(null);

View File

@ -12,13 +12,13 @@ import { SxProps, Theme } from '@mui/material';
import {Header} from './Header';
import { Scrollable } from '../../Components/Scrollable';
import { Scrollable } from './Scrollable';
import { Footer } from './Footer';
import { Snack, SetSnackType } from '../../Components/Snack';
import { Snack, SetSnackType } from './Snack';
import { useUser } from './UserContext';
import { User } from '../../types/types';
import { User } from '../types/types';
import { getBackstoryDynamicRoutes } from './BackstoryRoutes';
import { LoadingComponent } from "../Components/LoadingComponent";
import { LoadingComponent } from "./LoadingComponent";
type NavigationLinkType = {
name: string;

View File

@ -3,22 +3,22 @@ import { Route } from "react-router-dom";
import { useUser } from "./UserContext";
import { Box, Typography, Container, Paper } from '@mui/material';
import { BackstoryPageProps } from '../../Components/BackstoryTab';
import { BackstoryPageProps } from './BackstoryTab';
import { ConversationHandle } from './Conversation';
import { User } from '../../types/types';
import { User } from '../types/types';
import { ChatPage } from '../Pages/ChatPage';
import { ResumeBuilderPage } from '../Pages/ResumeBuilderPage';
import { DocsPage } from '../Pages/DocsPage';
import { CreateProfilePage } from '../Pages/CreateProfilePage';
import { VectorVisualizerPage } from 'Pages/VectorVisualizerPage';
import { HomePage } from '../Pages/HomePage';
import { BetaPage } from '../Pages/BetaPage';
import { CandidateListingPage } from '../Pages/CandidateListingPage';
import { JobAnalysisPage } from '../Pages/JobAnalysisPage';
import { DemoComponent } from "NewApp/Pages/DemoComponent";
import { GenerateCandidate } from "NewApp/Pages/GenerateCandidate";
import { ControlsPage } from '../../Pages/ControlsPage';
import { ChatPage } from '../pages/ChatPage';
import { ResumeBuilderPage } from '../pages/ResumeBuilderPage';
import { DocsPage } from '../pages/DocsPage';
import { CreateProfilePage } from '../pages/CreateProfilePage';
import { VectorVisualizerPage } from '../pages/VectorVisualizerPage';
import { HomePage } from '../pages/HomePage';
import { BetaPage } from '../pages/BetaPage';
import { CandidateListingPage } from '../pages/CandidateListingPage';
import { JobAnalysisPage } from '../pages/JobAnalysisPage';
import { DemoComponent } from "pages/DemoComponent";
import { GenerateCandidate } from "pages/GenerateCandidate";
import { ControlsPage } from '../pages/ControlsPage';
const DashboardPage = () => (<BetaPage><Typography variant="h4">Dashboard</Typography></BetaPage>);
const ProfilePage = () => (<BetaPage><Typography variant="h4">Profile</Typography></BetaPage>);

View File

@ -1,7 +1,7 @@
import React, { ReactElement, JSXElementConstructor } from 'react';
import Box from '@mui/material/Box';
import { SxProps, Theme } from '@mui/material';
import { ChatSubmitQueryInterface } from '../NewApp/Components/ChatQuery';
import { ChatSubmitQueryInterface } from './ChatQuery';
import { SetSnackType } from './Snack';
interface BackstoryElementProps {

View File

@ -10,8 +10,8 @@ import {
import { useMediaQuery } from '@mui/material';
import { useNavigate } from 'react-router-dom';
import { useUser } from "./UserContext";
import { Candidate } from '../../types/types';
import { CopyBubble } from "../../Components/CopyBubble";
import { Candidate } from '../types/types';
import { CopyBubble } from "./CopyBubble";
interface CandidateInfoProps {
sessionId: string;

View File

@ -1,7 +1,7 @@
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import { Query } from "../../types/types";
import { Query } from "../types/types";
type ChatSubmitQueryInterface = (query: Query) => void;

View File

@ -9,13 +9,13 @@ import CancelIcon from '@mui/icons-material/Cancel';
import { SxProps, Theme } from '@mui/material';
import PropagateLoader from "react-spinners/PropagateLoader";
import { Message, MessageList, BackstoryMessage, MessageRoles } from '../../Components/Message';
import { DeleteConfirmation } from '../../Components/DeleteConfirmation';
import { Query } from '../../types/types';
import { BackstoryTextField, BackstoryTextFieldRef } from '../../Components/BackstoryTextField';
import { BackstoryElementProps } from '../../Components/BackstoryTab';
import { connectionBase } from '../../Global';
import { useUser } from "../Components/UserContext";
import { Message, MessageList, BackstoryMessage, MessageRoles } from './Message';
import { DeleteConfirmation } from './DeleteConfirmation';
import { Query } from '../types/types';
import { BackstoryTextField, BackstoryTextFieldRef } from './BackstoryTextField';
import { BackstoryElementProps } from './BackstoryTab';
import { connectionBase } from '../Global';
import { useUser } from "./UserContext";
import { streamQueryResponse, StreamQueryController } from './streamQueryResponse';
import './Conversation.css';

View File

@ -1,9 +1,5 @@
import React, { useState, useEffect } from 'react';
import { Box, Typography } from '@mui/material';
import { Message } from '../../Components/Message';
import { ChatBubble } from '../../Components/ChatBubble';
import { BackstoryElementProps } from '../../Components/BackstoryTab';
import { BackstoryElementProps } from './BackstoryTab';
import { StyledMarkdown } from './StyledMarkdown';
interface DocumentProps extends BackstoryElementProps {

View File

@ -8,19 +8,19 @@ import IconButton from '@mui/material/IconButton';
import CancelIcon from '@mui/icons-material/Cancel';
import SendIcon from '@mui/icons-material/Send';
import PropagateLoader from 'react-spinners/PropagateLoader';
import { CandidateInfo } from '../Components/CandidateInfo';
import { Query } from '../../types/types'
import { Quote } from 'NewApp/Components/Quote';
import { streamQueryResponse, StreamQueryController } from '../Components/streamQueryResponse';
import { CandidateInfo } from './CandidateInfo';
import { Query } from '../types/types'
import { Quote } from 'components/Quote';
import { streamQueryResponse, StreamQueryController } from './streamQueryResponse';
import { connectionBase } from 'Global';
import { User } from '../../types/types';
import { BackstoryElementProps } from 'Components/BackstoryTab';
import { BackstoryTextField, BackstoryTextFieldRef } from 'Components/BackstoryTextField';
import { User } from '../types/types';
import { BackstoryElementProps } from 'components/BackstoryTab';
import { BackstoryTextField, BackstoryTextFieldRef } from 'components/BackstoryTextField';
import { jsonrepair } from 'jsonrepair';
import { StyledMarkdown } from 'NewApp/Components/StyledMarkdown';
import { Scrollable } from 'Components/Scrollable';
import { Pulse } from 'NewApp/Components/Pulse';
import { useUser } from '../Components/UserContext';
import { StyledMarkdown } from 'components/StyledMarkdown';
import { Scrollable } from './Scrollable';
import { Pulse } from 'components/Pulse';
import { useUser } from './UserContext';
interface GenerateImageProps extends BackstoryElementProps {
prompt: string

View File

@ -35,9 +35,9 @@ import { NavigationLinkType } from './BackstoryLayout';
import { Beta } from './Beta';
import './Header.css';
import { useUser } from './UserContext';
import { Candidate, Employer } from '../../types/types';
import { SetSnackType } from '../../Components/Snack';
import { CopyBubble } from '../../Components/CopyBubble';
import { Candidate, Employer } from '../types/types';
import { SetSnackType } from './Snack';
import { CopyBubble } from './CopyBubble';
// Styled components
const StyledAppBar = styled(AppBar, {

View File

@ -10,18 +10,22 @@ import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import CardContent from '@mui/material/CardContent';
import CardActions from '@mui/material/CardActions';
import Collapse from '@mui/material/Collapse';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { ExpandMore } from './ExpandMore';
import { SxProps, Theme } from '@mui/material';
import JsonView from '@uiw/react-json-view';
import React from 'react';
import { Box } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { SxProps, Theme } from '@mui/material';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import LocationSearchingIcon from '@mui/icons-material/LocationSearching';
import { ChatBubble } from './ChatBubble';
import { StyledMarkdown } from '../NewApp/Components/StyledMarkdown';
import { ErrorOutline, InfoOutline, Memory, Psychology, /* Stream, */ } from '@mui/icons-material';
import { StyledMarkdown } from './StyledMarkdown';
import { VectorVisualizer } from './VectorVisualizer';
import { SetSnackType } from './Snack';
@ -72,6 +76,213 @@ type BackstoryMessage = {
expandable?: boolean,
};
interface ChatBubbleProps {
role: MessageRoles,
isInfo?: boolean;
children: React.ReactNode;
sx?: SxProps<Theme>;
className?: string;
title?: string;
expanded?: boolean;
expandable?: boolean;
onExpand?: (open: boolean) => void;
}
function ChatBubble(props: ChatBubbleProps) {
const { role, children, sx, className, title, onExpand, expandable, expanded } = props;
const theme = useTheme();
const defaultRadius = '16px';
const defaultStyle = {
padding: theme.spacing(1, 2),
fontSize: '0.875rem',
alignSelf: 'flex-start',
maxWidth: '100%',
minWidth: '100%',
height: 'fit-content',
'& > *': {
color: 'inherit',
overflow: 'hidden',
m: 0,
},
'& > :last-child': {
mb: 0,
m: 0,
p: 0,
},
};
const styles: any = {
assistant: {
...defaultStyle,
backgroundColor: theme.palette.primary.main,
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`,
color: theme.palette.primary.contrastText,
},
content: {
...defaultStyle,
backgroundColor: '#F5F2EA',
border: `1px solid ${theme.palette.custom.highlight}`,
borderRadius: 0,
alignSelf: 'center',
color: theme.palette.text.primary,
padding: '8px 8px',
marginBottom: '0px',
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.05)',
fontSize: '0.9rem',
lineHeight: '1.3',
fontFamily: theme.typography.fontFamily,
},
error: {
...defaultStyle,
backgroundColor: '#F8E7E7',
border: `1px solid #D83A3A`,
borderRadius: defaultRadius,
maxWidth: '90%',
minWidth: '90%',
alignSelf: 'center',
color: '#8B2525',
padding: '10px 16px',
boxShadow: '0 1px 3px rgba(216, 58, 58, 0.15)',
},
'fact-check': 'qualifications',
'job-description': 'content',
'job-requirements': 'qualifications',
info: {
...defaultStyle,
backgroundColor: '#BFD8D8',
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: defaultRadius,
color: theme.palette.text.primary,
opacity: 0.95,
},
processing: 'status',
qualifications: {
...defaultStyle,
backgroundColor: theme.palette.primary.light,
border: `1px solid ${theme.palette.secondary.main}`,
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`,
color: theme.palette.primary.contrastText,
},
resume: 'content',
searching: 'status',
status: {
...defaultStyle,
backgroundColor: 'rgba(74, 122, 125, 0.15)',
border: `1px solid ${theme.palette.secondary.light}`,
borderRadius: '4px',
maxWidth: '75%',
minWidth: '75%',
alignSelf: 'center',
color: theme.palette.secondary.dark,
fontWeight: 500,
fontSize: '0.95rem',
padding: '8px 12px',
opacity: 0.9,
transition: 'opacity 0.3s ease-in-out',
},
streaming: 'assistant',
system: {
...defaultStyle,
backgroundColor: '#EDEAE0',
border: `1px dashed ${theme.palette.custom.highlight}`,
borderRadius: defaultRadius,
maxWidth: '90%',
minWidth: '90%',
alignSelf: 'center',
color: theme.palette.text.primary,
fontStyle: 'italic',
},
thinking: 'status',
user: {
...defaultStyle,
backgroundColor: theme.palette.background.default,
border: `1px solid ${theme.palette.custom.highlight}`,
borderRadius: `${defaultRadius} ${defaultRadius} 0 ${defaultRadius}`,
alignSelf: 'flex-end',
color: theme.palette.primary.main,
},
};
// Resolve string references in styles
for (const [key, value] of Object.entries(styles)) {
if (typeof value === 'string') {
styles[key] = styles[value];
}
}
const icons: any = {
error: <ErrorOutline color="error" />,
info: <InfoOutline color="info" />,
processing: <LocationSearchingIcon />,
searching: <Memory />,
thinking: <Psychology />,
tooling: <LocationSearchingIcon />,
};
// Render Accordion for expandable content
if (expandable || title) {
// Determine if Accordion is controlled
const isControlled = typeof expanded === 'boolean' && typeof onExpand === 'function';
return (
<Accordion
expanded={isControlled ? expanded : undefined} // Omit expanded prop for uncontrolled
defaultExpanded={expanded} // Default to collapsed for uncontrolled Accordion
className={className}
onChange={(_event, newExpanded) => {
if (isControlled && onExpand) {
onExpand(newExpanded); // Call onExpand with new state
}
}}
sx={{ ...styles[role], ...sx }}
>
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
slotProps={{
content: {
sx: {
fontWeight: 'bold',
fontSize: '1.1rem',
m: 0,
p: 0,
display: 'flex',
justifyItems: 'center',
},
},
}}
>
{title || ''}
</AccordionSummary>
<AccordionDetails sx={{ mt: 0, mb: 0, p: 0, pl: 2, pr: 2 }}>
{children}
</AccordionDetails>
</Accordion>
);
}
// Render non-expandable content
return (
<Box
className={className}
sx={{
...(role in styles ? styles[role] : styles['status']),
gap: 1,
display: 'flex',
...sx,
flexDirection: 'row',
}}
>
{icons[role] !== undefined && icons[role]}
<Box sx={{ p: 0, m: 0, gap: 0, display: 'flex', flexGrow: 1, flexDirection: 'column' }}>
{children}
</Box>
</Box>
);
}
interface MessageMetaData {
query?: {
query_embedding: number[];

View File

@ -6,13 +6,13 @@ import { ChatQuery } from './ChatQuery';
import Box from '@mui/material/Box';
import JsonView from '@uiw/react-json-view';
import { vscodeTheme } from '@uiw/react-json-view/vscode';
import { Mermaid } from '../../Components/Mermaid';
import { Scrollable } from '../../Components/Scrollable';
import { Mermaid } from './Mermaid';
import { Scrollable } from './Scrollable';
import { jsonrepair } from 'jsonrepair';
import { GenerateImage } from './GenerateImage';
import './StyledMarkdown.css';
import { BackstoryElementProps } from '../../Components/BackstoryTab';
import { BackstoryElementProps } from './BackstoryTab';
interface StyledMarkdownProps extends BackstoryElementProps {
className?: string,

View File

@ -1,8 +1,8 @@
import React, { createContext, useContext, useEffect, useState } from "react";
import { Tunables } from '../../types/types';
import { SetSnackType } from '../../Components/Snack';
import { connectionBase } from '../../Global';
import { User } from '../../types/types';
import { Tunables } from '../types/types';
import { SetSnackType } from './Snack';
import { connectionBase } from '../Global';
import { User } from '../types/types';
// Define the UserInfo interface for type safety
interface UserQuestion {

View File

@ -20,7 +20,7 @@ import { Scrollable } from './Scrollable';
import { connectionBase } from '../Global';
import './VectorVisualizer.css';
import { BackstoryPageProps } from './BackstoryTab';
import { BackstoryPageProps } from '../NewApp/Components/BackstoryTab';
import { relative } from 'path';
interface VectorVisualizerProps extends BackstoryPageProps {

View File

@ -1,5 +1,5 @@
import { BackstoryMessage } from '../../Components/Message';
import { Query } from '../../types/types';
import { BackstoryMessage } from './Message';
import { Query } from '../types/types';
import { jsonrepair } from 'jsonrepair';
type StreamQueryOptions = {

View File

@ -3,8 +3,8 @@ import ReactDOM from 'react-dom/client';
import { ThemeProvider } from '@mui/material/styles';
import { backstoryTheme } from './BackstoryTheme';
import { BrowserRouter as Router } from "react-router-dom";
import { BackstoryApp } from './NewApp/BackstoryApp';
import { BackstoryTestApp } from 'NewApp/TestApp';
import { BackstoryApp } from './BackstoryApp';
import { BackstoryTestApp } from 'TestApp';
import './index.css';

View File

@ -14,7 +14,7 @@ import {
import { useTheme } from '@mui/material/styles';
import ConstructionIcon from '@mui/icons-material/Construction';
import RocketLaunchIcon from '@mui/icons-material/RocketLaunch';
import { Beta } from '../Components/Beta';
import { Beta } from '../components/Beta';
interface BetaPageProps {
children?: React.ReactNode;

View File

@ -3,10 +3,10 @@ import { useNavigate } from "react-router-dom";
import Button from '@mui/material/Button';
import Box from '@mui/material/Box';
import { BackstoryPageProps } from '../../Components/BackstoryTab';
import { CandidateInfo } from 'NewApp/Components/CandidateInfo';
import { connectionBase } from '../../Global';
import { Candidate } from "../../types/types";
import { BackstoryPageProps } from '../components/BackstoryTab';
import { CandidateInfo } from 'components/CandidateInfo';
import { connectionBase } from '../Global';
import { Candidate } from "../types/types";
const CandidateListingPage = (props: BackstoryPageProps) => {
const navigate = useNavigate();

View File

@ -5,15 +5,15 @@ import Box from '@mui/material/Box';
import { useTheme } from '@mui/material/styles';
import MuiMarkdown from 'mui-markdown';
import { BackstoryPageProps } from '../../Components/BackstoryTab';
import { Conversation, ConversationHandle } from '../Components/Conversation';
import { ChatQuery } from '../Components/ChatQuery';
import { MessageList } from '../../Components/Message';
import { CandidateInfo } from 'NewApp/Components/CandidateInfo';
import { connectionBase } from '../../Global';
import { LoadingComponent } from 'NewApp/Components/LoadingComponent';
import { useUser } from "../Components/UserContext";
import { Candidate, Tunables } from "../../types/types";
import { BackstoryPageProps } from '../components/BackstoryTab';
import { Conversation, ConversationHandle } from '../components/Conversation';
import { ChatQuery } from '../components/ChatQuery';
import { MessageList } from '../components/Message';
import { CandidateInfo } from 'components/CandidateInfo';
import { connectionBase } from '../Global';
import { LoadingComponent } from 'components/LoadingComponent';
import { useUser } from "../components/UserContext";
import { Candidate, Tunables } from "../types/types";
import { Navigate } from 'react-router-dom';
const ChatPage = forwardRef<ConversationHandle, BackstoryPageProps>((props: BackstoryPageProps, ref) => {

View File

@ -15,7 +15,7 @@ import Typography from '@mui/material/Typography';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
import { connectionBase } from '../Global';
import { BackstoryPageProps } from '../Components/BackstoryTab';
import { BackstoryPageProps } from '../components/BackstoryTab';
interface ServerTunables {
system_prompt: string,

View File

Before

Width:  |  Height:  |  Size: 1.0 MiB

After

Width:  |  Height:  |  Size: 1.0 MiB

View File

Before

Width:  |  Height:  |  Size: 5.6 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

View File

@ -21,7 +21,7 @@ import {
import { styled } from '@mui/material/styles';
import { CloudUpload, PhotoCamera } from '@mui/icons-material';
import { useTheme } from '@mui/material/styles';
import { Beta } from '../Components/Beta';
import { Beta } from '../components/Beta';
// Interfaces
interface ProfileFormData {

View File

@ -1,5 +1,5 @@
import React from 'react';
import {JobMatchAnalysis} from '../Components/JobMatchAnalysis';
import { JobMatchAnalysis } from '../components/JobMatchAnalysis';
// Mock data and functions to simulate your backend
const mockRequirements = [

View File

@ -32,8 +32,8 @@ import PaletteIcon from '@mui/icons-material/Palette';
import AnalyticsIcon from '@mui/icons-material/Analytics';
import ViewQuiltIcon from '@mui/icons-material/ViewQuilt';
import { Document } from '../Components/Document';
import { BackstoryPageProps } from '../../Components/BackstoryTab';
import { Document } from '../components/Document';
import { BackstoryPageProps } from '../components/BackstoryTab';
import { BackstoryUIOverviewPage } from './documents/BackstoryUIOverviewPage';
import { BackstoryAppAnalysisPage } from './documents/BackstoryAppAnalysisPage';
import { BackstoryThemeVisualizerPage } from './documents/BackstoryThemeVisualizerPage';

View File

@ -8,18 +8,18 @@ import IconButton from '@mui/material/IconButton';
import CancelIcon from '@mui/icons-material/Cancel';
import SendIcon from '@mui/icons-material/Send';
import PropagateLoader from 'react-spinners/PropagateLoader';
import { CandidateInfo } from '../Components/CandidateInfo';
import { Query } from '../../types/types'
import { Quote } from 'NewApp/Components/Quote';
import { streamQueryResponse, StreamQueryController } from '../Components/streamQueryResponse';
import { CandidateInfo } from '../components/CandidateInfo';
import { Query } from '../types/types'
import { Quote } from 'components/Quote';
import { streamQueryResponse, StreamQueryController } from '../components/streamQueryResponse';
import { connectionBase } from 'Global';
import { Candidate } from '../../types/types';
import { BackstoryElementProps } from 'Components/BackstoryTab';
import { BackstoryTextField, BackstoryTextFieldRef } from 'Components/BackstoryTextField';
import { Candidate } from '../types/types';
import { BackstoryElementProps } from 'components/BackstoryTab';
import { BackstoryTextField, BackstoryTextFieldRef } from 'components/BackstoryTextField';
import { jsonrepair } from 'jsonrepair';
import { StyledMarkdown } from 'NewApp/Components/StyledMarkdown';
import { Scrollable } from 'Components/Scrollable';
import { Pulse } from 'NewApp/Components/Pulse';
import { StyledMarkdown } from 'components/StyledMarkdown';
import { Scrollable } from '../components/Scrollable';
import { Pulse } from 'components/Pulse';
const emptyUser: Candidate = {
description: "[blank]",

View File

@ -33,7 +33,7 @@ import WorkIcon from '@mui/icons-material/Work';
import AssessmentIcon from '@mui/icons-material/Assessment';
import DescriptionIcon from '@mui/icons-material/Description';
import FileUploadIcon from '@mui/icons-material/FileUpload';
import {JobMatchAnalysis} from '../Components/JobMatchAnalysis';
import { JobMatchAnalysis } from '../components/JobMatchAnalysis';
// Mock types for our application
interface Candidate {

View File

@ -1,6 +1,6 @@
import Box from '@mui/material/Box';
import { BackstoryPageProps } from '../Components/BackstoryTab';
import { BackstoryMessage, Message } from '../Components/Message';
import { BackstoryPageProps } from '../components/BackstoryTab';
import { BackstoryMessage, Message } from '../components/Message';
const LoadingPage = (props: BackstoryPageProps) => {
const backstoryPreamble: BackstoryMessage = {

View File

@ -6,11 +6,11 @@ import {
} from '@mui/material';
import { SxProps } from '@mui/material';
import { ChatQuery } from '../Components/ChatQuery';
import { MessageList, BackstoryMessage } from '../../Components/Message';
import { Conversation } from '../Components/Conversation';
import { BackstoryPageProps } from '../../Components/BackstoryTab';
import { Query } from "../../types/types";
import { ChatQuery } from '../components/ChatQuery';
import { MessageList, BackstoryMessage } from '../components/Message';
import { Conversation } from '../components/Conversation';
import { BackstoryPageProps } from '../components/BackstoryTab';
import { Query } from "../types/types";
import './ResumeBuilderPage.css';

View File

@ -1,7 +1,7 @@
import React from 'react';
import { VectorVisualizer } from '../Components/VectorVisualizer';
import { BackstoryPageProps } from '../Components/BackstoryTab';
import { VectorVisualizer } from '../components/VectorVisualizer';
import { BackstoryPageProps } from '../components/BackstoryTab';
import './VectorVisualizerPage.css';

View File

@ -1,11 +1,11 @@
import React, { useEffect } from "react";
import { Navigate, useParams, useNavigate, useLocation } from "react-router-dom";
import { useUser } from "../Components/UserContext";
import { User } from "../../types/types";
import { useUser } from "../components/UserContext";
import { User } from "../types/types";
import { Box } from "@mui/material";
import { connectionBase } from "../../Global";
import { SetSnackType } from '../../Components/Snack';
import { LoadingComponent } from "../Components/LoadingComponent";
import { connectionBase } from "../Global";
import { SetSnackType } from '../components/Snack';
import { LoadingComponent } from "../components/LoadingComponent";
interface UserRouteProps {
sessionId?: string | null;

View File

@ -983,6 +983,7 @@ class WebServer:
except Exception as e:
raise HTTPException(status_code=503, detail=f"Redis connection failed: {e}")
@self.app.get("/api/redis/stats")
async def redis_stats(redis_client: redis.Redis = Depends(self.get_redis)):
try: