File size: 16,394 Bytes
e6da03d
 
92c1e12
e6da03d
21fc809
e6da03d
196b3e3
8508e0f
9b52263
8508e0f
3dce584
5ec3426
3cab104
 
3dce584
 
 
 
 
 
 
5ec3426
3cab104
5ec3426
 
3cab104
5ec3426
 
 
72af144
5ec3426
 
72af144
e6da03d
 
3dce584
e6da03d
3dce584
 
 
8508e0f
3dce584
 
 
e6da03d
 
 
 
 
 
 
 
 
 
 
 
3dce584
 
 
9b52263
3dce584
 
e6da03d
 
 
 
 
 
 
 
 
 
 
 
 
3dce584
e6da03d
3dce584
 
3cab104
3dce584
 
5ec3426
3cab104
5ec3426
3dce584
5ec3426
8508e0f
658912b
 
 
 
5ec3426
 
3dce584
5ec3426
 
72af144
21fc809
3dce584
 
8508e0f
658912b
 
 
 
3dce584
5ec3426
3dce584
 
5ec3426
 
72af144
21fc809
 
e6da03d
 
 
196b3e3
e6da03d
 
 
 
 
 
 
 
 
196b3e3
e6da03d
 
3dce584
e6da03d
8508e0f
3dce584
5ec3426
21fc809
72af144
e6da03d
 
 
196b3e3
 
3dce584
 
 
 
e6da03d
3dce584
5ec3426
3dce584
 
196b3e3
21fc809
196b3e3
 
 
ab1685d
196b3e3
 
3dce584
196b3e3
e6da03d
196b3e3
e6da03d
21fc809
 
 
 
 
 
 
 
 
 
 
 
08c9450
 
21fc809
72af144
e6da03d
 
 
 
d01ea44
e6da03d
 
 
 
 
d01ea44
72af144
 
e6da03d
72af144
 
 
5ec3426
e6da03d
3dce584
 
 
 
e6da03d
5ec3426
196b3e3
8508e0f
3dce584
72af144
 
e6da03d
fe22d3a
3dce584
 
 
 
21fc809
8508e0f
3dce584
3cab104
3dce584
9b52263
3cab104
5ec3426
e6da03d
 
 
 
 
 
 
 
 
 
 
 
 
3dce584
fe22d3a
196b3e3
72af144
 
 
 
e6da03d
196b3e3
e6da03d
 
 
 
 
 
 
 
 
196b3e3
 
 
 
 
 
 
 
 
72af144
 
 
 
e6da03d
 
3cab104
e6da03d
3cab104
 
 
 
e6da03d
 
3cab104
fe22d3a
3cab104
 
 
66a9f93
3cab104
72af144
 
 
 
 
e6da03d
 
 
 
 
 
 
 
 
 
72af144
 
 
 
e6da03d
 
 
3cab104
 
72af144
3cab104
 
 
7b91819
e6da03d
f779dd3
196b3e3
 
f779dd3
3cab104
20f92b6
e6da03d
196b3e3
c97f1e2
e6da03d
3cab104
 
 
 
e6da03d
3cab104
 
 
 
e6da03d
 
3cab104
9b52263
196b3e3
e6da03d
196b3e3
 
9b52263
e6da03d
 
 
196b3e3
e6da03d
 
 
196b3e3
 
 
 
 
e6da03d
196b3e3
e6da03d
 
 
9b52263
3dce584
9b52263
 
3dce584
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
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"""<p style="text-align: left; font-size: 14px;">{cleaned_ideal_answer}</p>"""

                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)