import streamlit as st from groq import Groq import re from fpdf import FPDF import datetime import os # ── Page Config ─────────────────────────────────── st.set_page_config( page_title = "InterviewGen AI", page_icon = "🎯", layout = "wide" ) # ── Custom CSS ──────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True) # ── Groq Client ─────────────────────────────────── GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "") client = Groq(api_key=GROQ_API_KEY) # ── Helper Functions ────────────────────────────── def generate_questions(role, difficulty, q_type, num, job_desc=""): job_context = f"Job Description: {job_desc[:500]}" if job_desc else "" prompt = f"""You are a senior technical interviewer at a top tech company. {job_context} Generate exactly {num} {difficulty} level {q_type} interview questions for a {role}. Format EXACTLY like this: Q1: [question] A1: [detailed answer] Q2: [question] A2: [detailed answer] Only output questions and answers. Nothing else.""" response = client.chat.completions.create( model = "llama-3.3-70b-versatile", messages = [{"role": "user", "content": prompt}], temperature = 0.7, max_tokens = 2000 ) return response.choices[0].message.content def evaluate_answer(question, user_answer, correct_answer): prompt = f"""You are a technical interviewer evaluating a candidate answer. Question: {question} Candidate Answer: {user_answer} Expected Answer: {correct_answer} Evaluate the candidate answer and provide: 1. Score: X/10 2. Strengths: what they got right 3. Improvements: what they missed 4. Verdict: Pass/Fail Be concise and professional.""" response = client.chat.completions.create( model = "llama-3.3-70b-versatile", messages = [{"role": "user", "content": prompt}], temperature = 0.3, max_tokens = 500 ) return response.choices[0].message.content def parse_questions(text): qa_pairs = [] blocks = re.split(r"Q\d+:", text) blocks = [b.strip() for b in blocks if b.strip()] for block in blocks: if re.search(r"A\d+:", block): parts = re.split(r"A\d+:", block, maxsplit=1) question = parts[0].strip() answer = parts[1].strip() if len(parts) > 1 else "N/A" else: question = block.strip() answer = "N/A" qa_pairs.append({"question": question, "answer": answer}) return qa_pairs # ── Session State Init ──────────────────────────── if "history" not in st.session_state: st.session_state.history = [] if "total_generated" not in st.session_state: st.session_state.total_generated = 0 if "parsed_qa" not in st.session_state: st.session_state.parsed_qa = [] if "mock_index" not in st.session_state: st.session_state.mock_index = 0 if "mock_scores" not in st.session_state: st.session_state.mock_scores = [] if "mock_active" not in st.session_state: st.session_state.mock_active = False # ── Header ──────────────────────────────────────── st.markdown("
🎯 InterviewGen AI
", unsafe_allow_html=True) st.markdown("Professional Interview Preparation Powered by LLaMA-3.3 & Groq
", unsafe_allow_html=True) st.divider() # ── Top Metrics ─────────────────────────────────── col1, col2, col3, col4 = st.columns(4) with col1: st.metric("Questions Generated", st.session_state.total_generated) with col2: st.metric("Sessions", len(st.session_state.history)) with col3: st.metric("Mock Interviews", len(st.session_state.mock_scores)) with col4: avg = sum(st.session_state.mock_scores) / len(st.session_state.mock_scores) if st.session_state.mock_scores else 0 st.metric("Avg Mock Score", f"{avg:.1f}/10") st.divider() # ── Sidebar ─────────────────────────────────────── with st.sidebar: st.markdown("## Settings") role = st.selectbox( "Select Role", ["Python Developer", "Data Scientist", "Software Engineer", "ML Engineer", "DevOps Engineer", "Full Stack Developer", "Data Analyst", "Backend Developer", "Frontend Developer", "AI Engineer"] ) difficulty = st.select_slider( "Difficulty Level", options=["Junior", "Mid-Level", "Senior"] ) num_questions = st.slider( "Number of Questions", min_value=1, max_value=10, value=5 ) show_answers = st.toggle("Show Answers", value=True) st.divider() st.markdown("### Paste Job Description (Optional)") job_desc = st.text_area( "Job Description", placeholder="Paste job description here for targeted questions...", height=150 ) # ── Tabs ────────────────────────────────────────── tab1, tab2, tab3 = st.tabs([ "📋 Generate Questions", "🎯 Mock Interview Mode", "📚 History" ]) # ════════════════════════════════════════════════ # TAB 1 — Generate Questions # ════════════════════════════════════════════════ with tab1: q_type = st.radio( "Question Type", ["Technical", "Behavioral", "Mixed"], horizontal=True ) generate_btn = st.button( "🚀 Generate Interview Questions", use_container_width=True ) if generate_btn: with st.spinner("LLaMA-3.3 is generating questions..."): raw = generate_questions(role, difficulty, q_type, num_questions, job_desc) parsed = parse_questions(raw) st.session_state.parsed_qa = parsed st.markdown(f"### {role} | {difficulty} | {q_type}") st.divider() questions = [] answers = [] for i, qa in enumerate(parsed): q = qa["question"] a = qa["answer"] questions.append(q) answers.append(a) st.info(f"**Q{i+1}.** {q}") if show_answers: st.success(f"**Answer:** {a}") st.write("") st.session_state.total_generated += len(parsed) st.session_state.history.append({ "time" : datetime.datetime.now().strftime("%H:%M:%S"), "role" : role, "difficulty": difficulty, "type" : q_type, "questions" : questions, "answers" : answers }) # ── PDF Export ──────────────────────────── try: pdf = FPDF() pdf.add_page() pdf.set_font("Arial", "B", 14) pdf.cell(190, 10, f"Interview Questions - {role}", ln=True, align="C") pdf.set_font("Arial", "", 9) pdf.cell(190, 8, f"Type: {q_type} | Difficulty: {difficulty}", ln=True, align="C") pdf.ln(4) for i, (q, a) in enumerate(zip(questions, answers)): q_c = q.encode("latin-1", "replace").decode("latin-1") a_c = a.encode("latin-1", "replace").decode("latin-1") pdf.set_font("Arial", "B", 10) pdf.multi_cell(190, 7, f"Q{i+1}. {q_c}") if show_answers: pdf.set_font("Arial", "", 9) pdf.multi_cell(190, 6, f"Answer: {a_c}") pdf.ln(2) pdf_path = "/tmp/interview_questions.pdf" pdf.output(pdf_path) with open(pdf_path, "rb") as f: st.download_button( label = "📥 Download as PDF", data = f, file_name = f"interview_{role.replace(' ','_')}.pdf", mime = "application/pdf" ) except Exception as e: st.warning(f"PDF error: {e}") # ════════════════════════════════════════════════ # TAB 2 — Mock Interview Mode # ════════════════════════════════════════════════ with tab2: st.markdown("### 🎯 Mock Interview Mode") st.markdown("Answer questions one by one — AI will evaluate your answers!") st.divider() if not st.session_state.parsed_qa: st.info("First generate questions in Tab 1, then come back here!") else: total_q = len(st.session_state.parsed_qa) idx = st.session_state.mock_index if idx < total_q: current_qa = st.session_state.parsed_qa[idx] st.markdown(f"**Question {idx+1} of {total_q}**") st.progress((idx) / total_q) st.markdown(f"""