gperdrizet commited on
Commit
146e731
·
verified ·
1 Parent(s): e20dc23

Added defaults for linkedin profile pdf and github profile url

Browse files
Files changed (3) hide show
  1. configuration.py +5 -1
  2. functions/gradio.py +94 -8
  3. resumate.py +25 -6
configuration.py CHANGED
@@ -1,10 +1,14 @@
1
  """Global configuration for the Resumate application."""
2
 
 
3
  from smolagents import OpenAIServerModel
4
 
 
 
5
  AGENT_MODEL = OpenAIServerModel(
6
  model_id="gpt-4.1",
7
- max_tokens=8000
 
8
  )
9
 
10
  INSTRUCTIONS = """
 
1
  """Global configuration for the Resumate application."""
2
 
3
+ import os
4
  from smolagents import OpenAIServerModel
5
 
6
+ DEFAULT_GITHUB_PROFILE = "https://github.com/gperdrizet"
7
+
8
  AGENT_MODEL = OpenAIServerModel(
9
  model_id="gpt-4.1",
10
+ max_tokens=8000,
11
+ api_key=os.getenv("OPENAI_API_KEY")
12
  )
13
 
14
  INSTRUCTIONS = """
functions/gradio.py CHANGED
@@ -5,22 +5,70 @@ Functions for handling Gradio UI interactions and processing user inputs.
5
  """
6
 
7
  import logging
 
 
8
  from functions.linkedin_resume import extract_text_from_linkedin_pdf
9
  from functions.github import get_github_repositories
10
  from functions.job_call import summarize_job_call
11
  from functions.writer_agent import write_resume
 
12
 
13
  # Set up logging
14
  logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
19
  """
20
  Process the input files and URLs from the Gradio interface.
21
 
22
  Args:
23
- linkedin_pdf: Uploaded LinkedIn resume export PDF file
24
  github_url (str): GitHub profile URL
25
  job_post_text (str): Job post text content
26
  user_instructions (str): Additional instructions from the user
@@ -34,11 +82,33 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
34
 
35
  # Process LinkedIn PDF file
36
  if linkedin_pdf is not None:
37
- result += "✅ LinkedIn Resume PDF uploaded\n"
38
- logger.info("Processing LinkedIn PDF: %s", linkedin_pdf.name)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
  # Extract and structure text from the PDF
41
- extraction_result = extract_text_from_linkedin_pdf(linkedin_pdf.name)
42
 
43
  if extraction_result["status"] == "success":
44
  result += " ✅ Text extraction successful\n\n"
@@ -55,12 +125,24 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
55
  logger.info("No LinkedIn PDF file provided")
56
 
57
  # Process GitHub profile
 
58
  if github_url and github_url.strip():
59
- result += "✅ GitHub Profile URL provided\n"
60
- logger.info("Processing GitHub URL: %s", github_url)
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  # Retrieve repositories from GitHub
63
- github_result = get_github_repositories(github_url)
64
 
65
  if github_result["status"] == "success":
66
  result += " ✅ GitHub list download successful\n\n"
@@ -94,6 +176,7 @@ def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
94
  if user_instructions and user_instructions.strip():
95
  result += "✅ Additional instructions provided\n"
96
  logger.info("User instructions provided (%d characters)", len(user_instructions))
 
97
  else:
98
  result += "ℹ️ No additional instructions provided\n"
99
  logger.info("No additional instructions provided")
@@ -145,7 +228,10 @@ def get_processed_data(linkedin_pdf, github_url, job_post_text, instructions):
145
 
146
  # Process LinkedIn PDF
147
  if linkedin_pdf is not None:
148
- extraction_result = extract_text_from_linkedin_pdf(linkedin_pdf.name)
 
 
 
149
 
150
  if extraction_result["status"] == "success":
151
  processed_data["linkedin"] = extraction_result
 
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 summarize_job_call
13
  from functions.writer_agent import write_resume
14
+ from configuration import DEFAULT_GITHUB_PROFILE
15
 
16
  # Set up logging
17
  logging.basicConfig(level=logging.INFO)
18
  logger = logging.getLogger(__name__)
19
 
20
 
21
+ class MockFile:
22
+ """Mock file object that mimics uploaded file interface with just a file path."""
23
+
24
+ def __init__(self, path):
25
+ self.name = path
26
+
27
+
28
+ def check_default_linkedin_pdf():
29
+ """Check if default LinkedIn PDF exists in data directory."""
30
+
31
+ # Get the project root directory (parent of functions directory)
32
+ project_root = Path(__file__).parent.parent
33
+ default_pdf = f'{project_root}/data/linkedin_profile.pdf'
34
+
35
+ if not Path(default_pdf).exists():
36
+ logger.warning("Default LinkedIn PDF not found at %s", default_pdf)
37
+
38
+ return False, None
39
+
40
+ return True, default_pdf
41
+
42
+
43
+ def process_with_default_option(
44
+ use_default_pdf,
45
+ linkedin_pdf,
46
+ github_profile,
47
+ job_post,
48
+ user_instructions
49
+ ):
50
+ """Process inputs with consideration for default PDF option."""
51
+
52
+ has_default, default_path = check_default_linkedin_pdf()
53
+
54
+ # Determine which PDF file to use
55
+ pdf_file = None
56
+
57
+ if use_default_pdf and has_default:
58
+ pdf_file = MockFile(default_path)
59
+
60
+ elif linkedin_pdf is not None:
61
+ pdf_file = linkedin_pdf
62
+
63
+ return process_inputs(pdf_file, github_profile, job_post, user_instructions)
64
+
65
+
66
  def process_inputs(linkedin_pdf, github_url, job_post_text, user_instructions):
67
  """
68
  Process the input files and URLs from the Gradio interface.
69
 
70
  Args:
71
+ linkedin_pdf: Uploaded LinkedIn resume export PDF file or mock file object with path
72
  github_url (str): GitHub profile URL
73
  job_post_text (str): Job post text content
74
  user_instructions (str): Additional instructions from the user
 
82
 
83
  # Process LinkedIn PDF file
84
  if linkedin_pdf is not None:
85
+ # Handle both file objects and mock file objects with path strings
86
+ file_path = linkedin_pdf.name
87
+ file_display_name = Path(file_path).name
88
+
89
+ result += "✅ LinkedIn Resume PDF provided\n"
90
+ logger.info("Processing LinkedIn PDF: %s", file_display_name)
91
+
92
+ # Save uploaded file as new default (only if it's not already the default)
93
+ project_root = Path(__file__).parent.parent
94
+ default_pdf_path = project_root / "data" / "linkedin_profile.pdf"
95
+
96
+ # Check if this is an uploaded file (not the default file)
97
+ if not isinstance(linkedin_pdf, MockFile):
98
+ try:
99
+ # Create data directory if it doesn't exist
100
+ default_pdf_path.parent.mkdir(exist_ok=True)
101
+
102
+ # Copy uploaded file to default location
103
+ shutil.copy2(file_path, default_pdf_path)
104
+ result += " ✅ Saved as new default LinkedIn profile\n"
105
+ logger.info("Saved uploaded LinkedIn PDF as new default: %s", default_pdf_path)
106
+ except Exception as save_error:
107
+ result += f" ⚠️ Could not save as default: {str(save_error)}\n"
108
+ logger.warning("Failed to save LinkedIn PDF as default: %s", str(save_error))
109
 
110
  # Extract and structure text from the PDF
111
+ extraction_result = extract_text_from_linkedin_pdf(file_path)
112
 
113
  if extraction_result["status"] == "success":
114
  result += " ✅ Text extraction successful\n\n"
 
125
  logger.info("No LinkedIn PDF file provided")
126
 
127
  # Process GitHub profile
128
+ # Use default GitHub profile if none provided
129
  if github_url and github_url.strip():
130
+ github_url_to_use = github_url.strip()
131
+
132
+ else:
133
+ github_url_to_use = DEFAULT_GITHUB_PROFILE
134
+
135
+ if github_url_to_use:
136
+ if github_url and github_url.strip():
137
+ result += "✅ GitHub Profile URL provided\n"
138
+
139
+ else:
140
+ result += "✅ Using default GitHub Profile URL\n"
141
+
142
+ logger.info("Processing GitHub URL: %s", github_url_to_use)
143
 
144
  # Retrieve repositories from GitHub
145
+ github_result = get_github_repositories(github_url_to_use)
146
 
147
  if github_result["status"] == "success":
148
  result += " ✅ GitHub list download successful\n\n"
 
176
  if user_instructions and user_instructions.strip():
177
  result += "✅ Additional instructions provided\n"
178
  logger.info("User instructions provided (%d characters)", len(user_instructions))
179
+
180
  else:
181
  result += "ℹ️ No additional instructions provided\n"
182
  logger.info("No additional instructions provided")
 
228
 
229
  # Process LinkedIn PDF
230
  if linkedin_pdf is not None:
231
+
232
+ # Handle both file objects and mock file objects with path strings
233
+ file_path = linkedin_pdf.name
234
+ extraction_result = extract_text_from_linkedin_pdf(file_path)
235
 
236
  if extraction_result["status"] == "success":
237
  processed_data["linkedin"] = extraction_result
resumate.py CHANGED
@@ -13,14 +13,18 @@ Upon submission, the input values are processed and displayed in the output box.
13
  To run:
14
  python resumate.py
15
  """
 
16
 
17
  import gradio as gr
18
- from functions.gradio import process_inputs
19
 
20
 
 
 
 
21
  with gr.Blocks() as demo:
22
  gr.Markdown("# Resumate: tailored resume generator")
23
-
24
  gr.Markdown("""
25
  ## 1. Biographical details
26
 
@@ -36,7 +40,22 @@ with gr.Blocks() as demo:
36
 
37
  **Tip**: Make sure your LinkedIn profile is complete and up-to-date before exporting for best results!
38
  """)
39
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  linkedin_pdf = gr.File(
41
  label="LinkedIn Resume Export PDF",
42
  file_types=[".pdf"],
@@ -83,9 +102,9 @@ with gr.Blocks() as demo:
83
  output = gr.Textbox(label="Output", lines=5, max_lines=50, show_copy_button=True)
84
 
85
  submit_btn.click( # pylint: disable=no-member
86
- process_inputs,
87
- inputs=[linkedin_pdf, github_profile, job_post, user_instructions],
88
  outputs=output
89
  )
90
 
91
- demo.launch()
 
13
  To run:
14
  python resumate.py
15
  """
16
+ from pathlib import Path
17
 
18
  import gradio as gr
19
+ from functions.gradio import check_default_linkedin_pdf, process_with_default_option
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")
27
+
28
  gr.Markdown("""
29
  ## 1. Biographical details
30
 
 
40
 
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
  output = gr.Textbox(label="Output", lines=5, max_lines=50, show_copy_button=True)
103
 
104
  submit_btn.click( # pylint: disable=no-member
105
+ process_with_default_option,
106
+ inputs=[use_default_pdf, linkedin_pdf, github_profile, job_post, user_instructions],
107
  outputs=output
108
  )
109
 
110
+ demo.launch()