Working
This commit is contained in:
parent
b6dd4878c8
commit
538caba9f4
21
frontend/deployed/docs/about-app.md
Normal file
21
frontend/deployed/docs/about-app.md
Normal file
@ -0,0 +1,21 @@
|
||||
Backstory is developed using:
|
||||
|
||||
## Frontend
|
||||
|
||||
* React
|
||||
* MUI
|
||||
* Plotly.js
|
||||
* MuiMarkdown
|
||||
* Mermaid
|
||||
|
||||
## Backend
|
||||
|
||||
* Python
|
||||
* FastAPI
|
||||
* HuggingFace Transformers
|
||||
* Ollama
|
||||
* Backstory Agent Framework
|
||||
* Prometheus
|
||||
* Grafana
|
||||
* ze-monitor
|
||||
* Jupyter Notebook
|
100
frontend/deployed/docs/resume-generation.md
Normal file
100
frontend/deployed/docs/resume-generation.md
Normal file
@ -0,0 +1,100 @@
|
||||
The system follows a carefully designed pipeline with isolated stages to prevent fabrication:
|
||||
|
||||
## System Architecture Overview
|
||||
|
||||
The system uses a pipeline of isolated analysis and generation steps:
|
||||
|
||||
1. **Stage 1: Isolated Analysis** (three sub-stages)
|
||||
- **1A: Job Analysis** - Extracts requirements from job description only
|
||||
- **1B: Candidate Analysis** - Catalogs qualifications from resume/context only
|
||||
- **1C: Mapping Analysis** - Identifies legitimate matches between requirements and qualifications
|
||||
|
||||
2. **Stage 2: Resume Generation**
|
||||
- Uses mapping output to create a tailored resume with evidence-based content
|
||||
|
||||
3. **Stage 3: Verification**
|
||||
- Performs fact-checking to catch any remaining fabrications
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
subgraph "Stage 1: Isolated Analysis"
|
||||
subgraph "Stage 1A: Job Analysis"
|
||||
A1[Job Description Input] --> A2[Job Analysis LLM]
|
||||
A2 --> A3[Job Requirements JSON]
|
||||
end
|
||||
|
||||
subgraph "Stage 1B: Candidate Analysis"
|
||||
B1[Resume & Context Input] --> B2[Candidate Analysis LLM]
|
||||
B2 --> B3[Candidate Qualifications JSON]
|
||||
end
|
||||
|
||||
subgraph "Stage 1C: Mapping Analysis"
|
||||
C1[Job Requirements JSON] --> C2[Candidate Qualifications JSON]
|
||||
C2 --> C3[Mapping Analysis LLM]
|
||||
C3 --> C4[Skills Mapping JSON]
|
||||
end
|
||||
end
|
||||
|
||||
subgraph "Stage 2: Resume Generation"
|
||||
D1[Skills Mapping JSON] --> D2[Original Resume Reference]
|
||||
D2 --> D3[Resume Generation LLM]
|
||||
D3 --> D4[Tailored Resume Draft]
|
||||
end
|
||||
|
||||
subgraph "Stage 3: Verification"
|
||||
E1[Skills Mapping JSON] --> E2[Original Materials]
|
||||
E2 --> E3[Tailored Resume Draft]
|
||||
E3 --> E4[Verification LLM]
|
||||
E4 --> E5{Verification Check}
|
||||
E5 -->|PASS| E6[Approved Resume]
|
||||
E5 -->|FAIL| E7[Correction Instructions]
|
||||
E7 --> D3
|
||||
end
|
||||
|
||||
A3 --> C1
|
||||
B3 --> C2
|
||||
C4 --> D1
|
||||
D4 --> E3
|
||||
|
||||
style A2 fill:#f9d77e,stroke:#333,stroke-width:2px
|
||||
style B2 fill:#f9d77e,stroke:#333,stroke-width:2px
|
||||
style C3 fill:#f9d77e,stroke:#333,stroke-width:2px
|
||||
style D3 fill:#f9d77e,stroke:#333,stroke-width:2px
|
||||
style E4 fill:#f9d77e,stroke:#333,stroke-width:2px
|
||||
style E5 fill:#a3e4d7,stroke:#333,stroke-width:2px
|
||||
style E6 fill:#aed6f1,stroke:#333,stroke-width:2px
|
||||
style E7 fill:#f5b7b1,stroke:#333,stroke-width:2px
|
||||
```
|
||||
|
||||
## Stage 1: Isolated Analysis (three separate sub-stages)
|
||||
|
||||
1. **Job Analysis**: Extracts requirements from just the job description
|
||||
2. **Candidate Analysis**: Catalogs qualifications from just the resume/context
|
||||
3. **Mapping Analysis**: Identifies legitimate matches between requirements and qualifications
|
||||
|
||||
## Stage 2: Resume Generation
|
||||
|
||||
Creates a tailored resume using only verified information from the mapping
|
||||
|
||||
## Stage 3: Verification
|
||||
|
||||
1. Performs fact-checking to catch any remaining fabrications
|
||||
2. Corrects issues if needed and re-verifies
|
||||
|
||||
### Key Anti-Fabrication Mechanisms
|
||||
|
||||
The system uses several techniques to prevent fabrication:
|
||||
|
||||
* **Isolation of Analysis Stages**: By analyzing the job and candidate separately, the system prevents the LLM from prematurely creating connections that might lead to fabrication.
|
||||
* **Evidence Requirements**: Each qualification included must have explicit evidence from the original materials.
|
||||
* **Conservative Transferability**: The system is instructed to be conservative when claiming skills are transferable.
|
||||
* **Verification Layer**: A dedicated verification step acts as a safety check to catch any remaining fabrications.
|
||||
* **Strict JSON Structures**: Using structured JSON formats ensures information flows properly between stages.
|
||||
|
||||
## Implementation Details
|
||||
|
||||
* **Prompt Engineering**: Each stage has carefully designed prompts with clear instructions and output formats.
|
||||
* **Error Handling**: Comprehensive validation and error handling throughout the pipeline.
|
||||
* **Correction Loop**: If verification fails, the system attempts to correct issues and re-verify.
|
||||
* **Traceability**: Information in the final resume can be traced back to specific evidence in the original materials.
|
||||
|
@ -10,11 +10,8 @@ const AboutPage = (props: BackstoryPageProps) => {
|
||||
const [ subRoute, setSubRoute] = useState<string>("");
|
||||
|
||||
useEffect(() => {
|
||||
console.log(`AboutPage: ${page}`);
|
||||
}, [page]);
|
||||
useEffect(() => {
|
||||
console.log(`AboutPage: ${page} - subRoute: ${subRoute}`);
|
||||
}, [subRoute]);
|
||||
console.log(`AboutPage: ${page} - route - ${route} - subRoute: ${subRoute}`);
|
||||
}, [page, route, subRoute]);
|
||||
|
||||
useEffect(() => {
|
||||
if (route === undefined) { return; }
|
||||
@ -31,13 +28,10 @@ const AboutPage = (props: BackstoryPageProps) => {
|
||||
console.log("Document expanded:", document, open);
|
||||
if (open) {
|
||||
setPage(document);
|
||||
if (setRoute) setRoute(document);
|
||||
} else {
|
||||
setPage("");
|
||||
}
|
||||
/* This is just to quiet warnings for now...*/
|
||||
if (route === "never" && subRoute && setRoute) {
|
||||
setRoute(document);
|
||||
setSubRoute(document);
|
||||
if (setRoute) setRoute("");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,14 +79,12 @@ const App = () => {
|
||||
};
|
||||
|
||||
const tabs: BackstoryTabProps[] = useMemo(() => {
|
||||
const tabSx = { flexGrow: 1, fontSize: '1rem' };
|
||||
|
||||
const homeTab: BackstoryTabProps = {
|
||||
label: "",
|
||||
path: "",
|
||||
tabProps: {
|
||||
label: "Backstory",
|
||||
sx: tabSx,
|
||||
sx: { flexGrow: 1, fontSize: '1rem' },
|
||||
icon:
|
||||
<Avatar sx={{
|
||||
width: 24,
|
||||
@ -151,6 +149,20 @@ const App = () => {
|
||||
];
|
||||
}, [sessionId, setSnack, subRoute]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (sessionId === undefined || activeTab > tabs.length - 1) { return; }
|
||||
console.log(`route - '${tabs[activeTab].path}', subRoute - '${subRoute}'`);
|
||||
|
||||
let path = tabs[activeTab].path ? `/${tabs[activeTab].path}` : '';
|
||||
if (subRoute) {
|
||||
path += `/${subRoute}`;
|
||||
}
|
||||
path += `/${sessionId}`;
|
||||
console.log('pushState: ', path);
|
||||
// window.history.pushState({}, '', path);
|
||||
}, [activeTab, sessionId, subRoute, tabs]);
|
||||
|
||||
const fetchSession = useCallback((async (pathParts?: string[]) => {
|
||||
try {
|
||||
const response = await fetch(connectionBase + `/api/context`, {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React from 'react';
|
||||
import { Box } from '@mui/material';
|
||||
import { useTheme } from '@mui/material/styles';
|
||||
import { SxProps, Theme } from '@mui/material';
|
||||
@ -9,7 +9,7 @@ import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import LocationSearchingIcon from '@mui/icons-material/LocationSearching';
|
||||
|
||||
import { MessageRoles } from './Message';
|
||||
import { ErrorOutline, InfoOutline, Memory, Message, Psychology, /* Stream, */ } from '@mui/icons-material';
|
||||
import { ErrorOutline, InfoOutline, Memory, Psychology, /* Stream, */ } from '@mui/icons-material';
|
||||
|
||||
interface ChatBubbleProps {
|
||||
role: MessageRoles,
|
||||
@ -24,9 +24,7 @@ interface ChatBubbleProps {
|
||||
}
|
||||
|
||||
function ChatBubble(props: ChatBubbleProps) {
|
||||
const { role, children, sx, className, title, onExpand, expandable, expanded }: ChatBubbleProps = props;
|
||||
|
||||
console.log("ChatBubbble():", props.expanded);
|
||||
const { role, children, sx, className, title, onExpand, expandable, expanded } = props;
|
||||
|
||||
const theme = useTheme();
|
||||
|
||||
@ -34,12 +32,12 @@ function ChatBubble(props: ChatBubbleProps) {
|
||||
const defaultStyle = {
|
||||
padding: theme.spacing(1, 2),
|
||||
fontSize: '0.875rem',
|
||||
alignSelf: 'flex-start', // Left-aligned is used by default
|
||||
alignSelf: 'flex-start',
|
||||
maxWidth: '100%',
|
||||
minWidth: '100%',
|
||||
height: 'fit-content',
|
||||
'& > *': {
|
||||
color: 'inherit', // Children inherit 'color' from parent
|
||||
color: 'inherit',
|
||||
overflow: 'hidden',
|
||||
m: 0,
|
||||
},
|
||||
@ -47,130 +45,151 @@ function ChatBubble(props: ChatBubbleProps) {
|
||||
mb: 0,
|
||||
m: 0,
|
||||
p: 0,
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
const styles: any = {
|
||||
'assistant': {
|
||||
assistant: {
|
||||
...defaultStyle,
|
||||
backgroundColor: theme.palette.primary.main, // Midnight Blue (#1A2536)
|
||||
border: `1px solid ${theme.palette.secondary.main}`, // Dusty Teal (#4A7A7D)
|
||||
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`, // Rounded, flat bottom-left for assistant
|
||||
color: theme.palette.primary.contrastText, // Warm Gray (#D3CDBF) for text
|
||||
backgroundColor: theme.palette.primary.main,
|
||||
border: `1px solid ${theme.palette.secondary.main}`,
|
||||
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`,
|
||||
color: theme.palette.primary.contrastText,
|
||||
},
|
||||
'content': {
|
||||
content: {
|
||||
...defaultStyle,
|
||||
backgroundColor: '#F5F2EA', // Light cream background for easy reading
|
||||
border: `1px solid ${theme.palette.custom.highlight}`, // Golden Ochre border
|
||||
backgroundColor: '#F5F2EA',
|
||||
border: `1px solid ${theme.palette.custom.highlight}`,
|
||||
borderRadius: 0,
|
||||
alignSelf: 'center', // Centered in the chat
|
||||
color: theme.palette.text.primary, // Charcoal Black for maximum readability
|
||||
padding: '8px 8px', // More generous padding for better text framing
|
||||
marginBottom: '0px', // Space between content and conversation
|
||||
boxShadow: '0 2px 4px rgba(0, 0, 0, 0.05)', // Subtle elevation
|
||||
fontSize: '0.9rem', // Slightly smaller than default
|
||||
lineHeight: '1.3', // More compact line height
|
||||
fontFamily: theme.typography.fontFamily, // Consistent font with your theme
|
||||
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': {
|
||||
error: {
|
||||
...defaultStyle,
|
||||
backgroundColor: '#F8E7E7', // Soft light red background
|
||||
border: `1px solid #D83A3A`, // Prominent red border
|
||||
backgroundColor: '#F8E7E7',
|
||||
border: `1px solid #D83A3A`,
|
||||
borderRadius: defaultRadius,
|
||||
maxWidth: '90%',
|
||||
minWidth: '90%',
|
||||
alignSelf: 'center',
|
||||
color: '#8B2525', // Deep red text for good contrast
|
||||
color: '#8B2525',
|
||||
padding: '10px 16px',
|
||||
boxShadow: '0 1px 3px rgba(216, 58, 58, 0.15)', // Subtle shadow with red tint
|
||||
boxShadow: '0 1px 3px rgba(216, 58, 58, 0.15)',
|
||||
},
|
||||
'fact-check': 'qualifications',
|
||||
'job-description': 'content',
|
||||
'job-requirements': 'qualifications',
|
||||
'info': {
|
||||
info: {
|
||||
...defaultStyle,
|
||||
backgroundColor: '#BFD8D8', // Softened Dusty Teal
|
||||
border: `1px solid ${theme.palette.secondary.main}`, // Dusty Teal
|
||||
backgroundColor: '#BFD8D8',
|
||||
border: `1px solid ${theme.palette.secondary.main}`,
|
||||
borderRadius: defaultRadius,
|
||||
color: theme.palette.text.primary, // Charcoal Black (#2E2E2E) — much better contrast
|
||||
color: theme.palette.text.primary,
|
||||
opacity: 0.95,
|
||||
},
|
||||
'processing': "status",
|
||||
'qualifications': {
|
||||
processing: 'status',
|
||||
qualifications: {
|
||||
...defaultStyle,
|
||||
backgroundColor: theme.palette.primary.light, // Lighter shade, e.g., Soft Blue (#2A3B56)
|
||||
border: `1px solid ${theme.palette.secondary.main}`, // Keep Dusty Teal (#4A7A7D) for contrast
|
||||
borderRadius: `${defaultRadius} ${defaultRadius} ${defaultRadius} 0`, // Unchanged
|
||||
color: theme.palette.primary.contrastText, // Warm Gray (#D3CDBF) for readable text
|
||||
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': {
|
||||
resume: 'content',
|
||||
searching: 'status',
|
||||
status: {
|
||||
...defaultStyle,
|
||||
backgroundColor: 'rgba(74, 122, 125, 0.15)', // Translucent dusty teal
|
||||
border: `1px solid ${theme.palette.secondary.light}`, // Lighter dusty teal
|
||||
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, // Darker dusty teal for text
|
||||
fontWeight: 500, // Slightly bolder than normal
|
||||
fontSize: '0.95rem', // Slightly smaller
|
||||
color: theme.palette.secondary.dark,
|
||||
fontWeight: 500,
|
||||
fontSize: '0.95rem',
|
||||
padding: '8px 12px',
|
||||
opacity: 0.9,
|
||||
transition: 'opacity 0.3s ease-in-out', // Smooth fade effect for appearing/disappearing
|
||||
transition: 'opacity 0.3s ease-in-out',
|
||||
},
|
||||
'streaming': "assistant",
|
||||
'system': {
|
||||
streaming: 'assistant',
|
||||
system: {
|
||||
...defaultStyle,
|
||||
backgroundColor: '#EDEAE0', // Soft warm gray that plays nice with #D3CDBF
|
||||
border: `1px dashed ${theme.palette.custom.highlight}`, // Golden Ochre
|
||||
backgroundColor: '#EDEAE0',
|
||||
border: `1px dashed ${theme.palette.custom.highlight}`,
|
||||
borderRadius: defaultRadius,
|
||||
maxWidth: '90%',
|
||||
minWidth: '90%',
|
||||
alignSelf: 'center',
|
||||
color: theme.palette.text.primary, // Charcoal Black
|
||||
color: theme.palette.text.primary,
|
||||
fontStyle: 'italic',
|
||||
},
|
||||
'thinking': "status",
|
||||
'user': {
|
||||
thinking: 'status',
|
||||
user: {
|
||||
...defaultStyle,
|
||||
backgroundColor: theme.palette.background.default, // Warm Gray (#D3CDBF)
|
||||
border: `1px solid ${theme.palette.custom.highlight}`, // Golden Ochre (#D4A017)
|
||||
borderRadius: `${defaultRadius} ${defaultRadius} 0 ${defaultRadius}`, // Rounded, flat bottom-right for user
|
||||
alignSelf: 'flex-end', // Right-aligned for user
|
||||
color: theme.palette.primary.main, // Midnight Blue (#1A2536) for text
|
||||
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 as any)[key] = styles[value];
|
||||
if (typeof value === 'string') {
|
||||
styles[key] = styles[value];
|
||||
}
|
||||
}
|
||||
|
||||
const icons: any = {
|
||||
"error": <ErrorOutline color='error' />,
|
||||
"info": <InfoOutline color='info' />,
|
||||
"processing": <LocationSearchingIcon />,
|
||||
// "streaming": <Stream />,
|
||||
"searching": <Memory />,
|
||||
"thinking": <Psychology />,
|
||||
"tooling": <LocationSearchingIcon />,
|
||||
error: <ErrorOutline color="error" />,
|
||||
info: <InfoOutline color="info" />,
|
||||
processing: <LocationSearchingIcon />,
|
||||
searching: <Memory />,
|
||||
thinking: <Psychology />,
|
||||
tooling: <LocationSearchingIcon />,
|
||||
};
|
||||
|
||||
// Render Accordion for expandable content
|
||||
if (expandable || (role === 'content' && title)) {
|
||||
// Determine if Accordion is controlled
|
||||
const isControlled = typeof expanded === 'boolean' && typeof onExpand === 'function';
|
||||
|
||||
return (
|
||||
<Accordion
|
||||
expanded={expanded}
|
||||
expanded={isControlled ? expanded : undefined} // Omit expanded prop for uncontrolled
|
||||
defaultExpanded={expanded} // Default to collapsed for uncontrolled Accordion
|
||||
className={className}
|
||||
onChange={() => { console.log(`onChange(${expanded} inverse)`); onExpand && onExpand(!expanded); }}
|
||||
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' } } }}
|
||||
slotProps={{
|
||||
content: {
|
||||
sx: {
|
||||
fontWeight: 'bold',
|
||||
fontSize: '1.1rem',
|
||||
m: 0,
|
||||
p: 0,
|
||||
display: 'flex',
|
||||
justifyItems: 'center',
|
||||
},
|
||||
},
|
||||
}}
|
||||
>
|
||||
{title || ""}
|
||||
{title || ''}
|
||||
</AccordionSummary>
|
||||
<AccordionDetails sx={{ mt: 0, mb: 0, p: 0, pl: 2, pr: 2 }}>
|
||||
{children}
|
||||
@ -179,10 +198,20 @@ function ChatBubble(props: ChatBubbleProps) {
|
||||
);
|
||||
}
|
||||
|
||||
// Render non-expandable content
|
||||
return (
|
||||
<Box className={className} sx={{ ...(role in styles ? styles[role] : styles["status"]), gap: 1, display: "flex", ...sx, flexDirection: "row" }}>
|
||||
<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" }}>
|
||||
<Box sx={{ p: 0, m: 0, gap: 0, display: 'flex', flexGrow: 1, flexDirection: 'column' }}>
|
||||
{children}
|
||||
</Box>
|
||||
</Box>
|
||||
|
@ -511,7 +511,7 @@ const Conversation = forwardRef<ConversationHandle, ConversationProps>(({
|
||||
>
|
||||
{
|
||||
filteredConversation.map((message, index) =>
|
||||
<Message key={index} {...{ sendQuery, message, connectionBase, sessionId, setSnack, submitQuery }} />
|
||||
<Message key={index} expanded={message.expanded === undefined ? true : message.expanded} {...{ sendQuery, message, connectionBase, sessionId, setSnack, submitQuery }} />
|
||||
)
|
||||
}
|
||||
{
|
||||
|
@ -15,8 +15,6 @@ interface DocumentProps extends BackstoryElementProps {
|
||||
const Document = (props: DocumentProps) => {
|
||||
const { setSnack, submitQuery, filepath, content, title, expanded, disableCopy, onExpand, sessionId } = props;
|
||||
|
||||
console.log(`${filepath} expanded: ${expanded}`);
|
||||
|
||||
const [document, setDocument] = useState<string>("");
|
||||
|
||||
// Get the markdown
|
||||
|
@ -1,5 +1,4 @@
|
||||
const getConnectionBase = (loc: any): string => {
|
||||
console.log(`getConnectionBase(${loc})`)
|
||||
if (!loc.host.match(/.*battle-linux.*/)) {
|
||||
return loc.protocol + "//" + loc.host;
|
||||
} else {
|
||||
|
@ -26,7 +26,7 @@ It was written by James Ketrenos in order to provide answers to
|
||||
questions potential employers may have about his work history.
|
||||
|
||||
What would you like to know about James?
|
||||
`
|
||||
`,
|
||||
}
|
||||
];
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { useState, useRef, useEffect } from 'react';
|
||||
import { useState, useRef } from 'react';
|
||||
import Divider from '@mui/material/Divider';
|
||||
import Accordion from '@mui/material/Accordion';
|
||||
import AccordionSummary from '@mui/material/AccordionSummary';
|
||||
@ -237,8 +237,8 @@ const MessageMeta = (props: MessageMetaProps) => {
|
||||
};
|
||||
|
||||
const Message = (props: MessageProps) => {
|
||||
const { message, submitQuery, sx, className, onExpand, expanded } = props;
|
||||
const [metaExpanded, setMetaExpanded] = useState<boolean>(props.expanded || false);
|
||||
const { message, submitQuery, sx, className, onExpand, expanded, sessionId, setSnack } = props;
|
||||
const [metaExpanded, setMetaExpanded] = useState<boolean>(false);
|
||||
const textFieldRef = useRef(null);
|
||||
|
||||
const handleMetaExpandClick = () => {
|
||||
@ -287,7 +287,7 @@ const Message = (props: MessageProps) => {
|
||||
overflow: "auto", /* Handles scrolling for the div */
|
||||
}}
|
||||
>
|
||||
<StyledMarkdown {...{ content: formattedContent, submitQuery }} />
|
||||
<StyledMarkdown {...{ content: formattedContent, submitQuery, sessionId, setSnack }} />
|
||||
</Scrollable>
|
||||
:
|
||||
<Typography
|
||||
@ -318,7 +318,7 @@ const Message = (props: MessageProps) => {
|
||||
)}
|
||||
</CardActions>
|
||||
{message.metadata && <>
|
||||
<Collapse in={expanded} timeout="auto" unmountOnExit>
|
||||
<Collapse in={metaExpanded} timeout="auto" unmountOnExit>
|
||||
<CardContent>
|
||||
<MessageMeta messageProps={props} metadata={message.metadata} />
|
||||
</CardContent>
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { MuiMarkdown } from 'mui-markdown';
|
||||
import { SxProps, useTheme } from '@mui/material/styles';
|
||||
import { Link } from '@mui/material';
|
||||
import { ChatQuery, QueryOptions } from './ChatQuery';
|
||||
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';
|
||||
@ -11,12 +11,12 @@ import { Scrollable } from './Scrollable';
|
||||
import { jsonrepair } from 'jsonrepair';
|
||||
|
||||
import './StyledMarkdown.css';
|
||||
import { BackstoryElementProps } from './BackstoryTab';
|
||||
|
||||
interface StyledMarkdownProps {
|
||||
interface StyledMarkdownProps extends BackstoryElementProps {
|
||||
className?: string,
|
||||
content: string,
|
||||
sx?: SxProps,
|
||||
submitQuery?: (prompt: string, tunables?: QueryOptions) => void,
|
||||
};
|
||||
|
||||
const StyledMarkdown: React.FC<StyledMarkdownProps> = (props: StyledMarkdownProps) => {
|
||||
@ -53,6 +53,7 @@ const StyledMarkdown: React.FC<StyledMarkdownProps> = (props: StyledMarkdownProp
|
||||
displayDataTypes={false}
|
||||
objectSortKeys={false}
|
||||
collapsed={false}
|
||||
shortenTextAfterLength={100}
|
||||
value={JSON.parse(fixed)}>
|
||||
<JsonView.String
|
||||
render={({ children, ...reset }) => {
|
||||
@ -84,17 +85,13 @@ const StyledMarkdown: React.FC<StyledMarkdownProps> = (props: StyledMarkdownProp
|
||||
}
|
||||
}
|
||||
},
|
||||
chatQuery: undefined
|
||||
};
|
||||
|
||||
if (submitQuery) {
|
||||
overrides.ChatQuery = {
|
||||
ChatQuery: {
|
||||
component: ChatQuery,
|
||||
props: {
|
||||
submitQuery,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return <Box
|
||||
className={`MuiMarkdown ${className || ""}`}
|
||||
|
@ -108,7 +108,7 @@ const symbolMap: Record<string, string> = {
|
||||
};
|
||||
|
||||
const VectorVisualizer: React.FC<VectorVisualizerProps> = (props: VectorVisualizerProps) => {
|
||||
const { setSnack, rag, inline, sessionId, sx } = props;
|
||||
const { setSnack, rag, inline, sessionId, sx, submitQuery } = props;
|
||||
const [plotData, setPlotData] = useState<PlotData | null>(null);
|
||||
const [newQuery, setNewQuery] = useState<string>('');
|
||||
const [newQueryEmbedding, setNewQueryEmbedding] = useState<ChromaResult | undefined>(undefined);
|
||||
@ -436,7 +436,7 @@ const VectorVisualizer: React.FC<VectorVisualizerProps> = (props: VectorVisualiz
|
||||
wordBreak: 'break-all',
|
||||
}}
|
||||
>
|
||||
<StyledMarkdown sx={{ p: 1, pt: 0 }} content={tooltip?.content || "Select a node in the visualization."} />
|
||||
<StyledMarkdown sx={{ p: 1, pt: 0 }} content={tooltip?.content || "Select a node in the visualization."} {...{ sessionId, setSnack, submitQuery }} />
|
||||
</Scrollable>
|
||||
}
|
||||
</Card>
|
||||
|
Loading…
x
Reference in New Issue
Block a user