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);.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}#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}#component-50,#component-62{" \ "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="24") 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="Type 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): with gr.Column(): 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), \ gr.update(interactive=False), \ gr.update(interactive=False), \ gr.update(interactive=False), \ gr.update(interactive=False) def enable_input(): return gr.update(interactive=True), \ gr.update(interactive=True), \ gr.update(interactive=True), \ gr.update(interactive=True), \ gr.update(interactive=True) 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()