|
|
|
|
|
import logging |
|
|
import streamlit as st |
|
|
from streamlit_mic_recorder import speech_to_text |
|
|
from pathlib import Path |
|
|
from chatbot_functionalities.generate_questions import generate_questions |
|
|
from chatbot_functionalities.vectordb_operations import get_collection_from_vector_db |
|
|
from chatbot_functionalities.evaluate_answers import evaluate_all_answers, get_overall_feedback |
|
|
|
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
|
logger = logging.getLogger("simple-chatbot") |
|
|
|
|
|
|
|
|
|
|
|
def initialize_app(): |
|
|
"""Performs processing that should happen upon loading of the web app and |
|
|
sets all session state variables to their desired initial state. |
|
|
""" |
|
|
|
|
|
st.session_state.p01_show_mock_interview = False |
|
|
st.session_state.p01_profile_details_taken = False |
|
|
st.session_state.p01_questions_generated = False |
|
|
st.session_state.p01_record_answer_disabled = False |
|
|
st.session_state.p01_start_mock_interview_disabled = False |
|
|
|
|
|
|
|
|
st.session_state.p01_current_question = None |
|
|
st.session_state.p01_current_question_index = -1 |
|
|
st.session_state.p01_questions_count = 0 |
|
|
st.session_state.p01_interview_history = [] |
|
|
|
|
|
|
|
|
|
|
|
st.session_state.p01_candidate_profile_question = ( |
|
|
"Please provide a brief summary about your education background and prior work experience " |
|
|
"that may be relevant to the chosen job position." |
|
|
) |
|
|
|
|
|
|
|
|
st.session_state.p01_recording_instructions = ( |
|
|
"All responses will be captured through the microphone available on your device. " |
|
|
"Ensure that the microphone is working and configured correctly." |
|
|
"Press the 'Record Answer' button and start speaking on the microphone after 1 second." |
|
|
) |
|
|
|
|
|
|
|
|
st.session_state.p01_questions_collection = get_collection_from_vector_db( |
|
|
vdb_path=(Path.cwd() / "data" / "chromadb").__str__(), |
|
|
collection_name="question_collection", |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
st.session_state.p01_init_complete = True |
|
|
|
|
|
|
|
|
def load_interview_questions(): |
|
|
"""Helper function to call question generation module""" |
|
|
if not st.session_state.p01_questions_generated: |
|
|
|
|
|
st.session_state.p01_questions_df = generate_questions( |
|
|
position=st.session_state.p01_job_position, |
|
|
candidate_profile=st.session_state.p01_interview_history[1]["content"], |
|
|
question_collection=st.session_state.p01_questions_collection, |
|
|
) |
|
|
|
|
|
|
|
|
st.session_state.p01_questions_count = st.session_state.p01_questions_df.shape[ |
|
|
0 |
|
|
] |
|
|
|
|
|
|
|
|
st.session_state.p01_questions_generated = True |
|
|
st.session_state.p01_mock_interview_concluded = False |
|
|
|
|
|
|
|
|
|
|
|
def start_mock_interview(): |
|
|
"""Resets mock interview section of the app and adds the question to |
|
|
collect candidate profile details. |
|
|
""" |
|
|
st.session_state.p01_show_mock_interview = True |
|
|
|
|
|
st.session_state.p01_questions_generated = False |
|
|
st.session_state.p01_interview_history = [] |
|
|
st.session_state.p01_record_answer_disabled = False |
|
|
st.session_state.p01_start_mock_interview_disabled = True |
|
|
st.session_state.overall_feedback = None |
|
|
|
|
|
|
|
|
st.session_state.p01_current_question = ( |
|
|
st.session_state.p01_candidate_profile_question[:] |
|
|
) |
|
|
|
|
|
def speech_recognition_callback(): |
|
|
if st.session_state.my_stt_output is None: |
|
|
st.session_state.p01_error_message = "Please record your reponse again." |
|
|
return |
|
|
|
|
|
st.session_state.p01_error_message = None |
|
|
|
|
|
st.session_state.p01_last_candidate_response = st.session_state.my_stt_output |
|
|
|
|
|
|
|
|
|
|
|
st.session_state.p01_interview_history.append( |
|
|
dict(role="assistant", content=st.session_state.p01_current_question) |
|
|
) |
|
|
st.session_state.p01_interview_history.append( |
|
|
dict(role="user", content=st.session_state.my_stt_output) |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if not st.session_state.p01_questions_generated: |
|
|
with st.spinner("Preparing questions for your mock interview"): |
|
|
load_interview_questions() |
|
|
|
|
|
|
|
|
if st.session_state.p01_current_question_index > -1: |
|
|
|
|
|
st.session_state.p01_questions_df.loc[st.session_state.p01_current_question_index, 'answer'] = st.session_state.my_stt_output |
|
|
|
|
|
|
|
|
|
|
|
if ( |
|
|
st.session_state.p01_current_question_index |
|
|
< st.session_state.p01_questions_count - 1 |
|
|
): |
|
|
st.session_state.p01_current_question_index += 1 |
|
|
st.session_state.p01_current_question = ( |
|
|
st.session_state.p01_questions_df.iloc[ |
|
|
st.session_state.p01_current_question_index |
|
|
].question |
|
|
) |
|
|
|
|
|
else: |
|
|
st.session_state.p01_current_question = "Your mock interview is over" |
|
|
st.session_state.p01_record_answer_disabled = True |
|
|
st.session_state.p01_start_mock_interview_disabled = False |
|
|
st.session_state.p01_mock_interview_concluded = True |
|
|
|
|
|
|
|
|
|
|
|
st.experimental_rerun() |
|
|
|
|
|
def get_feedback(): |
|
|
evaluate_all_answers( |
|
|
interview_history=st.session_state.p01_questions_df, |
|
|
questions_collection=st.session_state.p01_questions_collection, |
|
|
) |
|
|
|
|
|
|
|
|
st.session_state.overall_feedback = get_overall_feedback() |
|
|
|
|
|
|
|
|
def run_web_app(): |
|
|
"""Renders the web application, captures user actions and |
|
|
invokes appropriate event specific callbacks. |
|
|
""" |
|
|
|
|
|
|
|
|
st.set_page_config(page_title="Interview Preparation Assistant") |
|
|
|
|
|
|
|
|
if "p01_init_complete" not in st.session_state: |
|
|
initialize_app() |
|
|
|
|
|
|
|
|
|
|
|
st.sidebar.markdown( |
|
|
"<h4 style='color: orange;'>Candidate Profile</h4>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
|
|
|
candidate_name = st.sidebar.text_input( |
|
|
label="Candidate Name", |
|
|
placeholder="Enter your name", |
|
|
key="p01_candidate_name", |
|
|
) |
|
|
|
|
|
|
|
|
job_position_options = [ |
|
|
"Customer Service Representative", |
|
|
"Sales Manager", |
|
|
"Marketing Manager ", |
|
|
"Nurse", |
|
|
"Medical Assistance", |
|
|
] |
|
|
|
|
|
job_position = st.sidebar.selectbox( |
|
|
label="Job Position", |
|
|
placeholder="Select a job position", |
|
|
options=job_position_options, |
|
|
key="p01_job_position", |
|
|
) |
|
|
|
|
|
|
|
|
st.sidebar.button( |
|
|
label="Start Mock Interview", |
|
|
on_click=start_mock_interview, |
|
|
disabled=st.session_state.p01_start_mock_interview_disabled, |
|
|
key="p01_start_mock_interview", |
|
|
) |
|
|
|
|
|
|
|
|
combined_tabs = st.tabs(["Q&A", "History", "Results"]) |
|
|
tab1, tab2, tab3 = combined_tabs |
|
|
|
|
|
|
|
|
if st.session_state.p01_show_mock_interview: |
|
|
with tab1: |
|
|
|
|
|
p01_interview_section_title = ( |
|
|
f"Mock Interview for {st.session_state.p01_job_position}" |
|
|
) |
|
|
with st.container(): |
|
|
st.markdown( |
|
|
f"<h4 style='color: orange;'>{p01_interview_section_title}</h4>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
|
|
|
with st.container(): |
|
|
p01_current_question_title = "Current Question" |
|
|
with st.container(): |
|
|
st.markdown( |
|
|
f"<h6 style='color: orange;'>{p01_current_question_title}</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
with st.chat_message("assistant"): |
|
|
st.markdown(st.session_state.p01_current_question) |
|
|
|
|
|
|
|
|
if 'p01_start_mock_interview_disabled' in st.session_state and st.session_state.p01_start_mock_interview_disabled is True: |
|
|
with st.spinner(): |
|
|
speech_to_text( |
|
|
key='my_stt', |
|
|
callback=speech_recognition_callback |
|
|
) |
|
|
|
|
|
|
|
|
if "p01_error_message" in st.session_state: |
|
|
if st.session_state.p01_error_message is not None: |
|
|
with st.container(): |
|
|
st.error(st.session_state.p01_error_message) |
|
|
|
|
|
|
|
|
with tab2: |
|
|
|
|
|
p01_interview_history_title = "Interview History" |
|
|
with st.container(): |
|
|
st.markdown( |
|
|
f"<h4 style='color: orange;'>{p01_interview_history_title}</h4>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
for message in st.session_state.p01_interview_history[::-1]: |
|
|
with st.chat_message(message["role"]): |
|
|
st.markdown(message["content"]) |
|
|
|
|
|
|
|
|
|
|
|
with tab3: |
|
|
|
|
|
p01_interview_evaluation_title = "Evaluation Results & Feedback" |
|
|
with st.container(): |
|
|
st.markdown( |
|
|
f"<h4 style='color: orange;'>{p01_interview_evaluation_title}</h4>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
if 'p01_mock_interview_concluded' in st.session_state and st.session_state.p01_mock_interview_concluded is True: |
|
|
st.button( |
|
|
label="Get Feedback", |
|
|
type="primary", |
|
|
on_click=get_feedback, |
|
|
key="p01_get_feedback" |
|
|
) |
|
|
|
|
|
if 'overall_feedback' in st.session_state and st.session_state.overall_feedback is not None: |
|
|
if 'p01_questions_df' in st.session_state: |
|
|
st.markdown( |
|
|
f"<h6 style='color: orange;'>Question Level Feedback</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
with st.container(): |
|
|
col1, col2, col3 = st.columns(3) |
|
|
with col1: |
|
|
st.markdown( |
|
|
f"<h6 style='color: red;'>Question</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
with col2: |
|
|
st.markdown( |
|
|
f"<h6 style='color: red;'>Answer</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
with col3: |
|
|
st.markdown( |
|
|
f"<h6 style='color: red;'>Rating & Feedback</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
|
|
|
for row in st.session_state.p01_questions_df.itertuples(): |
|
|
with st.container(): |
|
|
col1, col2, col3 = st.columns(3) |
|
|
with col1: |
|
|
st.markdown(row.question) |
|
|
with col2: |
|
|
st.markdown(row.answer) |
|
|
with col3: |
|
|
st.markdown(row.feedback) |
|
|
|
|
|
with st.container(): |
|
|
st.markdown( |
|
|
f"<h6 style='color: orange;'>Overall Feedback</h6>", |
|
|
unsafe_allow_html=True, |
|
|
) |
|
|
with st.chat_message("assistant"): |
|
|
st.markdown("This functionality will be available in next release.") |
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
run_web_app() |
|
|
|