mockInterview / Analyze_endpoint.py
Rawanfx's picture
initial commit
3b7703c
Raw
History Blame Contribute Delete
3.35 kB
import os
import subprocess
import tempfile
import json
import httpx
from fastapi import HTTPException
from pydantic import BaseModel, Field, ConfigDict
from models import AnalyzeResponse, BodyLanguageResult
class AnalyzeRequest(BaseModel):
model_config = ConfigDict(populate_by_name=True)
video_url: str = Field(alias="videoUrl")
question_id: int = Field(alias="questionId")
async def _download_video(url: str) -> bytes:
async with httpx.AsyncClient(timeout=120) as client:
resp = await client.get(url)
if resp.status_code != 200:
raise HTTPException(status_code=502, detail=f"Failed to download video: HTTP {resp.status_code}")
return resp.content
def _extract_audio(video_path: str) -> bytes:
with tempfile.NamedTemporaryFile(suffix=".wav", delete=False) as tmp:
audio_path = tmp.name
try:
subprocess.run(
["ffmpeg", "-y", "-i", video_path, "-ac", "1", "-ar", "16000", "-vn", audio_path],
check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
)
with open(audio_path, "rb") as f:
return f.read()
finally:
os.unlink(audio_path)
async def analyze(request: AnalyzeRequest) -> AnalyzeResponse:
video_bytes = await _download_video(request.video_url)
with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as tmp:
tmp.write(video_bytes)
video_path = tmp.name
try:
from Video_Analysis import BodyLanguageAnalyzer
body_analyzer = BodyLanguageAnalyzer(
pose_model_path=os.environ["POSE_MODEL_PATH"],
face_model_path=os.environ["FACE_MODEL_PATH"],
hand_model_path=os.environ["HAND_MODEL_PATH"],
)
body_result_raw = body_analyzer.process_video(video_path)
audio_bytes = _extract_audio(video_path)
finally:
os.unlink(video_path)
from speech_analysis import SpeechAnalyzer
from Tone_analyzer import ToneAnalyzer
speech_result = SpeechAnalyzer().transcribe(audio_bytes)
tone_result = ToneAnalyzer().analyze(audio_bytes)
return AnalyzeResponse(
success=True,
question_id=request.question_id,
body_language=BodyLanguageResult(
avg_eye_contact_pct=body_result_raw["summary"].get("avg_eye_contact_pct") or 0.0,
poor_posture_window_pct=body_result_raw["summary"].get("poor_posture_window_pct") or 0.0,
avg_head_movement_score=body_result_raw["summary"].get("avg_head_movement_score") or 0.0,
avg_brow_tension_score=body_result_raw["summary"].get("avg_brow_tension_score") or 0.0,
total_face_touch_events=body_result_raw["summary"].get("total_face_touch_events") or 0,
blink_rate_per_minute=body_result_raw["summary"].get("blink_rate_per_minute") or 0.0,
frames_with_face_detected_pct=body_result_raw["summary"].get("frames_with_face_detected_pct") or 0.0,
frames_with_pose_detected_pct=body_result_raw["summary"].get("frames_with_pose_detected_pct") or 0.0,
frames_with_hand_detected_pct=body_result_raw["summary"].get("frames_with_hand_detected_pct") or 0.0,
performance_over_time_json=json.dumps(body_result_raw.get("time_series", [])),
),
speech=speech_result,
tone=tone_result,
)