mystery_manor / app.py
mswhite's picture
Upload 32 files
ce7c258 verified
raw
history blame
9.28 kB
# ==========================
# Imports
# ==========================
import os, sys, random
import gradio as gr
from langchain_openai import ChatOpenAI
from langchain.schema import AIMessage, HumanMessage
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain_core.runnables import RunnableLambda
from langchain_core.messages import AIMessage, AIMessageChunk, HumanMessage, HumanMessageChunk
from game_info import *
# ==========================
# Constants / Globals
# ==========================
NVIDIA_API_KEY = os.environ["API_KEY"] # API Key for the LLM - Using NVIDIA's NIM to access an 8 Billion parameter Llama3 model
CHATBOT_HEIGHT = 700 # Height of Gradio Chatbot
LINES_PER_BOX = 20 # Number of text lines in a gradio text box
SUSPECTS_PER_PAGE = 10 # Number of suspects shown per page
game = cMystery() # New mystery game imported from game_info
# ==========================
# LLM Functions
# ==========================
# Using NVIDIA's NIM (NVIDIA Inference Microservices) to access an 8 Billion parameter Llama3 model
llm = ChatOpenAI(model = "meta/llama3-8b-instruct",temperature=0.5,max_tokens=1024,timeout=None,max_retries=2,
base_url = "https://integrate.api.nvidia.com/v1",
api_key = NVIDIA_API_KEY)
# ================================
# Custom LangChain Tools and Pipes
# ================================
def output_parser(ai_message: AIMessage) -> str:
global game
current_suspect = game.get_current_suspect()
game.add_note_to_recap(ai_message.content, current_suspect) # Save a record of the conversation with the suspect name in the recap
return ai_message.content
# ==========================
# UI Functions
# ==========================
# ============================================
# Feed the chat message to the LLM
# ============================================
def predict(message, history):
global game
global llm
current_suspect = game.get_current_suspect()
if current_suspect is None:
return "Please select a suspect."
AI_Instructions = f"You are a suspect in an art theft." + \
f"Your name is {game.get_suspect_proper_name(current_suspect)} " + \
f"and your background is {game.get_suspect_background(current_suspect)}. " + \
f"Your motive for stealing the painting is {game.get_suspect_motive(current_suspect)}. " + \
f"If you stole the painting do not admit it. " + \
f"Base all conversations on the following JSON text:{game.create_interview(current_suspect)}"
prompt = ChatPromptTemplate.from_messages([
("system", f"{AI_Instructions}"),
("human", f"{message}"),
])
history_langchain_format = []
history_langchain_format.append(AIMessage(content=AI_Instructions))
history_langchain_format.append(HumanMessage(content=message))
gpt_response = llm(history_langchain_format)
output_parser(gpt_response)
response = gpt_response.content
# LCEL configuration for future game expansion / options
# lcel_chain = prompt | llm | output_parser
# response = lcel_chain.invoke(message)
return response
# ==========================
# Generate recap of game
# ==========================
def get_recap():
global game
recap = ""
recap += "๐Ÿ’ก Hints ๐Ÿ’ก \n\n" + game.get_hints_recap() + "\n" # Add revealed hints
recap += "๐Ÿ•ต Suspect Interview Notes ๐Ÿ•ต \n\n" # Add notes from interviews
recap += game.get_crime_recap()
return gr.Textbox(lines=LINES_PER_BOX, label="Recap of the Mystery", value=recap)
# ==========================
# Question suspect
# ==========================
def question_suspect(image, name):
global game
game.set_current_suspect(name)
current_suspect = game.get_current_suspect()
return gr.Textbox(lines = LINES_PER_BOX,
label = "About the Suspect",
value = game.get_suspect_profile(current_suspect))
# ==========================
# Generate game hint
# ==========================
def get_hint():
global game
return gr.Textbox(lines = LINES_PER_BOX,
label = "Hint About the Mystery",
value = game.give_hint())
# ===============================
# Reset game for a new mystery
# ===============================
def new_crime():
global game
game = cMystery()
game.print_game()
return [gr.Image (value = game.get_stolen_painting(), height=500, width=500, label = game.get_stolen_painting_name(), interactive=False),
gr.Textbox(lines = LINES_PER_BOX, label="A Crime has been Committed", value = game.get_crime_text()),
gr.Image (value = "Question_Mark.jpg", height=500, width=500, label = "Suspect", interactive=False),
gr.Textbox(lines = LINES_PER_BOX, label="About the Suspect", value = ""),]
# ============================================
# Arrest attempt - Are you correct ?
# ============================================
def arrest():
global game
current_suspect = game.get_current_suspect()
guilty_suspect = game.get_guilty_suspect_name()
if current_suspect is None:
arrest_results = "Please select a suspect on the right to arrest."
elif current_suspect == guilty_suspect:
arrest_results = "๐Ÿ‘๐Ÿ‘ Congratulations ๐Ÿ‘๐Ÿ‘ \n\nYou caught " + guilty_suspect + " and recovered the painting.\n\n" + \
guilty_suspect + " confessed why: \n\n'" + game.get_suspect_motive(guilty_suspect) + "'" + \
"and said 'I would have gotten away with it too if it weren't for you meddling detectives'"
else:
arrest_results = "โŒโŒโŒ You Failed Detective โŒโŒโŒ\n\n" + guilty_suspect + " stole the painting and snuck away while you were arresting the wrong person"
return gr.Textbox(lines = LINES_PER_BOX,
label = "Results of Your Arrest",
value = arrest_results)
# ================================
# Main Code - Draw Gradio UI
# ================================
game.print_game() # DEBUG - Print out the game settings
with gr.Blocks() as demo:
image_manor = gr.Image(value = "mystery_manor.jpg", width=2400, interactive=False)
with gr.Row():
with gr.Column():
painting = gr.Image (value = game.get_stolen_painting(), height=500, width=500, label = game.get_stolen_painting_name(), interactive=False)
crime_desc = gr.Textbox(lines = LINES_PER_BOX, label="A Crime has been Committed", value = game.get_crime_text() )
with gr.Row():
btn_new_crime = gr.Button("โšก New Crime โšก")
btn_recap = gr.Button("๐Ÿ’ก Recap ๐Ÿ’ก")
with gr.Column():
suspect_image = gr.Image (value = "Question_Mark.jpg", height=500,width=500, label="Suspect", interactive=False)
suspect_desc = gr.Textbox(lines = LINES_PER_BOX, label = "About the Suspect", value="")
with gr.Row():
btn_arrest= gr.Button("๐Ÿ‘ฎ Arrest ๐Ÿ‘ฎ")
btn_hint = gr.Button("๐Ÿ•ต Clue ๐Ÿ•ต")
with gr.Column():
suspect_list = gr.Examples(examples = game.get_suspect_images(), inputs = [suspect_image,suspect_desc], outputs=[suspect_desc], examples_per_page=SUSPECTS_PER_PAGE, fn=question_suspect, run_on_click=True, label="Suspect List", cache_examples=False)
with gr.Column():
QnA = gr.ChatInterface(fn=predict, examples=game.get_sample_questions(), title="โ“"+" Question the Suspect "+"โ“", fill_height=False, retry_btn=None, undo_btn=None, cache_examples=False)
btn_new_crime.click(new_crime, inputs=None, outputs=[painting, crime_desc, suspect_image, suspect_desc]) # Resets game to new one
btn_recap.click (get_recap, inputs=None, outputs=[crime_desc]) # Prints out summary of notes
btn_arrest.click (arrest, inputs=None, outputs=[suspect_desc]) # Arrest selected subject
btn_hint.click (get_hint, inputs=None, outputs=[suspect_desc]) # Ask for hint/clue
if __name__ == "__main__":
demo.launch()