Anthropic backend working
Add regenerate skill assessment
This commit is contained in:
parent
fd6ec5015c
commit
179bef1564
@ -15,6 +15,7 @@ services:
|
||||
- REDIS_URL=redis://redis:6379
|
||||
- REDIS_DB=0
|
||||
- SSL_ENABLED=true
|
||||
# To use Anthropic, uncomment the following lines and comment out the OpenAI lines
|
||||
# - DEFAULT_LLM_PROVIDER=anthropic
|
||||
# - MODEL_NAME=claude-3-5-haiku-latest
|
||||
- DEFAULT_LLM_PROVIDER=openai
|
||||
|
@ -15,10 +15,13 @@ import {
|
||||
Button,
|
||||
Paper,
|
||||
SxProps,
|
||||
Tooltip,
|
||||
IconButton,
|
||||
} from '@mui/material';
|
||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';
|
||||
import CheckCircleIcon from '@mui/icons-material/CheckCircle';
|
||||
import ErrorIcon from '@mui/icons-material/Error';
|
||||
import ModelTrainingIcon from '@mui/icons-material/ModelTraining';
|
||||
import PendingIcon from '@mui/icons-material/Pending';
|
||||
import WarningIcon from '@mui/icons-material/Warning';
|
||||
import { Candidate, SkillAssessment, SkillStatus } from 'types/types';
|
||||
@ -261,7 +264,8 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
const skillMatchHandlers = useMemo(() => {
|
||||
return {
|
||||
onStatus: (status: Types.ChatMessageStatus): void => {
|
||||
setMatchStatus(status.content.toLowerCase());
|
||||
console.log('Skill Match Status:', status.content);
|
||||
setMatchStatus(status.content);
|
||||
},
|
||||
};
|
||||
}, [setMatchStatus]);
|
||||
@ -305,6 +309,7 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
const request = await apiClient.candidateMatchForRequirement(
|
||||
candidate.id || '',
|
||||
requirements[i].requirement,
|
||||
false,
|
||||
skillMatchHandlers
|
||||
);
|
||||
const result = await request.promise; /* Wait for the streaming result to complete */
|
||||
@ -410,6 +415,64 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
return <ErrorIcon color="error" />;
|
||||
};
|
||||
|
||||
const handleAssesmentRegenerate = async (index: number, skill: string): Promise<void> => {
|
||||
setSkillMatches(prev => {
|
||||
const updated = [...prev];
|
||||
updated[index] = {
|
||||
...updated[index],
|
||||
status: 'pending',
|
||||
assessment: '',
|
||||
evidenceDetails: [],
|
||||
evidenceStrength: 'none',
|
||||
matchScore: 0,
|
||||
};
|
||||
return updated;
|
||||
});
|
||||
setMatchStatus('Regenerating assessment...');
|
||||
const request = apiClient.candidateMatchForRequirement(
|
||||
candidate.id || '',
|
||||
skill,
|
||||
true,
|
||||
skillMatchHandlers
|
||||
);
|
||||
const result = await request.promise; /* Wait for the streaming result to complete */
|
||||
const skillMatch = result.skillAssessment;
|
||||
setMatchStatus('');
|
||||
setSkillMatches(prev => {
|
||||
const updated = [...prev];
|
||||
updated[index] = {
|
||||
...skillMatch,
|
||||
status: 'complete',
|
||||
matchScore: calculateScore(skillMatch),
|
||||
domain: updated[index].domain,
|
||||
};
|
||||
return updated;
|
||||
});
|
||||
// Update overall score
|
||||
setSkillMatches(current => {
|
||||
const completedMatches = current.filter(match => match.status === 'complete');
|
||||
if (completedMatches.length > 0) {
|
||||
const newOverallScore =
|
||||
completedMatches.reduce((sum, match) => sum + match.matchScore, 0) /
|
||||
completedMatches.length;
|
||||
setOverallScore(Math.round(newOverallScore));
|
||||
}
|
||||
return current;
|
||||
});
|
||||
setAnalysis({
|
||||
score: overallScore,
|
||||
skills: skillMatches,
|
||||
});
|
||||
onAnalysisComplete &&
|
||||
onAnalysisComplete({
|
||||
score: overallScore,
|
||||
skills: skillMatches,
|
||||
});
|
||||
setStartAnalysis(false);
|
||||
setAnalyzing(false);
|
||||
setFirstRun(false);
|
||||
};
|
||||
|
||||
const beginAnalysis = (): void => {
|
||||
initializeRequirements(job);
|
||||
setStartAnalysis(true);
|
||||
@ -595,6 +658,7 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
bgcolor: getMatchColor(match.matchScore),
|
||||
color: 'white',
|
||||
minWidth: 90,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
) : match.status === 'waiting' ? (
|
||||
@ -605,6 +669,7 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
bgcolor: 'rgb(189, 173, 85)',
|
||||
color: 'white',
|
||||
minWidth: 90,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
) : match.status === 'pending' ? (
|
||||
@ -615,6 +680,7 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
bgcolor: theme.palette.grey[400],
|
||||
color: 'white',
|
||||
minWidth: 90,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
@ -625,6 +691,7 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
bgcolor: theme.palette.error.main,
|
||||
color: 'white',
|
||||
minWidth: 90,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
@ -709,6 +776,19 @@ const JobMatchAnalysis: React.FC<JobAnalysisProps> = (props: JobAnalysisProps) =
|
||||
Skill description
|
||||
</Typography>
|
||||
<Typography paragraph>{match.description}</Typography>
|
||||
{match.status === 'complete' && (
|
||||
<Tooltip title="Regenerate Assessment">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(e): void => {
|
||||
e.stopPropagation();
|
||||
handleAssesmentRegenerate(index, match.skill);
|
||||
}}
|
||||
>
|
||||
<ModelTrainingIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
)}
|
||||
{/* { match.ragResults && match.ragResults.length !== 0 && <>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
RAG Information
|
||||
|
@ -211,11 +211,14 @@ const MessageMeta = (props: MessageMetaProps): JSX.Element => {
|
||||
/* MessageData */
|
||||
ragResults = [],
|
||||
tools = null,
|
||||
} = props.metadata || {};
|
||||
const {
|
||||
evalCount = 0,
|
||||
evalDuration = 0,
|
||||
promptEvalCount = 0,
|
||||
promptEvalDuration = 0,
|
||||
} = props.metadata || {};
|
||||
} = props.metadata.usage || {};
|
||||
|
||||
const message: ChatMessage | ChatMessageError | ChatMessageStatus = props.messageProps.message;
|
||||
|
||||
// let llm_submission = '<|system|>\n';
|
||||
|
@ -418,6 +418,7 @@ const JobsView: React.FC<JobsViewProps> = ({
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell>Description</TableCell>
|
||||
<TableCell>Pay Range</TableCell>
|
||||
{!isMobile && (
|
||||
<>
|
||||
<TableCell>Owner</TableCell>
|
||||
@ -499,6 +500,10 @@ const JobsView: React.FC<JobsViewProps> = ({
|
||||
{truncateDescription(job.summary || job.description || '', 100)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
{job.payMinimum ? job.payMinimum : 'N/A'}-
|
||||
{job.payMaximum ? job.payMaximum : 'N/A'}
|
||||
</TableCell>
|
||||
{!isMobile && (
|
||||
<>
|
||||
<TableCell>
|
||||
|
@ -26,10 +26,12 @@ const emptyMetadata: ChatMessageMetaData = {
|
||||
frequencyPenalty: 0,
|
||||
presencePenalty: 0,
|
||||
stopSequences: [],
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
usage: {
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultMessage: ChatMessage = {
|
||||
|
@ -32,10 +32,12 @@ const emptyMetadata: ChatMessageMetaData = {
|
||||
frequencyPenalty: 0,
|
||||
presencePenalty: 0,
|
||||
stopSequences: [],
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
usage: {
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultMessage: ChatMessage = {
|
||||
|
@ -38,10 +38,12 @@ const emptyMetadata: ChatMessageMetaData = {
|
||||
frequencyPenalty: 0,
|
||||
presencePenalty: 0,
|
||||
stopSequences: [],
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
usage: {
|
||||
evalCount: 0,
|
||||
evalDuration: 0,
|
||||
promptEvalCount: 0,
|
||||
promptEvalDuration: 0,
|
||||
},
|
||||
};
|
||||
|
||||
const defaultMessage: ChatMessage = {
|
||||
|
@ -1148,9 +1148,10 @@ class ApiClient {
|
||||
candidateMatchForRequirement(
|
||||
candidate_id: string,
|
||||
requirement: string,
|
||||
regenerate: boolean = false,
|
||||
streamingOptions?: StreamingOptions<Types.ChatMessageSkillAssessment>
|
||||
): StreamingResponse<Types.ChatMessageSkillAssessment> {
|
||||
const body = JSON.stringify(requirement);
|
||||
const body = JSON.stringify({ skill: requirement, regenerate });
|
||||
streamingOptions = {
|
||||
...streamingOptions,
|
||||
headers: this.defaultHeaders,
|
||||
|
@ -1,6 +1,6 @@
|
||||
// Generated TypeScript types from Pydantic models
|
||||
// Source: src/backend/models.py
|
||||
// Generated on: 2025-07-09T20:57:47.233946
|
||||
// Generated on: 2025-07-11T20:02:47.037054
|
||||
// DO NOT EDIT MANUALLY - This file is auto-generated
|
||||
|
||||
// ============================
|
||||
@ -323,10 +323,7 @@ export interface ChatMessageMetaData {
|
||||
stopSequences: Array<string>;
|
||||
ragResults?: Array<ChromaDBGetResponse>;
|
||||
llmHistory?: Array<any>;
|
||||
evalCount: number;
|
||||
evalDuration: number;
|
||||
promptEvalCount: number;
|
||||
promptEvalDuration: number;
|
||||
usage?: UsageStats;
|
||||
options?: ChatOptions;
|
||||
tools?: Tool;
|
||||
timers?: Record<string, number>;
|
||||
@ -416,6 +413,14 @@ export interface ChatQuery {
|
||||
agentOptions?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface ChatResponse {
|
||||
content: string;
|
||||
model: string;
|
||||
finishReason?: string;
|
||||
usage?: UsageStats;
|
||||
usage_dict?: Record<string, number>;
|
||||
}
|
||||
|
||||
export interface ChatSession {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
@ -714,6 +719,8 @@ export interface Job {
|
||||
title?: string;
|
||||
summary?: string;
|
||||
company?: string;
|
||||
payMinimum?: string;
|
||||
payMaximum?: string;
|
||||
description: string;
|
||||
requirements?: JobRequirements;
|
||||
createdAt?: Date;
|
||||
@ -1051,6 +1058,11 @@ export interface SkillAssessment {
|
||||
matchScore: number;
|
||||
}
|
||||
|
||||
export interface SkillMatchRequest {
|
||||
skill: string;
|
||||
regenerate: boolean;
|
||||
}
|
||||
|
||||
export interface SocialLink {
|
||||
platform: "linkedin" | "twitter" | "github" | "dribbble" | "behance" | "website" | "other";
|
||||
url: string;
|
||||
@ -1060,6 +1072,7 @@ export interface SystemInfo {
|
||||
installedRAM: string;
|
||||
graphicsCards: Array<GPUInfo>;
|
||||
CPU: string;
|
||||
llmBackend: string;
|
||||
llmModel: string;
|
||||
embeddingModel: string;
|
||||
maxContextLength: number;
|
||||
@ -1083,6 +1096,20 @@ export interface Tunables {
|
||||
enableContext: boolean;
|
||||
}
|
||||
|
||||
export interface UsageStats {
|
||||
promptTokens?: number;
|
||||
completionTokens?: number;
|
||||
totalTokens?: number;
|
||||
promptEvalCount?: number;
|
||||
promptEvalDuration?: number;
|
||||
evalCount?: number;
|
||||
evalDuration?: number;
|
||||
totalDuration?: number;
|
||||
tokensPerSecond?: number;
|
||||
promptTokensPerSecond?: number;
|
||||
extraStats?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface UserActivity {
|
||||
id?: string;
|
||||
userId?: string;
|
||||
|
Loading…
x
Reference in New Issue
Block a user