import json import os from groq import Groq from dotenv import load_dotenv load_dotenv() api_key = os.environ.get("GROQ_API_KEY", "") client = Groq(api_key=api_key) if api_key else None GROQ_MODEL = os.environ.get("GROQ_MODEL", "openai/gpt-oss-20b") def analyze_interview(session: dict) -> dict: messages = session.get("messages", []) mode = session.get("mode", "general") company = session.get("company", "") role = session.get("role", "SDE") transcript = "" for m in messages: if m["role"] == "user": transcript += f"CANDIDATE: {m['content']}\n\n" elif m["role"] == "assistant": transcript += f"INTERVIEWER: {m['content']}\n\n" if not transcript.strip(): return {"error": "No interview answers were recorded."} if not client: return {"error": "Feedback is unavailable because no LLM provider is configured."} rubric = ( "Evaluate structure, prioritization, business judgment, and communication. Explicitly score structuring ability, MECE decomposition, quantitative rigor, SQL correctness/efficiency, communication, clarity of thought, and comfort with ambiguity or missing information. For case studies and guesstimates, explicitly judge whether the candidate asked clarifying questions when useful, how clearly they articulated assumptions, and how effectively they communicated trade-offs. Return a PM/consulting rubric with each metric 0-100." if mode == "consulting_pm" else "" ) prompt = f"""You are an exacting but supportive interview coach analyzing a {mode} interview for a {role} role{' at ' + company.capitalize() if company else ''}. Here is the full interview transcript: --- {transcript[:6000]} --- {rubric} Analyze evidence from the candidate's actual answers. Do not praise generic traits or invent details. Return ONLY valid JSON with EXACTLY this structure: {{ "overall_score": , "summary": "<2-3 sentence honest assessment naming the clearest evidence>", "strong_points": [ {{"title": "", "detail": ""}}, {{"title": "", "detail": ""}}, {{"title": "", "detail": ""}} ], "pain_points": [ {{"title": "", "detail": ""}}, {{"title": "", "detail": ""}}, {{"title": "", "detail": ""}} ], "areas_of_improvement": [ {{"title": "", "action": ""}}, {{"title": "", "action": ""}}, {{"title": "", "action": ""}} ], "skill_scores": {{ "technical": <0-100>, "communication": <0-100>, "clarity_of_thought": <0-100>, "problem_solving": <0-100>, "confidence": <0-100>, "cultural_fit": <0-100>, "structured_reasoning": <0-100>, "business_judgment": <0-100> }}, "hiring_verdict": "", "verdict_reason": "", "next_steps": [ "", "" ] }}""" options = { "model": GROQ_MODEL, "messages": [{"role": "user", "content": prompt}], "max_tokens": 1200, } if GROQ_MODEL.startswith("openai/gpt-oss"): options["reasoning_effort"] = "low" response = client.chat.completions.create(**options) raw = response.choices[0].message.content.strip() if raw.startswith("```"): raw = raw.split("```")[1] if raw.startswith("json"): raw = raw[4:] raw = raw.strip() try: result = json.loads(raw) required = ["overall_score", "summary", "strong_points", "pain_points", "areas_of_improvement", "skill_scores", "hiring_verdict", "verdict_reason", "next_steps"] if not all(key in result for key in required): return {"error": "Feedback response was incomplete", "raw": raw} return result except Exception: return {"error": "Could not parse analysis", "raw": raw}