import pandas as pd import gradio as gr from gradio import ChatMessage from src.constants import FULL_QUESTIONS, DEFAULT_GRADING_SYSTEM_DF, CUSTOM_CSS from src.utils import generate_session_id, highlight_feedback, show_popup, reset_popup, generate_skills_evaluation_markdown from src.api_calls import chatbot_api_call, feedback_api_call, ideal_answer_api_call, conversation_feedback_api_call session_id = generate_session_id() first_question_selected = False current_turns = 0 interview_data_with_feedback = [] def enable_send_button(message, selected_question): if selected_question and message.strip(): return gr.update(interactive=True), gr.update(label="Choose an interview question") elif selected_question: return gr.update(interactive=False), gr.update(label="Choose an interview question") return gr.update(interactive=False), gr.update(label="Choose an interview question (Required)") def handle_question_change(history, selected_question, conversation_mode): global session_id, first_question_selected, current_turns, interview_data_with_feedback current_turns = 0 interview_data_with_feedback = [] if conversation_mode == 'Interviewer': updated_label = f"Conversation turns: {current_turns}" feedback_box = gr.update(value=None) else: updated_label = "Multimodal Coach Agent" feedback_box = gr.update(value=None, show_legend=False) grading_system_df = gr.update(value=DEFAULT_GRADING_SYSTEM_DF, label="Insights") if len(history) > 2: first_question_selected = True if first_question_selected: session_id = generate_session_id() transition_message = f"Alright, let's move on to the next question:\n\n{selected_question}" new_history = [ ChatMessage( role="user", content="I'm ready for the next question now.", ), ChatMessage( role="assistant", content=transition_message, ), ] return new_history, gr.update(interactive=False), gr.update(interactive=True), gr.update(label=updated_label), feedback_box, grading_system_df else: if selected_question: last_question = f"Great start! Here's your first question:\n\n{selected_question}" else: last_question = selected_question if last_question != None: history.append( { "role": "user", "content": "One moment...", } ) history.append( { "role": "assistant", "content": last_question, } ) return [entry for entry in history if entry["content"] is not None], gr.update(interactive=False), gr.update(interactive=True), gr.update(label=updated_label), feedback_box, grading_system_df def reset_interface(conversation_mode): global session_id, first_question_selected, current_turns, interview_data_with_feedback first_question_selected = False current_turns = 0 interview_data_with_feedback = [] if conversation_mode == "Interviewer": chatbot_label = f"Conversation turns: {current_turns}" session_id = generate_session_id() user_greeting_message = "I've selected Interviewer mode, and I'm ready to begin." chatbot_greeting_message = ( "Hello, and welcome to your interview for the Senior Product Manager position!\n\n" "Select a question from the list above to begin." ) slider_state = gr.update(interactive=True) feedback_box = gr.update(value=None) feedback_type_state = gr.update(interactive=True, value="Standard") else: chatbot_label = "Multimodal Coach Agent" session_id = generate_session_id() user_greeting_message = "Hey there! I've selected Coach mode. Let's dive in." chatbot_greeting_message = ( "Hi!\n\n" "Welcome to your interview preparation session for the Senior Product Manager role.\n\n" "Please pick a question above to get started!" ) slider_state = gr.update(interactive=False) feedback_box = gr.update(value=None, show_legend=False) feedback_type_state = gr.update(interactive=False, value=" ") grading_system_df = gr.update(value=DEFAULT_GRADING_SYSTEM_DF, label="Insights") include_company_name = gr.update(interactive=True, value=False) include_resume_text = gr.update(interactive=True, value=False) include_job_description = gr.update(interactive=True, value=True) history = [ ChatMessage( role="user", content=user_greeting_message, ), ChatMessage( role="assistant", content=chatbot_greeting_message, ) ] return ( gr.update(value=history, label=chatbot_label), gr.update(choices=FULL_QUESTIONS, value=None, label="Choose an interview question (Required)", interactive=True), "", gr.update(value="Send", interactive=False), slider_state, feedback_box, feedback_type_state, grading_system_df, include_company_name, include_resume_text, include_job_description ) # Gradio interface def create_demo(): with gr.Blocks(css=CUSTOM_CSS) as demo: gr.Markdown("# Talent Interview Prep - Conversational Model") gr.Markdown("""### Please select a conversation mode to begin""") with gr.Row(equal_height=True): with gr.Column(scale=6): conversation_mode = gr.Radio( choices=["Interviewer", "Coach"], label="""Choose "Interviewer" to simulate a real interview or "Coach" for guidance and feedback""", info=""">**Important note:**\n>This has been *hardcoded* for a **Senior Product Manager** role.""", value=None ) with gr.Column(scale=2, variant="panel"): include_company_name = gr.Checkbox(label="Include the company name in the request", value=False, interactive=False) include_job_description = gr.Checkbox(label="Include the job description in the request", value=True, interactive=False) include_resume_text = gr.Checkbox(label="Include the candidate's resume in the request", value=False, interactive=False) conversation_turns_limit = gr.Slider(minimum=1, maximum=20, step=1, label="Choose the number of exchanges (turns) between you and the AI agent (1 min, 20 max)", value=5, interactive=False) with gr.Row(): with gr.Column(scale=6): question_dropdown = gr.Dropdown(choices=[], label="Choose an interview question") with gr.Column(scale=2): feedback_type_dropdown = gr.Dropdown( choices=["Standard", "STAR"], value=" ", label="Select the feedback type", interactive=False, allow_custom_value=True ) chatbot = gr.Chatbot(type="messages", label="""The Multimodal Chatbot will be ready once you select a mode""", show_copy_button=True) with gr.Row(equal_height=True): with gr.Column(scale=10): msg = gr.Textbox(show_label=False, placeholder="Type a message...") with gr.Column(min_width=50): send_btn = gr.Button(value="Send\n", variant="primary", interactive=False, elem_id="fill-button") gr.Markdown(" ") gr.Markdown("---") gr.Markdown("## Conversation Feedback") feedback_box = gr.HighlightedText( label="Breakdown", show_legend=True, color_map={"Strength": "green", "Area for Improvement": "orange", "Action Item": "blue"} ) grading_system_df = gr.DataFrame(value=DEFAULT_GRADING_SYSTEM_DF, interactive=False, label="Insights", max_height=200, min_width=25) msg.change(fn=enable_send_button, inputs=[msg, question_dropdown], outputs=[send_btn, question_dropdown]) question_dropdown.change(fn=enable_send_button, inputs=[msg, question_dropdown], outputs=[send_btn, question_dropdown]) question_dropdown.change(fn=handle_question_change, inputs=[chatbot, question_dropdown, conversation_mode], outputs=[chatbot, send_btn, msg, chatbot, feedback_box, grading_system_df]) def respond(message, history, conversation_mode, selected_question, conversation_turns_limit, feedback_type, include_company_name, include_resume_text, include_job_description): global session_id, current_turns, interview_data_with_feedback feedback_value = None feedback_show_legend = False criteria_feedback_df = DEFAULT_GRADING_SYSTEM_DF if not message.strip(): return history, message clean_question = selected_question.split(":", 1)[1] if ": " in selected_question else selected_question bot_message, conversation_end_flag, chat_memory = chatbot_api_call(session_id, clean_question, message, conversation_mode, conversation_turns_limit, include_company_name, include_resume_text) print(f"Conversation end? {conversation_end_flag}\n") print(f"{chat_memory=}\n") updated_label = f"Conversation turns: {current_turns}" if conversation_mode == 'Interviewer' else "Multimodal Coach Agent" history.append( ChatMessage( role="user", content=message, ) ) history.append( ChatMessage( role="assistant", content=bot_message, ) ) if conversation_end_flag: if conversation_mode == 'Interviewer': feedback_output = conversation_feedback_api_call(chat_memory['messages'], feedback_type.lower(), include_resume_text, include_job_description) feedback_show_legend, highlighted_feedback = highlight_feedback(feedback_output) feedback_value = [("Whole conversation feedback\n\n", None)] + highlighted_feedback criteria_feedback_data = feedback_output["criteria_feedback"] skills_evaluation_data = feedback_output["skills_evaluation"] if criteria_feedback_data: criteria_feedback_df = pd.DataFrame(criteria_feedback_data) criteria_feedback_df.rename(columns={ "question_criteria": "Question criteria", "evaluation": "Evaluation" }, inplace=True) if skills_evaluation_data: skills_evaluation = generate_skills_evaluation_markdown(skills_evaluation_data) history.append(ChatMessage( role="assistant", content=skills_evaluation, metadata={"title": "🛠️ Skills evaluation"} )) print() print(feedback_output) print() print(highlighted_feedback) print() print(criteria_feedback_df) return ( history, "", gr.update(interactive=False), gr.update(interactive=False), gr.update(label=updated_label), gr.update(value=feedback_value, show_legend=feedback_show_legend), gr.update(value=criteria_feedback_df, label="Insights") ) if conversation_mode == 'Interviewer': current_turns += 1 interview_data = chat_memory['messages'][:-1] print(f"{interview_data=}\n") feedback_output = feedback_api_call(interview_data, feedback_type.lower(), include_resume_text) feedback_show_legend, highlighted_feedback = highlight_feedback(feedback_output) feedback_value = [(f"{current_turns}º conversation turn feedback\n\n", None)] + highlighted_feedback criteria_feedback_data = feedback_output["criteria_feedback"] if criteria_feedback_data: criteria_feedback_df = pd.DataFrame(criteria_feedback_data) criteria_feedback_df.rename(columns={ "question_criteria": "Question criteria", "evaluation": "Evaluation" }, inplace=True) print() print(feedback_output) print() print(highlighted_feedback) print() print(criteria_feedback_df) print() interview_data_with_feedback.extend(interview_data) interview_data_with_feedback.append({"type": "feedback", "content": feedback_output["feedback_text"]}) print(f"{interview_data_with_feedback=}\n") ideal_answer = ideal_answer_api_call(interview_data_with_feedback, feedback_type.lower(), include_resume_text) cleaned_ideal_answer = ideal_answer.replace("\\n", " ") cleaned_ideal_answer_html = f"""
{cleaned_ideal_answer}
""" print(cleaned_ideal_answer) history.insert(-1, ChatMessage( role="assistant", content=cleaned_ideal_answer_html, metadata={"title": "💡 Your last message framed as an ideal answer"} )) updated_label = f"Conversation turns: {current_turns}" if conversation_mode == 'Interviewer' else "Multimodal Coach Agent" return ( history, "", gr.update(interactive=True), gr.update(interactive=True), gr.update(label=updated_label), gr.update(value=feedback_value, show_legend=feedback_show_legend), gr.update(value=criteria_feedback_df, label="Insights") ) conversation_mode.change(fn=reset_interface, inputs=conversation_mode, outputs=[chatbot, question_dropdown, msg, send_btn, conversation_turns_limit, feedback_box, feedback_type_dropdown, grading_system_df, include_company_name, include_resume_text, include_job_description]) msg.submit(fn=respond, inputs=[msg, chatbot, conversation_mode, question_dropdown, conversation_turns_limit, feedback_type_dropdown, include_company_name, include_resume_text, include_job_description], outputs=[chatbot, msg, send_btn, msg, chatbot, feedback_box, grading_system_df]) send_btn.click(fn=respond, inputs=[msg, chatbot, conversation_mode, question_dropdown, conversation_turns_limit, feedback_type_dropdown, include_company_name, include_resume_text, include_job_description], outputs=[chatbot, msg, send_btn, msg, chatbot, feedback_box, grading_system_df]) popup = gr.HTML(label="Popup", elem_classes=["popup"]) include_company_name.change( fn=lambda selected: show_popup(False, selected, False) if selected else reset_popup(), inputs=include_company_name, outputs=popup ) include_job_description.change( fn=lambda selected: show_popup(False, False, selected) if selected else reset_popup(), inputs=include_job_description, outputs=popup ) include_resume_text.change( fn=lambda selected: show_popup(selected, False, False) if selected else reset_popup(), inputs=include_resume_text, outputs=popup ) return demo print("Launching Gradio interface...") app = create_demo().launch(share=False, inline=False)