Spaces:
Running
Running
# ========================== | |
# 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 | |
# ========================== | |
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 = 500 # Height of Gradio Chatbot | |
IMAGE_HEIGHT = 500 | |
IMAGE_WIDTH = 500 | |
LINES_PER_BOX = 12 # Number of text lines in a gradio text box | |
SUSPECTS_PER_PAGE = 8 # 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) | |
llm = ChatOpenAI(model = "gpt-4o",temperature=1.0,max_tokens=1024,timeout=None,max_retries=2,api_key=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=IMAGE_HEIGHT, width=IMAGE_WIDTH, 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=IMAGE_HEIGHT, width=IMAGE_WIDTH, 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=IMAGE_HEIGHT, width=IMAGE_WIDTH, 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=IMAGE_HEIGHT, width=IMAGE_WIDTH, 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() | |