# dependencies 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 # enable logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger("simple-chatbot") # function to initialize web app for the first time 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. """ # set status flags 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 # initialize variables related to question and interview history 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 = [] # first question that will be asked to every candidate # this can be replaced with CV summarization component 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." ) # instruction that will be printed before the microphone button 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." ) # fetch the necessary collections from vector db st.session_state.p01_questions_collection = get_collection_from_vector_db( vdb_path=(Path.cwd() / "data" / "chromadb").__str__(), collection_name="question_collection", ) # set the flag that indiciates initialization is done # this flag is crucial and should be done as the very last step in this function as # the web app invokes this function only when this variable is not set 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: # use candidate provided profile summary and generate subsequent questions to be asked 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, ) # set questions count st.session_state.p01_questions_count = st.session_state.p01_questions_df.shape[ 0 ] # set flag to indicate that questions have been generated st.session_state.p01_questions_generated = True st.session_state.p01_mock_interview_concluded = False # function(s) to process user interactions 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_profile_details_taken = False 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 # set current question to candidate profile request question 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 # if code reaches this point, then a response was successfully captured and transcribed # append current question and the utterance from the candidate to interview history 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) ) # generate questions if not already done # this is done here instead of 'Start Mock Interview' button because we # CV summarization component is not ready and we need to ask the candidate # to give a profile summary as part of first question if not st.session_state.p01_questions_generated: with st.spinner("Preparing questions for your mock interview"): load_interview_questions() # Add answer to question's dataframe if st.session_state.p01_current_question_index > -1: # ignoring the summary input st.session_state.p01_questions_df.loc[st.session_state.p01_current_question_index, 'answer'] = st.session_state.my_stt_output # change current question to the next available question # check if there are any more question(s) to be asked 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 ) # no more questions to be asked 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 # Since the update is async, the question will not update. # hence forced rerun required. 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, ) # get_ratings_for_answers(st.session_state.p01_questions_df) # get_feedback_for_answers(st.session_state.p01_questions_df) st.session_state.overall_feedback = get_overall_feedback() # function for rendering the main web application def run_web_app(): """Renders the web application, captures user actions and invokes appropriate event specific callbacks. """ # page or window title - this shows up as browser window title st.set_page_config(page_title="Interview Preparation Assistant") # call initialization function (only for the first time) if "p01_init_complete" not in st.session_state: initialize_app() # setup sidebar # siderbar title st.sidebar.markdown( "