Update app.py
Browse files
app.py
CHANGED
@@ -8,15 +8,46 @@ import google.generativeai as genai
|
|
8 |
from transformers import BertTokenizer, TFBertModel
|
9 |
import numpy as np
|
10 |
import speech_recognition as sr
|
11 |
-
# from gtts import gTTS # Not used directly in main app logic here
|
12 |
-
# import pygame # Not used directly in main app logic here
|
13 |
import time
|
14 |
from dotenv import load_dotenv
|
15 |
import soundfile as sf # For saving audio numpy array
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
# Load environment variables
|
18 |
load_dotenv()
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
# Configure Generative AI
|
21 |
genai.configure(api_key=os.getenv("GOOGLE_API_KEY") or "YOUR_DEFAULT_API_KEY_HERE") # Use environment variable or set a default
|
22 |
text_model = genai.GenerativeModel("gemini-pro")
|
@@ -32,7 +63,7 @@ except Exception as e:
|
|
32 |
model = None
|
33 |
tokenizer = None
|
34 |
|
35 |
-
# --- Helper Functions (Logic from Streamlit) ---
|
36 |
|
37 |
def getallinfo(data):
|
38 |
if not data or not data.strip(): # Check for None or empty/whitespace
|
@@ -239,7 +270,7 @@ def generate_metrics(data, answer, question):
|
|
239 |
}
|
240 |
return metrics
|
241 |
|
242 |
-
# --- Gradio UI Components and Logic ---
|
243 |
|
244 |
def process_resume(file_obj):
|
245 |
"""Handles resume upload and processing."""
|
@@ -484,31 +515,60 @@ def submit_interview(interview_state):
|
|
484 |
|
485 |
return "Interview submitted successfully!", interview_state
|
486 |
|
487 |
-
# --- Login and Navigation Logic ---
|
488 |
|
489 |
-
def login(
|
490 |
-
# Simple mock login - replace with real authentication logic
|
491 |
# For demo, accept any non-empty username/password
|
492 |
-
|
493 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
494 |
# Show main app, hide login
|
495 |
return (welcome_msg,
|
496 |
gr.update(visible=False), # login_section
|
497 |
gr.update(visible=True), # main_app
|
498 |
-
"", "", # Clear
|
499 |
-
|
500 |
-
|
501 |
-
return ("Please
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
506 |
|
507 |
def logout():
|
508 |
return ("", # Clear login status
|
509 |
gr.update(visible=True), # Show login section
|
510 |
gr.update(visible=False), # Hide main app
|
511 |
-
|
|
|
512 |
"") # Clear user_state
|
513 |
|
514 |
def navigate_to_interview():
|
@@ -517,22 +577,46 @@ def navigate_to_interview():
|
|
517 |
def navigate_to_chat():
|
518 |
return (gr.update(visible=False), gr.update(visible=True)) # Hide interview, show chat
|
519 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
# --- Gradio Interface ---
|
521 |
|
522 |
with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
523 |
gr.Markdown("# 🦈 PrepGenie")
|
524 |
# State to hold interview data
|
525 |
interview_state = gr.State({})
|
526 |
-
# State for username
|
527 |
user_state = gr.State("")
|
528 |
|
529 |
# --- Login Section ---
|
530 |
with gr.Column(visible=True) as login_section:
|
531 |
gr.Markdown("## Login")
|
532 |
-
|
533 |
-
|
534 |
login_btn = gr.Button("Login")
|
535 |
-
login_status = gr.Textbox(label="Status", interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
536 |
|
537 |
# --- Main App Sections (Initially Hidden) ---
|
538 |
with gr.Column(visible=False) as main_app:
|
@@ -546,18 +630,21 @@ with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
|
546 |
with gr.Row():
|
547 |
with gr.Column(scale=1):
|
548 |
interview_btn = gr.Button("Mock Interview")
|
549 |
-
|
|
|
|
|
|
|
550 |
with gr.Column(scale=4):
|
551 |
# --- Interview Section ---
|
552 |
-
with gr.Column(visible=False) as interview_selection:
|
553 |
gr.Markdown("## Mock Interview")
|
554 |
# File Upload Section
|
555 |
with gr.Row():
|
556 |
with gr.Column():
|
557 |
-
|
558 |
-
|
559 |
with gr.Column():
|
560 |
-
|
561 |
|
562 |
# Role Selection (Initially hidden)
|
563 |
role_selection = gr.Dropdown(
|
@@ -581,54 +668,61 @@ with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
|
581 |
feedback_display = gr.Textbox(label="Feedback", interactive=False, visible=False)
|
582 |
metrics_display = gr.JSON(label="Metrics", visible=False)
|
583 |
|
584 |
-
# Hidden textbox to hold processed resume data temporarily
|
585 |
-
|
586 |
|
587 |
# --- Chat Section ---
|
588 |
-
|
589 |
-
gr.
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
594 |
|
595 |
|
596 |
# Navigation buttons
|
597 |
-
# Define the components for navigation *before* using them in event listeners
|
598 |
interview_view = interview_selection
|
599 |
chat_view = chat_selection
|
600 |
|
601 |
interview_btn.click(fn=navigate_to_interview, inputs=None, outputs=[interview_view, chat_view])
|
602 |
-
|
|
|
603 |
# Update welcome message when user_state changes (basic)
|
604 |
user_state.change(fn=lambda user: f"### Welcome, {user}!" if user else "### Welcome, User!", inputs=[user_state], outputs=[welcome_display])
|
605 |
|
606 |
-
# --- Event Listeners ---
|
607 |
-
|
608 |
-
|
609 |
-
process_btn.click(
|
610 |
fn=process_resume,
|
611 |
-
inputs=[
|
612 |
outputs=[
|
613 |
-
|
614 |
question_display, answer_instructions, audio_input,
|
615 |
submit_answer_btn, next_question_btn, submit_interview_btn,
|
616 |
answer_display, feedback_display, metrics_display,
|
617 |
-
|
618 |
]
|
619 |
)
|
620 |
|
621 |
# Start Interview
|
622 |
start_interview_btn.click(
|
623 |
fn=start_interview,
|
624 |
-
inputs=[role_selection,
|
625 |
outputs=[
|
626 |
-
|
627 |
-
# Note: Directly accessing state dict keys in outputs like interview_state["questions"] is problematic.
|
628 |
-
# Gradio expects component objects or gr.Updates. We pass the state object itself.
|
629 |
-
# The function returns values to update UI components and the entire state dict.
|
630 |
-
# interview_state["questions"], interview_state["answers"], # Invalid
|
631 |
-
# interview_state["interactions"], interview_state["metrics_list"], # Invalid
|
632 |
# Outputs for UI updates
|
633 |
audio_input, submit_answer_btn, next_question_btn,
|
634 |
submit_interview_btn, feedback_display, metrics_display,
|
@@ -642,7 +736,7 @@ with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
|
642 |
fn=submit_answer,
|
643 |
inputs=[audio_input, interview_state],
|
644 |
outputs=[
|
645 |
-
|
646 |
feedback_display, feedback_display, # Update value and visibility
|
647 |
metrics_display, metrics_display, # Update value and visibility
|
648 |
audio_input, submit_answer_btn, next_question_btn,
|
@@ -655,7 +749,7 @@ with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
|
655 |
fn=next_question,
|
656 |
inputs=[interview_state],
|
657 |
outputs=[
|
658 |
-
|
659 |
audio_input, submit_answer_btn, next_question_btn,
|
660 |
feedback_display, metrics_display, submit_interview_btn,
|
661 |
question_display, answer_instructions,
|
@@ -667,21 +761,61 @@ with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
|
667 |
submit_interview_btn.click(
|
668 |
fn=submit_interview,
|
669 |
inputs=[interview_state],
|
670 |
-
outputs=[
|
671 |
# In a full app, you might navigate to an evaluation page here
|
672 |
)
|
673 |
|
674 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
675 |
login_btn.click(
|
676 |
fn=login,
|
677 |
-
inputs=[
|
678 |
-
outputs=[login_status, login_section, main_app,
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
)
|
680 |
|
681 |
logout_btn.click(
|
682 |
fn=logout,
|
683 |
inputs=None,
|
684 |
-
outputs=[login_status, login_section, main_app,
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
685 |
)
|
686 |
|
687 |
# Run the app
|
|
|
8 |
from transformers import BertTokenizer, TFBertModel
|
9 |
import numpy as np
|
10 |
import speech_recognition as sr
|
|
|
|
|
11 |
import time
|
12 |
from dotenv import load_dotenv
|
13 |
import soundfile as sf # For saving audio numpy array
|
14 |
+
import json
|
15 |
+
|
16 |
+
# --- Firebase Admin SDK Setup ---
|
17 |
+
import firebase_admin
|
18 |
+
from firebase_admin import credentials, auth, firestore
|
19 |
|
20 |
# Load environment variables
|
21 |
load_dotenv()
|
22 |
|
23 |
+
# Initialize Firebase Admin SDK (Use environment variable for credentials path or default)
|
24 |
+
firebase_credentials_path = os.getenv("FIREBASE_CREDENTIALS_PATH", "prepgenie-64134-firebase-adminsdk-fbsvc-3370ac4ab9.json")
|
25 |
+
if not firebase_admin._apps:
|
26 |
+
try:
|
27 |
+
# Try loading from file path first
|
28 |
+
cred = credentials.Certificate(firebase_credentials_path)
|
29 |
+
firebase_admin.initialize_app(cred)
|
30 |
+
print("Firebase Admin initialized successfully using credentials file.")
|
31 |
+
except FileNotFoundError:
|
32 |
+
print(f"Firebase credentials file not found at {firebase_credentials_path}. Trying environment variable...")
|
33 |
+
try:
|
34 |
+
# Fallback: Try loading from environment variable (expects JSON string)
|
35 |
+
firebase_credentials_json = os.getenv("FIREBASE_CREDENTIALS_JSON")
|
36 |
+
if firebase_credentials_json:
|
37 |
+
cred_dict = json.loads(firebase_credentials_json)
|
38 |
+
cred = credentials.Certificate(cred_dict)
|
39 |
+
firebase_admin.initialize_app(cred)
|
40 |
+
print("Firebase Admin initialized successfully using environment variable.")
|
41 |
+
else:
|
42 |
+
raise ValueError("FIREBASE_CREDENTIALS_JSON environment variable not set.")
|
43 |
+
except (json.JSONDecodeError, ValueError) as e:
|
44 |
+
print(f"Error initializing Firebase Admin: {e}")
|
45 |
+
print("Firebase authentication will not be available.")
|
46 |
+
# You might want to handle this case differently, e.g., disable features or show an error
|
47 |
+
except Exception as e:
|
48 |
+
print(f"Unexpected error initializing Firebase Admin: {e}")
|
49 |
+
print("Firebase authentication will not be available.")
|
50 |
+
|
51 |
# Configure Generative AI
|
52 |
genai.configure(api_key=os.getenv("GOOGLE_API_KEY") or "YOUR_DEFAULT_API_KEY_HERE") # Use environment variable or set a default
|
53 |
text_model = genai.GenerativeModel("gemini-pro")
|
|
|
63 |
model = None
|
64 |
tokenizer = None
|
65 |
|
66 |
+
# --- Helper Functions (Logic from Streamlit - Interview) ---
|
67 |
|
68 |
def getallinfo(data):
|
69 |
if not data or not data.strip(): # Check for None or empty/whitespace
|
|
|
270 |
}
|
271 |
return metrics
|
272 |
|
273 |
+
# --- Gradio UI Components and Logic (Interview) ---
|
274 |
|
275 |
def process_resume(file_obj):
|
276 |
"""Handles resume upload and processing."""
|
|
|
515 |
|
516 |
return "Interview submitted successfully!", interview_state
|
517 |
|
518 |
+
# --- Login and Navigation Logic (Firebase Integrated) ---
|
519 |
|
520 |
+
def login(email, password):
|
521 |
+
# Simple mock login using Firebase - replace with real authentication logic
|
522 |
# For demo, accept any non-empty username/password
|
523 |
+
# In a real app, you would verify the password against Firebase Auth (server-side)
|
524 |
+
# This is a simplified placeholder that checks if user exists.
|
525 |
+
if not email or not password:
|
526 |
+
return ("Please enter email and password.", gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, "")
|
527 |
+
|
528 |
+
try:
|
529 |
+
# Attempt to get user by email (this checks existence, not password in client-side code)
|
530 |
+
# A real implementation would involve secure server-side verification.
|
531 |
+
user = auth.get_user_by_email(email)
|
532 |
+
welcome_msg = f"Welcome, {user.display_name or user.uid}!" # Use display name or UID
|
533 |
# Show main app, hide login
|
534 |
return (welcome_msg,
|
535 |
gr.update(visible=False), # login_section
|
536 |
gr.update(visible=True), # main_app
|
537 |
+
"", "", # Clear email/password inputs
|
538 |
+
user.uid) # Update user_state with UID
|
539 |
+
except auth.UserNotFoundError:
|
540 |
+
return ("User not found. Please check your email or sign up.", gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, "")
|
541 |
+
except Exception as e:
|
542 |
+
error_msg = f"Login failed: {str(e)}"
|
543 |
+
print(error_msg)
|
544 |
+
return (error_msg, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, "")
|
545 |
+
|
546 |
+
def signup(email, password, username):
|
547 |
+
if not email or not password or not username:
|
548 |
+
return ("Please fill all fields.", gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, username, "")
|
549 |
+
|
550 |
+
try:
|
551 |
+
# Create user in Firebase
|
552 |
+
user = auth.create_user(email=email, password=password, uid=username, display_name=username)
|
553 |
+
success_msg = f"Account created successfully for {username}!"
|
554 |
+
# Automatically log the user in or prompt for login
|
555 |
+
# Here, we'll just show success and keep them on the signup form
|
556 |
+
return (success_msg, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), "", "", "", user.uid) # Clear inputs, set user state
|
557 |
+
except auth.UidAlreadyExistsError:
|
558 |
+
return ("Username already exists. Please choose another.", gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, username, "")
|
559 |
+
except auth.EmailAlreadyExistsError:
|
560 |
+
return ("Email already exists. Please use another email.", gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, username, "")
|
561 |
+
except Exception as e:
|
562 |
+
error_msg = f"Signup failed: {str(e)}"
|
563 |
+
print(error_msg)
|
564 |
+
return (error_msg, gr.update(visible=True), gr.update(visible=False), gr.update(visible=False), email, password, username, "")
|
565 |
|
566 |
def logout():
|
567 |
return ("", # Clear login status
|
568 |
gr.update(visible=True), # Show login section
|
569 |
gr.update(visible=False), # Hide main app
|
570 |
+
gr.update(visible=False), # Hide signup section (if it was visible)
|
571 |
+
"", "", "", # Clear email/password/username inputs
|
572 |
"") # Clear user_state
|
573 |
|
574 |
def navigate_to_interview():
|
|
|
577 |
def navigate_to_chat():
|
578 |
return (gr.update(visible=False), gr.update(visible=True)) # Hide interview, show chat
|
579 |
|
580 |
+
# --- Import Chat Module Functions ---
|
581 |
+
# Assuming chat.py is in the same directory or correctly in the Python path
|
582 |
+
try:
|
583 |
+
from login_module import chat as chat_module
|
584 |
+
CHAT_MODULE_AVAILABLE = True
|
585 |
+
print("Chat module imported successfully.")
|
586 |
+
except ImportError as e:
|
587 |
+
print(f"Warning: Could not import chat module: {e}")
|
588 |
+
CHAT_MODULE_AVAILABLE = False
|
589 |
+
chat_module = None
|
590 |
+
|
591 |
# --- Gradio Interface ---
|
592 |
|
593 |
with gr.Blocks(title="PrepGenie - Mock Interview") as demo:
|
594 |
gr.Markdown("# 🦈 PrepGenie")
|
595 |
# State to hold interview data
|
596 |
interview_state = gr.State({})
|
597 |
+
# State for username/UID
|
598 |
user_state = gr.State("")
|
599 |
|
600 |
# --- Login Section ---
|
601 |
with gr.Column(visible=True) as login_section:
|
602 |
gr.Markdown("## Login")
|
603 |
+
login_email_input = gr.Textbox(label="Email Address")
|
604 |
+
login_password_input = gr.Textbox(label="Password", type="password")
|
605 |
login_btn = gr.Button("Login")
|
606 |
+
login_status = gr.Textbox(label="Login Status", interactive=False)
|
607 |
+
# Switch to Signup
|
608 |
+
switch_to_signup_btn = gr.Button("Don't have an account? Sign Up")
|
609 |
+
|
610 |
+
# --- Signup Section ---
|
611 |
+
with gr.Column(visible=False) as signup_section:
|
612 |
+
gr.Markdown("## Sign Up")
|
613 |
+
signup_email_input = gr.Textbox(label="Email Address")
|
614 |
+
signup_password_input = gr.Textbox(label="Password", type="password")
|
615 |
+
signup_username_input = gr.Textbox(label="Unique Username")
|
616 |
+
signup_btn = gr.Button("Create my account")
|
617 |
+
signup_status = gr.Textbox(label="Signup Status", interactive=False)
|
618 |
+
# Switch to Login
|
619 |
+
switch_to_login_btn = gr.Button("Already have an account? Login")
|
620 |
|
621 |
# --- Main App Sections (Initially Hidden) ---
|
622 |
with gr.Column(visible=False) as main_app:
|
|
|
630 |
with gr.Row():
|
631 |
with gr.Column(scale=1):
|
632 |
interview_btn = gr.Button("Mock Interview")
|
633 |
+
if CHAT_MODULE_AVAILABLE:
|
634 |
+
chat_btn = gr.Button("Chat with Resume")
|
635 |
+
else:
|
636 |
+
chat_btn = gr.Button("Chat with Resume (Unavailable)", interactive=False)
|
637 |
with gr.Column(scale=4):
|
638 |
# --- Interview Section ---
|
639 |
+
with gr.Column(visible=False) as interview_selection:
|
640 |
gr.Markdown("## Mock Interview")
|
641 |
# File Upload Section
|
642 |
with gr.Row():
|
643 |
with gr.Column():
|
644 |
+
file_upload_interview = gr.File(label="Upload Resume (PDF)", file_types=[".pdf"])
|
645 |
+
process_btn_interview = gr.Button("Process Resume")
|
646 |
with gr.Column():
|
647 |
+
file_status_interview = gr.Textbox(label="Status", interactive=False)
|
648 |
|
649 |
# Role Selection (Initially hidden)
|
650 |
role_selection = gr.Dropdown(
|
|
|
668 |
feedback_display = gr.Textbox(label="Feedback", interactive=False, visible=False)
|
669 |
metrics_display = gr.JSON(label="Metrics", visible=False)
|
670 |
|
671 |
+
# Hidden textbox to hold processed resume data temporarily for interview
|
672 |
+
processed_resume_data_hidden_interview = gr.Textbox(visible=False)
|
673 |
|
674 |
# --- Chat Section ---
|
675 |
+
if CHAT_MODULE_AVAILABLE:
|
676 |
+
with gr.Column(visible=False) as chat_selection:
|
677 |
+
gr.Markdown("## Chat with Resume")
|
678 |
+
# File Upload Section (Chat uses its own upload)
|
679 |
+
with gr.Row():
|
680 |
+
with gr.Column():
|
681 |
+
file_upload_chat = gr.File(label="Upload Resume (PDF)", file_types=[".pdf"])
|
682 |
+
process_chat_btn = gr.Button("Process Resume")
|
683 |
+
with gr.Column():
|
684 |
+
file_status_chat = gr.Textbox(label="Status", interactive=False)
|
685 |
+
|
686 |
+
# Chat Section (Initially hidden)
|
687 |
+
chatbot = gr.Chatbot(label="Chat History", visible=False)
|
688 |
+
query_input = gr.Textbox(label="Ask about your resume", placeholder="Type your question here...", visible=False)
|
689 |
+
send_btn = gr.Button("Send", visible=False)
|
690 |
+
else:
|
691 |
+
with gr.Column(visible=False) as chat_selection:
|
692 |
+
gr.Markdown("## Chat with Resume (Unavailable)")
|
693 |
+
gr.Textbox(value="Chat module is not available.", interactive=False)
|
694 |
|
695 |
|
696 |
# Navigation buttons
|
|
|
697 |
interview_view = interview_selection
|
698 |
chat_view = chat_selection
|
699 |
|
700 |
interview_btn.click(fn=navigate_to_interview, inputs=None, outputs=[interview_view, chat_view])
|
701 |
+
if CHAT_MODULE_AVAILABLE:
|
702 |
+
chat_btn.click(fn=navigate_to_chat, inputs=None, outputs=[interview_view, chat_view])
|
703 |
# Update welcome message when user_state changes (basic)
|
704 |
user_state.change(fn=lambda user: f"### Welcome, {user}!" if user else "### Welcome, User!", inputs=[user_state], outputs=[welcome_display])
|
705 |
|
706 |
+
# --- Event Listeners for Interview ---
|
707 |
+
# Process Resume (Interview)
|
708 |
+
process_btn_interview.click(
|
|
|
709 |
fn=process_resume,
|
710 |
+
inputs=[file_upload_interview],
|
711 |
outputs=[
|
712 |
+
file_status_interview, role_selection, start_interview_btn,
|
713 |
question_display, answer_instructions, audio_input,
|
714 |
submit_answer_btn, next_question_btn, submit_interview_btn,
|
715 |
answer_display, feedback_display, metrics_display,
|
716 |
+
processed_resume_data_hidden_interview
|
717 |
]
|
718 |
)
|
719 |
|
720 |
# Start Interview
|
721 |
start_interview_btn.click(
|
722 |
fn=start_interview,
|
723 |
+
inputs=[role_selection, processed_resume_data_hidden_interview],
|
724 |
outputs=[
|
725 |
+
file_status_interview, question_display,
|
|
|
|
|
|
|
|
|
|
|
726 |
# Outputs for UI updates
|
727 |
audio_input, submit_answer_btn, next_question_btn,
|
728 |
submit_interview_btn, feedback_display, metrics_display,
|
|
|
736 |
fn=submit_answer,
|
737 |
inputs=[audio_input, interview_state],
|
738 |
outputs=[
|
739 |
+
file_status_interview, answer_display, interview_state,
|
740 |
feedback_display, feedback_display, # Update value and visibility
|
741 |
metrics_display, metrics_display, # Update value and visibility
|
742 |
audio_input, submit_answer_btn, next_question_btn,
|
|
|
749 |
fn=next_question,
|
750 |
inputs=[interview_state],
|
751 |
outputs=[
|
752 |
+
file_status_interview, question_display, interview_state,
|
753 |
audio_input, submit_answer_btn, next_question_btn,
|
754 |
feedback_display, metrics_display, submit_interview_btn,
|
755 |
question_display, answer_instructions,
|
|
|
761 |
submit_interview_btn.click(
|
762 |
fn=submit_interview,
|
763 |
inputs=[interview_state],
|
764 |
+
outputs=[file_status_interview, interview_state]
|
765 |
# In a full app, you might navigate to an evaluation page here
|
766 |
)
|
767 |
|
768 |
+
# --- Event Listeners for Chat (if available) ---
|
769 |
+
if CHAT_MODULE_AVAILABLE:
|
770 |
+
# Process Resume for Chat
|
771 |
+
process_chat_btn.click(
|
772 |
+
fn=chat_module.process_resume_chat,
|
773 |
+
inputs=[file_upload_chat],
|
774 |
+
outputs=[file_status_chat, processed_resume_data_state, query_input, send_btn, chatbot]
|
775 |
+
)
|
776 |
+
|
777 |
+
# Chat Interaction
|
778 |
+
send_btn.click(
|
779 |
+
fn=chat_module.chat_with_resume,
|
780 |
+
inputs=[query_input, processed_resume_data_state, chatbot], # chatbot provides history
|
781 |
+
outputs=[query_input, chatbot] # Update input (clear) and chatbot (new history)
|
782 |
+
)
|
783 |
+
query_input.submit( # Allow submitting with Enter key
|
784 |
+
fn=chat_module.chat_with_resume,
|
785 |
+
inputs=[query_input, processed_resume_data_state, chatbot],
|
786 |
+
outputs=[query_input, chatbot]
|
787 |
+
)
|
788 |
+
|
789 |
+
# --- Login/Logout Event Listeners ---
|
790 |
login_btn.click(
|
791 |
fn=login,
|
792 |
+
inputs=[login_email_input, login_password_input],
|
793 |
+
outputs=[login_status, login_section, main_app, signup_section, login_email_input, login_password_input, user_state]
|
794 |
+
)
|
795 |
+
|
796 |
+
signup_btn.click(
|
797 |
+
fn=signup,
|
798 |
+
inputs=[signup_email_input, signup_password_input, signup_username_input],
|
799 |
+
outputs=[signup_status, signup_section, login_section, main_app, signup_email_input, signup_password_input, signup_username_input, user_state]
|
800 |
)
|
801 |
|
802 |
logout_btn.click(
|
803 |
fn=logout,
|
804 |
inputs=None,
|
805 |
+
outputs=[login_status, login_section, main_app, signup_section, login_email_input, login_password_input, signup_username_input, user_state]
|
806 |
+
)
|
807 |
+
|
808 |
+
# Switch between Login and Signup
|
809 |
+
switch_to_signup_btn.click(
|
810 |
+
fn=lambda: (gr.update(visible=False), gr.update(visible=True)),
|
811 |
+
inputs=None,
|
812 |
+
outputs=[login_section, signup_section]
|
813 |
+
)
|
814 |
+
|
815 |
+
switch_to_login_btn.click(
|
816 |
+
fn=lambda: (gr.update(visible=True), gr.update(visible=False)),
|
817 |
+
inputs=None,
|
818 |
+
outputs=[login_section, signup_section]
|
819 |
)
|
820 |
|
821 |
# Run the app
|