HR-2 / app.py
DreamStream-1's picture
Update app.py
1d2b5c6 verified
import os
import gradio as gr
import requests
import PyPDF2
import spacy
from transformers import pipeline
# Load spaCy for NER tasks
nlp = spacy.load("en_core_web_sm")
# Summarization model
summarizer = pipeline("summarization", model="facebook/bart-large-cnn")
# Sentiment analysis model
sentiment_analyzer = pipeline("sentiment-analysis", model="distilbert-base-uncased-finetuned-sst-2-english")
# Set up your Groq API endpoint and API key
GROQ_API_URL = "https://api.groq.com/v1/models/llama" # Update this if needed
GROQ_API_KEY = "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" # Replace with your actual API key
def extract_text_from_pdf(file):
"""Extract text from uploaded PDF file."""
if file is None:
return ""
try:
pdf_reader = PyPDF2.PdfReader(file)
text = ""
for page in pdf_reader.pages:
page_text = page.extract_text() or ""
text += page_text
return text
except Exception as e:
return f"Error extracting PDF text: {str(e)}"
def extract_text_from_file(file):
"""Extract text from uploaded file (PDF or TXT)."""
if file is None:
return ""
if file.name.endswith('.pdf'):
return extract_text_from_pdf(file)
elif file.name.endswith('.txt'):
return file.read().decode('utf-8')
else:
return "Unsupported file format. Please upload PDF or TXT files only."
def extract_skills(text):
"""Extract skills from text using a pre-trained NER model."""
doc = nlp(text)
skills = [ent.text for ent in doc.ents if ent.label_ == "SKILL"]
return list(set(skills))
def extract_education_and_experience(text):
"""Extract education and experience information from text using NER."""
doc = nlp(text)
education = [ent.text for ent in doc.ents if ent.label_ in ["EDUCATION", "DEGREE"]]
experience = [ent.text for ent in doc.ents if ent.label_ == "EXPERIENCE"]
return {
'education': list(set(education)),
'experience': list(set(experience))
}
def calculate_match_percentage(resume_skills, job_skills):
"""Calculate the match percentage between resume skills and job requirements."""
if not job_skills:
return 0
matching_skills = set(resume_skills).intersection(set(job_skills))
return (len(matching_skills) / len(job_skills)) * 100
def call_groq_api(prompt):
"""Call the Groq API with the prompt and return the response."""
headers = {
"Authorization": f"Bearer {GROQ_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "llama3-8b-8192", # Use the specified LLaMA model
"prompt": prompt,
"max_tokens": 150 # Adjust as needed
}
try:
response = requests.post(GROQ_API_URL, headers=headers, json=payload)
if response.status_code == 200:
return response.json().get("output", "No output received.")
else:
return f"API call failed with status {response.status_code}: {response.text}"
except requests.exceptions.RequestException as e:
return f"Request failed: {str(e)}"
def summarize_text(text, max_length=100):
"""Summarize the input text using the summarization model."""
return summarizer(text, max_length=max_length, min_length=30, do_sample=False)[0]['summary_text']
def sentiment_analysis(text):
"""Perform sentiment analysis on the given text."""
return sentiment_analyzer(text)[0]
def analyze_resume_and_job(resume_file, job_desc_file):
"""Main function to analyze resume and job description."""
try:
# Extract text from files
resume_text = extract_text_from_file(resume_file)
job_desc_text = extract_text_from_file(job_desc_file)
if not resume_text or not job_desc_text:
return {
"error": "Could not extract text from one or both files"
}
# Summarize resume and job description
resume_summary = summarize_text(resume_text)
job_desc_summary = summarize_text(job_desc_text)
# Perform sentiment analysis on the resume summary
resume_sentiment = sentiment_analysis(resume_summary)
# Extract information from resume
resume_skills = extract_skills(resume_text)
resume_info = extract_education_and_experience(resume_text)
# Extract information from job description
job_skills = extract_skills(job_desc_text)
job_info = extract_education_and_experience(job_desc_text)
# Calculate match percentages
skills_match = calculate_match_percentage(resume_skills, job_skills)
# Prepare input for LLaMA via Groq API
input_prompt = f"Analyze the following resume: {resume_text[:300]} and job description: {job_desc_text[:300]}."
# Call Groq API to analyze using LLaMA
llama_analysis = call_groq_api(input_prompt)
# Prepare analysis results
summary = f"""
### Summary Analysis
- Overall Skills Match: {skills_match:.1f}%
- Experience Found: {', '.join(resume_info['experience'])}
- Education Found: {', '.join(resume_info['education'])}
"""
skills = f"""
### Skills Analysis
Resume Skills:
{', '.join(resume_skills)}
Required Skills:
{', '.join(job_skills)}
Missing Skills:
{', '.join(set(job_skills) - set(resume_skills))}
"""
qualifications = f"""
### Qualifications
Education Found:
{', '.join(resume_info['education'])}
Required Education:
{', '.join(job_info['education'])}
"""
sentiment = f"""
### Sentiment Analysis
Resume Sentiment: {resume_sentiment['label']} (Confidence: {resume_sentiment['score']:.2f})
"""
# Generate recommendation based on skills match
recommendation = "Recommendation based on skills match and experience."
if skills_match >= 70:
recommendation = "Strong Match - Recommended for interview."
elif skills_match >= 50:
recommendation = "Moderate Match - Consider for interview with focus on missing skills."
else:
recommendation = "Low Match - May not meet core requirements."
recommendation = f"""
### Recommendation
{recommendation}
"""
return {
"summary": summary.strip(),
"skills": skills.strip(),
"qualifications": qualifications.strip(),
"recommendation": recommendation.strip(),
"llama_analysis": llama_analysis.strip(),
"sentiment": sentiment.strip(),
"resume_summary": resume_summary.strip(),
"job_summary": job_desc_summary.strip()
}
except Exception as e:
return {
"error": f"Analysis failed: {str(e)}"
}
# Create Gradio interface
def create_interface():
with gr.Blocks(title="Resume Analyzer", theme=gr.themes.Soft()) as demo:
gr.Markdown("# Smart Resume Analyzer")
gr.Markdown("Upload your resume and job description for instant analysis")
with gr.Row():
resume_input = gr.File(label="Upload Resume (PDF/TXT)")
job_desc_input = gr.File(label="Upload Job Description (PDF/TXT)")
analyze_button = gr.Button("Analyze")
with gr.Tabs():
with gr.TabItem("Summary"):
summary_output = gr.Markdown()
with gr.TabItem("Skills Analysis"):
skills_output = gr.Markdown()
with gr.TabItem("Qualifications"):
qualifications_output = gr.Markdown()
with gr.TabItem("Recommendation"):
recommendation_output = gr.Markdown()
with gr.TabItem("LLaMA Analysis"):
llama_output = gr.Markdown()
with gr.TabItem("Sentiment Analysis"):
sentiment_output = gr.Markdown()
with gr.TabItem("Resume Summary"):
resume_summary_output = gr.Markdown()
with gr.TabItem("Job Description Summary"):
job_summary_output = gr.Markdown()
def analyze(resume_file, job_desc_file):
if not resume_file or not job_desc_file:
return "Please upload both resume and job description."
analysis_results = analyze_resume_and_job(resume_file, job_desc_file)
summary_output.update(analysis_results.get("summary", ""))
skills_output.update(analysis_results.get("skills", ""))
qualifications_output.update(analysis_results.get("qualifications", ""))
recommendation_output.update(analysis_results.get("recommendation", ""))
llama_output.update(analysis_results.get("llama_analysis", ""))
sentiment_output.update(analysis_results.get("sentiment", ""))
resume_summary_output.update(analysis_results.get("resume_summary", ""))
job_summary_output.update(analysis_results.get("job_summary", ""))
analyze_button.click(analyze, inputs=[resume_input, job_desc_input])
return demo
# Launch Gradio app
if __name__ == "__main__":
create_interface().launch()