# File: dashboard.py # Purpose: Streamlit recruiter dashboard with manual fetch report button import requests import streamlit as st API_BASE = "http://localhost:8000" st.set_page_config(page_title="AI Interview Caller", layout="wide") st.title("AI Interview Screening Caller") st.caption("Powered by Bland.ai · Groq · ElevenLabs") # ── Sidebar: Initiate New Call ──────────────────────────────────────────────── with st.sidebar: st.header("New Interview Call") candidate_name = st.text_input("Candidate Name") candidate_phone = st.text_input("Phone (E.164 e.g. +919876543210)") candidate_email = st.text_input("Email (optional)") resume_text = st.text_area("Paste Resume Text", height=200) if st.button("Initiate Call", type="primary"): if not candidate_name or not candidate_phone: st.error("Name and phone are required.") else: payload = { "candidate_name": candidate_name, "candidate_phone": candidate_phone, "candidate_email": candidate_email, "resume_text": resume_text, } with st.spinner("Initiating call via Bland.ai..."): resp = requests.post(f"{API_BASE}/api/initiate-call", json=payload) if resp.status_code == 200: data = resp.json() st.success(f"Call initiated! Session ID: {data['session_id']}") st.info("After the call ends, click 'Fetch Report' to get the evaluation.") else: st.error(f"Error: {resp.text}") # ── Main: Session List ──────────────────────────────────────────────────────── st.header("Recent Interviews") col_refresh, _ = st.columns([1, 5]) if col_refresh.button("Refresh List"): st.rerun() resp = requests.get(f"{API_BASE}/api/sessions") if resp.status_code != 200: st.warning("Could not reach the API server.") st.stop() sessions = resp.json() if not sessions: st.info("No interviews yet. Use the sidebar to start one.") st.stop() # Column headers h1, h2, h3, h4, h5, h6 = st.columns([2, 1, 1, 2, 1, 1]) h1.markdown("**Candidate**") h2.markdown("**Status**") h3.markdown("**Score**") h4.markdown("**Recommendation**") h5.markdown("**Action**") h6.markdown("**Report**") st.divider() for s in sessions: with st.container(): col1, col2, col3, col4, col5, col6 = st.columns([2, 1, 1, 2, 1, 1]) col1.write(f"**{s['candidate']}**") status_color = {"completed": "green", "active": "orange", "initiated": "blue"}.get(s["status"], "gray") col2.markdown(f":{status_color}[{s['status']}]") col3.write(f"{s['overall_score']:.1f}/10" if s["overall_score"] else "—") col4.write(s["recommendation"] or "—") if col5.button("Fetch Report", key=f"fetch_{s['id']}"): with st.spinner("Fetching report from Bland.ai..."): fetch_resp = requests.post(f"{API_BASE}/api/session/{s['id']}/fetch-report") if fetch_resp.status_code == 200: st.success(fetch_resp.json().get("message", "Done")) st.rerun() else: st.error(fetch_resp.text) if col6.button("View", key=f"view_{s['id']}"): st.session_state["selected_session"] = s["id"] st.divider() # ── Report Viewer ───────────────────────────────────────────────────────────── if "selected_session" in st.session_state: sid = st.session_state["selected_session"] report_resp = requests.get(f"{API_BASE}/api/session/{sid}/report") if report_resp.status_code == 200: data = report_resp.json() st.subheader(f"Report — {data['candidate']}") if data["status"] != "completed": st.warning(f"Status: {data['status']} — Click 'Fetch Report' after the call ends.") else: st.markdown("### Full Analysis is Below") col1, col2, col3, col4 = st.columns(4) col1.metric("Communication", f"{data['communication_score']:.1f}/10") col2.metric("Technical", f"{data['technical_score']:.1f}/10") col3.metric("Confidence", f"{data['confidence_score']:.1f}/10") col4.metric("Overall", f"{data['overall_score']:.1f}/10") st.markdown(f"**Recommendation:** {data['recommendation']}") st.markdown(f"**Skills:** {', '.join(data['skills'] or [])}") with st.expander("Full Report"): st.text(data["report"]) trans_resp = requests.get(f"{API_BASE}/api/session/{sid}/transcript") if trans_resp.status_code == 200: turns = trans_resp.json() if turns: with st.expander("View Transcript"): for t in turns: if t["speaker"] == "AI": st.markdown(f"**AI:** {t['text']}") else: st.markdown(f"**Candidate:** {t['text']}")