File size: 18,998 Bytes
aa2e875
fc5e389
df36d20
fcab49d
fc5e389
aa2e875
573f504
 
 
393576f
 
8166508
 
 
 
 
 
 
715d8c6
 
d111820
 
8166508
332919d
 
393576f
67a2db8
 
 
393576f
 
 
 
bb63de8
 
a0e8812
 
54f7f86
dd5547e
7f7ba6f
547e5c5
9327e4f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a0e8812
39193db
6b93fa1
393576f
c35fe56
8166508
e520696
0d614c5
 
4cfce75
 
 
7f7ba6f
e4434b8
4cfce75
6b93fa1
4cfce75
343724c
6b93fa1
c35fe56
6b93fa1
c35fe56
6b93fa1
64a8d23
 
67a2db8
64a8d23
 
6b93fa1
c35fe56
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
99d7111
 
 
 
 
 
39193db
99d7111
39193db
 
99d7111
39193db
64a8d23
99d7111
c35fe56
 
99d7111
 
d111820
 
c35fe56
99d7111
 
 
d111820
 
c35fe56
 
7fe812c
99d7111
 
 
 
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
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{" \
      "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-49{position:initial;background-image:url(" \
      "\"https://huggingface.co/spaces/hslu-di/Wiesli_Jonas/resolve/main/img/map.jpg\");background-position:center" \
      ";background-repeat:no-repeat;background-size:contain}#component-50,#component-57{" \
      "position:absolute;top:20px;right:20px;width:44px;height:44px;min-width:44px;min-height:44px}.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. 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 Mister "
                "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 weren’t in the building the whole day because you were at a "
                "meeting of another museum you are curating for. It’s very stressful to manage four museums. You and "
                "Mr. Eisenholz were in a tight spot lately, because you needed something new to display. There "
                "weren’t a lot of new artefacts 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. Brianna 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 promotion "
                "campaign. Dominic Schwartz, the conservationist, is an enthusiastic and passionate employee. But his "
                "passion can push it too far sometimes. I got involved in a discussion with him and Mr. Eisenholz. I "
                "think it was something about an Artefact we culturally appropriated or something, but I didn’t "
                "really care. I’m too old for this kind of topics where young people think they have to posture how "
                "good and right they are. Back in my day things were more normal. Now you're being interrogated by a "
                "detective. Director Eisenholz has been murdered. Use sophisticated language. You’re an old-fashioned "
                "gentleman, after all. ",
                "Your 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 artefacts! 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 not in France, since in France, the depiction of a beast was the "
                "lougarou; 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. Brianna, the conservationist, only cares about things she was involved with, anything other "
                "she doesn’t mind if it breaks. Now you're being interrogated by a detective. Director Eisenholz has "
                "been murdered. Your personality is enthusiastic, but slightly arrogant. 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 the 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 artefacts "
                "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 artefacts 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 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 do have access to the storage room, but you don’t know why that would be important. "
                "Your co-worker who left a few months ago did it so it’s not a room that interests you. Only talk "
                "about this if specifically asked about the box: A few weeks ago, Eisenholz donated a new artefact 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 "
                "artefact he thinks doesn’t belong here. If he keeps up his extremist attitude, he will cost us all "
                "the museum and our jobs. Now you're being interrogated by a detective. Director Eisenholz has been "
                "murdered. You are very ambitious. ",
                "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 Eisenholz "
                "very well because you had a secret relationship with him. 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, but he never came. After waiting for 2 hours in the closet, you decided to go home. 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. Some might think Steve could be the murderer because he has been out "
                "of his mind lately with his whole ghost thing, and because he has access to every room, "
                "but you don’t think he could have done it because he is kind-hearted. 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. 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="4")
            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(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(roles[i]))
            i += 1

        closeSolvingButton = gr.Button("X")

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


    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 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)

    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()