Download Backend/app/api/v1/endpoints/interview.py from aki-008/prepAI: direct link, hf CLI and curl.
- Browser
- Download file 7.58 kB
-
https://huggingface.co/spaces/aki-008/prepAI/resolve/main/Backend/app/api/v1/endpoints/interview.py
- Command line
-
hf download hf://spaces/aki-008/prepAI/Backend/app/api/v1/endpoints/interview.py
-
curl -L -o interview.py https://huggingface.co/spaces/aki-008/prepAI/resolve/main/Backend/app/api/v1/endpoints/interview.py
7.58 kB
| import os | |
| from app.models import User | |
| import uvicorn | |
| from fastapi import APIRouter, HTTPException, Request, Depends | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from pydantic import BaseModel, Field | |
| from app.config import settings | |
| from vapi import Vapi | |
| from dotenv import load_dotenv | |
| from app.api.deps import get_db, get_current_user, get_chroma_collection | |
| load_dotenv() | |
| router = APIRouter() | |
| # --- CONFIGURATION --- | |
| VAPI_PRIVATE_KEY = os.getenv("VAPI_PRIVATE_KEY") | |
| VAPI_ASSISTANT_ID = os.getenv("VAPI_ASSISTANT_ID") | |
| SERVER_URL = os.getenv("SERVER_URL", "http://localhost:8000") | |
| # Initialize Vapi Server SDK | |
| try: | |
| vapi_server = Vapi(token=VAPI_PRIVATE_KEY) | |
| except Exception as e: | |
| print(f"Vapi SDK Initialization Error: {e}") | |
| print("Ensure VAPI_PRIVATE_KEY is set in .env") | |
| # --- SCHEMAS --- | |
| class ConfigRequest(BaseModel): | |
| name: str | |
| job_role: str | |
| experience: str | |
| level: str = "Medium" | |
| # Optional customizable fields | |
| model_name: str = "gpt-4o" | |
| voice_provider: str = "11labs" | |
| voice_id: str = "burt" | |
| # --- ENDPOINTS --- | |
| async def get_vapi_config(data: ConfigRequest): | |
| """ | |
| Endpoint called by the Frontend to get the dynamically generated Assistant configuration. | |
| """ | |
| if not VAPI_ASSISTANT_ID: | |
| raise HTTPException( | |
| status_code=503, | |
| detail="VAPI_ASSISTANT_ID not configured in .env." | |
| ) | |
| try: | |
| print(f"\n--- New Interview Request ---") | |
| print(f"👤 User: {data.name}, Role: {data.job_role}, Exp: {data.experience}, Level: {data.level}") | |
| system_prompt = ( | |
| f"You are the hiring manager at a tech company. You are conducting a strict 5-minute screening interview " | |
| f"with {data.name} for a {data.job_role} role. The candidate has {data.experience} years of experience. " | |
| f"The difficulty level is {data.level}. Your style is clear, concise, and professional. Do not lecture. " | |
| "All questions must be relevant to the provided job role.\n\n" | |
| "You MUST strictly follow this interview flow:\n\n" | |
| "1. **Introduction**: You have already welcomed them. Wait for their confirmation to begin.\n\n" | |
| "2. **Background Snapshot**: Ask: " | |
| "'Give me a brief 30–40 second overview of your background and the type of work you've done related to this role.'\n\n" | |
| "3. **Technical Depth**: Ask the candidate to choose one project relevant to the job role. " | |
| "Ask: 'Pick one project you're proud of that aligns with this role. In under a minute, explain the problem, your approach, " | |
| "tools or techniques used, and the business impact.'\n\n" | |
| "4. **Core Skills Check**: Inform them you will ask 3 rapid questions tailored to the job. " | |
| "Generate **three crisp, role-specific skill checks** following this logic:\n" | |
| " - Question 1: A foundational concept essential to the role.\n" | |
| " - Question 2: A practical troubleshooting or decision-making question.\n" | |
| " - Question 3: A tool, framework, or technology familiarity question.\n" | |
| "Questions must be specific to the given job role.\n\n" | |
| "5. **Practical Scenario**: Generate **one short applied scenario** relevant to the role. " | |
| "Ask the candidate to describe their high-level approach to solve it.\n\n" | |
| "6. **Role & Communication Fit**: Ask a communication-focused question, such as: " | |
| "'This role requires cross-team collaboration. Can you give an example where you explained something complex " | |
| "to a non-technical or differently-skilled stakeholder?'\n\n" | |
| "7. **Wrap-Up**: Say: 'Thank you. Any questions for me?' Then conclude: 'We’ll get back to you with next steps.'\n\n" | |
| "**CRITICAL RULES:**\n" | |
| "- Do NOT exceed the boundaries of each segment.\n" | |
| "- If their answers run long, politely interrupt and move forward.\n" | |
| "- Keep your phrasing tight and professional.\n" | |
| "- All generated questions MUST be directly relevant to the specified job role." | |
| ) | |
| webhook_url = f"{SERVER_URL}/api/webhook" | |
| assistant_overrides = { | |
| "model": { | |
| "provider": "openai", | |
| "model": data.model_name, | |
| "temperature": 0.3, | |
| "maxTokens": 150, | |
| "emotionRecognitionEnabled": True, | |
| "messages": [ | |
| {"role": "system", "content": system_prompt} | |
| ] | |
| }, | |
| "voice": { | |
| "provider": data.voice_provider, | |
| "voiceId": data.voice_id, | |
| "speed": 1.1, | |
| "stability": 0.5 | |
| }, | |
| "firstMessage": f"Hi {data.name}, thanks for joining. I’m the hiring manager. This is a quick 5-minute screening to understand your background and fit. Shall we begin?", | |
| "maxDurationSeconds": 360, | |
| "silenceTimeoutSeconds": 40, | |
| "backgroundSound": "office", | |
| "backgroundDenoisingEnabled": True, | |
| "endCallPhrases": [ | |
| "Goodbye", | |
| "Have a great day", | |
| "We’ll get back to you with next steps", | |
| "Thank you for your time" | |
| ], | |
| # --- SERVER --- | |
| "server": { | |
| "url": webhook_url | |
| }, | |
| "metadata": { | |
| "user_name": data.name, | |
| "job_role": data.job_role, | |
| "environment": "production_screening" | |
| } | |
| } | |
| return { | |
| "assistantId": VAPI_ASSISTANT_ID, | |
| "overrides": assistant_overrides | |
| } | |
| except Exception as e: | |
| print(f"❌ Vapi Configuration Error: {e}") | |
| raise HTTPException(status_code=500, detail=f"Failed to configure agent: {str(e)}") | |
| async def vapi_webhook_receiver(request: Request): | |
| """ | |
| Endpoint that receives asynchronous events from Vapi's servers. | |
| Saves transcripts to a local file. | |
| """ | |
| payload = await request.json() | |
| message = payload.get("message", {}) | |
| call_id = payload.get("call", {}).get("id", "unknown_call") | |
| os.makedirs("transcripts", exist_ok=True) | |
| if message.get("type") == "transcript" and message.get("transcriptType") == "final": | |
| transcript_text = message.get('transcript') | |
| role = message.get('role', 'unknown') | |
| try: | |
| with open(f"transcripts/{call_id}.txt", "a", encoding="utf-8") as f: | |
| f.write(f"{role.upper()}: {transcript_text}\n") | |
| print(f"🗣️ [Saved] {role.upper()}: {transcript_text}") | |
| except Exception as e: | |
| print(f"❌ Error saving transcript: {e}") | |
| elif message.get("type") == "end-of-call-report": | |
| metadata = payload.get("assistant", {}).get("metadata", {}) | |
| summary = message.get('summary', 'N/A') | |
| # Save summary to the same file | |
| try: | |
| with open(f"transcripts/{call_id}.txt", "a", encoding="utf-8") as f: | |
| f.write(f"\n--- SUMMARY ---\n{summary}\n") | |
| except Exception as e: | |
| print(f"❌ Error saving summary: {e}") | |
| print(f"\n--- 🏁 Call Ended Report ---") | |
| print(f" User: {metadata.get('user_name')}") | |
| print(f" Summary: {summary}") | |
| print(f"---------------------------\n") | |
| return {"status": "ok"} |