This commit is contained in:
James Ketr 2025-06-09 16:37:47 -07:00
parent a197535bea
commit 149ce9e9b3
3 changed files with 114 additions and 16 deletions

View File

@ -61,16 +61,18 @@ const ResumeGenerator: React.FC<ResumeGeneratorProps> = (props: ResumeGeneratorP
if (!job || !candidate || !skills || resume || generating) {
return;
}
const generateResume = async () => {
setGenerating(true);
const generateResume = async () => {
const request : any = await apiClient.generateResume(candidate.id || '', skills, generateResumeHandlers);
const result = await request.promise;
setSystemPrompt(result.systemPrompt)
setPrompt(result.prompt)
setResume(result.resume)
setGenerating(false);
};
generateResume()
setGenerating(true);
generateResume().then(() =>{
setGenerating(false);
});
}, [job, candidate, apiClient, resume, skills, generating]);
return (
@ -82,9 +84,9 @@ const ResumeGenerator: React.FC<ResumeGeneratorProps> = (props: ResumeGeneratorP
}}>
<Box sx={{ borderBottom: 1, borderColor: 'divider', mb: 3 }}>
<Tabs value={tabValue} onChange={handleTabChange} centered>
<Tab value="system" icon={<TuneIcon />} label="System" />
<Tab value="prompt" icon={<InputIcon />} label="Prompt" />
<Tab value="resume" icon={<ArticleIcon />} label="Resume" />
<Tab sx={{display: systemPrompt ? "flex" : "none"}} value="system" icon={<TuneIcon />} label="System" />
<Tab sx={{display: prompt ? "flex" : "none"}}value="prompt" icon={<InputIcon />} label="Prompt" />
<Tab sx={{display: resume ? "flex" : "none"}}value="resume" icon={<ArticleIcon />} label="Resume" />
</Tabs>
</Box>
{ statusMessage && <Message message={statusMessage} />}

View File

@ -1,5 +1,5 @@
import React from 'react';
import { Box, Link, Typography, Avatar, Grid, SxProps, CardActions } from '@mui/material';
import React, { JSX } from 'react';
import { Box, Link, Typography, Avatar, Grid, SxProps, CardActions, Chip, Stack, CardHeader } from '@mui/material';
import {
Card,
CardContent,
@ -14,6 +14,7 @@ import { rest } from 'lodash';
import { AIBanner } from 'components/ui/AIBanner';
import { useAuth } from 'hooks/AuthContext';
import { DeleteConfirmation } from '../DeleteConfirmation';
import { Build, CheckCircle, Description, Psychology, Star, Work } from '@mui/icons-material';
interface JobInfoProps {
job: JobFull;
@ -45,7 +46,97 @@ const JobInfo: React.FC<JobInfoProps> = (props: JobInfoProps) => {
if (!job) {
return <Box>No user loaded.</Box>;
}
console.log(job);
const renderRequirementSection = (title: string, items: string[] | undefined, icon: JSX.Element, required = false) => {
if (!items || items.length === 0) return null;
return (
<Box sx={{ mb: 2 }}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1.5 }}>
{icon}
<Typography variant="subtitle1" sx={{ ml: 1, fontWeight: 600, fontSize: '0.85rem !important'}}>
{title}
</Typography>
{required && <Chip label="Required" size="small" color="error" sx={{ ml: 1, fontSize: '0.75rem !important' }} />}
</Box>
<Stack direction="row" spacing={1} flexWrap="wrap" useFlexGap>
{items.map((item, index) => (
<Chip
key={index}
label={item}
variant="outlined"
size="small"
sx={{ mb: 1, fontSize: '0.75rem !important' }}
/>
))}
</Stack>
</Box>
);
};
const renderJobRequirements = () => {
if (!job.requirements) return null;
return (
<Card elevation={0} sx={{ m: 0, p: 0, mt: 2, }}>
<CardHeader
title="Job Requirements Analysis"
avatar={<CheckCircle color="success" />}
sx={{ p: 0, pb: 1 }}
/>
<CardContent sx={{ p: 0 }}>
{renderRequirementSection(
"Technical Skills (Required)",
job.requirements.technicalSkills.required,
<Build color="primary" />,
true
)}
{renderRequirementSection(
"Technical Skills (Preferred)",
job.requirements.technicalSkills.preferred,
<Build color="action" />
)}
{renderRequirementSection(
"Experience Requirements (Required)",
job.requirements.experienceRequirements.required,
<Work color="primary" />,
true
)}
{renderRequirementSection(
"Experience Requirements (Preferred)",
job.requirements.experienceRequirements.preferred,
<Work color="action" />
)}
{renderRequirementSection(
"Soft Skills",
job.requirements.softSkills,
<Psychology color="secondary" />
)}
{renderRequirementSection(
"Experience",
job.requirements.experience,
<Star color="warning" />
)}
{renderRequirementSection(
"Education",
job.requirements.education,
<Description color="info" />
)}
{renderRequirementSection(
"Certifications",
job.requirements.certifications,
<CheckCircle color="success" />
)}
{renderRequirementSection(
"Preferred Attributes",
job.requirements.preferredAttributes,
<Star color="secondary" />
)}
</CardContent>
</Card>
);
};
return (
<Card
elevation={elevation}
@ -90,6 +181,10 @@ const JobInfo: React.FC<JobInfoProps> = (props: JobInfoProps) => {
</Typography>
}
</>}
<Divider/>
{renderJobRequirements()}
</CardContent>
<CardActions>
{isAdmin &&

View File

@ -136,13 +136,14 @@ Phone: {self.user.phone or 'N/A'}
- Professional Summary (highlight strongest skills and experience level)
- Skills (organized by strength)
- Professional Experience (focus on achievements and evidence of the skill)
- If present in material, provide an Education section
- If present in material, provide a Certifications section
4. Optional sections, to include only if evidence is present:
- Education section
Certifications section
- Additional sections as appropriate
4. Use action verbs and quantifiable achievements where possible.
5. Maintain a professional tone throughout.
6. Be concise and impactful - the resume should be 1-2 pages MAXIMUM.
7. Ensure all information is accurate to the original resume - do not embellish or fabricate experiences.
5. Use action verbs and quantifiable achievements where possible.
6. Maintain a professional tone throughout.
7. Be concise and impactful - the resume should be 1-2 pages MAXIMUM.
8. Ensure all information is accurate to the original resume - do not embellish or fabricate experiences.
## OUTPUT FORMAT:
Provide the resume in clean markdown format, ready for the candidate to use.