Jaykay73's picture
use openrouter free
4d43719 verified
import os
import json
import re
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
class LLMService:
def __init__(self):
self.api_key = os.getenv("OPENROUTER_API_KEY")
self.client = OpenAI(
base_url="https://openrouter.ai/api/v1",
api_key=self.api_key,
)
self.model = "deepseek/deepseek-chat-v3.1"
def _clean_json_response(self, content: str):
"""Helper to strip Markdown formatting """
try:
return json.loads(content)
except json.JSONDecodeError:
# Look for markdown code blocks
match = re.search(r"```json\s*(.*)\s*```", content, re.DOTALL)
if match:
return json.loads(match.group(1))
# Fallback: look for the first { and last }
match = re.search(r"(\{.*\})", content, re.DOTALL)
if match:
return json.loads(match.group(1))
raise ValueError("Could not parse JSON from LLM")
def analyze_match(self, resume_text: str, jd_text: str) -> dict:
"""
Uses LLM to Extract AND Match skills semantically in one pass.
"""
if not self.api_key:
return {
"score": 0,
"common_skills": [],
"missing_skills": ["API_KEY_MISSING"],
"reasoning": "Please check server secrets."
}
prompt = f"""
You are an expert AI Recruiter.
TASK:
Compare the Candidate's Resume against the Job Description (JD).
1. Extract the required Technical Skills & Soft Skills from the JD.
2. Check if the Candidate possesses these skills based on the Resume.
3. Calculate a Match Score (0-100).
JOB DESCRIPTION:
{jd_text[:]}
CANDIDATE RESUME:
{resume_text[:]}
OUTPUT FORMAT:
Return STRICT JSON with these keys:
- "score": (Integer 0-100)
- "common_skills": (List of strings)
- "missing_skills": (List of strings)
- "reasoning": (Short explanation)
"""
try:
response = self.client.chat.completions.create(
model=self.model,
messages=[
{"role": "system", "content": "Output strictly valid JSON only."},
{"role": "user", "content": prompt}
]
)
content = response.choices[0].message.content
return self._clean_json_response(content)
except Exception as e:
print(f"LLM MATCH ERROR: {str(e)}")
return {
"score": 0,
"common_skills": [],
"missing_skills": ["Error calculating match"],
"reasoning": "AI Service unavailable."
}
def generate_suggestions(self, resume_text: str, jd_text: str, missing_skills: list) -> dict:
prompt = f"""
You are a Career Coach.
CONTEXT:
Candidate is applying for this job
{jd_text[:1000]}
and this is their resume
{resume_text[:]}
They are missing: {", ".join(missing_skills)}
TASK:
1. Suggest 3 specific technical side projects to bridge these gaps.
2. Write a short, professional cover letter.
CRITICAL FORMATTING RULES:
- Project format: Give project title first then description.
- Do not use markdown headers in the project list.
OUTPUT JSON keys:
- "suggested_projects" (List of strings)
- "cover_letter" (String)
"""
try:
response = self.client.chat.completions.create(
model='openrouter/free',
messages=[
{"role": "system", "content": "Output strictly valid JSON only."},
{"role": "user", "content": prompt}
]
)
content = response.choices[0].message.content
return self._clean_json_response(content)
except Exception as e:
print(f"LLM SUGGESTION ERROR: {str(e)}")
return {
"suggested_projects": ["Error generating projects. Please try again."],
"cover_letter": "Error generating cover letter."
}
llm_service = LLMService()