Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -1,4 +1,3 @@
|
|
1 |
-
|
2 |
import os
|
3 |
import json
|
4 |
import time
|
@@ -71,6 +70,18 @@ def transcribe_audio(audio_file_path):
|
|
71 |
print(f"Error during audio transcription: {e}")
|
72 |
return None
|
73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
|
75 |
def conduct_interview(questions, language="English", history_limit=5):
|
76 |
"""
|
@@ -79,8 +90,27 @@ def conduct_interview(questions, language="English", history_limit=5):
|
|
79 |
"""
|
80 |
start_time = time.time()
|
81 |
openai_api_key = os.getenv("OPENAI_API_KEY")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
if not openai_api_key:
|
83 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
|
85 |
# LangChain-based ChatOpenAI
|
86 |
chat = ChatOpenAI(
|
@@ -110,15 +140,6 @@ def conduct_interview(questions, language="English", history_limit=5):
|
|
110 |
interview_stage = ["questioning"] # "questioning", "user_questions_prompt", "answering_user_questions", "final_message_stage", "finished"
|
111 |
user_questions_asked = [False] # Flag to track if "Do you have any questions?" has been asked
|
112 |
|
113 |
-
initial_message = (
|
114 |
-
"👋 Hi there, I'm Sarah, your friendly AI HR assistant! "
|
115 |
-
"I'll guide you through a series of interview questions to learn more about you. "
|
116 |
-
"Take your time and answer each question thoughtfully."
|
117 |
-
)
|
118 |
-
final_message_content = (
|
119 |
-
"That wraps up our interview. Thank you for your responses—it's been great learning more about you!"
|
120 |
-
" I will share the feedback with HR Team, and they will reach out to you soon." # added line
|
121 |
-
)
|
122 |
|
123 |
updated_system_prompt = system_prompt.replace("{final_message_placeholder}", final_message_content)
|
124 |
|
@@ -135,6 +156,14 @@ def conduct_interview(questions, language="English", history_limit=5):
|
|
135 |
|
136 |
step_start_time = time.time()
|
137 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
138 |
# If there's audio, transcribe it.
|
139 |
if audio_input:
|
140 |
transcript = transcribe_audio(audio_input)
|
@@ -200,7 +229,7 @@ def conduct_interview(questions, language="English", history_limit=5):
|
|
200 |
# Should not reach here as final message is sent directly and stage becomes "finished"
|
201 |
pass
|
202 |
elif interview_stage[0] == "finished":
|
203 |
-
return history, "", None
|
204 |
|
205 |
|
206 |
if messages: # Proceed only if messages are prepared (not in final_message_stage or finished)
|
@@ -273,7 +302,7 @@ def conduct_interview(questions, language="English", history_limit=5):
|
|
273 |
pass # Should not reach here
|
274 |
|
275 |
elif interview_stage[0] == "finished":
|
276 |
-
return history, "", None
|
277 |
|
278 |
print(f"DEBUG - Interview step time: {time.time() - step_start_time:.2f} seconds")
|
279 |
return history, "", audio_file_path
|
@@ -293,11 +322,10 @@ def main():
|
|
293 |
print(f"Error reading questions: {e}")
|
294 |
return
|
295 |
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
return
|
301 |
|
302 |
css = """
|
303 |
.contain { display: flex; flex-direction: column; }
|
@@ -308,8 +336,6 @@ def main():
|
|
308 |
.bot > div > .message { background-color: #f7f7f8 !important }
|
309 |
"""
|
310 |
|
311 |
-
initial_api_key_status_message = "API Key Status: Checking..."
|
312 |
-
|
313 |
# Build Gradio interface
|
314 |
with gr.Blocks(css=css) as demo:
|
315 |
gr.Markdown(
|
@@ -352,14 +378,11 @@ def main():
|
|
352 |
gr.Markdown("*This application does not store your API key. It is used only for this session and is not persisted when you close the app.*")
|
353 |
|
354 |
def update_api_key(api_key):
|
355 |
-
os.environ["OPENAI_API_KEY"] = api_key
|
356 |
-
global interview_func, initial_message, final_message # Declare globals to update them
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
except RuntimeError as e:
|
361 |
-
return f"❌ API Key Update Failed: {e}"
|
362 |
-
|
363 |
|
364 |
update_api_key_button.click(
|
365 |
update_api_key,
|
@@ -522,7 +545,14 @@ def main():
|
|
522 |
Must return a list of {'role':'assistant','content':'...'} messages
|
523 |
plus empty text for user_input and path for audio_output.
|
524 |
"""
|
525 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
526 |
try:
|
527 |
questions = read_questions_from_json(QUESTIONS_FILE_PATH) # Reload questions in case file changed
|
528 |
interview_func, initial_message, final_message = conduct_interview(questions) # Re-init interview func with new questions
|
@@ -570,7 +600,7 @@ def main():
|
|
570 |
Re-initialize the interview function entirely
|
571 |
to start from scratch, clearing the Chatbot.
|
572 |
"""
|
573 |
-
|
574 |
interview_func, initial_msg, final_msg = conduct_interview(questions) # Re-init with current questions
|
575 |
return [], "", None
|
576 |
|
@@ -620,4 +650,4 @@ def main():
|
|
620 |
|
621 |
|
622 |
if __name__ == "__main__":
|
623 |
-
main()
|
|
|
|
|
1 |
import os
|
2 |
import json
|
3 |
import time
|
|
|
70 |
print(f"Error during audio transcription: {e}")
|
71 |
return None
|
72 |
|
73 |
+
def check_api_key():
|
74 |
+
"""Checks if the OpenAI API key is valid."""
|
75 |
+
api_key = os.getenv("OPENAI_API_KEY")
|
76 |
+
if not api_key:
|
77 |
+
return "❌ API Key Not Found. Please enter in Admin Panel."
|
78 |
+
try:
|
79 |
+
client = OpenAI(api_key=api_key)
|
80 |
+
client.models.list() # Simple API call to check if the key is working
|
81 |
+
return "✅ API Key Loaded."
|
82 |
+
except Exception as e:
|
83 |
+
return f"❌ API Key Invalid: {e}"
|
84 |
+
|
85 |
|
86 |
def conduct_interview(questions, language="English", history_limit=5):
|
87 |
"""
|
|
|
90 |
"""
|
91 |
start_time = time.time()
|
92 |
openai_api_key = os.getenv("OPENAI_API_KEY")
|
93 |
+
|
94 |
+
initial_message = (
|
95 |
+
"👋 Hi there, I'm Sarah, your friendly AI HR assistant! "
|
96 |
+
"I'll guide you through a series of interview questions to learn more about you. "
|
97 |
+
"Take your time and answer each question thoughtfully."
|
98 |
+
)
|
99 |
+
final_message_content = (
|
100 |
+
"That wraps up our interview. Thank you for your responses—it's been great learning more about you!"
|
101 |
+
" I will share the feedback with HR Team, and they will reach out to you soon." # added line
|
102 |
+
)
|
103 |
+
|
104 |
if not openai_api_key:
|
105 |
+
placeholder_message = "⚠️ OpenAI API Key not configured. Please enter your API key in the Admin Panel to start the interview."
|
106 |
+
placeholder_audio_path = convert_text_to_speech(placeholder_message)
|
107 |
+
|
108 |
+
def placeholder_interview_step(user_input, audio_input, history):
|
109 |
+
history.append({"role": "assistant", "content": placeholder_message})
|
110 |
+
return history, "", placeholder_audio_path
|
111 |
+
|
112 |
+
return placeholder_interview_step, initial_message, final_message_content
|
113 |
+
|
114 |
|
115 |
# LangChain-based ChatOpenAI
|
116 |
chat = ChatOpenAI(
|
|
|
140 |
interview_stage = ["questioning"] # "questioning", "user_questions_prompt", "answering_user_questions", "final_message_stage", "finished"
|
141 |
user_questions_asked = [False] # Flag to track if "Do you have any questions?" has been asked
|
142 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
143 |
|
144 |
updated_system_prompt = system_prompt.replace("{final_message_placeholder}", final_message_content)
|
145 |
|
|
|
156 |
|
157 |
step_start_time = time.time()
|
158 |
|
159 |
+
# Check if API key is configured before proceeding with OpenAI calls
|
160 |
+
if not os.getenv("OPENAI_API_KEY"):
|
161 |
+
api_missing_message = "⚠️ OpenAI API Key not configured. Please enter your API key in the Admin Panel to continue the interview."
|
162 |
+
api_missing_audio_path = convert_text_to_speech(api_missing_message)
|
163 |
+
history.append({"role": "assistant", "content": api_missing_message})
|
164 |
+
return history, "", api_missing_audio_path
|
165 |
+
|
166 |
+
|
167 |
# If there's audio, transcribe it.
|
168 |
if audio_input:
|
169 |
transcript = transcribe_audio(audio_input)
|
|
|
229 |
# Should not reach here as final message is sent directly and stage becomes "finished"
|
230 |
pass
|
231 |
elif interview_stage[0] == "finished":
|
232 |
+
return history, "", None # Interview is finished
|
233 |
|
234 |
|
235 |
if messages: # Proceed only if messages are prepared (not in final_message_stage or finished)
|
|
|
302 |
pass # Should not reach here
|
303 |
|
304 |
elif interview_stage[0] == "finished":
|
305 |
+
return history, "", None # Interview already finished
|
306 |
|
307 |
print(f"DEBUG - Interview step time: {time.time() - step_start_time:.2f} seconds")
|
308 |
return history, "", audio_file_path
|
|
|
322 |
print(f"Error reading questions: {e}")
|
323 |
return
|
324 |
|
325 |
+
global initial_api_key_status_message # Declare as global to modify
|
326 |
+
initial_api_key_status_message = check_api_key() # Check API key and update status
|
327 |
+
|
328 |
+
interview_func, initial_message, final_message = conduct_interview(questions) # Initialize even if API key is missing
|
|
|
329 |
|
330 |
css = """
|
331 |
.contain { display: flex; flex-direction: column; }
|
|
|
336 |
.bot > div > .message { background-color: #f7f7f8 !important }
|
337 |
"""
|
338 |
|
|
|
|
|
339 |
# Build Gradio interface
|
340 |
with gr.Blocks(css=css) as demo:
|
341 |
gr.Markdown(
|
|
|
378 |
gr.Markdown("*This application does not store your API key. It is used only for this session and is not persisted when you close the app.*")
|
379 |
|
380 |
def update_api_key(api_key):
|
381 |
+
os.environ["OPENAI_API_KEY"] = api_key # Caution: Modifying os.environ is session-based
|
382 |
+
global interview_func, initial_message, final_message, questions, initial_api_key_status_message # Declare globals to update them and questions
|
383 |
+
initial_api_key_status_message = check_api_key() # Update status immediately after key is entered
|
384 |
+
interview_func, initial_message, final_message = conduct_interview(questions) # Re-init interview function
|
385 |
+
return initial_api_key_status_message # Return status message
|
|
|
|
|
|
|
386 |
|
387 |
update_api_key_button.click(
|
388 |
update_api_key,
|
|
|
545 |
Must return a list of {'role':'assistant','content':'...'} messages
|
546 |
plus empty text for user_input and path for audio_output.
|
547 |
"""
|
548 |
+
global interview_func, questions, initial_api_key_status_message # Access global variables
|
549 |
+
|
550 |
+
current_api_key_status = check_api_key() # Check API key status right before starting interview
|
551 |
+
if not current_api_key_status.startswith("✅"): # If API key is not valid
|
552 |
+
error_message = "Please set a valid OpenAI API Key in the Admin Panel before starting the interview."
|
553 |
+
tts_path = convert_text_to_speech(error_message)
|
554 |
+
return [{"role": "assistant", "content": error_message}], "", tts_path
|
555 |
+
|
556 |
try:
|
557 |
questions = read_questions_from_json(QUESTIONS_FILE_PATH) # Reload questions in case file changed
|
558 |
interview_func, initial_message, final_message = conduct_interview(questions) # Re-init interview func with new questions
|
|
|
600 |
Re-initialize the interview function entirely
|
601 |
to start from scratch, clearing the Chatbot.
|
602 |
"""
|
603 |
+
global interview_func, initial_message, final_message, questions # Access global variables
|
604 |
interview_func, initial_msg, final_msg = conduct_interview(questions) # Re-init with current questions
|
605 |
return [], "", None
|
606 |
|
|
|
650 |
|
651 |
|
652 |
if __name__ == "__main__":
|
653 |
+
main()
|