Utkarsh736 commited on
Commit
538765f
Β·
1 Parent(s): 479a9d6

Add application file

Browse files
Files changed (1) hide show
  1. app.py +318 -0
app.py ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import json
3
+ from datetime import datetime
4
+ import os
5
+ import tempfile
6
+
7
+ # Import the resume agent (assuming the previous code is saved as resume_agent.py)
8
+ from resume_agent import ResumeAgent, get_sample_resume, get_sample_job_description
9
+
10
+ class GradioResumeApp:
11
+ """Gradio interface for the Resume Optimization Agent"""
12
+
13
+ def __init__(self):
14
+ self.agent = ResumeAgent()
15
+ self.sample_resume = get_sample_resume()
16
+ self.sample_job_desc = get_sample_job_description()
17
+
18
+ def process_resume(self, resume_file, resume_text, job_file, job_text, api_key):
19
+ """Process resume optimization request"""
20
+
21
+ # Validate API key
22
+ if not api_key or api_key.strip() == "":
23
+ return self._create_error_output("❌ Please provide a valid Gemini API key")
24
+
25
+ # Set API key
26
+ import google.generativeai as genai
27
+ try:
28
+ genai.configure(api_key=api_key.strip())
29
+ except Exception as e:
30
+ return self._create_error_output(f"❌ Invalid API key: {str(e)}")
31
+
32
+ # Get resume content
33
+ resume_content = self._get_content(resume_file, resume_text, self.sample_resume, "resume")
34
+ if not resume_content:
35
+ return self._create_error_output("❌ No resume content provided")
36
+
37
+ # Get job description content
38
+ job_content = self._get_content(job_file, job_text, self.sample_job_desc, "job description")
39
+
40
+ try:
41
+ # Process optimization
42
+ results = self.agent.optimize_resume(resume_content, job_content)
43
+
44
+ # Format results for display
45
+ return self._format_results(results)
46
+
47
+ except Exception as e:
48
+ return self._create_error_output(f"❌ Error during optimization: {str(e)}")
49
+
50
+ def _get_content(self, file, text, sample, content_type):
51
+ """Extract content from file or text input"""
52
+ if file is not None:
53
+ try:
54
+ content = file.decode('utf-8') if isinstance(file, bytes) else file.read()
55
+ return content
56
+ except Exception as e:
57
+ print(f"Error reading {content_type} file: {str(e)}")
58
+
59
+ if text and text.strip():
60
+ return text.strip()
61
+
62
+ return sample
63
+
64
+ def _create_error_output(self, error_message):
65
+ """Create error output tuple"""
66
+ return (
67
+ error_message, # summary
68
+ "", # experience_analysis
69
+ "", # keyword_analysis
70
+ "", # design_suggestions
71
+ "", # editing_suggestions
72
+ "" # full_results
73
+ )
74
+
75
+ def _format_results(self, results):
76
+ """Format optimization results for Gradio display"""
77
+
78
+ # New Summary
79
+ new_summary = results.get("new_summary", "No summary generated")
80
+
81
+ # Experience Analysis
82
+ experience_analysis = ""
83
+ if "experience_matching" in results:
84
+ exp_data = results["experience_matching"]
85
+ if isinstance(exp_data, dict) and "ranked_experiences" in exp_data:
86
+ experience_analysis = "πŸ“Š **Experience Relevance Analysis:**\n\n"
87
+ for i, exp in enumerate(exp_data["ranked_experiences"][:3], 1):
88
+ if isinstance(exp, dict):
89
+ score = exp.get("relevance_score", "N/A")
90
+ points = exp.get("matching_points", [])
91
+ experience_analysis += f"**Experience {i}:** Score {score}/10\n"
92
+ experience_analysis += f"Key matches: {', '.join(points[:3])}\n\n"
93
+ else:
94
+ experience_analysis = "Experience analysis completed"
95
+
96
+ # Keyword Analysis
97
+ keyword_analysis = ""
98
+ if "keyword_optimization" in results:
99
+ kw_data = results["keyword_optimization"]
100
+ if isinstance(kw_data, dict):
101
+ ats_score = kw_data.get("ats_score", "N/A")
102
+ missing_kw = kw_data.get("missing_keywords", [])
103
+ keyword_analysis = f"🎯 **ATS Optimization Score:** {ats_score}/100\n\n"
104
+ if missing_kw:
105
+ keyword_analysis += f"**Missing Keywords:** {', '.join(missing_kw[:10])}\n\n"
106
+
107
+ recommendations = kw_data.get("recommendations", [])
108
+ if recommendations:
109
+ keyword_analysis += "**Recommendations:**\n"
110
+ for rec in recommendations[:3]:
111
+ keyword_analysis += f"β€’ {rec}\n"
112
+ else:
113
+ keyword_analysis = "Keyword optimization completed"
114
+
115
+ # Design Suggestions
116
+ design_suggestions = ""
117
+ if "design_suggestions" in results:
118
+ design_data = results["design_suggestions"]
119
+ if isinstance(design_data, dict):
120
+ template = design_data.get("recommended_template", "Standard")
121
+ layout_tips = design_data.get("layout_suggestions", [])
122
+ design_suggestions = f"🎨 **Recommended Template:** {template}\n\n"
123
+ if layout_tips:
124
+ design_suggestions += "**Layout Suggestions:**\n"
125
+ for tip in layout_tips[:5]:
126
+ design_suggestions += f"β€’ {tip}\n"
127
+ else:
128
+ design_suggestions = "Design suggestions generated"
129
+
130
+ # Editing Suggestions
131
+ editing_suggestions = ""
132
+ if "editing_suggestions" in results:
133
+ edit_data = results["editing_suggestions"]
134
+ if isinstance(edit_data, dict):
135
+ score = edit_data.get("overall_score", "N/A")
136
+ feedback = edit_data.get("summary_feedback", "")
137
+ editing_suggestions = f"✏️ **Overall Quality Score:** {score}/100\n\n"
138
+ if feedback:
139
+ editing_suggestions += f"**Feedback:** {feedback}\n\n"
140
+
141
+ grammar_errors = edit_data.get("grammar_errors", [])
142
+ if grammar_errors:
143
+ editing_suggestions += "**Grammar Improvements:**\n"
144
+ for error in grammar_errors[:3]:
145
+ if isinstance(error, dict):
146
+ original = error.get("original", "")
147
+ corrected = error.get("corrected", "")
148
+ editing_suggestions += f"β€’ '{original}' β†’ '{corrected}'\n"
149
+ else:
150
+ editing_suggestions = "Editing analysis completed"
151
+
152
+ # Full Results (JSON)
153
+ full_results = json.dumps(results, indent=2, default=str)
154
+
155
+ return (
156
+ new_summary,
157
+ experience_analysis,
158
+ keyword_analysis,
159
+ design_suggestions,
160
+ editing_suggestions,
161
+ full_results
162
+ )
163
+
164
+ def create_interface(self):
165
+ """Create and return Gradio interface"""
166
+
167
+ with gr.Blocks(
168
+ title="AI Resume Optimizer",
169
+ theme=gr.themes.Soft(),
170
+ css="""
171
+ .gradio-container {
172
+ max-width: 1200px !important;
173
+ }
174
+ .main-header {
175
+ text-align: center;
176
+ margin-bottom: 30px;
177
+ }
178
+ """
179
+ ) as interface:
180
+
181
+ gr.HTML("""
182
+ <div class="main-header">
183
+ <h1>πŸš€ AI Resume Optimization Agent</h1>
184
+ <p>Upload your resume and job description to get AI-powered optimization suggestions</p>
185
+ </div>
186
+ """)
187
+
188
+ with gr.Row():
189
+ with gr.Column(scale=1):
190
+ gr.HTML("<h2>πŸ“„ Input</h2>")
191
+
192
+ # API Key input
193
+ api_key = gr.Textbox(
194
+ label="πŸ”‘ Gemini API Key",
195
+ placeholder="Enter your Gemini API key here...",
196
+ type="password",
197
+ info="Get your free API key from Google AI Studio"
198
+ )
199
+
200
+ # Resume input
201
+ with gr.Tab("Resume Upload"):
202
+ resume_file = gr.File(
203
+ label="Upload Resume (PDF/TXT/DOCX)",
204
+ file_types=[".pdf", ".txt", ".docx"]
205
+ )
206
+
207
+ with gr.Tab("Resume Text"):
208
+ resume_text = gr.Textbox(
209
+ label="Paste Resume Text",
210
+ placeholder="Paste your resume content here...",
211
+ lines=8,
212
+ value=self.sample_resume
213
+ )
214
+
215
+ # Job description input
216
+ with gr.Tab("Job Description Upload"):
217
+ job_file = gr.File(
218
+ label="Upload Job Description",
219
+ file_types=[".pdf", ".txt", ".docx"]
220
+ )
221
+
222
+ with gr.Tab("Job Description Text"):
223
+ job_text = gr.Textbox(
224
+ label="Paste Job Description",
225
+ placeholder="Paste job description here...",
226
+ lines=6,
227
+ value=self.sample_job_desc
228
+ )
229
+
230
+ # Optimize button
231
+ optimize_btn = gr.Button(
232
+ "πŸš€ Optimize Resume",
233
+ variant="primary",
234
+ size="lg"
235
+ )
236
+
237
+ with gr.Column(scale=1):
238
+ gr.HTML("<h2>πŸ“Š Results</h2>")
239
+
240
+ with gr.Tab("✨ New Summary"):
241
+ summary_output = gr.Textbox(
242
+ label="Optimized Professional Summary",
243
+ lines=4,
244
+ interactive=False
245
+ )
246
+
247
+ with gr.Tab("πŸ“ˆ Experience Analysis"):
248
+ experience_output = gr.Markdown(
249
+ label="Experience Relevance Analysis"
250
+ )
251
+
252
+ with gr.Tab("🎯 Keywords & ATS"):
253
+ keyword_output = gr.Markdown(
254
+ label="Keyword Optimization & ATS Score"
255
+ )
256
+
257
+ with gr.Tab("🎨 Design Tips"):
258
+ design_output = gr.Markdown(
259
+ label="Design & Formatting Suggestions"
260
+ )
261
+
262
+ with gr.Tab("✏️ Editing Tips"):
263
+ editing_output = gr.Markdown(
264
+ label="Grammar & Content Improvements"
265
+ )
266
+
267
+ with gr.Tab("πŸ“‹ Full Report"):
268
+ full_output = gr.Code(
269
+ label="Complete Analysis (JSON)",
270
+ language="json"
271
+ )
272
+
273
+ # Event handlers
274
+ optimize_btn.click(
275
+ fn=self.process_resume,
276
+ inputs=[resume_file, resume_text, job_file, job_text, api_key],
277
+ outputs=[
278
+ summary_output,
279
+ experience_output,
280
+ keyword_output,
281
+ design_output,
282
+ editing_output,
283
+ full_output
284
+ ]
285
+ )
286
+
287
+ # Example section
288
+ with gr.Row():
289
+ gr.HTML("""
290
+ <div style="margin-top: 30px; padding: 20px; background-color: #f8f9fa; border-radius: 10px;">
291
+ <h3>πŸ’‘ Quick Start Guide:</h3>
292
+ <ol>
293
+ <li>Get your free Gemini API key from <a href="https://makersuite.google.com/app/apikey" target="_blank">Google AI Studio</a></li>
294
+ <li>Upload your resume or use the sample provided</li>
295
+ <li>Add a job description you're targeting (optional)</li>
296
+ <li>Click "Optimize Resume" to get AI-powered suggestions</li>
297
+ </ol>
298
+ <p><strong>Features:</strong> Professional Summary Generation β€’ Experience Matching β€’ ATS Optimization β€’ Design Suggestions β€’ Grammar & Style Improvements</p>
299
+ </div>
300
+ """)
301
+
302
+ return interface
303
+
304
+ def main():
305
+ """Launch the Gradio app"""
306
+ app = GradioResumeApp()
307
+ interface = app.create_interface()
308
+
309
+ # Launch the app
310
+ interface.launch(
311
+ server_name="0.0.0.0", # Allow external access
312
+ server_port=7860,
313
+ share=True, # Create public link
314
+ debug=True
315
+ )
316
+
317
+ if __name__ == "__main__":
318
+ main()