Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -38,13 +38,11 @@ def load_models():
|
|
38 |
# Load smaller summarization model for speed
|
39 |
models['summarizer'] = pipeline("summarization", model="facebook/bart-large-cnn", max_length=130)
|
40 |
|
41 |
-
# Load
|
42 |
models['evaluator'] = pipeline(
|
43 |
-
"
|
44 |
-
model="
|
45 |
-
|
46 |
-
do_sample=True,
|
47 |
-
temperature=0.7
|
48 |
)
|
49 |
|
50 |
return models
|
@@ -305,85 +303,94 @@ def summarize_resume_text(resume_text):
|
|
305 |
return formatted_summary, execution_time
|
306 |
|
307 |
#####################################
|
308 |
-
# Function:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
309 |
#####################################
|
310 |
@st.cache_data(show_spinner=False)
|
311 |
def evaluate_google_fit(candidate_summary, _evaluator=None):
|
312 |
"""
|
313 |
-
Use
|
|
|
314 |
"""
|
315 |
start_time = time.time()
|
316 |
|
317 |
evaluator = _evaluator or models['evaluator']
|
318 |
|
319 |
-
#
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
3. Mention 1-2 specific strengths relevant to Google
|
329 |
-
4. Mention 1 specific area where they might need improvement to better fit Google's requirements
|
330 |
|
331 |
-
|
332 |
-
{candidate_summary}
|
333 |
|
334 |
-
Google
|
335 |
-
{GOOGLE_DESCRIPTION}
|
336 |
-
<|im_end|>
|
337 |
|
338 |
-
|
339 |
"""
|
340 |
|
341 |
-
# Generate the
|
342 |
-
|
343 |
|
344 |
-
#
|
345 |
-
|
346 |
-
|
|
|
347 |
|
348 |
-
|
349 |
-
if "<|im_end|>" in assistant_response:
|
350 |
-
assistant_response = assistant_response.split("<|im_end|>")[0].strip()
|
351 |
|
352 |
-
#
|
353 |
-
|
354 |
-
|
355 |
|
356 |
-
if
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
score = int(group)
|
361 |
-
normalized_score = min(100, max(0, score)) / 100 # Ensure it's in 0-1 range
|
362 |
-
break
|
363 |
-
else:
|
364 |
-
normalized_score = 0.5 # Default if no group was extracted
|
365 |
-
else:
|
366 |
-
# If no explicit score, try to infer from sentiments
|
367 |
-
positive_words = ['excellent', 'perfect', 'outstanding', 'ideal', 'great', 'strong']
|
368 |
-
negative_words = ['poor', 'inadequate', 'insufficient', 'lacks', 'mismatch', 'weak']
|
369 |
-
|
370 |
-
positive_count = sum(assistant_response.lower().count(word) for word in positive_words)
|
371 |
-
negative_count = sum(assistant_response.lower().count(word) for word in negative_words)
|
372 |
-
|
373 |
-
if positive_count > negative_count * 2:
|
374 |
-
normalized_score = 0.85
|
375 |
-
elif positive_count > negative_count:
|
376 |
-
normalized_score = 0.7
|
377 |
-
elif negative_count > positive_count * 2:
|
378 |
-
normalized_score = 0.3
|
379 |
-
elif negative_count > positive_count:
|
380 |
-
normalized_score = 0.4
|
381 |
-
else:
|
382 |
-
normalized_score = 0.5
|
383 |
|
384 |
execution_time = time.time() - start_time
|
385 |
|
386 |
-
return
|
387 |
|
388 |
#####################################
|
389 |
# Main Streamlit Interface - with Progress Reporting
|
@@ -453,7 +460,7 @@ if uploaded_file is not None and st.button("Analyze My Google Fit"):
|
|
453 |
else:
|
454 |
st.error(f"**Google Match Score:** {score_percent}% π")
|
455 |
|
456 |
-
# Display the
|
457 |
st.markdown("### Feedback from Google AI Recruiter")
|
458 |
st.markdown(evaluation)
|
459 |
|
@@ -469,9 +476,9 @@ if uploaded_file is not None and st.button("Analyze My Google Fit"):
|
|
469 |
""")
|
470 |
elif fit_score >= 0.60:
|
471 |
st.markdown("""
|
472 |
-
- Focus on strengthening the
|
473 |
- Work on projects that demonstrate your skills in Google's key technology areas
|
474 |
-
- Consider taking additional courses in
|
475 |
""")
|
476 |
else:
|
477 |
st.markdown("""
|
|
|
38 |
# Load smaller summarization model for speed
|
39 |
models['summarizer'] = pipeline("summarization", model="facebook/bart-large-cnn", max_length=130)
|
40 |
|
41 |
+
# Load T5-small model for evaluation
|
42 |
models['evaluator'] = pipeline(
|
43 |
+
"text2text-generation",
|
44 |
+
model="google-t5/t5-small",
|
45 |
+
max_length=200
|
|
|
|
|
46 |
)
|
47 |
|
48 |
return models
|
|
|
303 |
return formatted_summary, execution_time
|
304 |
|
305 |
#####################################
|
306 |
+
# Function: Calculate Google Match Score
|
307 |
+
#####################################
|
308 |
+
def calculate_google_match_score(candidate_summary):
|
309 |
+
"""
|
310 |
+
Calculate a match score based on skills and experience in the candidate summary
|
311 |
+
compared with what Google requires.
|
312 |
+
"""
|
313 |
+
# Key skills and keywords that Google values
|
314 |
+
google_keywords = {
|
315 |
+
"high_value": [
|
316 |
+
"python", "java", "c++", "go", "javascript",
|
317 |
+
"algorithms", "data structures", "system design",
|
318 |
+
"artificial intelligence", "machine learning", "problem solving",
|
319 |
+
"cloud computing", "cybersecurity", "ux/ui"
|
320 |
+
],
|
321 |
+
"medium_value": [
|
322 |
+
"react", "angular", "node.js", "sql", "nosql", "git",
|
323 |
+
"agile", "scrum", "docker", "kubernetes", "aws", "azure",
|
324 |
+
"analytics", "automation", "leadership", "teamwork"
|
325 |
+
]
|
326 |
+
}
|
327 |
+
|
328 |
+
summary_lower = candidate_summary.lower()
|
329 |
+
|
330 |
+
# Count occurrences of high and medium value keywords
|
331 |
+
high_value_count = sum(summary_lower.count(keyword) for keyword in google_keywords["high_value"])
|
332 |
+
medium_value_count = sum(summary_lower.count(keyword) for keyword in google_keywords["medium_value"])
|
333 |
+
|
334 |
+
# Calculate a weighted score
|
335 |
+
score = (high_value_count * 2 + medium_value_count) / (len(google_keywords["high_value"]) * 2 + len(google_keywords["medium_value"]))
|
336 |
+
|
337 |
+
# Normalize to 0-1 range
|
338 |
+
normalized_score = min(1.0, max(0.0, score * 2.5))
|
339 |
+
|
340 |
+
return normalized_score
|
341 |
+
|
342 |
+
#####################################
|
343 |
+
# Function: Evaluate Google Fit with T5
|
344 |
#####################################
|
345 |
@st.cache_data(show_spinner=False)
|
346 |
def evaluate_google_fit(candidate_summary, _evaluator=None):
|
347 |
"""
|
348 |
+
Use T5-small model to evaluate how well the candidate matches with Google's requirements.
|
349 |
+
Uses third-person tone in the evaluation.
|
350 |
"""
|
351 |
start_time = time.time()
|
352 |
|
353 |
evaluator = _evaluator or models['evaluator']
|
354 |
|
355 |
+
# Calculate a match score
|
356 |
+
match_score = calculate_google_match_score(candidate_summary)
|
357 |
+
score_percent = int(match_score * 100)
|
358 |
+
|
359 |
+
# Create a template for the T5 prompt
|
360 |
+
# T5 works well with task prefixes
|
361 |
+
prompt = f"""
|
362 |
+
Evaluate in third-person tone if this candidate is a good fit for Google based on the resume summary and Google's requirements.
|
363 |
+
Mention specific skills that match or don't match. Keep it concise.
|
|
|
|
|
364 |
|
365 |
+
Resume Summary: {candidate_summary[:500]}
|
|
|
366 |
|
367 |
+
Google Requirements: {GOOGLE_DESCRIPTION[:500]}
|
|
|
|
|
368 |
|
369 |
+
Score: {score_percent}/100
|
370 |
"""
|
371 |
|
372 |
+
# Generate the evaluation
|
373 |
+
evaluation_result = evaluator(prompt)[0]['generated_text']
|
374 |
|
375 |
+
# Ensure the output uses third-person tone
|
376 |
+
# T5-small may not always follow instructions perfectly, so we'll check and adjust
|
377 |
+
first_person_pronouns = ["i ", "i'm", "i am", "my ", "mine ", "we ", "our "]
|
378 |
+
second_person_pronouns = ["you ", "your ", "yours "]
|
379 |
|
380 |
+
evaluation_lower = evaluation_result.lower()
|
|
|
|
|
381 |
|
382 |
+
# If the model used first or second person, prepend a third-person context
|
383 |
+
if any(pronoun in evaluation_lower for pronoun in first_person_pronouns + second_person_pronouns):
|
384 |
+
evaluation_result = f"The candidate {evaluation_result}"
|
385 |
|
386 |
+
# Ensure evaluation starts with third-person phrasing if it doesn't already
|
387 |
+
if not any(evaluation_result.lower().startswith(phrase) for phrase in
|
388 |
+
["this candidate", "the candidate", "candidate", "this applicant", "the applicant"]):
|
389 |
+
evaluation_result = f"This candidate {evaluation_result}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
|
391 |
execution_time = time.time() - start_time
|
392 |
|
393 |
+
return match_score, evaluation_result, execution_time
|
394 |
|
395 |
#####################################
|
396 |
# Main Streamlit Interface - with Progress Reporting
|
|
|
460 |
else:
|
461 |
st.error(f"**Google Match Score:** {score_percent}% π")
|
462 |
|
463 |
+
# Display the evaluation in third-person tone
|
464 |
st.markdown("### Feedback from Google AI Recruiter")
|
465 |
st.markdown(evaluation)
|
466 |
|
|
|
476 |
""")
|
477 |
elif fit_score >= 0.60:
|
478 |
st.markdown("""
|
479 |
+
- Focus on strengthening the areas mentioned in the evaluation
|
480 |
- Work on projects that demonstrate your skills in Google's key technology areas
|
481 |
+
- Consider taking additional courses in algorithms, system design, or other Google focus areas
|
482 |
""")
|
483 |
else:
|
484 |
st.markdown("""
|