Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import streamlit as st | |
| from PyPDF2 import PdfReader | |
| import docx | |
| from langchain import LLMChain | |
| from langchain.prompts import PromptTemplate | |
| from langsmith import Client | |
| from typing import List, Dict | |
| import langchain | |
| from pydantic import BaseModel | |
| # Initialize LangSmith Client for monitoring | |
| client = Client(api_key="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") | |
| # Load Local LLM model (For demo, we'll use a dummy function) | |
| def load_local_llm(): | |
| # You can integrate a local LLM like GPT4All, or HuggingFace model here | |
| return lambda prompt: f"Dummy LLM response for: {prompt}" | |
| llm = load_local_llm() | |
| # LangChain setup for monitoring | |
| class LLMMonitor: | |
| def __init__(self, name: str): | |
| self.name = name | |
| def call(self, prompt: str): | |
| result = llm(prompt) # Execute the LLM locally | |
| # Log the run to LangSmith (dummy logging to console for now) | |
| print(f"Logging to LangSmith: {self.name} - Input: {prompt} | Output: {result}") | |
| return result | |
| # Resume Reader Agent | |
| def read_resume(file_path: str) -> str: | |
| if file_path.endswith('.pdf'): | |
| reader = PdfReader(file_path) | |
| text = ''.join([page.extract_text() for page in reader.pages]) | |
| elif file_path.endswith('.docx'): | |
| doc = docx.Document(file_path) | |
| text = '\n'.join([para.text for para in doc.paragraphs]) | |
| else: | |
| raise ValueError("Unsupported file type. Please upload a PDF or DOCX.") | |
| return text | |
| # Entity Extraction Agent | |
| class EntityExtractionAgent: | |
| def __init__(self): | |
| self.monitor = LLMMonitor("EntityExtractor") | |
| def extract_entities(self, resume_text: str) -> Dict: | |
| prompt = f"Extract personal info, education, experience, and skills from this resume:\n\n{resume_text}" | |
| response = self.monitor.call(prompt) | |
| # For simplicity, we return a dummy structured data | |
| return {"name": "John Doe", "education": "B.Sc in CS", "experience": "2 years at XYZ", "skills": ["Python", "SQL"]} | |
| # Entity Validation Agent | |
| class EntityValidationAgent: | |
| def __init__(self): | |
| self.monitor = LLMMonitor("EntityValidator") | |
| def validate_entities(self, entities: Dict) -> Dict: | |
| # Add dummy validation logic here | |
| if not entities["name"] or not entities["education"]: | |
| feedback = "Invalid or incomplete entity data. Please correct." | |
| st.write(feedback) | |
| return {"status": "validation_failed", "entities": entities, "feedback": feedback} | |
| else: | |
| return {"status": "validated", "entities": entities} | |
| # Streamlit Human Feedback Loop | |
| def human_feedback(entities: Dict): | |
| st.write("Please review the extracted entities below:") | |
| name = st.text_input("Name", entities["name"]) | |
| education = st.text_input("Education", entities["education"]) | |
| experience = st.text_area("Experience", entities["experience"]) | |
| skills = st.text_input("Skills (comma-separated)", ','.join(entities["skills"])) | |
| if st.button("Submit Feedback"): | |
| return {"name": name, "education": education, "experience": experience, "skills": skills.split(",")} | |
| return entities | |
| # Human Feedback Loop after resume reading | |
| def resume_feedback(resume_text: str): | |
| st.write("Resume Text: Please review the resume text extracted:") | |
| resume_text = st.text_area("Resume Text", resume_text) | |
| if st.button("Submit Resume Feedback"): | |
| st.write("Resume feedback submitted!") | |
| return resume_text | |
| # Human Feedback Loop after entity extraction | |
| def entity_extraction_feedback(entities: Dict): | |
| st.write("Extracted Entities: Please review and update the extracted entities:") | |
| entities = human_feedback(entities) | |
| if st.button("Submit Extraction Feedback"): | |
| st.write("Extraction feedback submitted!") | |
| return entities | |
| # Generate JSON Output | |
| def generate_json_output(entities: Dict) -> str: | |
| output_path = "resume_entities.json" | |
| json_data = json.dumps(entities, indent=4) # Create JSON string from the entities dictionary | |
| with open(output_path, 'w') as f: | |
| f.write(json_data) | |
| st.write(f"Output saved as {output_path}") | |
| return json_data # Return the JSON data instead of file path | |
| # Main function to orchestrate workflow | |
| def main(): | |
| st.title("LLM-Powered Multi-Agent Resume Processor") | |
| uploaded_file = st.file_uploader("Upload Resume (PDF or DOCX)", type=["pdf", "docx"]) | |
| if uploaded_file is not None: | |
| file_path = os.path.join("/tmp", uploaded_file.name) | |
| with open(file_path, "wb") as f: | |
| f.write(uploaded_file.getbuffer()) | |
| # Resume Reading | |
| resume_text = read_resume(file_path) | |
| st.write("Resume successfully read!") | |
| # Human feedback after resume reading | |
| resume_text = resume_feedback(resume_text) | |
| # Entity Extraction | |
| extractor = EntityExtractionAgent() | |
| entities = extractor.extract_entities(resume_text) | |
| st.write("Entities extracted:", entities) | |
| # Human feedback after entity extraction | |
| entities = entity_extraction_feedback(entities) | |
| # Entity Validation | |
| validator = EntityValidationAgent() | |
| validation_result = validator.validate_entities(entities) | |
| if validation_result["status"] == "validation_failed": | |
| st.write(validation_result["feedback"]) | |
| entities = human_feedback(validation_result["entities"]) | |
| # Final validated entities | |
| st.write("Final entities:", entities) | |
| # Generate JSON output | |
| json_data = generate_json_output(entities) # Use JSON data instead of file path | |
| # Pass the JSON data to st.download_button | |
| st.download_button("Download JSON Output", data=json_data, file_name="resume_entities.json") | |
| # Streamlit app entry point | |
| if __name__ == "__main__": | |
| main() | |