Spaces:
Sleeping
Sleeping
| # 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']}") |