earlsab commited on
Commit
b389c69
·
1 Parent(s): 72bb1f5

working wake

Browse files
Files changed (2) hide show
  1. app.py +187 -28
  2. input_outputs.md +13 -2
app.py CHANGED
@@ -1,32 +1,155 @@
1
  import gradio as gr
2
-
3
- from model_skill_extraction import SkillExtractionModel
4
- from model_section_segmentation import SegmentationModelJobDescription, SegmentationModelResume
5
- from model_skill_quality_extraction import SkillQualityExtractionModel
6
- from model_date_extraction import DateExtractionModel
7
-
8
  import json
9
- from typing import List, Dict
10
  import time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- # Initialize models
13
- segmentation_model_resume = SegmentationModelResume()
14
- segmentation_model_job_description= SegmentationModelJobDescription()
15
- skill_model = SkillExtractionModel()
16
- skill_quality_model = SkillQualityExtractionModel()
17
- date_model = DateExtractionModel()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
 
19
  def process_job_description(job_description: str) -> Dict:
20
- """Process job description and extract skills"""
21
- result = skill_model.process_text(job_description)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  return result
23
 
24
- def process_resume(resume_text: str, job_skills: List[str]) -> Dict:
25
- """Process resume and analyze against job skills"""
26
- # result = resume_model.process_resume(resume_text, job_skills)
27
- result = skill_model.process_text(resume_text)
 
 
 
 
28
  return result
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  def create_html_output(job_result: Dict, resume_results: List[Dict]) -> str:
31
  """Create HTML output for the interface"""
32
  html = "<div style='font-family: Arial, sans-serif;'>"
@@ -45,16 +168,47 @@ def create_html_output(job_result: Dict, resume_results: List[Dict]) -> str:
45
  for i, resume_result in enumerate(resume_results, 1):
46
  html += f"<div style='margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 5px;'>"
47
  html += f"<h3>Resume {i}</h3>"
48
- # html += f"<p><strong>Skill Match Quality:</strong> {resume_result['skill_quality']['quality_score']:.2%}</p>"
49
- # html += f"<p><strong>Matched Skills:</strong> {resume_result['skill_quality']['matched_skills_count']}/{resume_result['skill_quality']['total_required_skills']}</p>"
50
- html += "<p><strong>Matched Skills:</strong></p>"
51
  html += "<div style='background-color: #f0f0f0; padding: 10px; border-radius: 5px;'>"
52
- # for skill in resume_result['skill_quality']['matched_skills']:
53
- # html += f"<span style='background-color: #e0e0e0; padding: 2px 5px; margin: 2px; border-radius: 3px; display: inline-block;'>{skill}</span>"
54
  html += "</div>"
55
- html += "<details><summary>View Full Resume</summary>"
56
- # html += f"<pre style='white-space: pre-wrap;'>{resume_result['full_text']}</pre>"
57
- html += "</details>"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  html += "</div>"
59
 
60
  html += "</div>"
@@ -83,10 +237,15 @@ def process_inputs(job_description: str, input_type: str, resume_text: str, resu
83
  return create_html_output(job_result, resume_results)
84
 
85
  # Create Gradio interface
86
- with gr.Blocks(title="Resume Analysis System") as demo:
87
  gr.Markdown("# Beyond Keywords: Job Description and Resume Analyzer")
88
  gr.Markdown("Upload a job description and resume(s) to analyze skill matches and quality.")
89
 
 
 
 
 
 
90
  with gr.Row():
91
  with gr.Column():
92
  job_description = gr.Textbox(
 
1
  import gradio as gr
2
+ import requests
 
 
 
 
 
3
  import json
4
+ import os
5
  import time
6
+ from typing import List, Dict, Any
7
+ from dotenv import load_dotenv
8
+
9
+ # Load environment variables
10
+ load_dotenv(".env.local")
11
+
12
+ # Load endpoints from JSON file
13
+ with open('endpoints.json', 'r') as f:
14
+ ENDPOINTS = json.load(f)
15
+
16
+ # Get HuggingFace API token from environment variable
17
+ HF_TOKEN = os.getenv('HUGGINGFACE_TOKEN')
18
+ if not HF_TOKEN:
19
+ print("Warning: HUGGINGFACE_TOKEN environment variable not set")
20
+
21
+ # API calling function with retry logic
22
+ def call_api(endpoint_url: str, payload: Dict[str, Any], max_retries: int = 5, retry_delay: int = 2) -> Dict:
23
+ """Call API endpoint with retry logic"""
24
+ headers = {"Authorization": f"Bearer {HF_TOKEN}"}
25
+
26
+ for attempt in range(max_retries):
27
+ try:
28
+ response = requests.post(
29
+ endpoint_url,
30
+ json=payload,
31
+ headers=headers,
32
+ timeout=30
33
+ )
34
+
35
+ if response.status_code == 200:
36
+ return response.json()
37
+ elif response.status_code == 503:
38
+ print(f"Service temporarily unavailable (503). Retrying... (Attempt {attempt + 1}/{max_retries})")
39
+ time.sleep(retry_delay * (attempt + 1)) # Exponential backoff
40
+ continue
41
+ else:
42
+ print(f"Error calling API: {response.status_code}")
43
+ print(f"Response: {response.text}")
44
+ return {}
45
+
46
+ except requests.exceptions.Timeout:
47
+ print(f"Request timed out. Attempt {attempt + 1}/{max_retries}")
48
+ if attempt < max_retries - 1:
49
+ time.sleep(retry_delay)
50
+ except Exception as e:
51
+ print(f"Exception while calling API: {str(e)}")
52
+ if attempt < max_retries - 1:
53
+ time.sleep(retry_delay)
54
+
55
+ return {}
56
 
57
+ def wake_servers(progress=gr.Progress()):
58
+ """Send wake-up requests to all endpoints"""
59
+ results = {}
60
+
61
+ total_endpoints = len(ENDPOINTS)
62
+ for i, (name, url) in enumerate(ENDPOINTS.items()):
63
+ progress(i/total_endpoints, desc=f"Waking up {name} endpoint...")
64
+ print(f"Waking up {name} endpoint...")
65
+ try:
66
+ # Send a small payload just to wake up the server
67
+ minimal_payload = {"inputs": "Hello"}
68
+ response = requests.post(
69
+ url,
70
+ json=minimal_payload,
71
+ headers={"Authorization": f"Bearer {HF_TOKEN}"},
72
+ timeout=45
73
+ )
74
+ results[name] = f"Status: {response.status_code}"
75
+ except Exception as e:
76
+ results[name] = f"Error: {str(e)}"
77
+
78
+ progress(1.0, desc="Complete!")
79
+ status_html = "<h3>Server Wake-up Results:</h3><ul>"
80
+ for name, status in results.items():
81
+ status_color = "green" if "Status: 200" in status else "red"
82
+ status_html += f"<li><strong>{name}</strong>: <span style='color:{status_color}'>{status}</span></li>"
83
+ status_html += "</ul>"
84
+
85
+ return status_html
86
 
87
  def process_job_description(job_description: str) -> Dict:
88
+ """Process job description and extract skills using the job endpoint"""
89
+ payload = {"inputs": job_description}
90
+ result = call_api(ENDPOINTS["job"], payload)
91
+
92
+ if not result:
93
+ # Return a fallback structure if API call fails
94
+ return {"skills": [], "total_skills": 0}
95
+
96
+ # Format the result to match expected structure
97
+ if "skills" in result:
98
+ # Add a "text" field to each skill for compatibility
99
+ for skill in result["skills"]:
100
+ skill["text"] = skill.get("name", "Unknown Skill")
101
+
102
+ result["total_skills"] = len(result["skills"])
103
+ else:
104
+ result = {"skills": [], "total_skills": 0}
105
+
106
  return result
107
 
108
+ def process_skill_quality(text: str) -> Dict:
109
+ """Process a sentence through the skill quality endpoint"""
110
+ payload = {"inputs": text}
111
+ result = call_api(ENDPOINTS["skill_quality"], payload)
112
+
113
+ if not result:
114
+ return {"leadership": 0, "leadership_token": "No", "collaboration": 0, "collaboration_token": "No"}
115
+
116
  return result
117
 
118
+ def process_resume(resume_text: str, job_skills: List[str]) -> Dict:
119
+ """Process resume using the resume endpoint"""
120
+ payload = {"inputs": resume_text}
121
+ result = call_api(ENDPOINTS["resume"], payload)
122
+
123
+ if not result:
124
+ return {"skills": [], "total_skills": 0}
125
+
126
+ # Extract all skills from all job experiences
127
+ all_skills = []
128
+ # Process skill quality for each role description
129
+ for job in result:
130
+ if "skills" in job:
131
+ for skill in job["skills"]:
132
+ # Add a "text" field for compatibility
133
+ skill["text"] = skill.get("name", "Unknown Skill")
134
+ all_skills.append(skill)
135
+
136
+ # Process skill quality for each bullet point in the job description
137
+ if "description" in job:
138
+ quality_scores = []
139
+ for sentence in job.get("description", []):
140
+ quality_score = process_skill_quality(sentence)
141
+ quality_scores.append({"sentence": sentence, "quality": quality_score})
142
+ job["quality_scores"] = quality_scores
143
+
144
+ # Add fields to match expected structure
145
+ formatted_result = {
146
+ "skills": all_skills,
147
+ "total_skills": len(all_skills),
148
+ "roles": result # Keep the original roles data
149
+ }
150
+
151
+ return formatted_result
152
+
153
  def create_html_output(job_result: Dict, resume_results: List[Dict]) -> str:
154
  """Create HTML output for the interface"""
155
  html = "<div style='font-family: Arial, sans-serif;'>"
 
168
  for i, resume_result in enumerate(resume_results, 1):
169
  html += f"<div style='margin-bottom: 20px; padding: 10px; border: 1px solid #ddd; border-radius: 5px;'>"
170
  html += f"<h3>Resume {i}</h3>"
171
+
172
+ # Display all skills found in the resume
173
+ html += "<p><strong>Skills Found:</strong></p>"
174
  html += "<div style='background-color: #f0f0f0; padding: 10px; border-radius: 5px;'>"
175
+ for skill in resume_result['skills']:
176
+ html += f"<span style='background-color: #e0e0e0; padding: 2px 5px; margin: 2px; border-radius: 3px; display: inline-block;'>{skill['text']}</span>"
177
  html += "</div>"
178
+
179
+ # Job roles section
180
+ if 'roles' in resume_result and resume_result['roles']:
181
+ html += "<p><strong>Job Experience:</strong></p>"
182
+ for role in resume_result['roles']:
183
+ html += f"<div style='margin: 10px 0; padding: 10px; background-color: #f9f9f9; border-radius: 5px;'>"
184
+ html += f"<p><strong>Title:</strong> {' '.join(role.get('title', ['Unknown']))}</p>"
185
+ if 'dates' in role and role['dates']:
186
+ html += f"<p><strong>Period:</strong> {role['dates'].get('date_started', 'Unknown')} to {role['dates'].get('date_ended', 'Unknown')}</p>"
187
+ html += f"<p><strong>Role Skills:</strong></p>"
188
+ html += "<div style='margin-left: 20px;'>"
189
+ for skill in role.get('skills', []):
190
+ html += f"<span style='background-color: #e0e0e0; padding: 2px 5px; margin: 2px; border-radius: 3px; display: inline-block;'>{skill.get('name', 'Unknown')}</span>"
191
+ html += "</div>"
192
+
193
+ # Display skill quality analysis
194
+ if 'quality_scores' in role and role['quality_scores']:
195
+ html += "<p><strong>Skill Quality Analysis:</strong></p>"
196
+ html += "<table style='width: 100%; border-collapse: collapse; margin-top: 10px;'>"
197
+ html += "<tr style='background-color: #eee;'><th style='padding: 8px; text-align: left; border: 1px solid #ddd;'>Statement</th><th style='padding: 8px; text-align: center; border: 1px solid #ddd;'>Leadership</th><th style='padding: 8px; text-align: center; border: 1px solid #ddd;'>Collaboration</th></tr>"
198
+
199
+ for score in role['quality_scores']:
200
+ quality = score['quality']
201
+ leadership_class = "green-text" if quality.get('leadership', 0) == 1 else "red-text"
202
+ collab_class = "green-text" if quality.get('collaboration', 0) == 1 else "red-text"
203
+
204
+ html += f"<tr><td style='padding: 8px; border: 1px solid #ddd;'>{score['sentence']}</td>"
205
+ html += f"<td style='padding: 8px; text-align: center; border: 1px solid #ddd; color: {'green' if quality.get('leadership', 0) == 1 else 'red'};'>{quality.get('leadership_token', 'No')}</td>"
206
+ html += f"<td style='padding: 8px; text-align: center; border: 1px solid #ddd; color: {'green' if quality.get('collaboration', 0) == 1 else 'red'};'>{quality.get('collaboration_token', 'No')}</td></tr>"
207
+
208
+ html += "</table>"
209
+
210
+ html += "</div>"
211
+
212
  html += "</div>"
213
 
214
  html += "</div>"
 
237
  return create_html_output(job_result, resume_results)
238
 
239
  # Create Gradio interface
240
+ with gr.Blocks(title="Beyond Keywords: Resume Analysis System") as demo:
241
  gr.Markdown("# Beyond Keywords: Job Description and Resume Analyzer")
242
  gr.Markdown("Upload a job description and resume(s) to analyze skill matches and quality.")
243
 
244
+ # Wake servers button
245
+ wake_btn = gr.Button("Wake Servers (Do this first!)")
246
+ wake_status = gr.HTML(label="Server Status")
247
+ wake_btn.click(fn=wake_servers, inputs=None, outputs=wake_status)
248
+
249
  with gr.Row():
250
  with gr.Column():
251
  job_description = gr.Textbox(
input_outputs.md CHANGED
@@ -1,6 +1,5 @@
1
 
2
  # Job Description
3
-
4
  ### Expected INPUT
5
  ```{
6
  "inputs": "About the job\nJob Title: Frontend Developer\nJob Type: Full-time or Part-Time\nLocation: Remote\n\nAbout Us:\nOur mission at micro1 is to match the most talented people in the world with their dream jobs. If you are looking to be at the forefront of AI innovation and work with some of the fastest growing companies in Silicon Valley, we invite you to apply for a role. By joining the micro1 community, your resume will become visible to top industry leaders, unlocking access to the best career opportunities on the market.\n\nJob Summary:\nJoin our dynamic team at micro1 as a Frontend Developer where you will be instrumental in creating engaging and dynamic user experiences for web applications. At micro1, we provide opportunities to work with leading companies in Silicon Valley, ensuring a stable and competitive income in a flexible remote setting. Embrace the opportunity to grow your career, access top industry opportunities, and enjoy a range of great benefits.\n\nKey Responsibilities:\nDevelop high-quality frontend components for web applications.\nOptimize user interfaces to enhance user experiences.\nCollaborate with cross-functional teams to define and design new features.\nEnsure cross-browser compatibility and implement responsive designs.\nMaintain code quality and ensure responsiveness of applications.\nUtilize industry best practices and design patterns.\nParticipate in code reviews to maintain high code quality standards.\n\nRequired Skills and Qualifications:\nProficiency in HTML, CSS, and JavaScript.\nStrong experience with React and Angular frameworks.\nExcellent written and verbal communication skills.\nAbility to work effectively in a remote setting.\nDemonstrated ability to develop and optimize user interfaces.\nExperience with ensuring cross-browser compatibility of applications.\nStrong problem-solving skills and attention to detail.\n\nPreferred Qualifications:\nExperience with responsive design and mobile-first development.\nFamiliarity with version control systems, such as Git.\nUnderstanding of Agile methodologies.\nIt's okay if you don't. Having a Native to C2/C1 level in another language such as German, French, or Spanish is nice to have."
@@ -158,4 +157,16 @@
158
  ]
159
  }
160
  ]
161
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
1
 
2
  # Job Description
 
3
  ### Expected INPUT
4
  ```{
5
  "inputs": "About the job\nJob Title: Frontend Developer\nJob Type: Full-time or Part-Time\nLocation: Remote\n\nAbout Us:\nOur mission at micro1 is to match the most talented people in the world with their dream jobs. If you are looking to be at the forefront of AI innovation and work with some of the fastest growing companies in Silicon Valley, we invite you to apply for a role. By joining the micro1 community, your resume will become visible to top industry leaders, unlocking access to the best career opportunities on the market.\n\nJob Summary:\nJoin our dynamic team at micro1 as a Frontend Developer where you will be instrumental in creating engaging and dynamic user experiences for web applications. At micro1, we provide opportunities to work with leading companies in Silicon Valley, ensuring a stable and competitive income in a flexible remote setting. Embrace the opportunity to grow your career, access top industry opportunities, and enjoy a range of great benefits.\n\nKey Responsibilities:\nDevelop high-quality frontend components for web applications.\nOptimize user interfaces to enhance user experiences.\nCollaborate with cross-functional teams to define and design new features.\nEnsure cross-browser compatibility and implement responsive designs.\nMaintain code quality and ensure responsiveness of applications.\nUtilize industry best practices and design patterns.\nParticipate in code reviews to maintain high code quality standards.\n\nRequired Skills and Qualifications:\nProficiency in HTML, CSS, and JavaScript.\nStrong experience with React and Angular frameworks.\nExcellent written and verbal communication skills.\nAbility to work effectively in a remote setting.\nDemonstrated ability to develop and optimize user interfaces.\nExperience with ensuring cross-browser compatibility of applications.\nStrong problem-solving skills and attention to detail.\n\nPreferred Qualifications:\nExperience with responsive design and mobile-first development.\nFamiliarity with version control systems, such as Git.\nUnderstanding of Agile methodologies.\nIt's okay if you don't. Having a Native to C2/C1 level in another language such as German, French, or Spanish is nice to have."
 
157
  ]
158
  }
159
  ]
160
+ ```
161
+
162
+ # Skill Quality
163
+ ### Expected Input
164
+ {"inputs": "I am a leader."}
165
+
166
+ ### Expected Output
167
+ {
168
+ "leadership": 1,
169
+ "leadership_token": "Yes",
170
+ "collaboration": 0,
171
+ "collaboration_token": "No"
172
+ }