Spaces:
Configuration error
Configuration error
Removed default document loading logic
Browse files- functions/gradio.py +12 -117
- functions/writer_agent.py +5 -5
- resumate.py +3 -24
- tests/test_gradio.py +26 -59
functions/gradio.py
CHANGED
@@ -5,13 +5,11 @@ Functions for handling Gradio UI interactions and processing user inputs.
|
|
5 |
"""
|
6 |
|
7 |
import logging
|
8 |
-
import shutil
|
9 |
from pathlib import Path
|
10 |
-
from functions.linkedin_resume import extract_text_from_linkedin_pdf
|
11 |
from functions.github import get_github_repositories
|
12 |
-
from functions.job_call import
|
13 |
from functions.writer_agent import write_resume
|
14 |
-
from configuration import DEFAULT_GITHUB_PROFILE
|
15 |
|
16 |
# pylint: disable=broad-exception-caught
|
17 |
|
@@ -20,35 +18,12 @@ logging.basicConfig(level=logging.INFO)
|
|
20 |
logger = logging.getLogger(__name__)
|
21 |
|
22 |
|
23 |
-
def process_with_default_option(
|
24 |
-
use_default_pdf,
|
25 |
-
linkedin_pdf,
|
26 |
-
github_profile,
|
27 |
-
job_post,
|
28 |
-
user_instructions
|
29 |
-
):
|
30 |
-
"""Process inputs with consideration for default PDF option."""
|
31 |
-
|
32 |
-
has_default, default_path = check_default_linkedin_pdf()
|
33 |
-
|
34 |
-
# Determine which PDF file to use
|
35 |
-
pdf_file = None
|
36 |
-
|
37 |
-
if use_default_pdf and has_default:
|
38 |
-
pdf_file = MockFile(default_path)
|
39 |
-
|
40 |
-
elif linkedin_pdf is not None:
|
41 |
-
pdf_file = linkedin_pdf
|
42 |
-
|
43 |
-
return process_inputs(pdf_file, github_profile, job_post, user_instructions)
|
44 |
-
|
45 |
-
|
46 |
def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
|
47 |
"""
|
48 |
Process the input files and URLs from the Gradio interface.
|
49 |
|
50 |
Args:
|
51 |
-
linkedin_pdf: Uploaded LinkedIn resume export PDF file
|
52 |
github_url (str): GitHub profile URL
|
53 |
job_post_text (str): Job post text content
|
54 |
user_instructions (str): Additional instructions from the user
|
@@ -62,33 +37,12 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
|
|
62 |
|
63 |
# Process LinkedIn PDF file
|
64 |
if linkedin_pdf is not None:
|
65 |
-
|
66 |
-
# Handle both file objects and mock file objects with path strings
|
67 |
file_path = linkedin_pdf.name
|
68 |
file_display_name = Path(file_path).name
|
69 |
|
70 |
result += "β
LinkedIn Resume PDF provided\n"
|
71 |
logger.info("Processing LinkedIn PDF: %s", file_display_name)
|
72 |
|
73 |
-
# Save uploaded file as new default (only if it's not already the default)
|
74 |
-
project_root = Path(__file__).parent.parent
|
75 |
-
default_pdf_path = project_root / "data" / "linkedin_profile.pdf"
|
76 |
-
|
77 |
-
# Check if this is an uploaded file (not the default file)
|
78 |
-
if not isinstance(linkedin_pdf, MockFile):
|
79 |
-
try:
|
80 |
-
# Create data directory if it doesn't exist
|
81 |
-
default_pdf_path.parent.mkdir(exist_ok=True)
|
82 |
-
|
83 |
-
# Copy uploaded file to default location
|
84 |
-
shutil.copy2(file_path, default_pdf_path)
|
85 |
-
result += " β
Saved as new default LinkedIn profile\n"
|
86 |
-
logger.info("Saved uploaded LinkedIn PDF as new default: %s", default_pdf_path)
|
87 |
-
|
88 |
-
except Exception as save_error:
|
89 |
-
result += f" β οΈ Could not save as default: {str(save_error)}\n"
|
90 |
-
logger.warning("Failed to save LinkedIn PDF as default: %s", str(save_error))
|
91 |
-
|
92 |
# Extract and structure text from the PDF
|
93 |
extraction_result = extract_text_from_linkedin_pdf(file_path)
|
94 |
|
@@ -107,24 +61,12 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
|
|
107 |
logger.info("No LinkedIn PDF file provided")
|
108 |
|
109 |
# Process GitHub profile
|
110 |
-
# Use default GitHub profile if none provided
|
111 |
if github_url and github_url.strip():
|
112 |
-
|
113 |
-
|
114 |
-
else:
|
115 |
-
github_url_to_use = DEFAULT_GITHUB_PROFILE
|
116 |
-
|
117 |
-
if github_url_to_use:
|
118 |
-
if github_url and github_url.strip():
|
119 |
-
result += "β
GitHub Profile URL provided\n"
|
120 |
-
|
121 |
-
else:
|
122 |
-
result += "β
Using default GitHub Profile URL\n"
|
123 |
-
|
124 |
-
logger.info("Processing GitHub URL: %s", github_url_to_use)
|
125 |
|
126 |
# Retrieve repositories from GitHub
|
127 |
-
github_result = get_github_repositories(
|
128 |
|
129 |
if github_result["status"] == "success":
|
130 |
result += " β
GitHub list download successful\n\n"
|
@@ -144,42 +86,15 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
|
|
144 |
if job_post_text and job_post_text.strip():
|
145 |
result += "β
Job post text provided\n"
|
146 |
logger.info("Job post text provided (%d characters)", len(job_post_text))
|
147 |
-
job_text_to_use = job_post_text.strip()
|
148 |
-
|
149 |
-
else:
|
150 |
-
result += "βΉοΈ No job post provided, attempting to use default\n"
|
151 |
-
logger.info("No job post text provided, trying default")
|
152 |
-
|
153 |
-
# Try to load default job call
|
154 |
-
default_job = load_default_job_call()
|
155 |
|
156 |
-
|
157 |
-
|
|
|
158 |
|
159 |
-
else:
|
160 |
-
result += "βΉοΈ No default job post available, proceeding without job post\n"
|
161 |
-
logger.info("No default job post available, proceeding without job analysis")
|
162 |
-
job_text_to_use = None
|
163 |
-
|
164 |
-
# Generate job summary (will use default if job_text_to_use is None)
|
165 |
-
summary = None
|
166 |
-
|
167 |
-
if job_text_to_use:
|
168 |
-
summary = summarize_job_call(job_text_to_use)
|
169 |
-
|
170 |
-
if summary:
|
171 |
-
if job_post_text and job_post_text.strip():
|
172 |
-
result += " β
Job post summary generated\n"
|
173 |
-
else:
|
174 |
-
result += "β
Using default job post\n"
|
175 |
-
result += " β
Job post summary generated\n"
|
176 |
-
logger.info("Job post summary generated (%d characters)", len(summary))
|
177 |
-
else:
|
178 |
-
result += " β Job post summary generation failed\n"
|
179 |
-
logger.warning("Job post summary generation failed")
|
180 |
else:
|
181 |
-
result += "
|
182 |
-
logger.info("No job post
|
|
|
183 |
|
184 |
# Process user instructions
|
185 |
if user_instructions and user_instructions.strip():
|
@@ -227,17 +142,6 @@ def get_processed_data(linkedin_pdf, github_url, job_post_text, instructions):
|
|
227 |
job_post_text = job_post_text.strip() if job_post_text and job_post_text.strip() else None
|
228 |
instructions = instructions.strip() if instructions and instructions.strip() else None
|
229 |
|
230 |
-
# If no job post text provided, try to get default
|
231 |
-
if not job_post_text:
|
232 |
-
default_job = load_default_job_call()
|
233 |
-
|
234 |
-
if default_job:
|
235 |
-
job_post_text = default_job
|
236 |
-
else:
|
237 |
-
# No job post provided and no default available
|
238 |
-
logger.info("No job post provided and no default available")
|
239 |
-
job_post_text = None
|
240 |
-
|
241 |
processed_data = {
|
242 |
"linkedin": None,
|
243 |
"github": None,
|
@@ -248,8 +152,6 @@ def get_processed_data(linkedin_pdf, github_url, job_post_text, instructions):
|
|
248 |
|
249 |
# Process LinkedIn PDF
|
250 |
if linkedin_pdf is not None:
|
251 |
-
|
252 |
-
# Handle both file objects and mock file objects with path strings
|
253 |
file_path = linkedin_pdf.name
|
254 |
extraction_result = extract_text_from_linkedin_pdf(file_path)
|
255 |
|
@@ -270,10 +172,3 @@ def get_processed_data(linkedin_pdf, github_url, job_post_text, instructions):
|
|
270 |
processed_data["errors"].append(f"GitHub: {github_result['message']}")
|
271 |
|
272 |
return processed_data
|
273 |
-
|
274 |
-
|
275 |
-
class MockFile:
|
276 |
-
"""Mock file object that mimics uploaded file interface with just a file path."""
|
277 |
-
|
278 |
-
def __init__(self, path):
|
279 |
-
self.name = path
|
|
|
5 |
"""
|
6 |
|
7 |
import logging
|
|
|
8 |
from pathlib import Path
|
9 |
+
from functions.linkedin_resume import extract_text_from_linkedin_pdf
|
10 |
from functions.github import get_github_repositories
|
11 |
+
from functions.job_call import summarize_job_call
|
12 |
from functions.writer_agent import write_resume
|
|
|
13 |
|
14 |
# pylint: disable=broad-exception-caught
|
15 |
|
|
|
18 |
logger = logging.getLogger(__name__)
|
19 |
|
20 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
21 |
def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
|
22 |
"""
|
23 |
Process the input files and URLs from the Gradio interface.
|
24 |
|
25 |
Args:
|
26 |
+
linkedin_pdf: Uploaded LinkedIn resume export PDF file
|
27 |
github_url (str): GitHub profile URL
|
28 |
job_post_text (str): Job post text content
|
29 |
user_instructions (str): Additional instructions from the user
|
|
|
37 |
|
38 |
# Process LinkedIn PDF file
|
39 |
if linkedin_pdf is not None:
|
|
|
|
|
40 |
file_path = linkedin_pdf.name
|
41 |
file_display_name = Path(file_path).name
|
42 |
|
43 |
result += "β
LinkedIn Resume PDF provided\n"
|
44 |
logger.info("Processing LinkedIn PDF: %s", file_display_name)
|
45 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
# Extract and structure text from the PDF
|
47 |
extraction_result = extract_text_from_linkedin_pdf(file_path)
|
48 |
|
|
|
61 |
logger.info("No LinkedIn PDF file provided")
|
62 |
|
63 |
# Process GitHub profile
|
|
|
64 |
if github_url and github_url.strip():
|
65 |
+
result += "β
GitHub Profile URL provided\n"
|
66 |
+
logger.info("Processing GitHub URL: %s", github_url.strip())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
# Retrieve repositories from GitHub
|
69 |
+
github_result = get_github_repositories(github_url.strip())
|
70 |
|
71 |
if github_result["status"] == "success":
|
72 |
result += " β
GitHub list download successful\n\n"
|
|
|
86 |
if job_post_text and job_post_text.strip():
|
87 |
result += "β
Job post text provided\n"
|
88 |
logger.info("Job post text provided (%d characters)", len(job_post_text))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
|
90 |
+
summary = summarize_job_call(job_post_text.strip())
|
91 |
+
result += " β
Job post summary generated\n"
|
92 |
+
logger.info("Job post summary generated (%d characters)", len(summary))
|
93 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
else:
|
95 |
+
result += "β Job post not provided\n"
|
96 |
+
logger.info("No job post text provided")
|
97 |
+
summary = None
|
98 |
|
99 |
# Process user instructions
|
100 |
if user_instructions and user_instructions.strip():
|
|
|
142 |
job_post_text = job_post_text.strip() if job_post_text and job_post_text.strip() else None
|
143 |
instructions = instructions.strip() if instructions and instructions.strip() else None
|
144 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
processed_data = {
|
146 |
"linkedin": None,
|
147 |
"github": None,
|
|
|
152 |
|
153 |
# Process LinkedIn PDF
|
154 |
if linkedin_pdf is not None:
|
|
|
|
|
155 |
file_path = linkedin_pdf.name
|
156 |
extraction_result = extract_text_from_linkedin_pdf(file_path)
|
157 |
|
|
|
172 |
processed_data["errors"].append(f"GitHub: {github_result['message']}")
|
173 |
|
174 |
return processed_data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
functions/writer_agent.py
CHANGED
@@ -11,7 +11,7 @@ from configuration import INFERENCE_URL, AGENT_MODEL, AGENT_INSTRUCTIONS
|
|
11 |
logging.basicConfig(level=logging.INFO)
|
12 |
logger = logging.getLogger(__name__)
|
13 |
|
14 |
-
def write_resume(content: str, user_instructions: str = None, job_summary:
|
15 |
|
16 |
"""
|
17 |
Generates a resume based on the provided content.
|
@@ -19,7 +19,7 @@ def write_resume(content: str, user_instructions: str = None, job_summary: str =
|
|
19 |
Args:
|
20 |
content (str): The content to be used for generating the resume.
|
21 |
user_instructions (str, optional): Additional instructions from the user.
|
22 |
-
job_summary (
|
23 |
|
24 |
Returns:
|
25 |
str: The generated resume.
|
@@ -46,9 +46,9 @@ def write_resume(content: str, user_instructions: str = None, job_summary: str =
|
|
46 |
# Prepare instructions - combine default with user instructions and job summary
|
47 |
instructions = AGENT_INSTRUCTIONS
|
48 |
|
49 |
-
if job_summary is not None
|
50 |
-
instructions += f"\n\nJob Requirements and Details:\n{
|
51 |
-
logger.info("Added job summary to agent prompt
|
52 |
|
53 |
if user_instructions and user_instructions.strip():
|
54 |
|
|
|
11 |
logging.basicConfig(level=logging.INFO)
|
12 |
logger = logging.getLogger(__name__)
|
13 |
|
14 |
+
def write_resume(content: str, user_instructions: str = None, job_summary: dict = None) -> str:
|
15 |
|
16 |
"""
|
17 |
Generates a resume based on the provided content.
|
|
|
19 |
Args:
|
20 |
content (str): The content to be used for generating the resume.
|
21 |
user_instructions (str, optional): Additional instructions from the user.
|
22 |
+
job_summary (dict, optional): Extracted/summarized job call information.
|
23 |
|
24 |
Returns:
|
25 |
str: The generated resume.
|
|
|
46 |
# Prepare instructions - combine default with user instructions and job summary
|
47 |
instructions = AGENT_INSTRUCTIONS
|
48 |
|
49 |
+
if job_summary is not None:
|
50 |
+
instructions += f"\n\nJob Requirements and Details:\n{json.dumps(job_summary)}"
|
51 |
+
logger.info("Added job summary to agent prompt")
|
52 |
|
53 |
if user_instructions and user_instructions.strip():
|
54 |
|
resumate.py
CHANGED
@@ -13,14 +13,8 @@ Upon submission, the input values are processed and displayed in the output box.
|
|
13 |
To run:
|
14 |
python resumate.py
|
15 |
"""
|
16 |
-
from pathlib import Path
|
17 |
-
|
18 |
import gradio as gr
|
19 |
-
from functions.gradio import
|
20 |
-
|
21 |
-
|
22 |
-
# Check if default PDF exists at startup
|
23 |
-
has_default, default_path = check_default_linkedin_pdf()
|
24 |
|
25 |
with gr.Blocks() as demo:
|
26 |
gr.Markdown("# Resumate: tailored resume generator")
|
@@ -41,21 +35,6 @@ with gr.Blocks() as demo:
|
|
41 |
**Tip**: Make sure your LinkedIn profile is complete and up-to-date before exporting for best results!
|
42 |
""")
|
43 |
|
44 |
-
# Default PDF option
|
45 |
-
if has_default:
|
46 |
-
use_default_pdf = gr.Checkbox(
|
47 |
-
label=f"Use default LinkedIn PDF ({Path(default_path).name})",
|
48 |
-
value=False,
|
49 |
-
info="Use the default LinkedIn PDF stored in the data directory"
|
50 |
-
)
|
51 |
-
else:
|
52 |
-
use_default_pdf = gr.Checkbox(
|
53 |
-
label="Use default LinkedIn PDF (not available)",
|
54 |
-
value=False,
|
55 |
-
interactive=False,
|
56 |
-
info="No default LinkedIn PDF found in data directory"
|
57 |
-
)
|
58 |
-
|
59 |
linkedin_pdf = gr.File(
|
60 |
label="LinkedIn Resume Export PDF",
|
61 |
file_types=[".pdf"],
|
@@ -102,8 +81,8 @@ with gr.Blocks() as demo:
|
|
102 |
output = gr.Textbox(label="Output", lines=5, max_lines=50, show_copy_button=True)
|
103 |
|
104 |
submit_btn.click( # pylint: disable=no-member
|
105 |
-
|
106 |
-
inputs=[
|
107 |
outputs=output
|
108 |
)
|
109 |
|
|
|
13 |
To run:
|
14 |
python resumate.py
|
15 |
"""
|
|
|
|
|
16 |
import gradio as gr
|
17 |
+
from functions.gradio import process_inputs
|
|
|
|
|
|
|
|
|
18 |
|
19 |
with gr.Blocks() as demo:
|
20 |
gr.Markdown("# Resumate: tailored resume generator")
|
|
|
35 |
**Tip**: Make sure your LinkedIn profile is complete and up-to-date before exporting for best results!
|
36 |
""")
|
37 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
linkedin_pdf = gr.File(
|
39 |
label="LinkedIn Resume Export PDF",
|
40 |
file_types=[".pdf"],
|
|
|
81 |
output = gr.Textbox(label="Output", lines=5, max_lines=50, show_copy_button=True)
|
82 |
|
83 |
submit_btn.click( # pylint: disable=no-member
|
84 |
+
process_inputs,
|
85 |
+
inputs=[linkedin_pdf, github_profile, job_post, user_instructions],
|
86 |
outputs=output
|
87 |
)
|
88 |
|
tests/test_gradio.py
CHANGED
@@ -10,12 +10,8 @@ from functions import gradio
|
|
10 |
class TestProcessInputs(unittest.TestCase):
|
11 |
"""Test cases for the process_inputs function."""
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
"""Test when no inputs are provided and default job is available."""
|
16 |
-
# Mock default job call loading to return content
|
17 |
-
mock_load_default.return_value = "Default job content from sample_job.txt"
|
18 |
-
|
19 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
20 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
21 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
@@ -24,18 +20,13 @@ class TestProcessInputs(unittest.TestCase):
|
|
24 |
result = gradio.process_inputs(None, "", "", "")
|
25 |
|
26 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
27 |
-
self.assertIn("
|
28 |
-
self.assertIn("
|
29 |
-
self.assertIn("β
Using default job post", result)
|
30 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
31 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
32 |
|
33 |
-
|
34 |
-
|
35 |
-
"""Test when no inputs are provided and no default job is available."""
|
36 |
-
# Mock default job call loading to return None (no default available)
|
37 |
-
mock_load_default.return_value = None
|
38 |
-
|
39 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
40 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
41 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
@@ -44,10 +35,9 @@ class TestProcessInputs(unittest.TestCase):
|
|
44 |
result = gradio.process_inputs(None, "", "", "")
|
45 |
|
46 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
47 |
-
self.assertIn("
|
48 |
-
self.assertIn("
|
49 |
-
self.assertIn("βΉοΈ No
|
50 |
-
self.assertIn("βΉοΈ Proceeding without job post analysis", result)
|
51 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
52 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
53 |
|
@@ -177,12 +167,8 @@ class TestProcessInputs(unittest.TestCase):
|
|
177 |
# Verify write_resume was NOT called since no LinkedIn data
|
178 |
mock_write_resume.assert_not_called()
|
179 |
|
180 |
-
|
181 |
-
|
182 |
-
"""Test inputs with only whitespace and default job available."""
|
183 |
-
# Mock default job call loading to return content
|
184 |
-
mock_load_default.return_value = "Default job content from sample_job.txt"
|
185 |
-
|
186 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
187 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
188 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
@@ -191,18 +177,13 @@ class TestProcessInputs(unittest.TestCase):
|
|
191 |
result = gradio.process_inputs(None, " ", " ", " ")
|
192 |
|
193 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
194 |
-
self.assertIn("
|
195 |
-
self.assertIn("
|
196 |
-
self.assertIn("β
Using default job post", result)
|
197 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
198 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
199 |
|
200 |
-
|
201 |
-
|
202 |
-
"""Test inputs with only whitespace and no default job available."""
|
203 |
-
# Mock default job call loading to return None
|
204 |
-
mock_load_default.return_value = None
|
205 |
-
|
206 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
207 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
208 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
@@ -211,10 +192,8 @@ class TestProcessInputs(unittest.TestCase):
|
|
211 |
result = gradio.process_inputs(None, " ", " ", " ")
|
212 |
|
213 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
214 |
-
self.assertIn("
|
215 |
-
self.assertIn("
|
216 |
-
self.assertIn("βΉοΈ No default job post available, proceeding without job post", result)
|
217 |
-
self.assertIn("βΉοΈ Proceeding without job post analysis", result)
|
218 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
219 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
220 |
|
@@ -302,26 +281,18 @@ class TestProcessInputs(unittest.TestCase):
|
|
302 |
class TestGetProcessedData(unittest.TestCase):
|
303 |
"""Test cases for the get_processed_data function."""
|
304 |
|
305 |
-
|
306 |
-
def test_no_inputs(self, mock_load_default):
|
307 |
"""Test with no inputs provided."""
|
308 |
-
# Mock the default job call loading
|
309 |
-
mock_load_default.return_value = "Default job call content from sample_job.txt"
|
310 |
-
|
311 |
result = gradio.get_processed_data(None, "", "", "")
|
312 |
|
313 |
self.assertIsNone(result["linkedin"])
|
314 |
self.assertIsNone(result["github"])
|
315 |
-
self.
|
316 |
self.assertIsNone(result["user_instructions"])
|
317 |
self.assertEqual(len(result["errors"]), 0)
|
318 |
|
319 |
-
|
320 |
-
|
321 |
-
"""Test with no inputs provided and no default job available."""
|
322 |
-
# Mock the default job call loading to return None
|
323 |
-
mock_load_default.return_value = None
|
324 |
-
|
325 |
result = gradio.get_processed_data(None, "", "", "")
|
326 |
|
327 |
self.assertIsNone(result["linkedin"])
|
@@ -430,23 +401,19 @@ class TestGetProcessedData(unittest.TestCase):
|
|
430 |
self.assertIn("LinkedIn: LinkedIn error", result["errors"])
|
431 |
self.assertIn("GitHub: GitHub error", result["errors"])
|
432 |
|
433 |
-
|
434 |
-
def test_job_post_whitespace_handling(self, mock_load_default):
|
435 |
"""Test job post whitespace handling."""
|
436 |
-
# Mock the default job call loading
|
437 |
-
mock_load_default.return_value = "Default job content"
|
438 |
-
|
439 |
# Test with leading/trailing whitespace
|
440 |
result = gradio.get_processed_data(None, "", " Job content ", "")
|
441 |
self.assertEqual(result["job_post"], "Job content")
|
442 |
|
443 |
-
# Test with only whitespace - should
|
444 |
result = gradio.get_processed_data(None, "", " ", "")
|
445 |
-
self.
|
446 |
|
447 |
-
# Test with empty string - should
|
448 |
result = gradio.get_processed_data(None, "", "", "")
|
449 |
-
self.
|
450 |
|
451 |
def test_github_url_whitespace_handling(self):
|
452 |
"""Test GitHub URL whitespace handling."""
|
|
|
10 |
class TestProcessInputs(unittest.TestCase):
|
11 |
"""Test cases for the process_inputs function."""
|
12 |
|
13 |
+
def test_no_inputs_provided(self):
|
14 |
+
"""Test when no inputs are provided."""
|
|
|
|
|
|
|
|
|
15 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
16 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
17 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
|
|
20 |
result = gradio.process_inputs(None, "", "", "")
|
21 |
|
22 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
23 |
+
self.assertIn("β No GitHub profile URL provided", result)
|
24 |
+
self.assertIn("β Job post not provided", result)
|
|
|
25 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
26 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
27 |
|
28 |
+
def test_no_inputs_no_default_job(self):
|
29 |
+
"""Test when no inputs are provided (same as test_no_inputs_provided now)."""
|
|
|
|
|
|
|
|
|
30 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
31 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
32 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
|
|
35 |
result = gradio.process_inputs(None, "", "", "")
|
36 |
|
37 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
38 |
+
self.assertIn("β No GitHub profile URL provided", result)
|
39 |
+
self.assertIn("β Job post not provided", result)
|
40 |
+
self.assertIn("βΉοΈ No additional instructions provided", result)
|
|
|
41 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
42 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
43 |
|
|
|
167 |
# Verify write_resume was NOT called since no LinkedIn data
|
168 |
mock_write_resume.assert_not_called()
|
169 |
|
170 |
+
def test_whitespace_only_inputs(self):
|
171 |
+
"""Test inputs with only whitespace."""
|
|
|
|
|
|
|
|
|
172 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
173 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
174 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
|
|
177 |
result = gradio.process_inputs(None, " ", " ", " ")
|
178 |
|
179 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
180 |
+
self.assertIn("β No GitHub profile URL provided", result)
|
181 |
+
self.assertIn("β Job post not provided", result)
|
|
|
182 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
183 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
184 |
|
185 |
+
def test_whitespace_only_inputs_no_default(self):
|
186 |
+
"""Test inputs with only whitespace (same as test_whitespace_only_inputs now)."""
|
|
|
|
|
|
|
|
|
187 |
with patch('functions.gradio.get_github_repositories') as mock_github, \
|
188 |
patch('functions.gradio.summarize_job_call') as mock_summarize:
|
189 |
mock_github.return_value = {"status": "success", "metadata": {"username": "gperdrizet"}}
|
|
|
192 |
result = gradio.process_inputs(None, " ", " ", " ")
|
193 |
|
194 |
self.assertIn("β No LinkedIn resume PDF file uploaded", result)
|
195 |
+
self.assertIn("β No GitHub profile URL provided", result)
|
196 |
+
self.assertIn("β Job post not provided", result)
|
|
|
|
|
197 |
self.assertIn("βΉοΈ No additional instructions provided", result)
|
198 |
self.assertIn("β Cannot generate resume: No valid LinkedIn data extracted", result)
|
199 |
|
|
|
281 |
class TestGetProcessedData(unittest.TestCase):
|
282 |
"""Test cases for the get_processed_data function."""
|
283 |
|
284 |
+
def test_no_inputs(self):
|
|
|
285 |
"""Test with no inputs provided."""
|
|
|
|
|
|
|
286 |
result = gradio.get_processed_data(None, "", "", "")
|
287 |
|
288 |
self.assertIsNone(result["linkedin"])
|
289 |
self.assertIsNone(result["github"])
|
290 |
+
self.assertIsNone(result["job_post"])
|
291 |
self.assertIsNone(result["user_instructions"])
|
292 |
self.assertEqual(len(result["errors"]), 0)
|
293 |
|
294 |
+
def test_no_inputs_no_default_job(self):
|
295 |
+
"""Test with no inputs provided (same as test_no_inputs now)."""
|
|
|
|
|
|
|
|
|
296 |
result = gradio.get_processed_data(None, "", "", "")
|
297 |
|
298 |
self.assertIsNone(result["linkedin"])
|
|
|
401 |
self.assertIn("LinkedIn: LinkedIn error", result["errors"])
|
402 |
self.assertIn("GitHub: GitHub error", result["errors"])
|
403 |
|
404 |
+
def test_job_post_whitespace_handling(self):
|
|
|
405 |
"""Test job post whitespace handling."""
|
|
|
|
|
|
|
406 |
# Test with leading/trailing whitespace
|
407 |
result = gradio.get_processed_data(None, "", " Job content ", "")
|
408 |
self.assertEqual(result["job_post"], "Job content")
|
409 |
|
410 |
+
# Test with only whitespace - should be None
|
411 |
result = gradio.get_processed_data(None, "", " ", "")
|
412 |
+
self.assertIsNone(result["job_post"])
|
413 |
|
414 |
+
# Test with empty string - should be None
|
415 |
result = gradio.get_processed_data(None, "", "", "")
|
416 |
+
self.assertIsNone(result["job_post"])
|
417 |
|
418 |
def test_github_url_whitespace_handling(self):
|
419 |
"""Test GitHub URL whitespace handling."""
|