Spaces:
Running
Running
Arjun Singh
commited on
Commit
·
d83dcfb
1
Parent(s):
0fe9950
Added hallucination detection to AI Recruiting Agent
Browse files
app.py
CHANGED
|
@@ -120,6 +120,38 @@ def store_resumes(resume_files: List[tempfile._TemporaryFileWrapper]) -> str:
|
|
| 120 |
resume_store.add_documents(all_docs)
|
| 121 |
return f"Successfully stored {len(resume_files)} resumes"
|
| 122 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 123 |
def analyze_candidates(job_description: str) -> str:
|
| 124 |
# First extract required skills from job description
|
| 125 |
skills_prompt = PromptTemplate(
|
|
@@ -225,6 +257,9 @@ def analyze_candidates(job_description: str) -> str:
|
|
| 225 |
"cultural_requirements": cultural_requirements
|
| 226 |
})
|
| 227 |
|
|
|
|
|
|
|
|
|
|
| 228 |
# Now analyze technical skills match
|
| 229 |
skills_analysis_prompt = PromptTemplate(
|
| 230 |
input_variables=["resume", "required_skills", "job_description"],
|
|
@@ -261,6 +296,9 @@ def analyze_candidates(job_description: str) -> str:
|
|
| 261 |
"job_description": job_description
|
| 262 |
})
|
| 263 |
|
|
|
|
|
|
|
|
|
|
| 264 |
# Create final recommendation
|
| 265 |
final_recommendation_prompt = PromptTemplate(
|
| 266 |
input_variables=["skills_analysis", "culture_analysis", "job_description"],
|
|
@@ -300,6 +338,11 @@ def analyze_candidates(job_description: str) -> str:
|
|
| 300 |
"job_description": job_description
|
| 301 |
})
|
| 302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
# Append the analysis for this candidate to the consolidated analyses
|
| 304 |
consolidated_analyses.append(f"""
|
| 305 |
=== Candidate Analysis (Resume ID: {resume_id}) ===
|
|
@@ -311,7 +354,7 @@ def analyze_candidates(job_description: str) -> str:
|
|
| 311 |
{skills_fit}
|
| 312 |
|
| 313 |
HIRING RECOMMENDATION:
|
| 314 |
-
{final_recommendation}
|
| 315 |
|
| 316 |
----------------------------------------
|
| 317 |
""")
|
|
@@ -329,8 +372,6 @@ def analyze_candidates(job_description: str) -> str:
|
|
| 329 |
return "\n".join(consolidated_analyses)
|
| 330 |
|
| 331 |
|
| 332 |
-
|
| 333 |
-
|
| 334 |
def clear_databases():
|
| 335 |
"""Clear both resume and culture document databases"""
|
| 336 |
global resume_store, culture_store
|
|
|
|
| 120 |
resume_store.add_documents(all_docs)
|
| 121 |
return f"Successfully stored {len(resume_files)} resumes"
|
| 122 |
|
| 123 |
+
def verify_analysis(analysis_text: str, source_documents: List[str]) -> Dict:
|
| 124 |
+
"""Verify analysis against source documents"""
|
| 125 |
+
verification_prompt = PromptTemplate(
|
| 126 |
+
input_variables=["analysis", "source_docs"],
|
| 127 |
+
template="""
|
| 128 |
+
Compare this analysis against source documents. Identify unsupported claims.
|
| 129 |
+
|
| 130 |
+
Analysis: {analysis}
|
| 131 |
+
Source Documents: {source_docs}
|
| 132 |
+
|
| 133 |
+
Provide:
|
| 134 |
+
UNSUPPORTED CLAIMS: [list or "None"]
|
| 135 |
+
FACTUALITY SCORE: [0-100]%
|
| 136 |
+
UNCERTAINTY: [areas or "None"]
|
| 137 |
+
"""
|
| 138 |
+
)
|
| 139 |
+
|
| 140 |
+
chain = LLMChain(llm=llm, prompt=verification_prompt)
|
| 141 |
+
result = chain.run({
|
| 142 |
+
"analysis": analysis_text,
|
| 143 |
+
"source_docs": "\n---\n".join(source_documents)
|
| 144 |
+
})
|
| 145 |
+
|
| 146 |
+
# Parse score
|
| 147 |
+
try:
|
| 148 |
+
score_line = [line for line in result.split('\n') if 'FACTUALITY SCORE:' in line][0]
|
| 149 |
+
score = int(score_line.split(':')[1].strip().replace('%', '')) / 100
|
| 150 |
+
except:
|
| 151 |
+
score = 0.5
|
| 152 |
+
|
| 153 |
+
return {"factuality_score": score, "verification_result": result}
|
| 154 |
+
|
| 155 |
def analyze_candidates(job_description: str) -> str:
|
| 156 |
# First extract required skills from job description
|
| 157 |
skills_prompt = PromptTemplate(
|
|
|
|
| 257 |
"cultural_requirements": cultural_requirements
|
| 258 |
})
|
| 259 |
|
| 260 |
+
# Verify culture analysis
|
| 261 |
+
culture_verification = verify_analysis(culture_fit, [resume_text, cultural_requirements])
|
| 262 |
+
|
| 263 |
# Now analyze technical skills match
|
| 264 |
skills_analysis_prompt = PromptTemplate(
|
| 265 |
input_variables=["resume", "required_skills", "job_description"],
|
|
|
|
| 296 |
"job_description": job_description
|
| 297 |
})
|
| 298 |
|
| 299 |
+
# Verify skills analysis
|
| 300 |
+
skills_verification = verify_analysis(skills_fit, [resume_text, skills, job_description])
|
| 301 |
+
|
| 302 |
# Create final recommendation
|
| 303 |
final_recommendation_prompt = PromptTemplate(
|
| 304 |
input_variables=["skills_analysis", "culture_analysis", "job_description"],
|
|
|
|
| 338 |
"job_description": job_description
|
| 339 |
})
|
| 340 |
|
| 341 |
+
# Add verification warnings if factuality score < 0.8
|
| 342 |
+
verification_notes = ""
|
| 343 |
+
if culture_verification["factuality_score"] < 0.8 or skills_verification["factuality_score"] < 0.8:
|
| 344 |
+
verification_notes = f"\n\n⚠️ VERIFICATION: Some claims may be unsupported. Culture: {culture_verification['factuality_score']:.0%}, Skills: {skills_verification['factuality_score']:.0%}"
|
| 345 |
+
|
| 346 |
# Append the analysis for this candidate to the consolidated analyses
|
| 347 |
consolidated_analyses.append(f"""
|
| 348 |
=== Candidate Analysis (Resume ID: {resume_id}) ===
|
|
|
|
| 354 |
{skills_fit}
|
| 355 |
|
| 356 |
HIRING RECOMMENDATION:
|
| 357 |
+
{final_recommendation}{verification_notes}
|
| 358 |
|
| 359 |
----------------------------------------
|
| 360 |
""")
|
|
|
|
| 372 |
return "\n".join(consolidated_analyses)
|
| 373 |
|
| 374 |
|
|
|
|
|
|
|
| 375 |
def clear_databases():
|
| 376 |
"""Clear both resume and culture document databases"""
|
| 377 |
global resume_store, culture_store
|