mkshari commited on
Commit
455f85f
Β·
verified Β·
1 Parent(s): d73a9c6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +38 -17
app.py CHANGED
@@ -9,6 +9,8 @@ import sys
9
  import os
10
  import torch
11
 
 
 
12
  # Initialize Models once at startup
13
  print("πŸš€ Initializing SETHU AI Engine...")
14
  try:
@@ -19,9 +21,16 @@ except:
19
  nlp = spacy.load("en_core_web_sm")
20
 
21
  # Use a high-quality Hugging Face model for embeddings
22
- # 'all-MiniLM-L6-v2' is fast and efficient for local use
23
  model = SentenceTransformer('all-MiniLM-L6-v2')
24
 
 
 
 
 
 
 
 
 
25
  TECH_SKILLS = [
26
  "python", "javascript", "react", "fastapi", "aws", "docker", "kubernetes", "sql",
27
  "git", "ml", "nlp", "tensorflow", "pytorch", "java", "golang", "postgresql",
@@ -99,8 +108,6 @@ def create_score_gauges(match_score, content_score, search_score, ats_score):
99
 
100
  fig = go.Figure()
101
  fig.add_trace(make_gauge(match_score, "Match Score", "#00dfd8"))
102
- # In a real dashboard we'd have 4 separate plots, but for simplicity we'll show the main one
103
- # and use different layout for others or just focus on the primary one.
104
 
105
  fig.update_layout(
106
  paper_bgcolor='rgba(0,0,0,0)',
@@ -147,7 +154,7 @@ def estimate_salary(score, skills):
147
  return f"${low}k - ${high}k"
148
 
149
  def main_process(resume_file, jd_text, progress=gr.Progress()):
150
- print("--- New Analysis Request ---")
151
  if not resume_file or not jd_text.strip():
152
  return [
153
  "⚠️ Please upload resume/JD.", "", None, None,
@@ -168,30 +175,31 @@ def main_process(resume_file, jd_text, progress=gr.Progress()):
168
  match_skills = sorted(list(r_skills.intersection(j_skills)))
169
  gap_skills = sorted(list(j_skills - r_skills))
170
 
171
- progress(0.6, desc="Calculating Match Intelligence...")
172
  emb1 = model.encode(resume_text, convert_to_tensor=True)
173
  emb2 = model.encode(jd_text, convert_to_tensor=True)
174
  score = round(util.pytorch_cos_sim(emb1, emb2).item() * 100, 1)
175
 
176
- # Heuristic metrics for the dashboard
 
 
 
 
 
 
 
 
 
177
  content_score = min(100, len(resume_text.split()) / 5)
178
  search_score = min(100, len(r_skills) * 10)
179
  ats_score = round(score * 0.9, 1)
180
 
181
- progress(0.8, desc="Generating Visualizations...")
182
  gauge_plot = create_score_gauges(score, content_score, search_score, ats_score)
183
  radar_plot = create_radar_chart(len(match_skills)*10, 75, 80, score, search_score)
184
 
185
  salary_range = estimate_salary(score, match_skills)
186
 
187
- ai_analysis = f"Based on our AI alignment, your profile shows {score}% match for this role. "
188
- if score > 80:
189
- ai_analysis += "Excellent match! You are a top-tier candidate."
190
- elif score > 50:
191
- ai_analysis += "Strong foundation, but some gaps in technical stacks were detected."
192
- else:
193
- ai_analysis += "Needs improvement. Focus on the learning roadmap to bridge gaps."
194
-
195
  present_str = ", ".join([s.upper() for s in match_skills]) if match_skills else "No direct matches."
196
  gap_str = ", ".join([s.upper() for s in gap_skills]) if gap_skills else "No gaps detected!"
197
 
@@ -206,13 +214,13 @@ def generate_roadmap(gap_skills):
206
  return """
207
  <div style='text-align: center; padding: 40px; background: rgba(0, 223, 216, 0.1); border-radius: 15px;'>
208
  <h2 style='color: #00dfd8;'>🌟 Profile is 100% Ready!</h2>
209
- <p>Your skills perfectly align with this role. Focus on interview storytelling and behavioral prep.</p>
210
  </div>
211
  """
212
 
213
  cards_html = "<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; margin-top: 20px;'>"
214
  for s in gap_skills:
215
- res = ROADMAP_DB.get(s.lower(), f"Master {s.upper()} via hands-on projects & documentation.")
216
  cards_html += f"""
217
  <div style='background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(0, 223, 216, 0.3); border-radius: 12px; padding: 20px; border-left: 5px solid #00dfd8;'>
218
  <div style='display: flex; justify-content: space-between; align-items: start;'>
@@ -233,6 +241,19 @@ def generate_roadmap(gap_skills):
233
  cards_html += "</div>"
234
  return f"### πŸš€ Learning Pathfinder\n{cards_html}"
235
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
  # Premium CSS for Glassmorphism
237
  STYLE = """
238
  .gradio-container {
 
9
  import os
10
  import torch
11
 
12
+ from transformers import pipeline
13
+
14
  # Initialize Models once at startup
15
  print("πŸš€ Initializing SETHU AI Engine...")
16
  try:
 
21
  nlp = spacy.load("en_core_web_sm")
22
 
23
  # Use a high-quality Hugging Face model for embeddings
 
24
  model = SentenceTransformer('all-MiniLM-L6-v2')
25
 
26
+ # Initialize LLM for Reasoning (using a lightweight model for local speed)
27
+ print("πŸ€– Loading Reasoning LLM (FLAN-T5)...")
28
+ try:
29
+ llm_reasoner = pipeline("text2text-generation", model="google/flan-t5-small", device_map="auto")
30
+ except Exception as e:
31
+ print(f"⚠️ LLM Load failed: {e}. Falling back to heuristic reasoning.")
32
+ llm_reasoner = None
33
+
34
  TECH_SKILLS = [
35
  "python", "javascript", "react", "fastapi", "aws", "docker", "kubernetes", "sql",
36
  "git", "ml", "nlp", "tensorflow", "pytorch", "java", "golang", "postgresql",
 
108
 
109
  fig = go.Figure()
110
  fig.add_trace(make_gauge(match_score, "Match Score", "#00dfd8"))
 
 
111
 
112
  fig.update_layout(
113
  paper_bgcolor='rgba(0,0,0,0)',
 
154
  return f"${low}k - ${high}k"
155
 
156
  def main_process(resume_file, jd_text, progress=gr.Progress()):
157
+ print("--- New Analysis Request (LLM Enabled) ---")
158
  if not resume_file or not jd_text.strip():
159
  return [
160
  "⚠️ Please upload resume/JD.", "", None, None,
 
175
  match_skills = sorted(list(r_skills.intersection(j_skills)))
176
  gap_skills = sorted(list(j_skills - r_skills))
177
 
178
+ progress(0.5, desc="Calculating Match Intelligence...")
179
  emb1 = model.encode(resume_text, convert_to_tensor=True)
180
  emb2 = model.encode(jd_text, convert_to_tensor=True)
181
  score = round(util.pytorch_cos_sim(emb1, emb2).item() * 100, 1)
182
 
183
+ progress(0.7, desc="Generating AI Analysis with LLM...")
184
+ if llm_reasoner:
185
+ prompt = f"Analyze resume match for Job Description. Match Score: {score}%. Gaps: {', '.join(gap_skills)}. Summarize fit in 2 sentences."
186
+ ai_response = llm_reasoner(prompt, max_length=100)[0]['generated_text']
187
+ ai_analysis = f"**AI Verdict**: {ai_response}"
188
+ else:
189
+ ai_analysis = f"Based on our AI alignment, your profile shows {score}% match. "
190
+ ai_analysis += "Strong foundation!" if score > 50 else "Focus on the gaps."
191
+
192
+ # Heuristic metrics
193
  content_score = min(100, len(resume_text.split()) / 5)
194
  search_score = min(100, len(r_skills) * 10)
195
  ats_score = round(score * 0.9, 1)
196
 
197
+ progress(0.9, desc="Finalizing Dashboard...")
198
  gauge_plot = create_score_gauges(score, content_score, search_score, ats_score)
199
  radar_plot = create_radar_chart(len(match_skills)*10, 75, 80, score, search_score)
200
 
201
  salary_range = estimate_salary(score, match_skills)
202
 
 
 
 
 
 
 
 
 
203
  present_str = ", ".join([s.upper() for s in match_skills]) if match_skills else "No direct matches."
204
  gap_str = ", ".join([s.upper() for s in gap_skills]) if gap_skills else "No gaps detected!"
205
 
 
214
  return """
215
  <div style='text-align: center; padding: 40px; background: rgba(0, 223, 216, 0.1); border-radius: 15px;'>
216
  <h2 style='color: #00dfd8;'>🌟 Profile is 100% Ready!</h2>
217
+ <p>Your skills perfectly align with this role. Focus on interview storytelling.</p>
218
  </div>
219
  """
220
 
221
  cards_html = "<div style='display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 20px; margin-top: 20px;'>"
222
  for s in gap_skills:
223
+ res = ROADMAP_DB.get(s.lower(), f"Master {s.upper()} via hands-on projects.")
224
  cards_html += f"""
225
  <div style='background: rgba(255, 255, 255, 0.05); border: 1px solid rgba(0, 223, 216, 0.3); border-radius: 12px; padding: 20px; border-left: 5px solid #00dfd8;'>
226
  <div style='display: flex; justify-content: space-between; align-items: start;'>
 
241
  cards_html += "</div>"
242
  return f"### πŸš€ Learning Pathfinder\n{cards_html}"
243
 
244
+ def generate_interview_questions(gaps):
245
+ if not llm_reasoner:
246
+ return "1. Can you walk us through your most successful project?\n2. How do you stay updated with tech trends?"
247
+
248
+ print("πŸ€– Generating questions with LLM...")
249
+ context = ", ".join(gaps[:3]) if gaps else "general tech"
250
+ prompt = f"Generate 3 technical interview questions for a candidate missing: {context}. Be specific."
251
+ try:
252
+ q_gen = llm_reasoner(prompt, max_length=150)[0]['generated_text']
253
+ return f"### 🎀 AI-Generated Questions\n{q_gen}\n\n*Tip: Leverage your adjacent skills to bridge these gaps.*"
254
+ except:
255
+ return "1. Describe a complex technical problem you solved.\n2. How do you handle deadlines?"
256
+
257
  # Premium CSS for Glassmorphism
258
  STYLE = """
259
  .gradio-container {