Spaces:
Build error
Build error
File size: 18,478 Bytes
1457228 90901b6 1457228 e7602c4 1457228 e7602c4 1457228 2288d1d 1457228 ff8b322 1457228 601a0b4 1457228 90901b6 1457228 cc21f28 1457228 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
import json
from anthropic import Anthropic
import os
def process_ksas(job_description):
ksas = _ksas(job_description)
job_duties, req_quals, pref_quals = ksas['job_duties'], ksas['required_qualifications'], ksas['preferred_qualifications']
ksas_str = 'Job Duties\n' + '\n'.join(job_duties) + '\nRequired Qualifications\n' + '\n'.join(req_quals) + '\nPreferred Qualifications\n' + '\n'.join(pref_quals)
return ksas_str
def _ksas(job_description):
prompt = _ksa_extraction_prompt(job_description)
system = "You are a job description analyzer. Return only JSON in the format: {\"job_duties\": [\"duty 1\", \"duty 2\"], \"required_qualifications\": [\"qual 1\", \"qual 2\"], \"preferred_qualifications\": [\"pref 1\", \"pref 2\"]}"
return call_claude(prompt=prompt, system=system)
def _ksa_extraction_prompt(job_description):
return f"""Extract Key Selection Areas (KSAs) from this job description, maintaining exact original wording. Organize them into these categories:
Job Duties:
- List duties/responsibilities as stated in description
- Include any key activities or deliverables mentioned
Required Qualifications:
- List all explicitly stated required qualifications
- Include any specific metrics (e.g., years of experience)
- Include required technical skills, expertise, or knowledge areas
Preferred Qualifications:
- List only qualifications explicitly marked as "preferred," "desired," or similar
- Maintain any specific metrics mentioned
Do not list any implied requirements.
Format the response as JSON:
{{
"job_duties": ["duty 1", "duty 2", ...],
"required_qualifications": ["qual 1", "qual 2", ...],
"preferred_qualifications": ["pref 1", "pref 2", ...]
}}
Job Description:
{job_description}"""
def process_analysis(resume_data, job_description, ksas, freeform_context):
raw_analysis_output = _analysis(resume_data, job_description, ksas, freeform_context)
output = ["Analysis:"]
for a in raw_analysis_output['analysis']:
output.append("- " + a)
output.append("Questions:")
for q in raw_analysis_output['questions']:
output.append("- " + q)
output.append("Recommendation: " + raw_analysis_output['recommendation']['decision'])
output.append("Rationale: " + raw_analysis_output['recommendation']['rationale'])
return("\n".join(output))
def _analysis(resume_data, job_description, ksas, freeform_context):
prompt = _analysis_prompt(resume_data, job_description, ksas, freeform_context)
system = """You are an expert resume consultant analyzing candidate fit. Return only JSON in the format: {
"analysis": ["key insight 1", "key insight 2", ...],
"questions": ["question 1", "question 2", ...],
"recommendation": {
"decision": "Go/No Go",
"rationale": "Brief explanation"
}
}"""
return call_claude(prompt=prompt, system=system)
def _analysis_prompt(resume_data, job_description, ksas, freeform_context):
return f"""You are an expert resume consultant analyzing a candidate's background for a specific role.
Target Job Description:
{job_description}
Core Requirements (for reference):
{ksas}
Candidate's Resume Data:
{resume_data}
Additional Context and Background:
{freeform_context}
Task:
Review all materials and provide two things:
1. Key insights about how the candidate's experience aligns with the role
2. If applicable, clarifying questions that would help optimize the candidate's application with respect to the core requirements
3. A clear "Go/No Go" recommendation with brief justification
Requirements for Analysis:
- Identify strongest alignment points between experience and job requirements
- Note any potential gaps or areas needing clarification
- Consider both explicit and implicit job requirements
- Focus on relevant experience only
- Do not make assumptions about undocumented experience
Requirements for Questions:
- Ask for specific details that would strengthen the application
- Focus questions on areas where additional context could help highlight relevant experience
- Ask about any ambiguous experiences that might be valuable if clarified
- Only ask questions that would materially improve the application if answered
- Prioritize questions about experiences mentioned in the materials, not hypothetical experience
- Questions should be relevant to the core requirements
Requirements for Recommendation:
- Provide a clear "Go" or "No Go" recommendation
- Base recommendation on alignment between requirements and documented experience
- Consider both minimum and preferred qualifications
- Include 1-2 sentences explaining the recommendation
- Be direct and honest while remaining constructive
Important:
- Only reference information provided in the materials
- Questions should be specific and actionable
- Don't feel like you always need to ask a specific number of questions if you have all of the information you need
- Focus on details that would be appropriate to include in a resume or cover letter
- Consider the role's specific requirements when forming questions
"""
def process_core_content(resume_data, job_description, ksas, freeform_context):
experience_bullets = process_job_experience(resume_data, job_description, ksas, freeform_context)
technical_skills = process_technical_skills(resume_data, job_description, ksas)
return experience_bullets, technical_skills
def process_job_experience(resume_data, job_description, ksas, freeform_context):
output = []
# Process each job experience
for job in resume_data['experience']:
output.append(f"\nOptimizing bullets for: {job['title']}")
optimized = optimize_job_experience(job, job_description, ksas, freeform_context)
output.append("\nOptimized bullets:")
for bullet in optimized['bullets']:
output.append(f"• {bullet}")
return "\n".join(output)
def optimize_job_experience(job_experience, job_description, ksas, freeform_context):
prompt = _experience_optimization_prompt(job_experience, job_description, ksas, freeform_context)
system = "You are an expert resume writer. Return ONLY valid JSON with no explanation, formatting, or additional text. The response must exactly match this format: {\"bullets\": [\"bullet1\", \"bullet2\", ...]}"
return call_claude(prompt=prompt, system=system)
def _experience_optimization_prompt(job_experience, job_description, ksas, freeform_context):
return f"""Given this job experience and target job description, create optimized bullet points that best position the candidate for the role. Choose the number of bullets based on the relevance and importance of this experience to the target role.
Historical Job Title: {job_experience['title']}
Complete Job Description:
{job_description}
Core Requirements (use these as your primary reference for optimization):
{ksas}
Available bullet points and variations:
{_formatted_bullets(job_experience['bullets'])}
Additional Context (use to enhance understanding of experiences):
{freeform_context}
Important:
- Read the complete job description for full context
- When prioritizing content, focus primarily on the Core Requirements listed above
- Use the Additional Context to better understand experience details. You can use the information from this section as necessary, but ensure use the experience bullets as the primary source of information
- If there's ambiguity about an experience, refer to the Additional Context for clarification
- Use strong action verbs
- Quantify impact where possible
- Highlight relevant technical skills
- Focus on achievements over responsibilities
- Maintain truthfulness - only use information present in the variations
- The reader should not be able to tell AI wrote the bullet points
"""
def _formatted_bullets(bullets):
formatted = []
for bullet in bullets:
formatted.append(f"Headline: {bullet['headline']}")
formatted.append("Variations:")
for variation in bullet['variations']:
formatted.append(f"- {variation}")
formatted.append("") # Empty line between bullet groups
return "\n".join(formatted)
def process_technical_skills(resume_data, job_description, ksas):
output = []
raw_tech_skills = resume_data['technical_skills']
optimized_tech_skills = optimize_technical_skills(raw_tech_skills, job_description, ksas)
output.append("Technical Skills:\n\n")
for skill_cat in optimized_tech_skills['technical_skills']:
output.append(skill_cat['category'] + ": " + ', '.join(skill_cat['skills']))
return "\n".join(output)
def optimize_technical_skills(tech_skills, job_description, ksas):
prompt = _skills_prompt(tech_skills, job_description, ksas)
system = "You are an expert resume writer. Return ONLY valid JSON with no explanation or additional text. The response must exactly match this format: {\"technical_skills\": [{\"category\": \"Category Name\", \"skills\": [\"Skill 1\", \"Skill 2\"]}, ...]}"
return call_claude(prompt=prompt, system=system)
def _skills_prompt(all_skills, job_description, ksas):
return f"""You are an expert resume writer helping optimize a technical skills section for a specific role.
Target Job Description:
{job_description}
Core Requirements (use these as your primary reference for optimization):
{ksas}
Available skills and their current categories:
{_formatted_skills(all_skills)}
Task:
Create an optimized technical skills section that best positions the candidate for this role.
Requirements:
1. Read the complete job description for context
2. When selecting and ordering skills, prioritize those that directly match the Core Requirements
3. If there's ambiguity about skill importance, defer to the Core Requirements
4. Order categories from most to least relevant for this specific role
5. Within each category, order skills from most to least relevant
6. Create new categories or rename existing ones if it would better align with the job requirements
7. Include only relevant skills; omit those that don't add value for this role
8. Keep categories and skills lists concise and impactful
9. Use standard industry terminology for categories
Format the response as a JSON list:
{{"technical_skills": [
{{"category": "Category Name", "skills": ["Skill 1", "Skill 2", ...]}},
...
]}}
Important:
- Don't assume skill importance based on frequency of appearance
- Only include skills that are present in the input list
- Focus on skills that align with job requirements
- Ensure category names reflect current industry standards
"""
def _formatted_skills(tech_skills):
cat_str_out = [f"{cat['category']}: " + ', '.join(cat['skills']) for cat in tech_skills]
return("\n".join(cat_str_out))
def process_summary(job_description, ksas, experience_bullets, technical_skills, resume_context, summary_sample):
summary = _summary(job_description, ksas, experience_bullets, technical_skills, resume_context, summary_sample)
summary_str = 'Summary\n' + '\n'.join(summary['summary'])
return summary_str
def _summary(job_description, ksas, experience_bullets, technical_skills, resume_context, summary_sample):
prompt = _summary_prompt(job_description, ksas, experience_bullets, technical_skills, resume_context, summary_sample)
system = "You are an expert resume writer. Return only JSON in the format: {\"summary\": [\"bullet1\", \"bullet2\", ...]}"
return call_claude(prompt=prompt, system=system)
def _summary_prompt(job_description, ksas, experience_bullets, technical_skills, resume_context, summary_sample):
return f"""You are an expert resume writer creating a powerful summary section for a specific role.
Target Job Description:
{job_description}
Core Requirements (use as primary reference):
{ksas}
Candidate's Optimized Experience:
{experience_bullets}
Candidate's Optimized Technical Skills:
{technical_skills}
Additional Context:
{resume_context}
Writing Style Reference:
{summary_sample}
Task:
Create 5-10 impactful summary bullets that will immediately convince the hiring manager to carefully review this resume.
Requirements:
1. Focus heavily on matching the Core Requirements, especially required qualifications
2. Use only information provided in the experience bullets, technical skills, and resume context
3. Do not fabricate or embellish experience
4. Order bullets from most to least relevant to the role
5. Keep total length under 100 words
6. Match the style of the provided summary sample while prioritizing content alignment with job requirements
7. Write for quick scanning - each bullet should build confidence in the candidate's fit
8. If a job requirement isn't addressed, assume the candidate lacks that experience
Format:
Return 5-10 bullets in JSON format: {{"summary": ["bullet1", "bullet2", ...]}}
Important:
- Prioritize demonstrating fit for core job requirements
- Use strong, active language
- Be specific and quantifiable where possible
- Focus on achievements and capabilities
- Maintain truthfulness - only use provided information
- The reader should not be able to tell AI wrote the summary
"""
def _cover_letter_prompt(job_description, ksas, experience_bullets, technical_skills, resume_context, summary, cover_letter_sample):
return f"""You are writing a compelling cover letter for a specific role, matching the candidate's authentic writing style.
Target Job Description:
{job_description}
Core Requirements (for reference):
{ksas}
Candidate's Qualifications and Experience:
Summary:
{summary}
Experience Details:
{experience_bullets}
Technical Skills:
{technical_skills}
Additional Background:
{resume_context}
Writing Style Reference (match this tone and structure):
{cover_letter_sample}
Task:
Write a one-page cover letter that demonstrates the candidate is an excellent fit for this role.
Requirements:
1. Match the candidate's writing style exactly - natural, professional, and personally engaging
2. Focus on experiences that directly address the job's core requirements
3. Use only information provided in the resume materials.
4. Highlight achievements that differentiate the candidate
5. Keep to one page in length
6. Maintain first-person perspective throughout
Important:
- Do not fabricate or embellish any experiences
- If a requirement isn't addressed in the provided materials, do not mention it
- Focus on specific, concrete examples rather than generic statements
- Match the personal, authentic tone of the sample letter
- Match the general structure of the sample letter
- The reader should not be able to tell AI wrote the cover letter
Format the response as JSON: {{"cover_letter": "Dear Hiring Manager,\\n\\n[cover letter content]\\n\\nSincerely,"}}"""
def _cover_letter(job_description, ksas, experience_bullets, technical_skills, resume_context, summary, cover_letter_sample):
prompt = _cover_letter_prompt(job_description, ksas, experience_bullets, technical_skills, resume_context, summary, cover_letter_sample)
system = "You are an expert resume writer crafting cover letters. Return ONLY valid JSON with no explanation or additional text. The response must exactly match this format: {\"cover_letter\": \"Dear Hiring Manager,\\n\\n[letter content]\\n\\nSincerely,\"} Maintain natural writing style and first-person perspective."
return call_claude(prompt=prompt, system=system)['cover_letter']
def call_claude(prompt, system, api_key=None):
api_key = os.environ.get("ANTHROPIC_API_KEY")
if not api_key:
raise ValueError(
"No API key found. Please add your Anthropic API key as a secret named 'ANTHROPIC_API_KEY' in your Space's settings."
)
client = Anthropic(api_key=api_key)
response = client.messages.create(
model="claude-3-7-sonnet-20250219",
max_tokens=1500,
temperature=0,
system=system,
messages=[{
"role": "user",
"content": prompt
}]
)
try:
result = json.loads(response.content[0].text)
return result
except Exception as e:
print("Raw response:", response.content[0].text) # Debug line
raise ValueError(f"Failed to parse Claude's response: {e}") |