Spaces:
Running
Running
Johnny
commited on
Commit
·
9387654
1
Parent(s):
79e434c
added unit tests
Browse files- config.py +4 -4
- test_module.py +67 -0
- utils.py +6 -2
config.py
CHANGED
@@ -19,7 +19,7 @@ supabase = create_client(SUPABASE_URL, SUPABASE_KEY)
|
|
19 |
embedding_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
20 |
|
21 |
HF_MODELS = {
|
22 |
-
"
|
23 |
}
|
24 |
|
25 |
HF_API_TOKEN = os.getenv("HF_API_TOKEN")
|
@@ -28,18 +28,18 @@ if not HF_API_TOKEN:
|
|
28 |
|
29 |
HF_HEADERS = {"Authorization": f"Bearer {HF_API_TOKEN}"}
|
30 |
|
31 |
-
def query(payload, model="
|
32 |
"""
|
33 |
Sends a request to the Hugging Face API with retries.
|
34 |
|
35 |
:param payload: The input data for inference.
|
36 |
-
:param model: The model name ('
|
37 |
:param retries: Number of times to retry if the request fails.
|
38 |
:param delay: Delay in seconds before retrying.
|
39 |
:return: The model's response in JSON format, or None if all retries fail.
|
40 |
"""
|
41 |
if model not in HF_MODELS:
|
42 |
-
raise ValueError("Invalid model name. Choose '
|
43 |
|
44 |
api_url = HF_MODELS[model]
|
45 |
|
|
|
19 |
embedding_model = SentenceTransformer("sentence-transformers/all-MiniLM-L6-v2")
|
20 |
|
21 |
HF_MODELS = {
|
22 |
+
"bart": "https://router.huggingface.co/hf-inference/models/facebook/bart-large-cnn"
|
23 |
}
|
24 |
|
25 |
HF_API_TOKEN = os.getenv("HF_API_TOKEN")
|
|
|
28 |
|
29 |
HF_HEADERS = {"Authorization": f"Bearer {HF_API_TOKEN}"}
|
30 |
|
31 |
+
def query(payload, model="bart", retries=3, delay=5):
|
32 |
"""
|
33 |
Sends a request to the Hugging Face API with retries.
|
34 |
|
35 |
:param payload: The input data for inference.
|
36 |
+
:param model: The model name ('bart' for summarization).
|
37 |
:param retries: Number of times to retry if the request fails.
|
38 |
:param delay: Delay in seconds before retrying.
|
39 |
:return: The model's response in JSON format, or None if all retries fail.
|
40 |
"""
|
41 |
if model not in HF_MODELS:
|
42 |
+
raise ValueError("Invalid model name. Choose 'bart' for summarization.")
|
43 |
|
44 |
api_url = HF_MODELS[model]
|
45 |
|
test_module.py
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import pytest
|
2 |
+
import fitz # PyMuPDF
|
3 |
+
import re
|
4 |
+
from io import BytesIO
|
5 |
+
import torch
|
6 |
+
from unittest.mock import MagicMock, patch
|
7 |
+
from config import SUPABASE_URL, SUPABASE_KEY, HF_API_TOKEN, HF_HEADERS, supabase, HF_MODELS, query, embedding_model
|
8 |
+
from utils import (
|
9 |
+
evaluate_resumes, parse_resume, extract_email, score_candidate,
|
10 |
+
summarize_resume, store_in_supabase, generate_pdf_report
|
11 |
+
)
|
12 |
+
|
13 |
+
def test_parse_resume():
|
14 |
+
pdf_content = BytesIO()
|
15 |
+
doc = fitz.open()
|
16 |
+
page = doc.new_page()
|
17 |
+
page.insert_text((50, 50), "Sample Resume Text")
|
18 |
+
doc.save(pdf_content)
|
19 |
+
pdf_content.seek(0)
|
20 |
+
|
21 |
+
extracted_text = parse_resume(pdf_content)
|
22 |
+
assert "Sample Resume Text" in extracted_text
|
23 |
+
|
24 |
+
def test_extract_email():
|
25 |
+
text = "Contact me at test@example.com for details."
|
26 |
+
assert extract_email(text) == "test@example.com"
|
27 |
+
|
28 |
+
text_no_email = "No email here."
|
29 |
+
assert extract_email(text_no_email) is None
|
30 |
+
|
31 |
+
@patch("test_module.embedding_model.encode")
|
32 |
+
def test_score_candidate(mock_encode):
|
33 |
+
# Mock embeddings as tensors with the same shape as actual embeddings
|
34 |
+
mock_encode.return_value = torch.tensor([0.1, 0.2, 0.3])
|
35 |
+
|
36 |
+
score = score_candidate("Resume text", "Job description")
|
37 |
+
|
38 |
+
assert isinstance(score, float)
|
39 |
+
assert 0 <= score <= 1 # Ensure score is within valid range
|
40 |
+
|
41 |
+
@patch("test_module.query")
|
42 |
+
def test_summarize_resume(mock_query):
|
43 |
+
mock_query.return_value = [{"generated_text": "This is a summary."}]
|
44 |
+
summary = summarize_resume("Long resume text")
|
45 |
+
assert summary == "This is a summary."
|
46 |
+
|
47 |
+
mock_query.return_value = None
|
48 |
+
assert summarize_resume("Long resume text") == "Summary could not be generated."
|
49 |
+
|
50 |
+
@patch("test_module.supabase.table")
|
51 |
+
def test_store_in_supabase(mock_table):
|
52 |
+
mock_insert = mock_table.return_value.insert.return_value.execute
|
53 |
+
mock_insert.return_value = {"status": "success"}
|
54 |
+
|
55 |
+
response = store_in_supabase("Resume text", 0.8, "John Doe", "john@example.com", "Summary")
|
56 |
+
assert response["status"] == "success"
|
57 |
+
|
58 |
+
def test_generate_pdf_report():
|
59 |
+
candidates = [{
|
60 |
+
"name": "John Doe",
|
61 |
+
"email": "john@example.com",
|
62 |
+
"score": 0.9,
|
63 |
+
"summary": "A skilled developer."
|
64 |
+
}]
|
65 |
+
pdf = generate_pdf_report(candidates)
|
66 |
+
assert isinstance(pdf, BytesIO)
|
67 |
+
assert pdf.getvalue() # Check that the PDF is not empty
|
utils.py
CHANGED
@@ -65,17 +65,21 @@ def score_candidate(resume_text, job_description):
|
|
65 |
except Exception as e:
|
66 |
print(f"Error computing similarity score: {e}")
|
67 |
return 0 # Return 0 if scoring fails
|
|
|
|
|
|
|
|
|
68 |
|
69 |
def summarize_resume(resume_text):
|
70 |
"""
|
71 |
-
Summarizes a resume using the Google
|
72 |
|
73 |
:param resume_text: The resume text to summarize.
|
74 |
:return: A summarized version of the resume.
|
75 |
"""
|
76 |
payload = {"inputs": f"Summarize this resume: {resume_text}"}
|
77 |
|
78 |
-
response = query(payload, model="
|
79 |
|
80 |
if response is None:
|
81 |
print("Error: API response is None")
|
|
|
65 |
except Exception as e:
|
66 |
print(f"Error computing similarity score: {e}")
|
67 |
return 0 # Return 0 if scoring fails
|
68 |
+
|
69 |
+
# create multiple agents for different scoring
|
70 |
+
# agent_experience, agent_programming_language, agent_education, agent_soft_skills, etc etc
|
71 |
+
# Scoring from 1-5
|
72 |
|
73 |
def summarize_resume(resume_text):
|
74 |
"""
|
75 |
+
Summarizes a resume using the Google bart model.
|
76 |
|
77 |
:param resume_text: The resume text to summarize.
|
78 |
:return: A summarized version of the resume.
|
79 |
"""
|
80 |
payload = {"inputs": f"Summarize this resume: {resume_text}"}
|
81 |
|
82 |
+
response = query(payload, model="bart") # Use bart for summarization
|
83 |
|
84 |
if response is None:
|
85 |
print("Error: API response is None")
|