husseinelsaadi commited on
Commit
1a04e25
·
1 Parent(s): 8e4e001

groq key adjusted

Browse files
Files changed (1) hide show
  1. backend/services/interview_engine.py +72 -100
backend/services/interview_engine.py CHANGED
@@ -1,3 +1,4 @@
 
1
  import os
2
  import json
3
  import asyncio
@@ -6,145 +7,116 @@ from faster_whisper import WhisperModel
6
  from langchain_groq import ChatGroq
7
  import logging
8
 
9
- # Initialize models
10
- chat_groq_api = os.getenv("GROQ_API_KEY", "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")
 
11
  groq_llm = ChatGroq(
12
  temperature=0.7,
13
- model_name="llama-3.3-70b-versatile",
14
- api_key=chat_groq_api
15
  )
16
 
17
- # Initialize Whisper model
18
  whisper_model = None
19
 
 
 
 
20
  def load_whisper_model():
21
  global whisper_model
22
  if whisper_model is None:
23
- device = "cuda" if os.system("nvidia-smi") == 0 else "cpu"
24
  compute_type = "float16" if device == "cuda" else "int8"
25
  whisper_model = WhisperModel("base", device=device, compute_type=compute_type)
26
  return whisper_model
27
 
 
 
 
28
  def generate_first_question(profile, job):
29
- """Generate the first interview question based on profile and job"""
 
 
 
 
 
 
 
 
 
30
  try:
31
- prompt = f"""
32
- You are conducting an interview for a {job.role} position at {job.company}.
33
- The candidate's profile shows:
34
- - Skills: {profile.get('skills', [])}
35
- - Experience: {profile.get('experience', [])}
36
- - Education: {profile.get('education', [])}
37
-
38
- Generate an appropriate opening interview question that is professional and relevant.
39
- Keep it concise and clear.
40
- """
41
-
42
- response = groq_llm.predict(prompt)
43
  return response.strip()
44
  except Exception as e:
45
- logging.error(f"Error generating first question: {e}")
46
  return "Tell me about yourself and why you're interested in this position."
47
 
 
 
 
48
  def edge_tts_to_file_sync(text, output_path, voice="en-US-AriaNeural"):
49
- """Synchronous wrapper for edge-tts"""
50
  try:
51
- # Ensure the directory exists and is writable
52
- directory = os.path.dirname(output_path)
53
- if not directory:
54
- directory = "/tmp" # Fallback to /tmp if no directory specified
55
- output_path = os.path.join(directory, os.path.basename(output_path))
56
-
57
  os.makedirs(directory, exist_ok=True)
58
-
59
- # Test write permissions
60
- test_file = os.path.join(directory, f"test_{os.getpid()}.tmp")
61
- try:
62
- with open(test_file, 'w') as f:
63
- f.write("test")
64
- os.remove(test_file)
65
- except (PermissionError, OSError) as e:
66
- logging.error(f"Directory {directory} is not writable: {e}")
67
- # Fallback to /tmp
68
- directory = "/tmp"
69
- output_path = os.path.join(directory, os.path.basename(output_path))
70
- os.makedirs(directory, exist_ok=True)
71
-
72
- async def generate_audio():
73
  communicate = edge_tts.Communicate(text, voice)
74
  await communicate.save(output_path)
75
-
76
- # Run async function in sync context
77
- try:
 
 
78
  loop = asyncio.get_event_loop()
79
- except RuntimeError:
80
- loop = asyncio.new_event_loop()
81
- asyncio.set_event_loop(loop)
82
-
83
- loop.run_until_complete(generate_audio())
84
-
85
- # Verify file was created and has content
86
  if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
87
  return output_path
88
- else:
89
- logging.error(f"Audio file was not created or is empty: {output_path}")
90
- return None
91
-
92
  except Exception as e:
93
- logging.error(f"Error in TTS generation: {e}")
94
- return None
95
 
 
 
 
96
  def whisper_stt(audio_path):
97
- """Speech-to-text using Faster-Whisper"""
 
98
  try:
99
- if not audio_path or not os.path.exists(audio_path):
100
- logging.error(f"Audio file does not exist: {audio_path}")
101
- return ""
102
-
103
- # Check if file has content
104
- if os.path.getsize(audio_path) == 0:
105
- logging.error(f"Audio file is empty: {audio_path}")
106
- return ""
107
-
108
  model = load_whisper_model()
109
  segments, _ = model.transcribe(audio_path)
110
- transcript = " ".join(segment.text for segment in segments)
111
- return transcript.strip()
112
  except Exception as e:
113
- logging.error(f"Error in STT: {e}")
114
  return ""
115
 
 
 
 
116
  def evaluate_answer(question, answer, ref_answer, job_role, seniority):
117
- """Evaluate candidate's answer"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  try:
119
- prompt = f"""
120
- You are evaluating a candidate's answer for a {seniority} {job_role} position.
121
-
122
- Question: {question}
123
- Candidate Answer: {answer}
124
- Reference Answer: {ref_answer}
125
-
126
- Evaluate based on technical correctness, clarity, and relevance.
127
- Respond with JSON format:
128
- {{
129
- "Score": "Poor|Medium|Good|Excellent",
130
- "Reasoning": "brief explanation",
131
- "Improvements": ["suggestion1", "suggestion2"]
132
- }}
133
- """
134
-
135
- response = groq_llm.predict(prompt)
136
- # Extract JSON from response
137
- start_idx = response.find("{")
138
- end_idx = response.rfind("}") + 1
139
- if start_idx >= 0 and end_idx > start_idx:
140
- json_str = response[start_idx:end_idx]
141
- return json.loads(json_str)
142
- else:
143
- raise ValueError("No valid JSON found in response")
144
  except Exception as e:
145
- logging.error(f"Error evaluating answer: {e}")
146
  return {
147
  "Score": "Medium",
148
  "Reasoning": "Evaluation failed",
149
- "Improvements": ["Please be more specific"]
150
- }
 
1
+ # Updated `interview_engine.py`
2
  import os
3
  import json
4
  import asyncio
 
7
  from langchain_groq import ChatGroq
8
  import logging
9
 
10
+ # ------------------
11
+ # Model Initialization (done once)
12
+ # ------------------
13
  groq_llm = ChatGroq(
14
  temperature=0.7,
15
+ model_name="llama-3-3-70b-versatile",
16
+ api_key=os.getenv("GROQ_API_KEY")
17
  )
18
 
 
19
  whisper_model = None
20
 
21
+ # ------------------
22
+ # Load Whisper lazily
23
+ # ------------------
24
  def load_whisper_model():
25
  global whisper_model
26
  if whisper_model is None:
27
+ device = "cuda" if os.system("nvidia-smi > /dev/null 2>&1") == 0 else "cpu"
28
  compute_type = "float16" if device == "cuda" else "int8"
29
  whisper_model = WhisperModel("base", device=device, compute_type=compute_type)
30
  return whisper_model
31
 
32
+ # ------------------
33
+ # Generate Question
34
+ # ------------------
35
  def generate_first_question(profile, job):
36
+ prompt = f"""
37
+ You are conducting an interview for a {job.role} position at {job.company}.
38
+ The candidate's profile shows:
39
+ - Skills: {profile.get('skills', [])}
40
+ - Experience: {profile.get('experience', [])}
41
+ - Education: {profile.get('education', [])}
42
+
43
+ Generate an appropriate opening interview question that is professional and relevant.
44
+ Keep it concise and clear.
45
+ """
46
  try:
47
+ response = groq_llm.invoke(prompt)
 
 
 
 
 
 
 
 
 
 
 
48
  return response.strip()
49
  except Exception as e:
50
+ logging.error(f"Question generation failed: {e}")
51
  return "Tell me about yourself and why you're interested in this position."
52
 
53
+ # ------------------
54
+ # TTS (Edge)
55
+ # ------------------
56
  def edge_tts_to_file_sync(text, output_path, voice="en-US-AriaNeural"):
 
57
  try:
58
+ directory = os.path.dirname(output_path) or "/tmp"
 
 
 
 
 
59
  os.makedirs(directory, exist_ok=True)
60
+
61
+ async def generate():
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  communicate = edge_tts.Communicate(text, voice)
63
  await communicate.save(output_path)
64
+
65
+ loop = asyncio.get_event_loop()
66
+ if loop.is_running():
67
+ import nest_asyncio
68
+ nest_asyncio.apply()
69
  loop = asyncio.get_event_loop()
70
+ loop.run_until_complete(generate())
71
+
 
 
 
 
 
72
  if os.path.exists(output_path) and os.path.getsize(output_path) > 0:
73
  return output_path
 
 
 
 
74
  except Exception as e:
75
+ logging.error(f"TTS generation failed: {e}")
76
+ return None
77
 
78
+ # ------------------
79
+ # Transcription
80
+ # ------------------
81
  def whisper_stt(audio_path):
82
+ if not audio_path or not os.path.exists(audio_path):
83
+ return ""
84
  try:
 
 
 
 
 
 
 
 
 
85
  model = load_whisper_model()
86
  segments, _ = model.transcribe(audio_path)
87
+ return " ".join(segment.text for segment in segments).strip()
 
88
  except Exception as e:
89
+ logging.error(f"STT failed: {e}")
90
  return ""
91
 
92
+ # ------------------
93
+ # Answer Evaluation
94
+ # ------------------
95
  def evaluate_answer(question, answer, ref_answer, job_role, seniority):
96
+ prompt = f"""
97
+ You are evaluating a candidate's answer for a {seniority} {job_role} position.
98
+
99
+ Question: {question}
100
+ Candidate Answer: {answer}
101
+ Reference Answer: {ref_answer}
102
+
103
+ Evaluate based on technical correctness, clarity, and relevance.
104
+ Respond with JSON format:
105
+ {{
106
+ "Score": "Poor|Medium|Good|Excellent",
107
+ "Reasoning": "brief explanation",
108
+ "Improvements": ["suggestion1", "suggestion2"]
109
+ }}
110
+ """
111
  try:
112
+ response = groq_llm.invoke(prompt)
113
+ start = response.find("{")
114
+ end = response.rfind("}") + 1
115
+ return json.loads(response[start:end]) if start >= 0 else {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  except Exception as e:
117
+ logging.error(f"Evaluation failed: {e}")
118
  return {
119
  "Score": "Medium",
120
  "Reasoning": "Evaluation failed",
121
+ "Improvements": ["Be more specific"]
122
+ }