-
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Expand file tree
/
Copy pathtemplates.py
More file actions
330 lines (268 loc) · 11.3 KB
/
templates.py
File metadata and controls
330 lines (268 loc) · 11.3 KB
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
"""LLM prompt templates for resume processing."""
# Language code to full name mapping
LANGUAGE_NAMES = {
"en": "English",
"es": "Spanish",
"zh": "Chinese (Simplified)",
"ja": "Japanese",
"pt": "Brazilian Portuguese",
}
def get_language_name(code: str) -> str:
"""Get full language name from code."""
return LANGUAGE_NAMES.get(code, "English")
# Schema with example values - used for prompts to show LLM expected format
RESUME_SCHEMA_EXAMPLE = """{
"personalInfo": {
"name": "John Doe",
"title": "Software Engineer",
"email": "john@example.com",
"phone": "+1-555-0100",
"location": "San Francisco, CA",
"website": "https://johndoe.dev",
"linkedin": "linkedin.com/in/johndoe",
"github": "github.com/johndoe"
},
"summary": "Experienced software engineer with 5+ years...",
"workExperience": [
{
"id": 1,
"title": "Senior Software Engineer",
"company": "Tech Corp",
"location": "San Francisco, CA",
"years": "2020 - Present",
"jobDescription": "Led platform modernization initiatives across customer-facing systems.",
"description": [
"Led development of microservices architecture",
"Improved system performance by 40%"
]
}
],
"education": [
{
"id": 1,
"institution": "University of California",
"degree": "B.S. Computer Science",
"years": "2014 - 2018",
"description": "Graduated with honors"
}
],
"personalProjects": [
{
"id": 1,
"name": "Open Source Tool",
"role": "Creator & Maintainer",
"years": "2021 - Present",
"description": [
"Built CLI tool with 1000+ GitHub stars",
"Used by 50+ companies worldwide"
]
}
],
"additional": {
"technicalSkills": ["Python", "JavaScript", "AWS", "Docker"],
"languages": ["English (Native)", "Spanish (Conversational)"],
"certificationsTraining": ["AWS Solutions Architect"],
"awards": ["Employee of the Year 2022"]
},
"customSections": {
"publications": {
"sectionType": "itemList",
"items": [
{
"id": 1,
"title": "Paper Title",
"subtitle": "Journal Name",
"years": "2023",
"description": ["Brief description of the publication"]
}
]
},
"volunteer_work": {
"sectionType": "text",
"text": "Description of volunteer activities..."
}
}
}"""
PARSE_RESUME_PROMPT = """Parse this resume into JSON. Output ONLY the JSON object, no other text.
Map content to standard sections when possible. For non-standard sections (like Publications, Volunteer Work, Research, Hobbies), add them to customSections with an appropriate type.
Example output format:
{schema}
Custom section types:
- "text": Single text block (e.g., objective, statement)
- "itemList": List of items with title, subtitle, years, description (e.g., publications, research)
- "stringList": Simple list of strings (e.g., hobbies, interests)
Rules:
- Use "" for missing text fields, [] for missing arrays, null for optional fields
- Number IDs starting from 1
- Format years as "YYYY - YYYY" or "YYYY - Present"
- Use snake_case for custom section keys (e.g., "volunteer_work", "publications")
- Preserve the original section name as a descriptive key
- Normalize dates: "Jan 2020" → "2020", "2020-2021" → "2020 - 2021", "Current"/"Ongoing" → "Present"
- For ambiguous dates like "3 years experience", infer approximate years from context or use "~YYYY"
- Flag overlapping dates (concurrent roles) by preserving both, don't merge
Resume to parse:
{resume_text}"""
EXTRACT_KEYWORDS_PROMPT = """Extract job requirements as JSON. Output ONLY the JSON object, no other text.
Example format:
{{
"required_skills": ["Python", "AWS"],
"preferred_skills": ["Kubernetes"],
"experience_requirements": ["5+ years"],
"education_requirements": ["Bachelor's in CS"],
"key_responsibilities": ["Lead team"],
"keywords": ["microservices", "agile"],
"experience_years": 5,
"seniority_level": "senior"
}}
Extract numeric years (e.g., "5+ years" → 5) and infer seniority level.
Job description:
{job_description}"""
CRITICAL_TRUTHFULNESS_RULES_TEMPLATE = """CRITICAL TRUTHFULNESS RULES - NEVER VIOLATE:
1. DO NOT add any skill, tool, technology, or certification that is not explicitly mentioned in the original resume
2. DO NOT invent numeric achievements (e.g., "increased by 30%") unless they exist in original
3. DO NOT add company names, product names, or technical terms not in the original
4. DO NOT upgrade experience level (e.g., "Junior" -> "Senior")
5. DO NOT add languages, frameworks, or platforms the candidate hasn't used
6. DO NOT extend employment dates or change timelines (start/end years)
7. {rule_7}
8. Preserve factual accuracy - only use information provided by the candidate
Violation of these rules could cause serious problems for the candidate in job interviews.
"""
def _build_truthfulness_rules(rule_7: str) -> str:
return CRITICAL_TRUTHFULNESS_RULES_TEMPLATE.format(rule_7=rule_7)
CRITICAL_TRUTHFULNESS_RULES = {
"nudge": _build_truthfulness_rules(
"DO NOT add new bullet points or content - only rephrase existing content"
),
"keywords": _build_truthfulness_rules(
"You may rephrase existing bullet points to include keywords, but do NOT add new bullet points"
),
"full": _build_truthfulness_rules(
"You may expand existing bullet points or add new ones that elaborate on existing work, but DO NOT invent entirely new responsibilities"
),
}
IMPROVE_RESUME_PROMPT_NUDGE = """Lightly nudge this resume toward the job description. Output ONLY the JSON object, no other text.
{critical_truthfulness_rules}
IMPORTANT: Generate ALL text content (summary, descriptions, skills) in {output_language}.
Rules:
- Make minimal, conservative edits only where there is a clear existing match
- Do NOT change the candidate's role, industry, or seniority level
- Do NOT introduce new tools, technologies, or certifications not already present
- Do NOT add new bullet points or sections
- Preserve original bullet count and ordering within each section
- Keep proper nouns (names, company names, locations) unchanged
- Preserve the structure of any customSections from the original resume
- Preserve original date ranges exactly - do not modify years
- If the resume is non-technical, do NOT add technical jargon
- Do NOT use em dash ("—") anywhere in the writing/output, even if it exists, remove it
Job Description:
{job_description}
Keywords to emphasize (only if already supported by resume content):
{job_keywords}
Original Resume:
{original_resume}
Output in this JSON format:
{schema}"""
IMPROVE_RESUME_PROMPT_KEYWORDS = """Enhance this resume with relevant keywords from the job description. Output ONLY the JSON object, no other text.
{critical_truthfulness_rules}
IMPORTANT: Generate ALL text content (summary, descriptions, skills) in {output_language}.
Rules:
- Strengthen alignment by weaving in relevant keywords where evidence already exists
- You may rephrase bullet points to include keyword phrasing
- Do NOT introduce new skills, tools, or certifications not in the resume
- Do NOT change role, industry, or seniority level
- Preserve the structure of any customSections from the original resume
- Preserve original date ranges exactly - do not modify years
- If resume is non-technical, keep language non-technical while still aligning keywords
- Do NOT use em dash ("—") anywhere in the writing/output, even if it exists, remove it
Job Description:
{job_description}
Keywords to emphasize:
{job_keywords}
Original Resume:
{original_resume}
Output in this JSON format:
{schema}"""
IMPROVE_RESUME_PROMPT_FULL = """Tailor this resume for the job. Output ONLY the JSON object, no other text.
{critical_truthfulness_rules}
IMPORTANT: Generate ALL text content (summary, descriptions, skills) in {output_language}.
Rules:
- Rephrase content to highlight relevant experience
- DO NOT invent new information
- Use action verbs and quantifiable achievements
- Keep proper nouns (names, company names, locations) unchanged
- Translate job titles, descriptions, and skills to {output_language}
- Preserve the structure of any customSections from the original resume
- Improve custom section content the same way as standard sections
- Preserve original date ranges exactly - do not modify years
- Calculate and emphasize total relevant experience duration when it matches requirements
- Do NOT use em dash ("—") anywhere in the writing/output, even if it exists, remove it
Job Description:
{job_description}
Keywords to emphasize:
{job_keywords}
Original Resume:
{original_resume}
Output in this JSON format:
{schema}"""
IMPROVE_PROMPT_OPTIONS = [
{
"id": "nudge",
"label": "Light nudge",
"description": "Minimal edits to better align existing experience.",
},
{
"id": "keywords",
"label": "Keyword enhance",
"description": "Blend in relevant keywords without changing role or scope.",
},
{
"id": "full",
"label": "Full tailor",
"description": "Comprehensive tailoring using the job description.",
},
]
IMPROVE_RESUME_PROMPTS = {
"nudge": IMPROVE_RESUME_PROMPT_NUDGE,
"keywords": IMPROVE_RESUME_PROMPT_KEYWORDS,
"full": IMPROVE_RESUME_PROMPT_FULL,
}
DEFAULT_IMPROVE_PROMPT_ID = "keywords"
# Backward-compatible alias
IMPROVE_RESUME_PROMPT = IMPROVE_RESUME_PROMPT_FULL
COVER_LETTER_PROMPT = """Write a brief cover letter for this job application.
IMPORTANT: Write in {output_language}.
Job Description:
{job_description}
Candidate Resume (JSON):
{resume_data}
Requirements:
- 100-150 words maximum
- 3-4 short paragraphs
- Opening: Reference ONE specific thing from the job description (product, tech stack, or problem they're solving) - not generic excitement about "the role"
- Middle: Pick 1-2 qualifications from resume that DIRECTLY match stated requirements - prioritize relevance over impressiveness
- Closing: Simple availability to discuss, no desperate enthusiasm
- If resume shows career transition, frame the pivot as intentional and relevant
- Extract company name from job description - do not use placeholders
- Do NOT invent information not in the resume
- Tone: Confident peer, not eager applicant
- Do NOT use em dash ("—") anywhere in the writing/output, even if it exists, remove it
Output plain text only. No JSON, no markdown formatting."""
OUTREACH_MESSAGE_PROMPT = """Generate a cold outreach message for LinkedIn or email about this job opportunity.
IMPORTANT: Write in {output_language}.
Job Description:
{job_description}
Candidate Resume (JSON):
{resume_data}
Guidelines:
- 70-100 words maximum (shorter than a cover letter)
- First sentence: Reference specific detail from job description (team, product, technical challenge) - never open with "I'm reaching out" or "I saw your posting"
- One sentence on strongest matching qualification with a concrete metric if available
- End with low-friction ask: "Worth a quick chat?" not "I'd love the opportunity to discuss"
- Tone: How you'd message a former colleague, not a stranger
- Do NOT include placeholder brackets
- Do NOT use phrases like "excited about" or "passionate about"
- Do NOT use em dash ("—") anywhere in the writing/output, even if it exists, remove it
Output plain text only. No JSON, no markdown formatting."""
# Alias for backward compatibility
RESUME_SCHEMA = RESUME_SCHEMA_EXAMPLE