File size: 6,002 Bytes
eb12e97
f81c707
eb12e97
 
 
 
0ec1ea6
eb12e97
 
 
 
f81c707
 
3f8e911
 
69967af
eb12e97
 
f81c707
 
eb12e97
 
69967af
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f81c707
69967af
 
 
eb12e97
3f8e911
69967af
 
f81c707
 
 
 
 
3a90466
f81c707
 
69967af
 
 
 
 
 
 
 
0ec1ea6
 
69967af
 
 
 
 
3f8e911
69967af
 
 
 
 
 
 
 
 
 
 
 
 
 
00ba8c2
 
69967af
 
 
 
 
 
 
 
 
 
 
 
 
 
f81c707
3a90466
69967af
 
f81c707
69967af
 
3f8e911
eb12e97
3f8e911
69967af
0ec1ea6
69967af
 
3f8e911
69967af
 
 
0ec1ea6
 
3f8e911
 
 
eb12e97
3f8e911
 
69967af
 
 
 
 
 
 
 
0ec1ea6
69967af
 
 
 
0ec1ea6
69967af
 
 
3f8e911
69967af
 
0ec1ea6
69967af
 
 
3f8e911
 
69967af
 
 
 
 
eb12e97
 
 
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
import random
from enum import Enum

import gradio as gr
from dotenv import load_dotenv

from client import AppClient

load_dotenv(verbose=True)


class ErrorMessage(Enum):
    unauthorized = "Unfortunately, you do not have access to the project. Please reach out to the admin to get access"
    not_signed_in = "Sign in with your hugging face account to get started!"
    agent_error = "error in agent processing: {error}"
    agent_error_unknown = "error in agent processing, contact admin for support"


def respond_dummy():
    return random.choice(["How are you?", "I love you", "I'm very hungry"])


def make_visible():
    return gr.update(visible=True)


def make_invisible():
    return gr.update(visible=False)


def error_response(error_message: ErrorMessage):
    return {
        error_bar: gr.update(value=error_message.value, visible=True),
        start_button: make_invisible(),
        logged_in_components_group: make_invisible()
    }


with gr.Blocks() as demo:
    ################################
    # Define the UI
    ################################

    chat_id = gr.State(None)
    interview_options = gr.State(None)
    interview_selected_index = gr.State(None)

    with gr.Row():
        login_button = gr.LoginButton()
        logout_button = gr.LogoutButton()

    start_button = gr.Button(value="Let's get started!!", visible=True)
    error_bar = gr.Textbox(visible=False)

    logged_in_components_group = gr.Group(visible=False)
    with logged_in_components_group:

        interview_selector_group = gr.Group(visible=True)
        chat_interface_group = gr.Group(visible=False)

        # make dropdown for selecting interview
        with interview_selector_group:
            # Note: DO NOT try to use type="index" as there's a gradio bug which will break the interface
            interview_dropdown = gr.Dropdown(type="value", label="Select the interview", show_label=True, interactive=True)
            interview_selection_submit = gr.Button(value="Start!")

        with chat_interface_group:
            chatbot = gr.Chatbot()
            user_input = gr.Textbox(label="Candidate response")

    ################################
    # Setup user response logic
    ################################

    def user(user_message, history):
        return "", history + [[user_message, None]]

    def bot(chat_id_val, history):
        user_message = history[-1][0]
        # bot_message = respond_dummy()
        response = AppClient.get_agent_response(user_message=user_message, chat_id=chat_id_val)
        if response.agent_message is not None:
            bot_message = response.agent_message
            history[-1][1] = bot_message
            if response.end_interview:
                return {user_input: make_invisible(), chatbot: history}
            return {chatbot: history}
        if response.error_message is not None:
            return {
                error_bar: gr.update(value=ErrorMessage.agent_error.value.format(error=response.error_message), visible=True),
                user_input: gr.update(visible=False)
            }

    user_input.submit(user, [user_input, chatbot], [user_input, chatbot], queue=False).then(
        bot, [chat_id, chatbot], [user_input, chatbot, error_bar]
    )

    ################################
    # Define the auth / interview control logic
    ################################

    # login_button.click(lambda: start_button.update(visible=True), None, [start_button])
    logout_button.click(lambda: logged_in_components_group.update(visible=False),
                        None, [logged_in_components_group])

    # initialize the dropdown for interview selection
    def get_chat_options(profile: gr.OAuthProfile | None):
        # grant access case
        if profile is not None:
            hf_id = profile["preferred_username"]
            available_chats = AppClient.get_chats(user_hf_id=hf_id)
            chats_dict = {f"{r.title} (by {r.creator_name})": r.id for r in available_chats}
            if available_chats is not None:
                print(f"granting access to user {hf_id} for interviews: {available_chats}")
                return {
                    logged_in_components_group: make_visible(),
                    interview_selector_group: make_visible(),
                    start_button: make_invisible(),
                    interview_dropdown: gr.Dropdown.update(choices=list(chats_dict.keys())),
                    interview_options: chats_dict
                }
            else:
                error = ErrorMessage.unauthorized
        else:
            error = ErrorMessage.not_signed_in
        # case: access not granted
        return error_response(error)


    start_button.click(
        get_chat_options, None,
        [logged_in_components_group, error_bar, start_button, interview_selector_group, interview_dropdown, interview_options])

    # process dropdown selection and start interview
    def start_interview(profile: gr.OAuthProfile, dropdown_text, options: dict[str, str]):
        if profile is None:
            return error_response(ErrorMessage.unauthorized)
        # initialize chat
        hf_id = profile["preferred_username"]
        response = AppClient.start_chat(user_hf_id=hf_id, interview_id=options[dropdown_text])
        if response is None:
            return error_response(ErrorMessage.agent_error_unknown)

        return {
            chat_id: response.chat_id,
            chatbot: gr.update(value=[(None, response.first_message)]),
            logged_in_components_group: make_visible(),
            start_button: make_invisible(),
            interview_selector_group: make_invisible(),
            chat_interface_group: make_visible()
        }


    interview_selection_submit.click(
        start_interview,
        [interview_dropdown, interview_options],
        [chat_id, chatbot, interview_selector_group, chat_interface_group, logged_in_components_group, error_bar, start_button])

# demo.queue()
demo.launch()