File size: 22,408 Bytes
aa2e875
fc5e389
df36d20
fcab49d
fc5e389
aa2e875
573f504
 
 
393576f
 
8166508
 
 
 
 
 
 
715d8c6
 
7f7dd9f
 
8166508
7f7dd9f
 
3d37f6a
67a2db8
 
7f7dd9f
3d37f6a
 
0a93dc2
 
3d37f6a
 
0a93dc2
 
bb63de8
 
a0e8812
 
54f7f86
dd5547e
7f7ba6f
547e5c5
9327e4f
 
 
 
 
 
 
 
3d37f6a
 
 
 
 
 
 
 
 
9327e4f
3d37f6a
9327e4f
 
 
3d37f6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9327e4f
3d37f6a
9327e4f
 
3d37f6a
 
9327e4f
3d37f6a
 
 
 
 
 
 
 
 
 
 
 
 
 
9327e4f
3d37f6a
 
9327e4f
3d37f6a
9327e4f
 
3d37f6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9327e4f
3d37f6a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a0e8812
39193db
6b93fa1
3d37f6a
c35fe56
8166508
e520696
0d614c5
 
3d37f6a
4cfce75
 
7f7ba6f
e4434b8
4cfce75
6b93fa1
4cfce75
343724c
6b93fa1
c35fe56
6b93fa1
c35fe56
6b93fa1
64a8d23
 
3d37f6a
64a8d23
 
6b93fa1
c35fe56
39193db
 
 
 
3d37f6a
 
 
 
 
 
 
 
39193db
7fe812c
 
 
288fcab
99d7111
9327e4f
288fcab
99d7111
9327e4f
288fcab
99d7111
9327e4f
288fcab
99d7111
9327e4f
343724c
99d7111
9327e4f
 
 
 
7fe812c
 
 
99d7111
 
 
573f504
30e9f08
b8ac00f
99d7111
b8ac00f
 
 
 
 
 
 
 
 
 
 
 
 
96e77e9
99d7111
 
 
 
 
e4434b8
99d7111
 
 
07fe324
d111820
67a2db8
 
 
 
 
d111820
 
67a2db8
 
 
 
 
d111820
99d7111
39193db
e4434b8
99d7111
c35fe56
e4434b8
99d7111
c35fe56
e4434b8
99d7111
c35fe56
39193db
3d37f6a
 
 
99d7111
 
 
 
 
 
39193db
99d7111
39193db
 
99d7111
39193db
64a8d23
99d7111
c35fe56
 
99d7111
 
d111820
 
c35fe56
99d7111
 
 
d111820
 
c35fe56
 
7fe812c
99d7111
 
 
 
3d37f6a
64a8d23
39193db
 
 
99d7111
 
 
 
 
39193db
99d7111
 
 
 
 
39193db
a803285
88d5b1a
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
import gradio as gr
import os
import openai

openai.api_key = os.environ['KEY']

theme = gr.themes.Monochrome(
    text_size="lg"
)
css = "@import url(https://fonts.googleapis.com/css2?family=Silkscreen:wght@400;700&display=swap);#component-3," \
      "#component-4{margin-bottom:10px}.gradio-container{" \
      "background-color:#cda678;font-family:Silkscreen;position:relative}#component-1{min-height:75vh}#component-4{" \
      "margin-top:auto}.tabs.svelte-btpldm{height:100%}.tabitem{background-color:#002366;border:1px solid " \
      "#fff}#component-17,#component-25,#component-33,#component-41,#component-9{" \
      "min-height:70vh;max-height:70vh}.secondary.svelte-58yet2{" \
      "background-color:#002366;font-weight:400}#component-10,#component-11,#component-18,#component-19," \
      "#component-26,#component-27,#component-34,#component-35,#component-42,#component-43{" \
      "background-color:#aaa}.message.svelte-a99nd8.svelte-a99nd8{" \
      "padding:15px;position:relative}.user.svelte-a99nd8.svelte-a99nd8{" \
      "margin-right:10px}.bot.svelte-a99nd8.svelte-a99nd8{" \
      "padding-left:15px;margin-left:10px}.bot.svelte-a99nd8.svelte-a99nd8:before," \
      ".user.svelte-a99nd8.svelte-a99nd8:after{" \
      "content:\"\";width:10px;height:10px;position:absolute;bottom:-1px;border:1px solid var(" \
      "--color-border-accent);background-color:var(--color-accent-soft)}.bot.svelte-a99nd8.svelte-a99nd8:before{" \
      "left:-10px;border-right:0}.user.svelte-a99nd8.svelte-a99nd8:after{right:-10px;border-left:0}textarea{" \
      "background-color:#fff;min-height:50px!important}#component-48,#component-51,#component-61{" \
      "position:absolute;left:50%;top:50%;transform:translateX(-50%) translateY(" \
      "-50%);width:50%;height:50vh;padding:80px 20px 20px;background-color:#fff;border:1px solid " \
      "#002366}#component-51{display:flex;flex-direction:column}#component-51.hide.svelte-1btyfsc{" \
      "display:none}#component-51:before{content:\"The Killer is: " \
      "\";position:absolute;top:20px;left:20px;color:#000;font-size:var(--text-lg)}#component-51>:not(:last-child){" \
      "flex-grow:1}#component-49{position:initial;background-image:url(" \
      "\"file/img/map.jpg\");background-position:center;background-repeat:no-repeat;background-size:contain" \
      "}#component-50,#component-57,#component-64{" \
      "position:absolute;top:20px;right:20px;width:44px;height:44px;min-width:44px;min" \
      "-height:44px;line-height:0}.output-class.svelte-1s28oeb.svelte-1s28oeb.svelte-1s28oeb,div.svelte-1eq475l{" \
      "font-weight:400}"

with gr.Blocks(theme=theme, css=css) as iface:
    chatbot = []
    msg = []
    accusationButtons = []
    culpritId = 3
    names = ["Steve Binner", "Albert Wright", "Dominic Schwartz", "Brianna Small", "Lyanne Brimes"]
    roles = ["Security Guard", "Curator", "Researcher", "Conservationist", "Tour Guide"]
    initText = ["You are Steve Binner, 31, a security guard for a museum of medieval history. You're absolutely sure "
                "that this place is haunted. A month ago, before the spooky stuff started, you were really happy with "
                "your job, but that changed real fast. The ghost is a French nobleman named Baron Hugo Antoine the "
                "Third. You've been trying to tell other people about this, but you've only been laughed at so far. "
                "But you've got evidence! Every Thursday, around 10pm, the broom closet gets locked from the inside "
                "and the interior gets wrecked. We're talking pushed over tables, broken containers, "
                "the whole shebang. When it comes to the murder of director Eisenholz last Thursday, that had to have "
                "been the ghost, no question. You even have the door card records for the room he was in: After the "
                "museum closed at 5pm, nobody entered that room till the next morning. You found the body at around "
                "2am in the warehouse during your second patrol for the night. Because of technical maintenance, "
                "all security cams were turned off during this week, because they had to be readied for the big "
                "exhibition that’ll happened soon. If asked about Brianna Small’s keycard, talk about how the last "
                "few days were stressful, because she accidentally destroyed her card. You had to open every door for "
                "her, and she made a big fuss about it, so everybody knows that she needs help. She’s a pain to work "
                "with.  Now you're being interrogated by a detective. Director Eisenholz has been murdered. You don't "
                "use uptight language, and you're not super well educated on most stuff, but when it comes to the "
                "paranormal, you're an ace. ",
                "You are Albert Wright, 61, the curator of this museum. You have been the curator here since it "
                "opened 32 years ago, because your family has close ties with the Eisenholz family. You knew Richard "
                "Eisenholz since he was a boy and would never hurt him. Even though you weren’t always on the same "
                "page, your values and traditions were the same, which was very important to you and your families. "
                "And imagine the scandal it would be, if a member of an upper-class family would commit such an "
                "atrocity. On the day of the murder, you left at 4pm to go check out if everything was alright in the "
                "other museum that you own. If asked, explain how you couldn’t have gotten in the storage room (where "
                "the body was found) because your card was missing for a few days. You and Mr. Eisenholz were in a "
                "tight spot lately, because you needed something new to display. There weren’t a lot of new artifacts "
                "lately and the Box Miss Small, the conservationist, was examining, wasn’t that promising according "
                "to Eisenholz. You were making requests to Mr. Eisenholz if he could lend you something novel from "
                "his collection of family heirlooms, but he wasn’t as cooperative as you’d wished for. Luckily the "
                "discovery Miss Small made saved the museum. Miss Small is a very good employee, mostly since that "
                "discovery she made. It was her idea to open that box, even though Eisenholz said there would be "
                "nothing in it. But with her skills, she opened it and - as she’d expected - a priceless object was "
                "inside. The museum immediately put it on display, since there weren’t any new things lately and we "
                "had less visitors, but now it’s time for a huge promotional campaign. Mister Schwartz, the resident "
                "researcher, is an enthusiastic and passionate employee. But his passion can push it too far "
                "sometimes. You got involved in a discussion with him and Mr. Eisenholz. I think it was something "
                "about an artifact the museum supposedly culturally appropriated or some other nonsense, "
                "but you didn’t really care. You’re too old for this kind of topic where young people think they have "
                "to posture how good and right they are. Back in your day, things were more normal. Miss Brimes, "
                "the visitor’s chaperone, is quite a pleasant lady. She’s a treat to be around and you have had a "
                "plethora of great interactions with her, since she frequently visited Richard’s offices for one "
                "reason or another. You don’t really know much about Mister Binner, the nightwatchman. Word is going "
                "around that he’s a bit of a nutcase, but as long as he does his job well, you do not mind. Now "
                "you're being interrogated by a detective. Director Eisenholz has been murdered. Use sophisticated "
                "language. You are an old-fashioned gentleman, after all. ",
                "You are Dominic Schwartz, 35, and the researcher in this museum. Start the conversation by "
                "explaining that you love the history of medieval times, mostly regarding French monarchs. You are so "
                "lucky to be able to work in this museum and do the research of the artifacts! Inform the detective "
                "about various neat facts about French medieval history. Importantly, mention that the museum uses a "
                "lot of symbols of a dragon to make everything look more authentic, even though back in the day they "
                "weren’t depicted and for sure never in France, since in France, the depiction of a beast was the "
                "Loup-Garou; a half bear half wolf creature. You may have exposed a bit too much here, "
                "but it’s probably fine, since only an expert in this field (such as yourself, of course) would know "
                "this. At the night of the murder, you weren’t at the museum. You left earlier because you had to go "
                "to a conference. The curator, Mister Wright, can vouch for that because he was responsible for "
                "covering the expenses (it was a business trip, after all). You mention that there is even a YouTube "
                "video of you holding a talk at that conference. If asked about Brianna, the conservationist, "
                "say that she only cares about things she was involved with, anything other she doesn’t care if it "
                "breaks. If asked about Lyanne Brimes, the guide, say that you think she is a nice person, "
                "but it is very obvious that Mr Eisenholz and she got something going on. It could be enough of a "
                "motive for the murder, but you’re hesitant to make accusations. If asked about Albert Wright, "
                "the curator, say that you think he is a self-absorbed man who believes in classism and capitalism "
                "like Mr Eisenholz, but at least Mr Eisenholz was more sensible. If asked about Steve, the security "
                "guard, talk about how he’s a bit of a weirdo, but harmless. His ghost stories would be very funny if "
                "he wasn’t serious. Now you're being interrogated by a detective. Director Eisenholz has been "
                "murdered. Your personality is enthusiastic, but slightly arrogant and annoying, although you’d never "
                "admit that. Your thoughts tend to bounce all over the place.",
                "You are Brianna Small, 43, a conservationist at a museum of medieval history, but you would call "
                "yourself almost a scientist. You worked here for decades at the same position, but you are hoping "
                "for a promotion soon. You knew the victim mainly because he was owner of almost 50% of the artifacts "
                "in this museum and, as a conservationist, you held a few meetings with him discussing the "
                "preservation. You had a few inputs and ideas on the display and handling of the artifacts and "
                "Eisenholz usually agreed, which made working with him pleasant. At the night of the murder, "
                "you left the building at 18:00 because you made a new discovery a few days ago and wanted to "
                "document it. Your office is in the west wing and has a small window, where you saw Steve, "
                "the security guard, pass by a few times. You think Steve could have been the murderer because he has "
                "access to every room and has been acting crazy lately. He thinks ghosts are real, but from a "
                "scientific viewpoint that could never be true. You couldn’t have done the murder because your "
                "security keycard fell in acid two days ago. Steve can confirm that, because he had to open all the "
                "rooms for you. Only talk about this if specifically asked about the box: A few weeks ago, "
                "Eisenholz donated a new artifact to the museum. It was a box made of wood with magnificent "
                "engravings, but it was sealed. You asked Eisenholz if you could try to open it and, with your skills "
                "of a conservationist, you’d be able to do so without damaging the box. Eisenholz was hesitant at "
                "first, but after a few discussions he let me do it. And of course, it worked. What you found was "
                "beyond imagination. There was a golden ring inside in perfect condition. It had the form of a dragon "
                "with ruby crystals as eyes. Since this is a valuable discovery and the museum hasn’t got anything "
                "new lately, you will talk to the director as soon as possible to immediately display it in a secure "
                "glass container. Let’s see if Dominic, a researcher at the museum, can find out anything about the "
                "ring. He has been occupied lately on an artifact he thinks doesn’t belong here. If he keeps up his "
                "extremist attitude, he will cost you all the museum and your jobs. Now you're being interrogated by "
                "a detective. Director Eisenholz has been murdered. You’re professional & to the point. ",
                "You are Lyanne Brimes, 27, a tour guide for a museum of medieval history. You graduated college a "
                "few years ago and have a degree in history. You work here part time. You know director Richard "
                "Eisenholz very well because you had a secret relationship with him. You don’t like talking about "
                "this in public. You met every Thursday in the broom closet. You thought nobody knew, but you are not "
                "sure anymore. Lately Eisenholz was behaving very strangely. Something was bothering him. You wanted "
                "to talk with him about it on the night of the murder at 5 pm, but he never came. You had to wait 3 "
                "hours to get out of the closet, because you heard Steve Binner walking up and down the east wing and "
                "talking to a portrait at the end of the corridor. On your way out, you noticed the door to the "
                "storage room was open but, thought it might have been Steve (the security guard) lurking around. You "
                "are not the murderer, but if you had to guess who it was, you would say it was the curator. The "
                "curator and Eisenholz were fighting lately because a medallion, that has been in his family "
                "possession for centuries, but he didn’t want to give it to the museum because it was too valuable. "
                "You don’t know Brianna Small (the conservationist) very well, but if you had to say something about "
                "her, it would be that she is very smart and ambitious but too focused on her merits. Now you're "
                "being interrogated by a detective. Director Eisenholz has been murdered. You use formal language, "
                "and you are very well educated in history stuff, mostly medieval. You have a bubbly personality."]

    with gr.Row() as chatRow:
        with gr.Column(scale=1):
            questionCounter = gr.Label(label="Remaining Questions", value="20")
            mapButton = gr.Button("Show Floor Plan")
            finishButton = gr.Button("Pick a Culprit")
        with gr.Column(scale=7):
            i = 0
            while i < len(roles):
                with gr.Tab("The " + roles[i]):
                    with gr.Row():
                        with gr.Column(scale=9):
                            chatbot.append(gr.Chatbot(label=names[i] + ", " + roles[i]))
                            msg.append(gr.Textbox(label="", placeholder="Ask a question..."))
                        with gr.Column(scale=3):
                            characterImage = gr.Label(label="")
                i += 1

    with gr.Row(visible=False) as mapRow:
        with gr.Column():
            closeMapButton = gr.Button("X")

    with gr.Row(visible=False) as solvingRow:
        i = 0
        while i < len(roles):
            accusationButtons.append(gr.Button("The " + roles[i]))
            i += 1

        closeSolvingButton = gr.Button("X")

    with gr.Row(visible=False) as resultRow:
        with gr.Column():
            resultLabel = gr.Label(label="Result")

    with gr.Row() as introRow:
        with gr.Column():
            introLabel = gr.Label(label="You are a detective investigating a murder. The victim was the director of a "
                                        "medieval museum, at which his body was found. There are five possible "
                                        "suspects for you to interrogate, all of which are members of the faculty. "
                                        "You can only ask 20 Questions. Good luck. ")
            closeIntroButton = gr.Button("X")


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

    # this is an ugly workaround, you cannot pass regular integers to gradio functions, so i had to do it this way
    def bot0(history, question_counter_text):
        return bot(0, history, question_counter_text)

    def bot1(history, question_counter_text):
        return bot(1, history, question_counter_text)

    def bot2(history, question_counter_text):
        return bot(2, history, question_counter_text)

    def bot3(history, question_counter_text):
        return bot(3, history, question_counter_text)

    def bot4(history, question_counter_text):
        return bot(4, history, question_counter_text)

    def bot(number, history, question_counter_text):
        bot_message = generate_ai_message(history, question_counter_text, number)
        history[-1][1] = bot_message
        return history

    def generate_ai_message(history, question_counter_text, character_id):
        if check_if_questions_left(question_counter_text):
            init_sys_message = initText[character_id] + "Stay in character. Use natural language. Don't reveal all of" \
                                                        "the information in a single message, and leave hints. Never " \
                                                        "reveal everything in a single message."
            message_history = [
                {"role": "system", "content": init_sys_message}
            ]
            for pair in history:
                message_history.append({"role": "user", "content": pair[0]})
                print()
                if pair[1] is not None:
                    message_history.append({"role": "assistant", "content": pair[1]})
            completion = openai.ChatCompletion.create(
                model="gpt-3.5-turbo",
                messages=message_history
            )
            return completion.choices[0].message.content
        else:
            return "--- YOU'VE RUN OUT OF QUESTIONS, MAKE YOUR CHOICE ---"

    def update_questions(question_counter_text):
        remaining_questions = int(question_counter_text["label"])
        if remaining_questions > 0:
            remaining_questions -= 1
        return str(remaining_questions)

    def check_if_questions_left(question_counter_text):
        remaining_questions = int(question_counter_text["label"])
        return remaining_questions > 0

    def disable_input():
        return gr.update(interactive=False, placeholder="Waiting for an answer..."), \
            gr.update(interactive=False, placeholder="Waiting for an answer..."), \
            gr.update(interactive=False, placeholder="Waiting for an answer..."), \
            gr.update(interactive=False, placeholder="Waiting for an answer..."), \
            gr.update(interactive=False, placeholder="Waiting for an answer...")

    def enable_input():
        return gr.update(interactive=True, placeholder="Ask a question..."), \
            gr.update(interactive=True, placeholder="Ask a question..."), \
            gr.update(interactive=True, placeholder="Ask a question..."), \
            gr.update(interactive=True, placeholder="Ask a question..."), \
            gr.update(interactive=True, placeholder="Ask a question...")

    def try_to_solve():
        return {solvingRow: gr.update(visible=True)}

    def show_map():
        return {mapRow: gr.update(visible=True)}

    def hide_solve_box():
        return {solvingRow: gr.update(visible=False)}

    def hide_map():
        return {mapRow: gr.update(visible=False)}

    def hide_intro():
        return {introRow: gr.update(visible=False)}

    def show_result():
        return {
            chatRow: gr.update(visible=False),
            solvingRow: gr.update(visible=False),
            resultRow: gr.update(visible=True)
        }

    def declare_loss():
        return "You failed! The real culprit got away... "

    def declare_victory():
        return "Congratulations, you found the killer! "

    bot_functions = [bot0, bot1, bot2, bot3, bot4]
    i = 0
    while i < len(roles):
        msg[i].submit(
            user, [msg[i], chatbot[i]], [msg[i], chatbot[i]], queue=False
        ).then(
            disable_input, None, [msg[0], msg[1], msg[2], msg[3], msg[4]]
        ).then(
            bot_functions[i], [chatbot[i], questionCounter], chatbot[i]
        ).then(
            update_questions, questionCounter, questionCounter
        ).then(
            enable_input, None, [msg[0], msg[1], msg[2], msg[3], msg[4]]
        )
        i += 1

    mapButton.click(show_map, None, mapRow)
    closeMapButton.click(hide_map, None, mapRow)
    finishButton.click(try_to_solve, None, solvingRow)
    closeSolvingButton.click(hide_solve_box, None, solvingRow)
    closeIntroButton.click(hide_intro, None, introRow)

    i = 0
    while i < len(roles):
        if i == culpritId:
            accusationButtons[i].click(
                show_result, None, [chatRow, solvingRow, resultRow]
            ).then(
                declare_victory, None, resultLabel
            )
        else:
            accusationButtons[i].click(
                show_result, None, [chatRow, solvingRow, resultRow]
            ).then(
                declare_loss, None, resultLabel
            )
        i += 1

iface.launch()