Spaces:
Sleeping
Sleeping
import gradio as gr | |
import random | |
from helper import load_world, save_world | |
from together import Together | |
from helper import get_together_api_key | |
# Initialize Together client | |
client = Together(api_key=get_together_api_key()) | |
# Load the world data from the JSON file | |
world_data = load_world('./YourWorld_L1.json') | |
# Set the content policy | |
safe_content_policy = { | |
"policy": """O1: Violence and Hate. | |
Should not | |
- Express hateful, derogatory, or demeaning sentiments against people based on sensitive personal characteristics. | |
- Use slurs based on personal characteristics | |
- Write gruesome / graphic violence. | |
Can | |
- Write tame fantasy violence | |
O2: Sexual Content. | |
Should not | |
- Write any somewhat sexual content that mentions sexual functions or sexual body parts. | |
- Write any content that would be inappropriate for kids. | |
Can | |
- Write romantic content (including kissing, flirting etc...) | |
O3: Self-Harm. | |
Should not | |
- Encourage people to harm themselves. | |
- Romanticize or condone self-harm or suicide. | |
- Write story depicting suicide. | |
O4: Profanity. | |
Should not | |
- Write with any profane language that wouldn't be appropriate for kids. | |
Can | |
- Write with kid appropriate language | |
O5: Regulated or Controlled Substances. | |
Should not | |
- Write stories that depicts, glorifies or encourages drug use.""" | |
} | |
# Function to randomly select a world, kingdom, town, and character | |
def randomly_select_from_json(world_data): | |
world_name = world_data["name"] | |
world_description = world_data["description"] | |
valid_kingdoms = { | |
k_name: k_data | |
for k_name, k_data in world_data["kingdoms"].items() | |
if any("npcs" in town_data and town_data["npcs"] for town_data in k_data["towns"].values()) | |
} | |
if not valid_kingdoms: | |
raise ValueError("No kingdoms with valid towns and NPCs found.") | |
kingdom_name, kingdom_data = random.choice(list(valid_kingdoms.items())) | |
kingdom_description = kingdom_data["description"] | |
valid_towns = { | |
t_name: t_data | |
for t_name, t_data in kingdom_data["towns"].items() | |
if "npcs" in t_data and t_data["npcs"] | |
} | |
if not valid_towns: | |
raise ValueError(f"No towns with NPCs found in kingdom: {kingdom_name}") | |
town_name, town_data = random.choice(list(valid_towns.items())) | |
town_description = town_data["description"] | |
npcs = town_data["npcs"] | |
character_name, character_data = random.choice(list(npcs.items())) | |
character_description = character_data["description"] | |
return { | |
"world": {"name": world_name, "description": world_description}, | |
"kingdom": {"name": kingdom_name, "description": kingdom_description}, | |
"town": {"name": town_name, "description": town_description}, | |
"character": {"name": character_name, "description": character_description}, | |
} | |
# Function to initialize or reinitialize the game state | |
def initialize_game_state(): | |
random_state = randomly_select_from_json(world_data) | |
world = random_state["world"] | |
kingdom = random_state["kingdom"] | |
town = random_state["town"] | |
character = random_state["character"] | |
system_prompt = """You are an AI Game master. Your job is to create a | |
start to an adventure based on the world, kingdom, town, and character | |
a player is playing as. | |
Instructions: | |
- You must use only 2-4 sentences. | |
- Please use simple and clear language that is easy for children to understand. | |
- Write in second person, e.g., "You are Jack." | |
- Write in present tense, e.g., "You stand at..." | |
- First describe the character and their backstory. | |
- Then describe where they start and what they see around them.""" | |
world_info = f""" | |
World: {world['description']} | |
Kingdom: {kingdom['description']} | |
Town: {town['description']} | |
Your Character: {character['description']} | |
""" | |
model_output = client.chat.completions.create( | |
model="meta-llama/Llama-3-70b-chat-hf", | |
temperature=1.0, | |
messages=[ | |
{"role": "system", "content": system_prompt}, | |
{"role": "user", "content": world_info + '\nYour Start:'} | |
], | |
) | |
start = model_output.choices[0].message.content | |
return { | |
"world": world["description"], | |
"kingdom": kingdom["description"], | |
"town": town["description"], | |
"character": character["description"], | |
"start": start, | |
} | |
def is_safe (message): | |
prompt = f"""[INST] Task: Check if there is unsafe content in | |
'user' messages in conversations according to our safety policy | |
with the below categories. | |
<BEGIN UNSAFE CONTENT CATEGORIES> | |
{safe_content_policy['policy']} | |
<END UNSAFE CONTENT CATEGORIES> | |
<BEGIN CONVERSATION> | |
user: {message} | |
Provide your safety assessment for user in the above conversation: | |
- First line must read 'safe' or 'unsafe'. | |
- If unsafe, a second line must include a comma-separated list of | |
violated categories. [/INST]""" | |
response = client.completions.create( | |
model="Meta-Llama/LlamaGuard-2-8b", | |
prompt=prompt, | |
) | |
result = response.choices[0].text | |
return result.strip() == 'safe' | |
# Initialize the game state | |
game_state = initialize_game_state() | |
game_running = True # Flag to manage game status | |
# Function to process user input and actions | |
def run_action(message, history): | |
global game_state, game_running # Access the global game state and game status | |
if not game_running: | |
return "The game has ended. Type 'restart the game' to play again." | |
if message.lower() == "start game": | |
return game_state["start"] | |
if message.lower() == "restart the game": | |
game_state = initialize_game_state() | |
return "Game restarted! " + game_state["start"] | |
if message.lower() == "exit": | |
game_running = False | |
return "The game has ended. Type 'restart the game' to play again." | |
system_prompt = """You are an AI Game master. Your job is to write what \ | |
happens next in a player's adventure game.\ | |
Instructions: \ | |
- Write only 1-3 sentences. \ | |
- Please use simple and clear language that is easy for children to understand. | |
- Always write in second person, e.g., "You look north and see..." \ | |
- Write in present tense.""" | |
world_info = f""" | |
World: {game_state['world']} | |
Kingdom: {game_state['kingdom']} | |
Town: {game_state['town']} | |
Your Character: {game_state['character']}""" | |
# Build the context for the conversation | |
messages = [ | |
{"role": "system", "content": system_prompt}, | |
{"role": "user", "content": world_info}, | |
] | |
for action in history: | |
if isinstance(action, tuple) and len(action) == 2: | |
messages.append({"role": "assistant", "content": action[0]}) | |
messages.append({"role": "user", "content": action[1]}) | |
# Add the user's current action | |
messages.append({"role": "user", "content": message}) | |
# Get the model's response | |
model_output = client.chat.completions.create( | |
model="meta-llama/Llama-3-70b-chat-hf", | |
messages=messages, | |
) | |
return model_output.choices[0].message.content | |
def main_loop(message, history): | |
if not is_safe(message): | |
return 'Invalid action.' | |
result = run_action(message, history) | |
safe = is_safe(result) | |
if(safe): | |
return result # only if safe? | |
else: | |
return 'Invalid output.' | |
# Gradio ChatInterface | |
demo = gr.ChatInterface( | |
main_loop, | |
chatbot=gr.Chatbot( | |
height=300, | |
placeholder="Type 'start game' to begin, 'restart the game' to restart, or 'exit' to end the game.", | |
type="messages", # Ensures proper rendering | |
), | |
textbox=gr.Textbox( | |
placeholder="What do you do next?", | |
container=False, | |
scale=7, | |
), | |
title="AI RPG", | |
theme="Monochrome", | |
examples=["Look around", "Continue the story"], | |
cache_examples=False, | |
) | |
# Launch the Gradio app | |
demo.launch(share=True, server_name="0.0.0.0") |