# utils/reporting.py import re import fitz # PyMuPDF from io import BytesIO from config import supabase, embedding_model, client, query from .screening import evaluate_resumes def generate_pdf_report(shortlisted_candidates, questions=None): """ Creates a PDF report summarizing top candidates and interview questions. """ pdf = BytesIO() doc = fitz.open() for candidate in shortlisted_candidates: page = doc.new_page() info = ( f"Candidate: {candidate['name']}\n" f"Email: {candidate['email']}\n" f"Score: {candidate['score']}\n\n" f"Summary:\n{candidate.get('summary', 'No summary available')}" ) page.insert_textbox(fitz.Rect(50, 50, 550, 750), info, fontsize=11, fontname="helv", align=0) if questions: q_page = doc.new_page() q_text = "Suggested Interview Questions:\n\n" + "\n".join(questions) q_page.insert_textbox(fitz.Rect(50, 50, 550, 750), q_text, fontsize=11, fontname="helv", align=0) doc.save(pdf) pdf.seek(0) return pdf def generate_interview_questions_from_summaries(candidates): if not isinstance(candidates, list): raise TypeError("Expected a list of candidate dictionaries.") summaries = " ".join(c.get("summary", "") for c in candidates) prompt = ( "Based on the following summary of a top candidate for a job role, " "generate 5 thoughtful, general interview questions that would help a recruiter assess their fit:\n\n" f"{summaries}" ) try: response = client.chat.completions.create( model="tgi", messages=[{"role": "user", "content": prompt}], temperature=0.7, max_tokens=500, ) result = response.choices[0].message.content # Clean and normalize questions raw_questions = result.split("\n") questions = [] for q in raw_questions: q = q.strip() # Skip empty lines and markdown headers if not q or re.match(r"^#+\s*", q): continue # Remove leading bullets like "1.", "1)", "- 1.", etc. q = re.sub(r"^(?:[-*]?\s*)?(?:Q?\d+[\.\)\-]?\s*)+", "", q) # Remove markdown bold/italics (**, *, etc.) q = re.sub(r"[*_]+", "", q) # Remove duplicate trailing punctuation q = q.strip(" .") questions.append(q.strip()) return [f"Q{i+1}. {q}" for i, q in enumerate(questions[:5])] or ["⚠️ No questions generated."] except Exception as e: print(f"❌ Error generating interview questions: {e}") return ["⚠️ Error generating questions."]