pankajrajdeo commited on
Commit
a4decd8
·
1 Parent(s): a0768ff

Update app.py: adjust file handling and UI for resume optimization

Browse files
Files changed (1) hide show
  1. app.py +105 -114
app.py CHANGED
@@ -38,122 +38,113 @@ def convert_md_to_pdf(md_path: str) -> str:
38
  def process_resume(openai_api_key, serper_api_key, model_choice, new_resume, company_name, job_url):
39
  """
40
  Processes the uploaded resume using ResumeCrew and converts the output Markdown files to PDFs.
41
-
42
- Parameters:
43
- openai_api_key (str): OpenAI API key.
44
- serper_api_key (str): Serper API key.
45
- model_choice (str): The selected model.
46
- new_resume: The uploaded resume file (file-like object or file path).
47
- company_name (str): The company name.
48
- job_url (str): The job posting URL.
49
-
50
- Returns:
51
- A 7-tuple:
52
- 1. Status message (Textbox)
53
- 2. Optimized Resume PDF viewer
54
- 3. Optimized Resume PDF download link
55
- 4. Final Report PDF viewer
56
- 5. Final Report PDF download link
57
- 6. Interview Questions PDF viewer
58
- 7. Interview Questions PDF download link
59
  """
60
- current_date = datetime.datetime.now().strftime("%Y%m%d")
61
-
62
- # --- Ensure a resume file is uploaded ---
63
- if new_resume is None or not (hasattr(new_resume, "name") and new_resume.name.strip() != ""):
64
- return ("Error: Please upload a resume.", None, None, None, None, None, None)
65
-
66
- # -- [MINIMAL CHANGE] -- Set environment variables so CrewAI sees these keys
67
- os.environ["OPENAI_API_KEY"] = openai_api_key or ""
68
- os.environ["SERPER_API_KEY"] = serper_api_key or ""
69
-
70
- # --- Save the uploaded file into "knowledge" directory ---
71
- if hasattr(new_resume, "read"):
72
- original_filename = os.path.basename(new_resume.name)
73
- file_data = new_resume.read()
74
- else:
75
- original_filename = os.path.basename(new_resume)
76
- file_data = None
77
-
78
- base_filename, ext = os.path.splitext(original_filename)
79
- new_resume_filename = f"{base_filename}_{current_date}{ext}" # e.g. CV_Yashwardhan_20250207.pdf
80
- physical_path = os.path.join("knowledge", new_resume_filename)
81
-
82
- os.makedirs("knowledge", exist_ok=True)
83
-
84
- if file_data is not None:
85
- with open(physical_path, "wb") as f:
86
- f.write(file_data)
87
- else:
88
- shutil.copy(new_resume, physical_path)
89
-
90
- # Pass ONLY the filename to ResumeCrew so it won't prepend "knowledge/" again:
91
- crew_instance = ResumeCrew(
92
- model=model_choice,
93
- openai_api_key=openai_api_key,
94
- serper_api_key=serper_api_key,
95
- resume_pdf_path=new_resume_filename # <-- Only filename
96
- )
97
-
98
- # Run the resume processing (kick off the crew)
99
- crew_instance.crew().kickoff(inputs={'job_url': job_url, 'company_name': company_name})
100
-
101
- # --- Retrieve output files ---
102
- job_analysis_path = os.path.join("output", "job_analysis.json")
103
  try:
104
- with open(job_analysis_path, "r") as f:
105
- job_data = json.load(f)
106
- position_name = job_data.get("job_title", "position")
107
- except Exception:
108
- position_name = "position"
109
-
110
- optimized_resume_path = os.path.join("output", "optimized_resume.md")
111
- candidate_name = "candidate"
112
- try:
113
- with open(optimized_resume_path, "r") as f:
114
- first_line = f.readline()
115
- if first_line.startswith("#"):
116
- candidate_name = first_line.lstrip("#").strip().replace(" ", "_")
117
- except Exception:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  candidate_name = "candidate"
119
-
120
- # --- Create the output folder ---
121
- folder_name = f"{company_name}_{position_name}_{candidate_name}_{current_date}"
122
- new_output_dir = os.path.join("output", folder_name)
123
- os.makedirs(new_output_dir, exist_ok=True)
124
-
125
- # --- Move generated output files ---
126
- for filename in os.listdir("output"):
127
- file_path = os.path.join("output", filename)
128
- if file_path == new_output_dir:
129
- continue
130
- if filename.endswith(".json") or filename.endswith(".md"):
131
- if os.path.isfile(file_path):
132
- shutil.move(file_path, os.path.join(new_output_dir, filename))
133
-
134
- # --- Convert each Markdown file in the new output directory to PDF ---
135
- def md_to_pdf_in_dir(md_filename):
136
- md_path = os.path.join(new_output_dir, md_filename)
137
- if os.path.isfile(md_path):
138
- return convert_md_to_pdf(md_path)
139
- return ""
140
-
141
- pdf_opt = md_to_pdf_in_dir("optimized_resume.md")
142
- pdf_final = md_to_pdf_in_dir("final_report.md")
143
- pdf_int = md_to_pdf_in_dir("interview_questions.md")
144
-
145
- message = f"Processing completed using model {model_choice}. Output saved in: {new_output_dir}"
146
-
147
- # RETURN EXACTLY 7 outputs to match the UI
148
- return (
149
- message, # 1) Status message
150
- pdf_opt, # 2) PDF viewer for optimized resume
151
- pdf_opt, # 3) File for downloading optimized resume
152
- pdf_final, # 4) PDF viewer for final report
153
- pdf_final, # 5) File for downloading final report
154
- pdf_int, # 6) PDF viewer for interview questions
155
- pdf_int # 7) File for downloading interview questions
156
- )
 
 
 
 
 
 
157
 
158
  # --- Define available models ---
159
  model_choices = {
@@ -179,7 +170,7 @@ with gr.Blocks(css=".output-column { width: 700px; }") as demo:
179
  model_dropdown = gr.Dropdown(
180
  choices=list(model_choices.values()),
181
  label="Select Model",
182
- value="o3-mini-2025-01-31",
183
  interactive=True,
184
  info="Select the model to use for processing."
185
  )
 
38
  def process_resume(openai_api_key, serper_api_key, model_choice, new_resume, company_name, job_url):
39
  """
40
  Processes the uploaded resume using ResumeCrew and converts the output Markdown files to PDFs.
41
+ Handles errors gracefully and stops execution upon failure.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  try:
44
+ current_date = datetime.datetime.now().strftime("%Y%m%d")
45
+
46
+ # --- Ensure a resume file is uploaded ---
47
+ if new_resume is None or not (hasattr(new_resume, "name") and new_resume.name.strip() != ""):
48
+ return ("Error: Please upload a resume.", None, None, None, None, None, None)
49
+
50
+ # --- Set API keys ---
51
+ os.environ["OPENAI_API_KEY"] = openai_api_key or ""
52
+ os.environ["SERPER_API_KEY"] = serper_api_key or ""
53
+
54
+ # --- Save uploaded file ---
55
+ try:
56
+ if hasattr(new_resume, "read"):
57
+ original_filename = os.path.basename(new_resume.name)
58
+ file_data = new_resume.read()
59
+ else:
60
+ original_filename = os.path.basename(new_resume)
61
+ file_data = None
62
+
63
+ base_filename, ext = os.path.splitext(original_filename)
64
+ new_resume_filename = f"{base_filename}_{current_date}{ext}"
65
+ physical_path = os.path.join("knowledge", new_resume_filename)
66
+ os.makedirs("knowledge", exist_ok=True)
67
+
68
+ if file_data is not None:
69
+ with open(physical_path, "wb") as f:
70
+ f.write(file_data)
71
+ else:
72
+ shutil.copy(new_resume, physical_path)
73
+ except Exception as e:
74
+ return (f"Error saving the uploaded resume: {str(e)}", None, None, None, None, None, None)
75
+
76
+ # --- Initialize ResumeCrew ---
77
+ try:
78
+ crew_instance = ResumeCrew(
79
+ model=model_choice,
80
+ openai_api_key=openai_api_key,
81
+ serper_api_key=serper_api_key,
82
+ resume_pdf_path=new_resume_filename
83
+ )
84
+ except Exception as e:
85
+ return (f"Error initializing ResumeCrew: {str(e)}", None, None, None, None, None, None)
86
+
87
+ # --- Run the resume processing ---
88
+ try:
89
+ crew_instance.crew().kickoff(inputs={'job_url': job_url, 'company_name': company_name})
90
+ except Exception as e:
91
+ return (f"Error during resume processing: {str(e)}", None, None, None, None, None, None)
92
+
93
+ # --- Retrieve output files ---
94
+ try:
95
+ job_analysis_path = os.path.join("output", "job_analysis.json")
96
+ with open(job_analysis_path, "r") as f:
97
+ job_data = json.load(f)
98
+ position_name = job_data.get("job_title", "position")
99
+ except Exception:
100
+ position_name = "position"
101
+
102
+ optimized_resume_path = os.path.join("output", "optimized_resume.md")
103
  candidate_name = "candidate"
104
+ try:
105
+ with open(optimized_resume_path, "r") as f:
106
+ first_line = f.readline()
107
+ if first_line.startswith("#"):
108
+ candidate_name = first_line.lstrip("#").strip().replace(" ", "_")
109
+ except Exception:
110
+ candidate_name = "candidate"
111
+
112
+ # --- Create the output folder ---
113
+ try:
114
+ folder_name = f"{company_name}_{position_name}_{candidate_name}_{current_date}"
115
+ new_output_dir = os.path.join("output", folder_name)
116
+ os.makedirs(new_output_dir, exist_ok=True)
117
+
118
+ for filename in os.listdir("output"):
119
+ file_path = os.path.join("output", filename)
120
+ if file_path == new_output_dir:
121
+ continue
122
+ if filename.endswith(".json") or filename.endswith(".md"):
123
+ if os.path.isfile(file_path):
124
+ shutil.move(file_path, os.path.join(new_output_dir, filename))
125
+ except Exception as e:
126
+ return (f"Error organizing output files: {str(e)}", None, None, None, None, None, None)
127
+
128
+ # --- Convert Markdown to PDF ---
129
+ def md_to_pdf_in_dir(md_filename):
130
+ try:
131
+ md_path = os.path.join(new_output_dir, md_filename)
132
+ if os.path.isfile(md_path):
133
+ return convert_md_to_pdf(md_path)
134
+ return ""
135
+ except Exception as e:
136
+ return f"Error converting {md_filename} to PDF: {str(e)}"
137
+
138
+ pdf_opt = md_to_pdf_in_dir("optimized_resume.md")
139
+ pdf_final = md_to_pdf_in_dir("final_report.md")
140
+ pdf_int = md_to_pdf_in_dir("interview_questions.md")
141
+
142
+ message = f"Processing completed using model {model_choice}. Output saved in: {new_output_dir}"
143
+
144
+ return (message, pdf_opt, pdf_opt, pdf_final, pdf_final, pdf_int, pdf_int)
145
+
146
+ except Exception as e:
147
+ return (f"Unexpected error: {str(e)}", None, None, None, None, None, None)
148
 
149
  # --- Define available models ---
150
  model_choices = {
 
170
  model_dropdown = gr.Dropdown(
171
  choices=list(model_choices.values()),
172
  label="Select Model",
173
+ value="gpt-4o-2024-08-06",
174
  interactive=True,
175
  info="Select the model to use for processing."
176
  )