| """ |
| Interview Prep AI Agent - Mock questions, company research, STAR framework coaching. |
| """ |
| import json |
| from enum import Enum |
| from typing import Any |
|
|
| import litellm |
| from sqlalchemy.ext.asyncio import AsyncSession |
|
|
| from app.core.config import settings |
|
|
|
|
| class InterviewType(str, Enum): |
| BEHAVIORAL = "behavioral" |
| TECHNICAL = "technical" |
| SYSTEM_DESIGN = "system_design" |
| CASE_STUDY = "case_study" |
| GENERAL = "general" |
|
|
|
|
| INTERVIEW_PROMPTS = { |
| InterviewType.BEHAVIORAL: """You are an expert interview coach specializing in behavioral interviews. |
| Generate realistic behavioral interview questions based on the job description and candidate's resume. |
| For each question, provide: |
| - The question itself |
| - Why this question matters for the role |
| - A STAR framework template with guidance |
| - Common pitfalls to avoid |
| - An example strong answer structure (not a full answer - the candidate should use their own experience) |
| |
| Return JSON: { |
| "questions": [ |
| { |
| "question": "...", |
| "category": "leadership|teamwork|conflict|failure|achievement|problem_solving", |
| "why_asked": "...", |
| "star_template": {"situation": "guidance...", "task": "guidance...", "action": "guidance...", "result": "guidance..."}, |
| "pitfalls": ["..."], |
| "strong_answer_tips": ["..."] |
| } |
| ] |
| }""", |
|
|
| InterviewType.TECHNICAL: """You are a senior technical interviewer. Generate realistic technical interview questions for the given role. |
| Include a mix of: |
| - Coding/algorithm questions (with hints, not full solutions) |
| - System/architecture questions |
| - Language/framework-specific questions |
| - Problem-solving scenarios |
| |
| Return JSON: { |
| "questions": [ |
| { |
| "question": "...", |
| "difficulty": "easy|medium|hard", |
| "category": "algorithms|system_design|language|debugging|architecture", |
| "follow_ups": ["..."], |
| "key_concepts": ["..."], |
| "approach_hints": ["..."] |
| } |
| ] |
| }""", |
|
|
| InterviewType.SYSTEM_DESIGN: """You are a system design interview expert. Generate system design questions appropriate for the role level. |
| For each question, provide the structured approach. |
| |
| Return JSON: { |
| "questions": [ |
| { |
| "question": "...", |
| "difficulty": "junior|mid|senior|staff", |
| "time_allocation": {"requirements": "5min", "high_level": "10min", "deep_dive": "15min", "tradeoffs": "10min"}, |
| "key_requirements_to_clarify": ["..."], |
| "components_to_discuss": ["..."], |
| "scaling_considerations": ["..."], |
| "common_mistakes": ["..."] |
| } |
| ] |
| }""", |
|
|
| InterviewType.GENERAL: """You are a career coach helping prepare for a job interview. Generate likely questions for this specific role and company. |
| Include a mix of motivational, situational, and role-specific questions. |
| |
| Return JSON: { |
| "questions": [ |
| { |
| "question": "...", |
| "category": "motivation|culture_fit|situational|role_specific|salary_negotiation", |
| "tips": ["..."], |
| "things_to_research": ["..."] |
| } |
| ] |
| }""", |
| } |
|
|
| COMPANY_RESEARCH_PROMPT = """You are a career research analyst. Based on the company name and any available information, provide a comprehensive research brief for interview preparation. |
| |
| Return JSON: { |
| "company_overview": "2-3 sentence description", |
| "key_facts": ["..."], |
| "recent_news_topics": ["topics to research (candidate should verify these)"], |
| "culture_signals": ["..."], |
| "interview_process_tips": ["common patterns for this type of company"], |
| "questions_to_ask_interviewer": ["thoughtful questions showing research"], |
| "red_flags_to_watch": ["..."], |
| "salary_negotiation_context": "market positioning and negotiation tips" |
| } |
| |
| IMPORTANT: Clearly mark any information that the candidate should verify independently. Do not fabricate specific recent events.""" |
|
|
| MOCK_ANSWER_FEEDBACK_PROMPT = """You are an interview coach providing feedback on a candidate's practice answer. |
| |
| Evaluate the answer on: |
| 1. Structure (STAR format adherence) |
| 2. Specificity (concrete details vs vague statements) |
| 3. Impact (quantified results) |
| 4. Relevance (connection to the role) |
| 5. Conciseness (appropriate length) |
| |
| Return JSON: { |
| "overall_score": 1-10, |
| "structure_score": 1-10, |
| "specificity_score": 1-10, |
| "impact_score": 1-10, |
| "relevance_score": 1-10, |
| "strengths": ["..."], |
| "improvements": ["..."], |
| "rewritten_version": "improved version preserving the candidate's actual experience", |
| "coaching_notes": "what to practice" |
| }""" |
|
|
|
|
| class InterviewPrepAgent: |
| """AI agent for interview preparation.""" |
|
|
| def __init__(self, db: AsyncSession): |
| self.db = db |
|
|
| def _get_model(self) -> str: |
| """Get the best available model for interview prep.""" |
| if settings.OPENAI_API_KEY: |
| return "openai/gpt-4o" |
| elif settings.ANTHROPIC_API_KEY: |
| return "anthropic/claude-sonnet-4-20250514" |
| elif settings.GOOGLE_API_KEY: |
| return "google/gemini-2.0-flash" |
| elif settings.DEEPSEEK_API_KEY: |
| return "deepseek/deepseek-chat" |
| return "ollama/llama3.2" |
|
|
| async def generate_questions( |
| self, |
| job_title: str, |
| job_description: str, |
| resume_text: str | None = None, |
| interview_type: InterviewType = InterviewType.GENERAL, |
| num_questions: int = 5, |
| ) -> dict: |
| """Generate interview questions tailored to the role.""" |
| system_prompt = INTERVIEW_PROMPTS[interview_type] |
|
|
| user_content = f"""Job Title: {job_title} |
| |
| Job Description: |
| {job_description[:3000]} |
| |
| {"Resume:" + chr(10) + resume_text[:2000] if resume_text else "No resume provided."} |
| |
| Generate {num_questions} questions.""" |
|
|
| response = await litellm.acompletion( |
| model=self._get_model(), |
| messages=[ |
| {"role": "system", "content": system_prompt}, |
| {"role": "user", "content": user_content}, |
| ], |
| response_format={"type": "json_object"}, |
| temperature=0.7, |
| ) |
|
|
| return json.loads(response.choices[0].message.content) |
|
|
| async def research_company( |
| self, |
| company_name: str, |
| job_title: str | None = None, |
| company_description: str | None = None, |
| ) -> dict: |
| """Generate company research brief for interview prep.""" |
| user_content = f"""Company: {company_name} |
| {f"Role: {job_title}" if job_title else ""} |
| {f"Company Info: {company_description[:1000]}" if company_description else ""} |
| |
| Provide a research brief for interview preparation.""" |
|
|
| response = await litellm.acompletion( |
| model=self._get_model(), |
| messages=[ |
| {"role": "system", "content": COMPANY_RESEARCH_PROMPT}, |
| {"role": "user", "content": user_content}, |
| ], |
| response_format={"type": "json_object"}, |
| temperature=0.5, |
| ) |
|
|
| return json.loads(response.choices[0].message.content) |
|
|
| async def evaluate_answer( |
| self, |
| question: str, |
| answer: str, |
| job_title: str | None = None, |
| ) -> dict: |
| """Evaluate a practice interview answer and provide coaching feedback.""" |
| user_content = f"""Question: {question} |
| |
| Candidate's Answer: |
| {answer} |
| |
| {f"Target Role: {job_title}" if job_title else ""} |
| |
| Provide detailed feedback.""" |
|
|
| response = await litellm.acompletion( |
| model=self._get_model(), |
| messages=[ |
| {"role": "system", "content": MOCK_ANSWER_FEEDBACK_PROMPT}, |
| {"role": "user", "content": user_content}, |
| ], |
| response_format={"type": "json_object"}, |
| temperature=0.3, |
| ) |
|
|
| return json.loads(response.choices[0].message.content) |
|
|
| async def generate_star_story( |
| self, |
| experience_bullet: str, |
| target_question_type: str = "general", |
| ) -> dict: |
| """Help convert a resume bullet into a full STAR story.""" |
| system_prompt = """You are a STAR story coach. Help the candidate expand their resume bullet point into a full STAR interview story. |
| |
| Rules: |
| - Only use information that can reasonably be inferred from the bullet |
| - Mark placeholders where the candidate needs to fill in specific details |
| - Do not fabricate metrics or outcomes not implied by the original |
| |
| Return JSON: { |
| "situation": "Expanded context (with [FILL IN] placeholders where needed)", |
| "task": "Your specific responsibility", |
| "action": "Step-by-step actions taken", |
| "result": "Outcomes and impact (with [QUANTIFY] placeholder if metrics not provided)", |
| "follow_up_prep": ["likely follow-up questions to prepare for"], |
| "versatility": ["other question types this story could answer"] |
| }""" |
|
|
| response = await litellm.acompletion( |
| model=self._get_model(), |
| messages=[ |
| {"role": "system", "content": system_prompt}, |
| {"role": "user", "content": f"Resume bullet: {experience_bullet}\nQuestion type: {target_question_type}"}, |
| ], |
| response_format={"type": "json_object"}, |
| temperature=0.5, |
| ) |
|
|
| return json.loads(response.choices[0].message.content) |
|
|