afouda commited on
Commit
6bc6f4a
·
verified ·
1 Parent(s): 1687f4a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +23 -29
app.py CHANGED
@@ -5,15 +5,15 @@ import csv
5
  import tempfile
6
  import time
7
  from typing import List, Dict, Any, Tuple
8
- import requests
9
  import PyPDF2
10
  import docx2txt
11
  import gradio as gr
12
  import pandas as pd
13
  import logging
 
14
 
15
  # Configure logging
16
- logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
17
 
18
  # Global Configuration
19
  DEEPINFRA_API_KEY = "kPEm10rrnxXrCf0TuB6Xcd7Y7lp3YgKa"
@@ -21,6 +21,12 @@ DEEPINFRA_BASE_URL = "https://api.deepinfra.com/v1/openai"
21
  DEFAULT_MODEL = "Qwen/Qwen3-32B"
22
  REQUEST_TIMEOUT_SECS = 120
23
 
 
 
 
 
 
 
24
  # Prompts for LLM Calls
25
  JD_SYSTEM = """You are an expert recruitment analyst. Extract a job description into STRICT JSON.
26
  Rules:
@@ -57,7 +63,6 @@ Schema:
57
  }
58
  """
59
 
60
- # New feedback system prompt with detailed scoring
61
  FEEDBACK_SYSTEM_DETAILED = """You are an expert technical recruiter. Compare a job and a candidate and return STRICT JSON with actionable feedback and a detailed score breakdown.
62
  Respond in the job description's language.
63
  Scores should be out of 100.
@@ -79,14 +84,13 @@ Keep each bullet short (max ~12 words).
79
  Output ONLY JSON.
80
  """
81
 
82
- # New recommendation system prompt
83
  RECOMMEND_SYSTEM = """You are a senior technical recruiter writing a concise recommendation summary for a hiring manager.
84
  Based on the provided candidate and job description, write a 2-3 sentence summary explaining why this candidate is a good match.
85
  Focus on key skills, relevant experience, and overall fit. Do not use a conversational tone.
86
- Output ONLY the summary text, no markdown or extra formatting."""
87
-
88
 
89
- # Helper Functions
90
  def _pdf_to_text(path: str) -> str:
91
  text = []
92
  with open(path, "rb") as f:
@@ -125,28 +129,20 @@ def safe_json_loads(text: str) -> dict:
125
  logging.error(f"Failed to parse JSON: {e}\nRaw Text: {text[:500]}...")
126
  return {}
127
 
 
128
  def deepinfra_chat(messages: List[Dict[str, str]], api_key: str, model: str, temperature: float = 0.2) -> str:
129
- if not api_key:
130
- raise RuntimeError("Missing API Key.")
131
- payload = {
132
- "model": model,
133
- "messages": messages,
134
- "temperature": temperature,
135
- }
136
  try:
137
- resp = requests.post(
138
- DEEPINFRA_BASE_URL,
139
- headers={
140
- "Authorization": f"Bearer {api_key}",
141
- "Content-Type": "application/json",
142
- },
143
- data=json.dumps(payload),
144
- timeout=REQUEST_TIMEOUT_SECS,
145
  )
146
- resp.raise_for_status()
147
- data = resp.json()
148
- return (data.get("choices", [{}])[0].get("message", {}).get("content", "") or "").strip()
149
- except requests.exceptions.RequestException as e:
150
  logging.error(f"API request failed: {e}")
151
  raise gr.Error(f"API request failed: {e}. Check your API key and model name.")
152
 
@@ -174,7 +170,7 @@ def load_resume(resume_file) -> Tuple[str, str]:
174
  text = read_file_safely(resume_file.name)
175
  return text, fname
176
 
177
- # LLM-based Extraction Functions
178
  def llm_extract_jd(jd_text: str, api_key: str, model: str, temperature: float = 0.1) -> Dict:
179
  messages = [
180
  {"role": "system", "content": JD_SYSTEM},
@@ -191,7 +187,6 @@ def llm_extract_resume(resume_text: str, api_key: str, model: str, temperature:
191
  raw = deepinfra_chat(messages, api_key=api_key, model=model, temperature=temperature)
192
  return safe_json_loads(raw)
193
 
194
- # New function for detailed feedback and scoring
195
  def llm_detailed_feedback(jd_struct: Dict, resume_struct: Dict, api_key: str, model: str, temperature: float = 0.2) -> Dict:
196
  prompt = json.dumps({"job": jd_struct, "candidate": resume_struct}, ensure_ascii=False)
197
  messages = [
@@ -201,7 +196,6 @@ def llm_detailed_feedback(jd_struct: Dict, resume_struct: Dict, api_key: str, mo
201
  raw = deepinfra_chat(messages, api_key=api_key, model=model, temperature=temperature)
202
  return safe_json_loads(raw)
203
 
204
- # New function for candidate recommendation summary
205
  def llm_recommend(jd_struct: Dict, resume_struct: Dict, api_key: str, model: str, temperature: float = 0.2) -> str:
206
  prompt = json.dumps({"job": jd_struct, "candidate": resume_struct}, ensure_ascii=False)
207
  messages = [
 
5
  import tempfile
6
  import time
7
  from typing import List, Dict, Any, Tuple
 
8
  import PyPDF2
9
  import docx2txt
10
  import gradio as gr
11
  import pandas as pd
12
  import logging
13
+ from openai import OpenAI
14
 
15
  # Configure logging
16
+ logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s")
17
 
18
  # Global Configuration
19
  DEEPINFRA_API_KEY = "kPEm10rrnxXrCf0TuB6Xcd7Y7lp3YgKa"
 
21
  DEFAULT_MODEL = "Qwen/Qwen3-32B"
22
  REQUEST_TIMEOUT_SECS = 120
23
 
24
+ # OpenAI client for DeepInfra
25
+ default_client = OpenAI(
26
+ api_key=DEEPINFRA_API_KEY,
27
+ base_url=DEEPINFRA_BASE_URL,
28
+ )
29
+
30
  # Prompts for LLM Calls
31
  JD_SYSTEM = """You are an expert recruitment analyst. Extract a job description into STRICT JSON.
32
  Rules:
 
63
  }
64
  """
65
 
 
66
  FEEDBACK_SYSTEM_DETAILED = """You are an expert technical recruiter. Compare a job and a candidate and return STRICT JSON with actionable feedback and a detailed score breakdown.
67
  Respond in the job description's language.
68
  Scores should be out of 100.
 
84
  Output ONLY JSON.
85
  """
86
 
 
87
  RECOMMEND_SYSTEM = """You are a senior technical recruiter writing a concise recommendation summary for a hiring manager.
88
  Based on the provided candidate and job description, write a 2-3 sentence summary explaining why this candidate is a good match.
89
  Focus on key skills, relevant experience, and overall fit. Do not use a conversational tone.
90
+ Output ONLY the summary text, no markdown or extra formatting.
91
+ """
92
 
93
+ # Helpers for file parsing
94
  def _pdf_to_text(path: str) -> str:
95
  text = []
96
  with open(path, "rb") as f:
 
129
  logging.error(f"Failed to parse JSON: {e}\nRaw Text: {text[:500]}...")
130
  return {}
131
 
132
+ # LLM chat wrapper
133
  def deepinfra_chat(messages: List[Dict[str, str]], api_key: str, model: str, temperature: float = 0.2) -> str:
 
 
 
 
 
 
 
134
  try:
135
+ client = default_client
136
+ if api_key and api_key != DEEPINFRA_API_KEY:
137
+ client = OpenAI(api_key=api_key, base_url=DEEPINFRA_BASE_URL)
138
+
139
+ resp = client.chat.completions.create(
140
+ model=model,
141
+ messages=messages,
142
+ temperature=temperature,
143
  )
144
+ return (resp.choices[0].message.content or "").strip()
145
+ except Exception as e:
 
 
146
  logging.error(f"API request failed: {e}")
147
  raise gr.Error(f"API request failed: {e}. Check your API key and model name.")
148
 
 
170
  text = read_file_safely(resume_file.name)
171
  return text, fname
172
 
173
+ # Extraction Functions
174
  def llm_extract_jd(jd_text: str, api_key: str, model: str, temperature: float = 0.1) -> Dict:
175
  messages = [
176
  {"role": "system", "content": JD_SYSTEM},
 
187
  raw = deepinfra_chat(messages, api_key=api_key, model=model, temperature=temperature)
188
  return safe_json_loads(raw)
189
 
 
190
  def llm_detailed_feedback(jd_struct: Dict, resume_struct: Dict, api_key: str, model: str, temperature: float = 0.2) -> Dict:
191
  prompt = json.dumps({"job": jd_struct, "candidate": resume_struct}, ensure_ascii=False)
192
  messages = [
 
196
  raw = deepinfra_chat(messages, api_key=api_key, model=model, temperature=temperature)
197
  return safe_json_loads(raw)
198
 
 
199
  def llm_recommend(jd_struct: Dict, resume_struct: Dict, api_key: str, model: str, temperature: float = 0.2) -> str:
200
  prompt = json.dumps({"job": jd_struct, "candidate": resume_struct}, ensure_ascii=False)
201
  messages = [