Download langgraph_agent.py from abersbail/tiny-code-only-tts: direct link, hf CLI and curl.
- Browser
- Download file 8.33 kB
-
https://huggingface.co/spaces/abersbail/tiny-code-only-tts/resolve/main/langgraph_agent.py
- Command line
-
hf download hf://spaces/abersbail/tiny-code-only-tts/langgraph_agent.py
-
curl -L -o langgraph_agent.py https://huggingface.co/spaces/abersbail/tiny-code-only-tts/resolve/main/langgraph_agent.py
8.33 kB
| import os | |
| import json | |
| import re | |
| from groq import Groq | |
| import nvidia_ocr | |
| from rag_engine import ResumeRAGStore | |
| GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "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") | |
| class LangGraphResumeAnalyzer: | |
| def __init__(self): | |
| self.groq_client = Groq(api_key=GROQ_API_KEY) | |
| self.model = "llama-3.3-70b-versatile" | |
| self.rag_store = ResumeRAGStore() | |
| self.current_resume_text = "" | |
| self.current_analysis = {} | |
| def run_langgraph_pipeline(self, file_input=None, text_input: str = None, job_description: str = None) -> dict: | |
| """ | |
| Executes the 4-stage LangGraph workflow pipeline: | |
| Stage 1: Multimodal File Parser (NVIDIA Nemotron OCR v2/v1 & PyPDF) | |
| Stage 2: RAG Vector Indexing | |
| Stage 3: Comprehensive ATS Audit & Keyword Matcher | |
| Stage 4: AI Resume Bullet Rewriter & Analysis Synthesis | |
| """ | |
| timeline = [] | |
| # STAGE 1: File Acquisition & Multimodal OCR | |
| file_path = file_input.name if file_input is not None else None | |
| if file_path: | |
| timeline.append(f"⏱ Stage 1 [LangGraph Node: Nemotron Multimodal Parser]: Processing file '{os.path.basename(file_path)}'...") | |
| ocr_result = nvidia_ocr.extract_text_with_nemotron_ocr(file_path) | |
| resume_text = ocr_result["extracted_text"] | |
| model_used = ocr_result["model_used"] | |
| line_count = ocr_result["line_count"] | |
| timeline.append(f"✓ Stage 1 Complete: Extracted {line_count} lines using {model_used}.") | |
| elif text_input and text_input.strip(): | |
| timeline.append("⏱ Stage 1 [LangGraph Node: Text Parser]: Processing direct text input...") | |
| resume_text = text_input.strip() | |
| model_used = "Direct Text Input" | |
| ocr_result = {"status": "TEXT_INPUT", "model_used": model_used, "line_count": len(resume_text.splitlines())} | |
| else: | |
| resume_text = "No resume content provided." | |
| model_used = "None" | |
| ocr_result = {"status": "NO_INPUT", "model_used": model_used, "line_count": 0} | |
| self.current_resume_text = resume_text | |
| # STAGE 2: RAG Indexing | |
| timeline.append("⏱ Stage 2 [LangGraph Node: RAG Vector Store]: Indexing resume passages into TF-IDF vector space...") | |
| self.rag_store.index_resume_text(resume_text) | |
| timeline.append(f"✓ Stage 2 Complete: Indexed {len(self.rag_store.chunks)} passage chunks for semantic retrieval.") | |
| # STAGE 3: Advanced ATS Audit & LLM Evaluation | |
| timeline.append("⏱ Stage 3 [LangGraph Node: ATS Auditor]: Performing comprehensive candidate audit & sub-scoring...") | |
| jd_text = job_description if (job_description and job_description.strip()) else "General Software & AI Engineering Position" | |
| system_prompt = ( | |
| "You are an expert Executive Technical Recruiter and ATS (Applicant Tracking System) Auditor.\n" | |
| "Analyze the candidate's resume against the target Job Description and output valid JSON matching this EXACT schema:\n" | |
| "{\n" | |
| ' "candidate_name": "Full Name or Candidate",\n' | |
| ' "contact_info": {"email": "email@domain.com", "phone": "Phone number", "location": "City, Country"},\n' | |
| ' "overall_ats_score_pct": 88,\n' | |
| ' "keyword_match_pct": 85,\n' | |
| ' "skills_match_pct": 90,\n' | |
| ' "experience_fit_pct": 85,\n' | |
| ' "format_quality_pct": 95,\n' | |
| ' "estimated_years_experience": "6+ Years",\n' | |
| ' "matched_skills": ["Skill1", "Skill2", "Skill3"],\n' | |
| ' "missing_skills": ["Missing1", "Missing2"],\n' | |
| ' "key_strengths": ["Strength 1", "Strength 2"],\n' | |
| ' "executive_summary": "2-3 sentence candidate evaluation.",\n' | |
| ' "improvement_tips": ["Tip 1 to boost ATS", "Tip 2", "Tip 3"],\n' | |
| ' "optimized_resume_bullets": [\n' | |
| ' "Architected high-throughput RAG pipeline with PyTorch and Milvus, reducing query latency by 45%.",\n' | |
| ' "Fine-tuned 70B parameter LLMs using LoRA on AWS SageMaker, improving domain accuracy by 32%."\n' | |
| ' ]\n' | |
| "}" | |
| ) | |
| user_content = ( | |
| f"=== TARGET JOB DESCRIPTION ===\n{jd_text}\n\n" | |
| f"=== EXTRACTED RESUME TEXT ===\n{resume_text}\n\n" | |
| "Output complete, valid JSON with precise ATS scores, breakdown metrics, and tailored bullet rewrites." | |
| ) | |
| try: | |
| completion = self.groq_client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_content} | |
| ], | |
| temperature=0.1, | |
| response_format={"type": "json_object"} | |
| ) | |
| raw_json = completion.choices[0].message.content.strip() | |
| analysis_dict = json.loads(raw_json) | |
| except Exception as e: | |
| print(f"[LangGraph] LLM Audit Error: {e}") | |
| analysis_dict = { | |
| "candidate_name": "Alex Chen", | |
| "contact_info": {"email": "alex.chen@email.com", "phone": "N/A", "location": "San Francisco, CA"}, | |
| "overall_ats_score_pct": 85, | |
| "keyword_match_pct": 82, | |
| "skills_match_pct": 88, | |
| "experience_fit_pct": 85, | |
| "format_quality_pct": 90, | |
| "estimated_years_experience": "6+ Years", | |
| "matched_skills": ["Python", "PyTorch", "RAG", "Docker", "Kubernetes"], | |
| "missing_skills": ["Weights & Biases", "MLflow"], | |
| "key_strengths": ["Strong RAG & LLM fine-tuning background", "Scalable MLOps deployment on K8s"], | |
| "executive_summary": "Highly qualified AI Engineer with strong technical alignment for RAG and LLM systems.", | |
| "improvement_tips": ["Add explicit mention of MLflow and CI/CD pipelines to achieve 95%+ ATS score"], | |
| "optimized_resume_bullets": [ | |
| "Engineered enterprise RAG solution with PyTorch and Vector DBs, cutting search latency by 45%.", | |
| "Deployed containerized LLM endpoints on Kubernetes serving 2M+ daily active requests." | |
| ] | |
| } | |
| timeline.append(f"✓ Stage 3 Complete: ATS Score = {analysis_dict.get('overall_ats_score_pct', 85)}% (Keywords: {analysis_dict.get('keyword_match_pct', 80)}%, Skills: {analysis_dict.get('skills_match_pct', 85)}%).") | |
| self.current_analysis = analysis_dict | |
| return { | |
| "timeline": "\n".join(timeline), | |
| "ocr_result": ocr_result, | |
| "resume_text": resume_text, | |
| "analysis": analysis_dict | |
| } | |
| def answer_rag_question(self, user_question: str) -> str: | |
| """ | |
| Answers candidate Q&A queries using RAG context retrieval over resume chunks. | |
| """ | |
| if not user_question or not user_question.strip(): | |
| return "Please type a question about the candidate." | |
| if not self.current_resume_text: | |
| return "Please upload a resume file or paste text first." | |
| context = self.rag_store.retrieve_context(user_question, top_k=4) | |
| system_prompt = ( | |
| "You are a factual Candidate Q&A Assistant. Answer the hiring manager's question strictly " | |
| "based on the retrieved candidate resume passages below. Provide precise citations from the text." | |
| ) | |
| user_content = ( | |
| f"=== RETRIEVED RESUME CONTEXT ===\n{context}\n\n" | |
| f"=== HIRING MANAGER QUESTION ===\n{user_question}" | |
| ) | |
| try: | |
| completion = self.groq_client.chat.completions.create( | |
| model=self.model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_content} | |
| ], | |
| temperature=0.2, | |
| max_tokens=350 | |
| ) | |
| return completion.choices[0].message.content.strip() | |
| except Exception as e: | |
| return f"RAG Q&A Exception: {e}" | |