Files
job-forge/src/backend/services/ai_service.py
2025-08-02 20:51:59 -04:00

222 lines
8.1 KiB
Python

"""
AI Service for Job Forge - Handles document generation and AI processing
"""
import structlog
from typing import Dict, Optional
import anthropic
import openai
from ..core.config import settings
logger = structlog.get_logger()
class AIService:
def __init__(self):
self.claude_client = None
self.openai_client = None
# Initialize Claude client if API key is available
if settings.claude_api_key:
self.claude_client = anthropic.Anthropic(api_key=settings.claude_api_key)
# Initialize OpenAI client if API key is available
if settings.openai_api_key:
self.openai_client = openai.AsyncOpenAI(api_key=settings.openai_api_key)
async def generate_cover_letter(
self,
job_description: str,
company_name: str,
role_title: str,
user_name: str,
user_resume: Optional[str] = None
) -> Dict[str, str]:
"""
Generate a personalized cover letter using AI
"""
try:
# Construct the prompt
prompt = f"""
You are a professional career coach helping someone write a compelling cover letter.
JOB DETAILS:
- Company: {company_name}
- Role: {role_title}
- Job Description: {job_description}
USER INFORMATION:
- Name: {user_name}
{f"- Resume/Background: {user_resume[:1000]}..." if user_resume else ""}
TASK:
Write a professional, personalized cover letter that:
1. Shows genuine interest in the specific role and company
2. Highlights relevant skills from the job description
3. Demonstrates understanding of the company's needs
4. Uses a professional but engaging tone
5. Is 3-4 paragraphs long
6. Includes a strong opening and closing
Format the response as a complete cover letter without any meta-commentary.
"""
# Try Claude first, fallback to OpenAI
if self.claude_client:
logger.info("Generating cover letter with Claude")
response = self.claude_client.messages.create(
model="claude-3-haiku-20240307",
max_tokens=1000,
messages=[
{"role": "user", "content": prompt}
]
)
content = response.content[0].text
model_used = "claude-3-haiku"
elif self.openai_client:
logger.info("Generating cover letter with OpenAI")
response = await self.openai_client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are a professional career coach helping write cover letters."},
{"role": "user", "content": prompt}
],
max_tokens=1000,
temperature=0.7
)
content = response.choices[0].message.content
model_used = "gpt-3.5-turbo"
else:
# Fallback to template-based generation
logger.warning("No AI API keys available, using template")
content = self._generate_template_cover_letter(
company_name, role_title, user_name, job_description
)
model_used = "template"
return {
"content": content,
"model_used": model_used,
"prompt": prompt[:500] + "..." if len(prompt) > 500 else prompt
}
except Exception as e:
logger.error("AI cover letter generation failed", error=str(e))
# Fallback to template
content = self._generate_template_cover_letter(
company_name, role_title, user_name, job_description
)
return {
"content": content,
"model_used": "template-fallback",
"prompt": "Template fallback due to AI service error"
}
async def generate_resume_optimization(
self,
current_resume: str,
job_description: str,
role_title: str
) -> Dict[str, str]:
"""
Optimize resume for specific job requirements
"""
try:
prompt = f"""
You are an expert resume writer helping optimize a resume for a specific job.
CURRENT RESUME:
{current_resume}
TARGET JOB:
- Role: {role_title}
- Job Description: {job_description}
TASK:
Optimize this resume by:
1. Highlighting relevant skills mentioned in the job description
2. Reordering sections to emphasize most relevant experience
3. Using keywords from the job posting
4. Maintaining truthfulness - only reorganize/reword existing content
5. Keeping the same general structure and format
Return the optimized resume without meta-commentary.
"""
if self.claude_client:
response = self.claude_client.messages.create(
model="claude-3-haiku-20240307",
max_tokens=2000,
messages=[
{"role": "user", "content": prompt}
]
)
content = response.content[0].text
model_used = "claude-3-haiku"
elif self.openai_client:
response = await self.openai_client.chat.completions.create(
model="gpt-3.5-turbo",
messages=[
{"role": "system", "content": "You are an expert resume writer."},
{"role": "user", "content": prompt}
],
max_tokens=2000,
temperature=0.5
)
content = response.choices[0].message.content
model_used = "gpt-3.5-turbo"
else:
content = f"Resume optimization for {role_title}\n\n{current_resume}\n\n[AI optimization would be applied here with API keys configured]"
model_used = "template"
return {
"content": content,
"model_used": model_used,
"prompt": prompt[:500] + "..." if len(prompt) > 500 else prompt
}
except Exception as e:
logger.error("Resume optimization failed", error=str(e))
return {
"content": f"Optimized Resume for {role_title}\n\n{current_resume}",
"model_used": "template-fallback",
"prompt": "Template fallback due to AI service error"
}
def _generate_template_cover_letter(
self,
company_name: str,
role_title: str,
user_name: str,
job_description: str
) -> str:
"""
Generate a basic template cover letter when AI services are unavailable
"""
# Extract a few keywords from job description
keywords = []
common_skills = ["python", "javascript", "react", "sql", "aws", "docker", "git", "api", "database"]
for skill in common_skills:
if skill.lower() in job_description.lower():
keywords.append(skill.title())
skills_text = f" with expertise in {', '.join(keywords[:3])}" if keywords else ""
return f"""Dear Hiring Manager,
I am writing to express my strong interest in the {role_title} position at {company_name}. Based on the job description, I am excited about the opportunity to contribute to your team{skills_text}.
Your requirements align well with my background and experience. I am particularly drawn to this role because it represents an excellent opportunity to apply my skills in a dynamic environment while contributing to {company_name}'s continued success.
I would welcome the opportunity to discuss how my experience and enthusiasm can benefit your team. Thank you for considering my application, and I look forward to hearing from you.
Best regards,
{user_name}
---
[Generated by Job Forge AI Assistant - Configure API keys for enhanced personalization]"""
# Create a singleton instance
ai_service = AIService()