interview / app.py
kandukurijaswanth's picture
Update app.py
95a7fec verified
Raw
History Blame Contribute Delete
4.34 kB
# app.py
from fastapi import FastAPI, UploadFile, File
from fastapi.responses import JSONResponse, FileResponse
from fastapi.middleware.cors import CORSMiddleware
import time, json, base64
import cv2, numpy as np
from PIL import Image
from io import BytesIO
import gradio as gr
# Optional YOLO & FER
try:
from ultralytics import YOLO
YOLO_MODEL = YOLO("yolov8n.pt")
except Exception:
YOLO_MODEL = None
try:
from fer import FER
EMO_MODEL = FER(mtcnn=True)
except Exception:
EMO_MODEL = None
app = FastAPI(title="GYaaNa SAroVar(GYSV) Interview Monitor Backend")
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"]
)
STORE = {"frames": [], "texts": [], "analysis": None, "meta_start": time.time()}
FILLERS = {"um","uh","like","you know","so","actually","basically","right","okay"}
def text_metrics(text):
words = len(text.split())
fillers = sum(text.lower().count(f) for f in FILLERS)
elapsed_min = max(1/60, (time.time() - STORE.get("meta_start", time.time())) / 60)
wpm = round(words / elapsed_min, 2)
quality = max(0, 100 - fillers*5)
return {"fillers": fillers, "wpm": wpm, "text_quality": quality, "technical_score": quality}
def decode_frame(b64str):
b64data = b64str.split(",")[1] if "," in b64str else b64str
img_data = base64.b64decode(b64data)
img = np.array(Image.open(BytesIO(img_data)))
if img.shape[2] == 4:
img = cv2.cvtColor(img, cv2.COLOR_RGBA2RGB)
return img
@app.post("/analyze_frame")
async def analyze_frame(payload: dict):
frame_b64 = payload.get("frame", "")
transcript = payload.get("transcript", "")
ts = time.time()
img = decode_frame(frame_b64) if frame_b64 else None
# Person detection
person_present = False
boxes = []
if img is not None and YOLO_MODEL:
results = YOLO_MODEL(img)
for r in results:
for det in r.boxes.xyxy:
boxes.append({"x": int(det[0]), "y": int(det[1]), "w": int(det[2]-det[0]), "h": int(det[3]-det[1]), "label": "person"})
person_present = len(boxes) > 0
# Expression detection
expression = {"label": "neutral", "conf": 0.6}
if img is not None and EMO_MODEL:
em_res = EMO_MODEL.detect_emotions(img)
if em_res:
expression = em_res[0]["emotions"]
metrics = text_metrics(transcript)
analysis = {
"time": ts,
"person_present": person_present,
"expression": expression,
"boxes": boxes,
"dress_style": "shirt (unisex)",
"live_transcript": transcript or "No speech yet.",
"metrics": metrics,
"technical_score": metrics.get("technical_score"),
"final_analysis": "Simulated live analysis"
}
STORE["analysis"] = analysis
return JSONResponse(analysis)
@app.post("/upload_audio")
async def upload_audio(audio: UploadFile = File(...)):
return JSONResponse({"message": "Audio received. Transcription can be integrated with Whisper or other ASR models."})
@app.get("/final_analysis")
async def final_analysis():
return JSONResponse(STORE.get("analysis", {}))
@app.get("/download_json")
async def download_json():
data = json.dumps(STORE, indent=2).encode("utf-8")
path = "/tmp/export_analysis.json"
with open(path,"wb") as f: f.write(data)
return FileResponse(path, media_type="application/json", filename="analysis.json")
# ------------------- Gradio Frontend -------------------
def analyze_audio(audio):
if audio is None:
return "No audio recorded"
# Compute transcript & metrics (mock example)
duration = len(audio[1])/audio[0]
text = f"Audio received ({duration:.2f}s)"
metrics = text_metrics(text)
return f"{text}\nMetrics: {metrics}"
with gr.Blocks() as demo:
gr.Markdown("## GYaaNa SAroVar (GYSV) Interview Monitor")
with gr.Row():
video_output = gr.Video(source="webcam", streaming=True, label="Camera")
audio_input = gr.Audio(source="microphone", type="numpy", label="Record your voice")
output_text = gr.Textbox(label="Transcript / Analysis")
audio_input.change(analyze_audio, inputs=audio_input, outputs=output_text)
# Only run frontend when script executed
if __name__ == "__main__":
demo.launch()