mirror of
https://github.com/x1xhlol/system-prompts-and-models-of-ai-tools.git
synced 2026-06-18 15:29:36 +00:00
Complete AI-powered personal brand automation for Sami Assiri.\n\n7 agents: LinkedIn, Email, Social Media, WhatsApp, CV Optimizer, Content Strategist, Opportunity Scout.\nInfra: FastAPI + APScheduler + Docker + Ollama/Groq LLM + GitHub Pages landing page.\n83 files, ~10K lines. Cost: $0-5/month.
165 lines
5.7 KiB
Python
165 lines
5.7 KiB
Python
"""CV content enhancer -- uses LLM to polish bullet points and optimize for ATS."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
from typing import Any
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# System prompt for the CV-enhancement LLM call
|
|
# ---------------------------------------------------------------------------
|
|
|
|
_SYSTEM_PROMPT = """\
|
|
You are an expert CV/resume writer specializing in engineering and technical roles.
|
|
Your task is to enhance the provided professional profile for maximum impact.
|
|
|
|
Rules:
|
|
1. Start every bullet point with a strong action verb (Engineered, Spearheaded, Optimized, etc.)
|
|
2. Quantify achievements wherever possible (%, $, counts, time saved)
|
|
3. Include relevant ATS keywords for: airport security, field services engineering,
|
|
mechanical engineering, Smiths Detection, X-ray screening, Python, data analytics
|
|
4. Keep descriptions concise -- max 2 lines per bullet
|
|
5. Maintain factual accuracy -- do NOT invent numbers or achievements
|
|
6. Preserve the original meaning; only improve phrasing and keyword density
|
|
7. Ensure the professional summary is compelling and tailored for field services /
|
|
airport security engineering roles
|
|
|
|
Return a JSON object with these keys:
|
|
- "summary_en": enhanced English professional summary (3-4 sentences)
|
|
- "summary_ar": enhanced Arabic professional summary (3-4 sentences)
|
|
- "current_role_bullets": list of enhanced bullet strings for the current role
|
|
- "previous_roles": list of objects, each with "company", "title", "bullets" (list of strings)
|
|
- "leadership": list of objects, each with "role", "organization", "bullets"
|
|
- "skills_keywords": list of top 20 ATS keywords extracted from the profile
|
|
"""
|
|
|
|
|
|
async def enhance_cv_content(llm_client: Any, brand_profile: dict) -> dict:
|
|
"""Call the LLM to enhance CV content and return an enriched profile dict.
|
|
|
|
Parameters
|
|
----------
|
|
llm_client:
|
|
An :class:`LLMClient` (or compatible) instance.
|
|
brand_profile:
|
|
Parsed ``brand_profile.yaml`` dict.
|
|
|
|
Returns
|
|
-------
|
|
dict
|
|
The original *brand_profile* merged with enhanced descriptions stored
|
|
under the ``"enhanced"`` key.
|
|
"""
|
|
# Build the user prompt with the raw profile data
|
|
personal = brand_profile.get("personal", {})
|
|
employment = brand_profile.get("employment", {})
|
|
leadership = brand_profile.get("leadership", [])
|
|
skills = brand_profile.get("skills", {})
|
|
certifications = brand_profile.get("certifications", [])
|
|
awards = brand_profile.get("awards", [])
|
|
|
|
user_prompt = f"""\
|
|
Enhance the following professional profile for a CV/resume.
|
|
|
|
=== PERSONAL ===
|
|
Name: {personal.get('name_en', '')}
|
|
Title: {personal.get('title_en', '')}
|
|
Bio (EN): {personal.get('bio_en', '')}
|
|
Bio (AR): {personal.get('bio_ar', '')}
|
|
|
|
=== CURRENT ROLE ===
|
|
Company: {employment.get('current', {}).get('company', '')}
|
|
Title: {employment.get('current', {}).get('title', '')}
|
|
Location: {employment.get('current', {}).get('location', '')}
|
|
Description:
|
|
{employment.get('current', {}).get('description_en', '')}
|
|
|
|
=== PREVIOUS ROLES ===
|
|
{_format_previous_roles(employment.get('previous', []))}
|
|
|
|
=== LEADERSHIP ===
|
|
{_format_leadership(leadership)}
|
|
|
|
=== SKILLS ===
|
|
{json.dumps(skills, indent=2, ensure_ascii=False)}
|
|
|
|
=== CERTIFICATIONS ===
|
|
{chr(10).join('- ' + c for c in certifications)}
|
|
|
|
=== AWARDS ===
|
|
{chr(10).join('- ' + a for a in awards)}
|
|
|
|
Return ONLY valid JSON matching the schema described in the system prompt.
|
|
"""
|
|
|
|
response = await llm_client.generate(
|
|
prompt=user_prompt,
|
|
system_prompt=_SYSTEM_PROMPT,
|
|
temperature=0.4,
|
|
max_tokens=3000,
|
|
)
|
|
|
|
# Parse the LLM response
|
|
enhanced = _parse_llm_response(response.text)
|
|
|
|
# Merge enhanced data back into profile
|
|
enriched_profile = {**brand_profile, "enhanced": enhanced}
|
|
return enriched_profile
|
|
|
|
|
|
def _format_previous_roles(roles: list[dict]) -> str:
|
|
"""Format previous roles for the LLM prompt."""
|
|
lines: list[str] = []
|
|
for role in roles:
|
|
lines.append(f"Company: {role.get('company', '')}")
|
|
lines.append(f"Title: {role.get('title', '')}")
|
|
lines.append(f"Period: {role.get('period', '')}")
|
|
for h in role.get("highlights", []):
|
|
lines.append(f" - {h}")
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def _format_leadership(entries: list[dict]) -> str:
|
|
"""Format leadership entries for the LLM prompt."""
|
|
lines: list[str] = []
|
|
for entry in entries:
|
|
lines.append(f"Role: {entry.get('role', '')}")
|
|
lines.append(f"Organization: {entry.get('organization', '')}")
|
|
lines.append(f"Period: {entry.get('period', '')}")
|
|
for h in entry.get("highlights", []):
|
|
lines.append(f" - {h}")
|
|
lines.append("")
|
|
return "\n".join(lines)
|
|
|
|
|
|
def _parse_llm_response(text: str) -> dict:
|
|
"""Extract JSON from the LLM response, handling markdown fences."""
|
|
cleaned = text.strip()
|
|
|
|
# Strip markdown code fences if present
|
|
if cleaned.startswith("```"):
|
|
# Remove opening fence (with optional language tag)
|
|
first_newline = cleaned.index("\n")
|
|
cleaned = cleaned[first_newline + 1 :]
|
|
# Remove closing fence
|
|
if cleaned.endswith("```"):
|
|
cleaned = cleaned[: -len("```")].rstrip()
|
|
|
|
try:
|
|
return json.loads(cleaned)
|
|
except json.JSONDecodeError:
|
|
logger.warning("Failed to parse LLM JSON response; returning raw text")
|
|
return {
|
|
"raw_response": text,
|
|
"summary_en": "",
|
|
"summary_ar": "",
|
|
"current_role_bullets": [],
|
|
"previous_roles": [],
|
|
"leadership": [],
|
|
"skills_keywords": [],
|
|
}
|