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