IliaLarchenko commited on
Commit
403487b
1 Parent(s): 8d9f6bc

Improved UI

Browse files
Files changed (2) hide show
  1. app.py +3 -13
  2. ui/coding.py +120 -79
app.py CHANGED
@@ -24,20 +24,10 @@ def initialize_services():
24
 
25
  def create_interface(llm, tts, stt, audio_params):
26
  """Create and configure the Gradio interface."""
27
- with gr.Blocks(title="AI Interviewer") as demo:
28
  audio_output = gr.Audio(label="Play audio", autoplay=True, visible=os.environ.get("DEBUG", False), streaming=tts.streaming)
29
- tabs = [
30
- get_instructions_ui(llm, tts, stt, audio_params),
31
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="Coding", interview_type="coding"),
32
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="ML Design (Beta)", interview_type="ml_design"),
33
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="ML Theory (Beta)", interview_type="ml_theory"),
34
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="System Design (Beta)", interview_type="system_design"),
35
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="Math (Beta)", interview_type="math"),
36
- get_problem_solving_ui(llm, tts, stt, audio_params, audio_output, name="SQL (Beta)", interview_type="sql"),
37
- ]
38
-
39
- for tab in tabs:
40
- tab.render()
41
  return demo
42
 
43
 
 
24
 
25
  def create_interface(llm, tts, stt, audio_params):
26
  """Create and configure the Gradio interface."""
27
+ with gr.Blocks(title="AI Interviewer", theme=gr.themes.Default()) as demo:
28
  audio_output = gr.Audio(label="Play audio", autoplay=True, visible=os.environ.get("DEBUG", False), streaming=tts.streaming)
29
+ get_problem_solving_ui(llm, tts, stt, audio_params, audio_output).render()
30
+ get_instructions_ui(llm, tts, stt, audio_params).render()
 
 
 
 
 
 
 
 
 
 
31
  return demo
32
 
33
 
ui/coding.py CHANGED
@@ -1,80 +1,106 @@
1
  import gradio as gr
2
  import numpy as np
 
3
 
4
  from resources.data import fixed_messages, topic_lists
5
  from utils.ui import add_candidate_message, add_interviewer_message
6
 
7
 
8
- def get_problem_solving_ui(llm, tts, stt, default_audio_params, audio_output, name="Coding", interview_type="coding"):
9
- with gr.Tab(name, render=False, elem_id=f"{interview_type}_tab") as problem_tab:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
  chat_history = gr.State([])
11
  previous_code = gr.State("")
12
- started_coding = gr.State(False)
13
- interview_type_var = gr.State(interview_type)
14
- with gr.Accordion("Settings") as init_acc:
15
- with gr.Row():
16
- with gr.Column():
17
- gr.Markdown("##### Problem settings")
18
- with gr.Row():
19
- gr.Markdown("Difficulty")
20
- difficulty_select = gr.Dropdown(
21
- label="Select difficulty",
22
- choices=["Easy", "Medium", "Hard"],
23
- value="Medium",
24
- container=False,
25
- allow_custom_value=True,
26
- elem_id=f"{interview_type}_difficulty_select",
27
- )
28
- with gr.Row():
29
- topics = topic_lists[interview_type].copy()
30
- np.random.shuffle(topics)
31
- gr.Markdown("Topic (can type custom value)")
32
- topic_select = gr.Dropdown(
33
- label="Select topic",
34
- choices=topics,
35
- value=topics[0],
36
- container=False,
37
- allow_custom_value=True,
38
- elem_id=f"{interview_type}_topic_select",
39
- )
40
- with gr.Column(scale=2):
41
- requirements = gr.Textbox(
42
- label="Requirements",
43
- placeholder="Specify additional requirements",
44
- lines=5,
45
- elem_id=f"{interview_type}_requirements",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
46
  )
47
- start_btn = gr.Button("Generate a problem", elem_id=f"{interview_type}_start_btn")
 
 
 
 
48
 
49
- with gr.Accordion("Problem statement", open=True) as problem_acc:
50
- description = gr.Markdown(elem_id=f"{interview_type}_problem_description")
51
- with gr.Accordion("Solution", open=False) as solution_acc:
52
  with gr.Row() as content:
53
  with gr.Column(scale=2):
54
- if interview_type == "coding":
55
- code = gr.Code(
56
- label="Please write your code here. You can use any language, but only Python syntax highlighting is available.",
57
- language="python",
58
- lines=46,
59
- elem_id=f"{interview_type}_code",
60
- )
61
- elif interview_type == "sql":
62
- code = gr.Code(
63
- label="Please write your query here.",
64
- language="sql",
65
- lines=46,
66
- elem_id=f"{interview_type}_code",
67
- )
68
- else:
69
- code = gr.Code(
70
- label="Please write any notes for your solution here.",
71
- language=None,
72
- lines=46,
73
- elem_id=f"{interview_type}_code",
74
- )
75
  with gr.Column(scale=1):
76
- end_btn = gr.Button("Finish the interview", interactive=False, variant="stop", elem_id=f"{interview_type}_end_btn")
77
- chat = gr.Chatbot(label="Chat", show_label=False, show_share_button=False, elem_id=f"{interview_type}_chat")
78
  message = gr.Textbox(
79
  label="Message",
80
  show_label=False,
@@ -82,31 +108,41 @@ def get_problem_solving_ui(llm, tts, stt, default_audio_params, audio_output, na
82
  max_lines=3,
83
  interactive=True,
84
  container=False,
85
- elem_id=f"{interview_type}_message",
86
  )
87
- send_btn = gr.Button("Send", interactive=False, elem_id=f"{interview_type}_send_btn")
88
- audio_input = gr.Audio(interactive=False, **default_audio_params, elem_id=f"{interview_type}_audio_input")
89
 
90
  audio_buffer = gr.State(np.array([], dtype=np.int16))
91
  transcript = gr.State({"words": [], "not_confirmed": 0, "last_cutoff": 0, "text": ""})
92
 
93
- with gr.Accordion("Feedback", open=True) as feedback_acc:
94
- feedback = gr.Markdown(elem_id=f"{interview_type}_feedback")
95
 
96
  # Start button click action chain
97
  start_btn.click(fn=add_interviewer_message(fixed_messages["start"]), inputs=[chat], outputs=[chat]).success(
98
- fn=lambda: True, outputs=[started_coding]
99
- ).success(fn=tts.read_last_message, inputs=[chat], outputs=[audio_output]).success(
100
- fn=lambda: (gr.update(open=False), gr.update(interactive=False)), outputs=[init_acc, start_btn]
 
 
 
 
 
 
 
 
 
 
101
  ).success(
102
  fn=llm.get_problem,
103
- inputs=[requirements, difficulty_select, topic_select, interview_type_var],
104
  outputs=[description],
105
  scroll_to_output=True,
106
  ).success(
107
- fn=llm.init_bot, inputs=[description, interview_type_var], outputs=[chat_history]
108
  ).success(
109
- fn=lambda: (gr.update(open=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
110
  outputs=[solution_acc, end_btn, audio_input, send_btn],
111
  )
112
 
@@ -124,7 +160,10 @@ def get_problem_solving_ui(llm, tts, stt, default_audio_params, audio_output, na
124
  ),
125
  outputs=[solution_acc, end_btn, problem_acc, audio_input, send_btn],
126
  ).success(
127
- fn=llm.end_interview, inputs=[description, chat_history, interview_type_var], outputs=[feedback]
 
 
 
128
  )
129
 
130
  send_btn.click(fn=add_candidate_message, inputs=[message, chat], outputs=[chat]).success(
@@ -154,9 +193,11 @@ def get_problem_solving_ui(llm, tts, stt, default_audio_params, audio_output, na
154
  fn=lambda: gr.update(interactive=True), outputs=[send_btn]
155
  ).success(fn=lambda: None, outputs=[audio_input])
156
 
157
- # TODO: add proper messages and clean up when changing the interview type
158
- # problem_tab.select(fn=add_interviewer_message(fixed_messages["intro"]), inputs=[chat, started_coding], outputs=[chat]).success(
159
- # fn=tts.read_last_message, inputs=[chat], outputs=[audio_output]
160
- # )
 
161
 
 
162
  return problem_tab
 
1
  import gradio as gr
2
  import numpy as np
3
+ import os
4
 
5
  from resources.data import fixed_messages, topic_lists
6
  from utils.ui import add_candidate_message, add_interviewer_message
7
 
8
 
9
+ def change_code_area(interview_type):
10
+ if interview_type == "coding":
11
+ return gr.update(
12
+ label="Please write your code here. You can use any language, but only Python syntax highlighting is available.",
13
+ language="python",
14
+ )
15
+ elif interview_type == "sql":
16
+ return gr.update(
17
+ label="Please write your query here.",
18
+ language="sql",
19
+ )
20
+ else:
21
+ return gr.update(
22
+ label="Please write any notes for your solution here.",
23
+ language=None,
24
+ )
25
+
26
+
27
+ def get_problem_solving_ui(llm, tts, stt, default_audio_params, audio_output):
28
+ with gr.Tab("Interview", render=False, elem_id=f"tab") as problem_tab:
29
  chat_history = gr.State([])
30
  previous_code = gr.State("")
31
+ hi_markdown = gr.Markdown(
32
+ "<h2 style='text-align: center;'> Hi! I'm here to guide you through a practice session for your technical interview. Choose the interview settings to begin.</h2>\n"
33
+ )
34
+ with gr.Row() as init_acc:
35
+ with gr.Column(scale=3):
36
+ interview_type_select = gr.Dropdown(
37
+ show_label=False,
38
+ info="Type of the interview.",
39
+ choices=["coding", "ml_design", "ml_theory", "system_design", "math", "sql"],
40
+ value="coding",
41
+ container=True,
42
+ allow_custom_value=False,
43
+ elem_id=f"interview_type_select",
44
+ scale=2,
45
+ )
46
+ difficulty_select = gr.Dropdown(
47
+ show_label=False,
48
+ info="Difficulty of the problem.",
49
+ choices=["Easy", "Medium", "Hard"],
50
+ value="Medium",
51
+ container=True,
52
+ allow_custom_value=True,
53
+ elem_id=f"difficulty_select",
54
+ scale=2,
55
+ )
56
+ topic_select = gr.Dropdown(
57
+ show_label=False,
58
+ info="Topic (you can type any value).",
59
+ choices=topic_lists[interview_type_select.value],
60
+ value=np.random.choice(topic_lists[interview_type_select.value]),
61
+ container=True,
62
+ allow_custom_value=True,
63
+ elem_id=f"topic_select",
64
+ scale=2,
65
+ )
66
+ with gr.Column(scale=4):
67
+ requirements = gr.Textbox(
68
+ label="Requirements",
69
+ show_label=False,
70
+ placeholder="Specify additional requirements if any.",
71
+ container=False,
72
+ lines=5,
73
+ elem_id=f"requirements",
74
+ )
75
+ with gr.Row():
76
+ terms_checkbox = gr.Checkbox(
77
+ label="",
78
+ container=False,
79
+ value=not os.getenv("IS_DEMO", False),
80
+ interactive=True,
81
+ elem_id=f"terms_checkbox",
82
+ min_width=20,
83
  )
84
+ with gr.Column(scale=100):
85
+ gr.Markdown(
86
+ "#### I agree to the [terms and conditions](https://github.com/IliaLarchenko/Interviewer?tab=readme-ov-file#important-legal-and-compliance-information)"
87
+ )
88
+ start_btn = gr.Button("Generate a problem", elem_id=f"start_btn", interactive=not os.getenv("IS_DEMO", False))
89
 
90
+ with gr.Accordion("Problem statement", open=True, visible=False) as problem_acc:
91
+ description = gr.Markdown(elem_id=f"problem_description", line_breaks=True)
92
+ with gr.Accordion("Solution", open=True, visible=False) as solution_acc:
93
  with gr.Row() as content:
94
  with gr.Column(scale=2):
95
+ code = gr.Code(
96
+ label="Please write your code here.",
97
+ language="python",
98
+ lines=46,
99
+ elem_id=f"code",
100
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  with gr.Column(scale=1):
102
+ end_btn = gr.Button("Finish the interview", interactive=False, variant="stop", elem_id=f"end_btn")
103
+ chat = gr.Chatbot(label="Chat", show_label=False, show_share_button=False, elem_id=f"chat")
104
  message = gr.Textbox(
105
  label="Message",
106
  show_label=False,
 
108
  max_lines=3,
109
  interactive=True,
110
  container=False,
111
+ elem_id=f"message",
112
  )
113
+ send_btn = gr.Button("Send", interactive=False, elem_id=f"send_btn")
114
+ audio_input = gr.Audio(interactive=False, **default_audio_params, elem_id=f"audio_input")
115
 
116
  audio_buffer = gr.State(np.array([], dtype=np.int16))
117
  transcript = gr.State({"words": [], "not_confirmed": 0, "last_cutoff": 0, "text": ""})
118
 
119
+ with gr.Accordion("Feedback", open=True, visible=False) as feedback_acc:
120
+ feedback = gr.Markdown(elem_id=f"feedback", line_breaks=True)
121
 
122
  # Start button click action chain
123
  start_btn.click(fn=add_interviewer_message(fixed_messages["start"]), inputs=[chat], outputs=[chat]).success(
124
+ fn=tts.read_last_message, inputs=[chat], outputs=[audio_output]
125
+ ).success(
126
+ fn=lambda: (
127
+ gr.update(visible=False),
128
+ gr.update(interactive=False),
129
+ gr.update(interactive=False),
130
+ gr.update(interactive=False),
131
+ gr.update(visible=False),
132
+ ),
133
+ outputs=[init_acc, start_btn, terms_checkbox, interview_type_select, hi_markdown],
134
+ ).success(
135
+ fn=lambda: (gr.update(visible=True)),
136
+ outputs=[problem_acc],
137
  ).success(
138
  fn=llm.get_problem,
139
+ inputs=[requirements, difficulty_select, topic_select, interview_type_select],
140
  outputs=[description],
141
  scroll_to_output=True,
142
  ).success(
143
+ fn=llm.init_bot, inputs=[description, interview_type_select], outputs=[chat_history]
144
  ).success(
145
+ fn=lambda: (gr.update(visible=True), gr.update(interactive=True), gr.update(interactive=True), gr.update(interactive=True)),
146
  outputs=[solution_acc, end_btn, audio_input, send_btn],
147
  )
148
 
 
160
  ),
161
  outputs=[solution_acc, end_btn, problem_acc, audio_input, send_btn],
162
  ).success(
163
+ fn=lambda: (gr.update(visible=True)),
164
+ outputs=[feedback_acc],
165
+ ).success(
166
+ fn=llm.end_interview, inputs=[description, chat_history, interview_type_select], outputs=[feedback]
167
  )
168
 
169
  send_btn.click(fn=add_candidate_message, inputs=[message, chat], outputs=[chat]).success(
 
193
  fn=lambda: gr.update(interactive=True), outputs=[send_btn]
194
  ).success(fn=lambda: None, outputs=[audio_input])
195
 
196
+ interview_type_select.change(
197
+ fn=lambda x: gr.update(choices=topic_lists[x], value=np.random.choice(topic_lists[x])),
198
+ inputs=[interview_type_select],
199
+ outputs=[topic_select],
200
+ ).success(fn=change_code_area, inputs=[interview_type_select], outputs=[code])
201
 
202
+ terms_checkbox.change(fn=lambda x: gr.update(interactive=x), inputs=[terms_checkbox], outputs=[start_btn])
203
  return problem_tab