File size: 12,232 Bytes
ed1e7f2
 
 
 
 
 
 
 
 
a48d60e
ed1e7f2
 
 
e59edb3
ed1e7f2
968d447
47b2c20
e59edb3
ed1e7f2
 
968d447
e59edb3
ed1e7f2
e59edb3
ed1e7f2
 
 
e59edb3
968d447
e59edb3
ed1e7f2
e59edb3
968d447
 
e59edb3
968d447
 
e59edb3
dcf6e29
ed1e7f2
 
e59edb3
 
ed1e7f2
 
3b220a6
ed1e7f2
e59edb3
ed1e7f2
 
e59edb3
ed1e7f2
e59edb3
ed1e7f2
 
 
b22e5b7
ed1e7f2
 
 
 
 
 
 
 
 
 
 
 
 
 
e87365c
ed1e7f2
 
 
 
 
e87365c
 
 
 
ed1e7f2
e87365c
ed1e7f2
4afdc85
ed1e7f2
e87365c
 
 
 
 
ed1e7f2
e87365c
ed1e7f2
 
 
 
 
 
 
 
 
 
 
 
e87365c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ed1e7f2
 
e87365c
ed1e7f2
 
 
 
 
 
e87365c
ed1e7f2
e87365c
ed1e7f2
 
e87365c
ed1e7f2
e87365c
ed1e7f2
 
 
 
 
 
 
 
e87365c
 
 
 
 
 
 
ed1e7f2
e87365c
ed1e7f2
 
e87365c
ed1e7f2
e87365c
 
 
 
 
ed1e7f2
e87365c
 
 
 
 
 
 
ed1e7f2
 
 
 
e87365c
ed1e7f2
 
 
 
 
 
 
 
 
 
 
 
 
 
6198eaa
 
 
 
ed1e7f2
 
 
 
 
 
 
 
 
 
6198eaa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1aa23f1
 
6198eaa
6a49eb1
52e5c0a
 
829fa32
 
 
 
 
 
ed1e7f2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
e87365c
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
import gradio as gr
from openai import OpenAI
import os
import random
import asyncio

client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))

DEFAULT_LANGUAGE = "English"
WELCOME_MESSAGE_EN = "Hi! I'm Robin, your dialogue partner.\nWe're about to begin a conversation that includes nine questions. Are you ready?\nPlease tell me which language you'd like to use."

# === Normal Question Bank ===
NORMAL_SET_I = [
    "When was the last time you walked for more than an hour? Please describe what you saw.",
    "What is the best gift you have ever received? Why?",
    "If you had to leave your current city, where would you move to? What do you miss most about your current city?",
    "How did you celebrate the New Year last year, if you still remember?",
    "Do you read newspapers often? Why?",
    "What is the ideal number of students to share a house with? Why?",
    "If you could invent a new flavor of ice cream, what flavor would you create?",
    "What is the best restaurant you have been to in the past month? Please describe it.",
    "Please describe the pet you last got.",
    "What is your favorite holiday? Why?",
    "Can you tell me something funny that happened when you were spending time with a child?"
]
NORMAL_SET_II = [
    "What gift did you get on your last birthday?",
    "Please tell me something about your last trip to the zoo.",
    "Is there someone in your family you feel especially close to? What makes your bond strong?",
    "Imagine we were both stranded on a tropical island. What would be the first thing you would do?",
    "Do you like to wake up early or stay up late? Has anything interesting ever happened to you because of this?",
    "If you could choose to live anywhere, what city or environment would you choose?",
    "What is your favorite subject in school and why?",
    "What is your plan for the next holiday?",
    "What gifts did you receive for Christmas or New Year last year?",
    "Who is your favorite actor or actress? ",
    "What was your impression of your university when you first came to it?",
    "What is the best TV show you have seen in the past month? Please describe it a little bit.",
    "Do you have a favorite season or time of year? Why do you like it?"
]
NORMAL_SET_III = [
    "What do you remember most about your time in high school?",
    "What is the best book you have read in the past three months? ",
    "What country would you most like to visit? What attracts you to it?",
    "Do you prefer digital or analog watches/clocks? Why?",
    "Can you think of someone your mother or father is really close to? What do you think makes their friendship special?",
    "What are the pros and cons of artificial Christmas trees?",
    "How often do you get your hair cut? Have you ever had a bad haircut?",
    "Did you have a class pet in elementary school? Do you remember its name?",
    "Do you think left-handed people are more creative than right-handed people?",
    "What was the last concert you attended? How was the concert?",
    "What magazines do you subscribe to? What have you subscribed to in the past?",
    "Have you ever participated in a school play? What role did you play? Did anything funny happen during the play?"
]

def generate_question_set():
    return random.sample(NORMAL_SET_I, 3) + random.sample(NORMAL_SET_II, 3) + random.sample(NORMAL_SET_III, 3)

async def gpt_translate(text, target_lang):
    if target_lang == "English":
        return text
    prompt = f"Translate the following into {target_lang}:\n\n{text}"
    response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=[{"role": "user", "content": prompt}],
        temperature=0.3
    )
    return response.choices[0].message.content.strip()

async def respond(user_input, history, step, language, questions, followup_mode):
    history.append({"role": "user", "content": user_input})

    if language == "":
        user_language = user_input.strip().capitalize()
        questions_en = generate_question_set()
        translated_questions = [await gpt_translate(q, user_language) for q in questions_en]
        welcome = await gpt_translate("Great! We will now continue in your selected language.", user_language)
        history.append({"role": "assistant", "content": ""})
        for c in f"{welcome}\n\n1. {translated_questions[0]}":
            history[-1]["content"] += c
            await asyncio.sleep(0.03)
        return history, "", 1, user_language, translated_questions, False

    if step >= len(questions):
        thank_you = await gpt_translate("Thank you for your response! It was a pleasure talking with you. I hope you enjoyed the conversation.", language)
        end_note = await gpt_translate("This concludes our questions. Please proceed with the rest of the survey. 📝", language)
        for msg in [thank_you, end_note]:
            history.append({"role": "assistant", "content": ""})
            for c in msg:
                history[-1]["content"] += c
                await asyncio.sleep(0.03)
        return history, "", step, language, questions, False

    if followup_mode:
        comment_prompt = [
            {"role": "system", "content": f"Write a short, empathetic comment in {language} responding to the user's last answer."},
            history[-2],
            history[-1]
        ]
        comment_response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=comment_prompt,
            temperature=0.7
        )
        comment = comment_response.choices[0].message.content.strip()

        rand = random.random()
        if rand < 0.1:
            followup_prompt = [
                {"role": "system", "content": f"Ask one open-ended follow-up question in {language} based on the user's last answer."},
                history[-2],
                history[-1]
            ]
            followup_response = client.chat.completions.create(
                model="gpt-3.5-turbo",
                messages=followup_prompt,
                temperature=0.7
            )
            followup_question = followup_response.choices[0].message.content.strip()

            history.append({"role": "assistant", "content": ""})
            for c in comment:
                history[-1]["content"] += c
                await asyncio.sleep(0.03)

            history.append({"role": "assistant", "content": ""})
            for c in followup_question:
                history[-1]["content"] += c
                await asyncio.sleep(0.03)

            return history, "", step, language, questions, True
        else:
            history.append({"role": "assistant", "content": ""})
            for c in comment:
                history[-1]["content"] += c
                await asyncio.sleep(0.03)

            next_question = f"{step+1}. {questions[step]}"
            history.append({"role": "assistant", "content": ""})
            for c in next_question:
                history[-1]["content"] += c
                await asyncio.sleep(0.03)

            return history, "", step + 1, language, questions, False

    comment_prompt = [
        {"role": "system", "content": f"Write a short, personalized comment in {language} responding to the user's answer. Add a light emoji."},
        history[-2],
        history[-1]
    ]
    comment_response = client.chat.completions.create(
        model="gpt-3.5-turbo",
        messages=comment_prompt,
        temperature=0.7
    )
    comment = comment_response.choices[0].message.content.strip()

    rand = random.random()
    if rand < 0.4:
        followup_prompt = [
            {"role": "system", "content": f"Ask one open-ended follow-up question in {language} based on the user's answer."},
            history[-2],
            history[-1]
        ]
        followup_response = client.chat.completions.create(
            model="gpt-3.5-turbo",
            messages=followup_prompt,
            temperature=0.7
        )
        followup_question = followup_response.choices[0].message.content.strip()

        history.append({"role": "assistant", "content": ""})
        for c in comment:
            history[-1]["content"] += c
            await asyncio.sleep(0.03)

        history.append({"role": "assistant", "content": ""})
        for c in followup_question:
            history[-1]["content"] += c
            await asyncio.sleep(0.03)

        return history, "", step, language, questions, True
    else:
        history.append({"role": "assistant", "content": ""})
        for c in comment:
            history[-1]["content"] += c
            await asyncio.sleep(0.03)

        next_question = f"{step+1}. {questions[step]}"
        history.append({"role": "assistant", "content": ""})
        for c in next_question:
            history[-1]["content"] += c
            await asyncio.sleep(0.03)

        return history, "", step + 1, language, questions, False

def init():
    return [{"role": "assistant", "content": WELCOME_MESSAGE_EN}], 0, "", [], False


with gr.Blocks(css="""
.send-btn {
  background-color: #25D366 !important;
  color: white !important;
  border: none;
  border-radius: 24px;
  font-size: 20px;
  padding: 8px 20px;
  height: 48px;
  width: 60px;
  margin-left: 8px;
  cursor: pointer;
}
#chatbox .avatar-container {
    width: 54px !important;
    height: 54px !important;
    min-width: 54px !important;
    min-height: 54px !important;
    background-size: 100% 100% !important;
    background-position: center center !important;
    border-radius: 50% !important;
    padding: 0 !important;
    margin: 0 !important;
    border: none !important;
    box-shadow: none !important;
    background-color: transparent !important;
}
#chatbox .message.user { background-color: #DCF8C6 !important; }
#chatbox .message {
  display: inline-block !important;
  font-size: 16px !important;
  line-height: 1.3em !important;
  min-width: 7ch !important;
  max-width: 60ch !important;
  padding: 2px 3px !important;
  border-radius: 8px !important;
  word-break: break-word !important;
  white-space: normal !important;
}
@media screen and (max-width: 768px) {
  #chatbox .message.user {
    max-width: 90vw !important;
  }
}
#chatbox .message.user {
  background-color: #DCF8C6 !important;
  min-width: 60px !important;        
  max-width: fit-content !important;  
}
#chatbox .message.assistant { background-color: #ffffff !important; }
footer { display: none !important; }
.svelte-1ipelgc { display: none !important; }
.icon-button-wrapper {
  display: none !important;
}
label.svelte-1to105q {
  display: none !important;
}
""") as demo:
    gr.HTML("""
    <script>
      const waitForChatbox = () => {
        const chatbox = document.getElementById("chatbox");
        if (chatbox) {
          const observer = new MutationObserver(() => {
            chatbox.scrollTop = chatbox.scrollHeight;
          });
          observer.observe(chatbox, { childList: true, subtree: true });
        } else {
          setTimeout(waitForChatbox, 500);
        }
      };
      waitForChatbox();
    </script>
    """)

    chatbot = gr.Chatbot(
        elem_id="chatbox",
        label="",
        avatar_images=["user_avatar.jpg", "humanlike_avatar.png"],
        bubble_full_width=False,
        height=500,
        show_copy_button=False,
        type="messages"
    )

    with gr.Row():
        user_input = gr.Textbox(
            show_label=False,
            placeholder="Type your message here and press send...",
            container=True,
            scale=10
        )
        send_btn = gr.Button(value="➤", elem_classes="send-btn")

    state = gr.State([])
    step = gr.State(0)
    language = gr.State("")
    questions = gr.State([])
    followup_mode = gr.State(False)

    demo.load(fn=init, outputs=[chatbot, step, language, questions, followup_mode])
    user_input.submit(respond, [user_input, state, step, language, questions, followup_mode],
                      [chatbot, user_input, step, language, questions, followup_mode])
    send_btn.click(respond, [user_input, state, step, language, questions, followup_mode],
                   [chatbot, user_input, step, language, questions, followup_mode])

    demo.queue().launch()