import gradio as gr import json import os import google.generativeai as genai testgeminiapi = os.getenv("testgemini") genai.configure(api_key=testgeminiapi) configcomptestexample = { "village": { "start": { "description": "You wake up in a small village. You hear a rumor about a lost treasure.", "choices": [ "explore village", "gather supplies", "rest" ], "transitions": { "explore village": "village_rumor", "gather supplies": "village_supplies", "rest": "village_start" }, "consequences": { "gather supplies": {} }, "media": [] }, "rumor": { "description": "You hear more details about the treasure hidden in the ancient ruins nearby.", "choices": [ "decide to go", "ignore" ], "transitions": { "decide to go": "village_supplies", "ignore": "village_start" }, "consequences": { "decide to go": {} }, "media": [] }, "supplies": { "description": "You gather supplies for your journey.", "choices": [ "head to forest", "stay in village" ], "transitions": { "head to forest": "forest_forest", "stay in village": "village_start" }, "media": [] } }, "forest": { "forest": { "description": "You enter the dense forest, heading towards the ruins.", "choices": [ "travel further", "return to village" ], "transitions": { "travel further": "ruins_ruins", "return to village": "village_start" }, "media": [] } }, "ruins": { "ruins": { "description": "You reach the ancient ruins. The entrance is dark and eerie.", "choices": [ "enter ruins", "return to forest" ], "transitions": { "enter ruins": "ruins_explore", "return to forest": "forest_forest" }, "media": [] }, "explore": { "description": "You explore the ruins, encountering traps and puzzles.", "choices": [ "solve puzzle", "avoid traps" ], "transitions": { "solve puzzle": "ruins_hiddenPassage", "avoid traps": "ruins_ruins" }, "media": [] }, "hiddenPassage": { "description": "You solve a challenging puzzle and unlock a hidden passage.", "choices": [ "enter passage", "go back" ], "transitions": { "enter passage": "ruins_treasureRoom", "go back": "ruins_explore" }, "media": [] }, "treasureRoom": { "description": "You enter the treasure room and find the treasure chest.", "choices": [ "take treasure", "leave" ], "transitions": { "take treasure": "ruins_celebrate", "leave": "ruins_ruins" }, "consequences": { "take treasure": {} }, "media": [] }, "celebrate": { "description": "You celebrate your discovery and decide to bring the treasure back to the village.", "choices": [ "return to village" ], "transitions": { "return to village": "village_return" }, "media": [] } }, "village_return": { "village_return": { "description": "You return to the village with the treasure and share it with the villagers.", "choices": [ "end adventure" ], "transitions": { "end adventure": "end_end" }, "media": [] } }, "end": { "end": { "description": "Your adventure ends here. The villagers are grateful and everyone's lives improve.", "choices": [], "transitions": {}, "media": [] } } } #------ # Create the model generation_config = { "temperature": 1, "top_p": 0.95, "top_k": 64, "max_output_tokens": 8192, "response_mime_type": "text/plain", } modelpro = genai.GenerativeModel( model_name="gemini-1.5-pro", generation_config=generation_config, # safety_settings = Adjust safety settings # See https://ai.google.dev/gemini-api/docs/safety-settings ) modelflash = genai.GenerativeModel( model_name="gemini-1.5-flash", generation_config=generation_config, # safety_settings = Adjust safety settings # See https://ai.google.dev/gemini-api/docs/safety-settings ) def geminiproinferenceinstance(text): global modelpro chat_session = modelpro.start_chat( history=[ ] ) #response = chat_session.send_message(f"NBNB property name must be enclosed in double quotes. Use this as inspiration to make a pirate story aka keep same format to work with an existing app: /n/n{configcomptestexample} ") response = chat_session.send_message(text) return response.text #print(response.text) def geminiflashinferenceinstance(text): global modelflash chat_session = modelflash.start_chat( history=[ ] ) #response = chat_session.send_message(f"NBNB property name must be enclosed in double quotes. Use this as inspiration to make a pirate story aka keep same format to work with an existing app: /n/n{configcomptestexample} ") response = chat_session.send_message(text) return response.text #print(response.text def brainstormconsiderations(text): Finaloutput = geminiproinferenceinstance(text) return Finaloutput def generateconfig(text): Finaloutput = geminiproinferenceinstance(f"NBNB property name must be enclosed in double quotes. Use this as inspiration to make a {text} (user requested) based story aka keep same format to work with an existing app: /n/n{configcomptestexample} ") return Finaloutput def debugsuggestions(text): Finaloutput = geminiproinferenceinstance(text) return Finaloutput #----- # Define the states all_states = { 'village': { 'start': { "description": "You wake up in a small village. You hear a rumor about a lost treasure.", "choices": ['explore village', 'gather supplies', 'rest'], "transitions": {'explore village': 'village_rumor', 'gather supplies': 'village_supplies', 'rest': 'village_start'}, "consequences": { 'gather supplies': lambda player: player.add_item('basic supplies') }, "media": [] }, 'rumor': { "description": "You hear more details about the treasure hidden in the ancient ruins nearby.", "choices": ['decide to go', 'ignore'], "transitions": {'decide to go': 'village_supplies', 'ignore': 'village_start'}, "consequences": { 'decide to go': lambda player: player.update_knowledge('treasure location') }, "media": [] }, 'supplies': { "description": "You gather supplies for your journey.", "choices": ['head to forest', 'stay in village'], "transitions": {'head to forest': 'forest_forest', 'stay in village': 'village_start'}, "media": [] }, }, 'forest': { 'forest': { "description": "You enter the dense forest, heading towards the ruins.", "choices": ['travel further', 'return to village'], "transitions": {'travel further': 'ruins_ruins', 'return to village': 'village_start'}, "media": [] }, }, 'ruins': { 'ruins': { "description": "You reach the ancient ruins. The entrance is dark and eerie.", "choices": ['enter ruins', 'return to forest'], "transitions": {'enter ruins': 'ruins_explore', 'return to forest': 'forest_forest'}, "media": [] }, 'explore': { "description": "You explore the ruins, encountering traps and puzzles.", "choices": ['solve puzzle', 'avoid traps'], "transitions": {'solve puzzle': 'ruins_hiddenPassage', 'avoid traps': 'ruins_ruins'}, "media": [] }, 'hiddenPassage': { "description": "You solve a challenging puzzle and unlock a hidden passage.", "choices": ['enter passage', 'go back'], "transitions": {'enter passage': 'ruins_treasureRoom', 'go back': 'ruins_explore'}, "media": [] }, 'treasureRoom': { "description": "You enter the treasure room and find the treasure chest.", "choices": ['take treasure', 'leave'], "transitions": {'take treasure': 'ruins_celebrate', 'leave': 'ruins_ruins'}, "consequences": { 'take treasure': lambda player: player.add_item('treasure') }, "media": [] }, 'celebrate': { "description": "You celebrate your discovery and decide to bring the treasure back to the village.", "choices": ['return to village'], "transitions": {'return to village': 'village_return'}, "media": [] }, }, 'village_return': { 'village_return': { "description": "You return to the village with the treasure and share it with the villagers.", "choices": ['end adventure'], "transitions": {'end adventure': 'end_end'}, "media": [] }, }, 'end': { 'end': { "description": "Your adventure ends here. The villagers are grateful and everyone's lives improve.", "choices": [], "transitions": {}, "media": [] }, } } class Player: def __init__(self): self.inventory = [] self.money = 20 self.knowledge = {} def add_item(self, item): self.inventory.append(item) def has_item(self, item): return item in self.inventory def update_knowledge(self, topic): self.knowledge[topic] = True #importing all_states from relatively_constant_variables def validate_transitions(all_states): errors = [] for location, states in all_states.items(): for state_key, state in states.items(): for transition_key, transition_state in state['transitions'].items(): # Check if the transition is to another location if transition_state in all_states: trans_location, trans_state = transition_state, 'start' # Assuming 'start' state for new locations elif '_' in transition_state: trans_location, trans_state = transition_state.split('_') else: trans_location, trans_state = location, transition_state # Validate the transition state if trans_location not in all_states or trans_state not in all_states[trans_location]: errors.append(f"Invalid transition from {location}.{state_key} to {trans_location}.{trans_state}") return errors path_errors = validate_transitions(all_states) if path_errors: for error in path_errors: print(error) else: print("All transitions are valid.") class GameSession: def __init__(self, starting_location='village', starting_state='start'): self.player = Player() self.current_location = starting_location self.current_state = starting_state self.game_log = [] def make_choice(self, choice_index): state = all_states[self.current_location][self.current_state] if 0 <= choice_index < len(state['choices']): choice = state['choices'][choice_index] next_state = state['transitions'][choice] self.game_log.append(f"You chose: {choice}") self.game_log.append(state['description']) if 'consequences' in state and choice in state['consequences']: if state['consequences'][choice]: state['consequences'][choice](self.player) else: # Handle empty consequence, e.g., log a message or provide a default action print(f"No consequence for choice: {choice}") # You can add any default action here if needed if '_' in next_state: self.current_location, self.current_state = next_state.split('_') else: self.current_state = next_state return self.get_current_state_info() else: return "Invalid choice. Please try again." def get_current_state_info(self): state = all_states[self.current_location][self.current_state] choices = [f"{idx + 1}. {choice}" for idx, choice in enumerate(state['choices'])] return state['description'], choices, "\n".join(self.game_log) def get_current_state_media(self): media = all_states[self.current_location][self.current_state]['media'] return media def start_game(starting_location='village', starting_state='start'): game_session = GameSession(starting_location, starting_state) description, choices, game_log = game_session.get_current_state_info() return description, choices, game_log, game_session def make_choice(choice, game_session, with_media=False): #Calls the nested make choice function in the game session class if not choice: description, choices, game_log = game_session.get_current_state_info() return description, choices, "Please select a choice before proceeding.", game_session choice_index = int(choice.split('.')[0]) - 1 result = game_session.make_choice(choice_index) if with_media: media = game_session.get_current_state_media() return result[0], gr.update(choices=result[1]), result[2], game_session, media else: return result[0], gr.update(choices=result[1]), result[2], game_session def load_game(custom_config=None, with_media=False): global all_states if not custom_config: return gr.update(value="No custom configuration provided."), None, None, None, None, None, None try: new_config = json.loads(custom_config) all_states = new_config # Determine the starting location and state starting_location = next(iter(all_states.keys())) starting_state = next(iter(all_states[starting_location].keys())) print(f"Starting location: {starting_location}, Starting state: {starting_state}") game_session = GameSession(starting_location, starting_state) description, choices, game_log = game_session.get_current_state_info() new_path_errors = validate_transitions(all_states) output_media = [] if with_media: media_list = all_states[starting_location][starting_state].get('media', []) print(f"Media list: {media_list}") if media_list: for media_path in media_list: #media_component = create_media_component(media_path) output_media.append(media_path) print(f"Created {len(output_media)} media components") success_message = f"Custom configuration loaded successfully!\n{new_path_errors}" return ( gr.update(value=success_message), game_log, description, gr.update(choices=choices), gr.update(value=custom_config), game_session, output_media if with_media else None ) except json.JSONDecodeError as e: error_message = format_json_error(custom_config, e) return gr.update(value=error_message), None, None, None, None, gr.update(value=custom_config), None except Exception as e: error_message = f"Error loading custom configuration: {str(e)}" return gr.update(value=error_message), None, None, None, None, gr.update(value=custom_config), None def format_json_error(config, error): lineno, colno = error.lineno, error.colno lines = config.split('\n') error_line = lines[lineno - 1] if lineno <= len(lines) else "" pointer = ' ' * (colno - 1) + '^' return f"""Invalid JSON format in custom configuration: Error at line {lineno}, column {colno}: {error_line} {pointer} Error details: {str(error)}""" initgameinfo = start_game() with gr.Blocks() as geminiapidemo: with gr.Tab("Generate and Debug"): gr.HTML("The user wants ") with gr.Accordion("Gemini Config", open=False): gr.Interface(brainstormconsiderations, inputs=["text"], outputs=["text"], description="some considerations for generated config") gr.Interface(generateconfig, inputs=["text"], outputs=["text"], description=" generated config") gr.Interface(debugsuggestions, inputs=["text"], outputs=["text"], description="debug generated config ") gr.Interface(geminiflashinferenceinstance, inputs=["text"], outputs=["text"], description="flash test") with gr.Tab("Manual - Config With Assets"): gr.HTML("Placeholder as not complete yet (3D not supported, and time (esp need for audio)") with gr.Row(): with gr.Column(scale=2): gr.Markdown("# Text-based Adventure Game") wadescription = gr.Textbox(label="Current Situation", lines=4, value=initgameinfo[0]) wamediabool = gr.State(value=True) wamedia = gr.State(["testmedia/Stable Audio - Raindrops, output.wav"]) @gr.render(inputs=wamedia) def dynamic_with_media(media_items): print(media_items) with gr.Group() as wamediagrouping: gr.HTML("Placeholder to load all media tests - still need to test clearing media on ") if media_items == []: gr.Markdown("No media items to display.") else: for item in media_items: render = create_media_component(item) return wamediagrouping wachoices = gr.Radio(label="Your Choices", choices=initgameinfo[1]) wasubmit_btn = gr.Button("Make Choice") wagame_log = gr.Textbox(label="Game Log", lines=20, value=initgameinfo[2]) wagame_session = gr.State(value=initgameinfo[3]) wasubmit_btn.click( make_choice, inputs=[wachoices, wagame_session, wamediabool], outputs=[wadescription, wachoices, wagame_log, wagame_session, wamedia] ) with gr.Column(scale=1): gr.Markdown("# Debugging") waerror_box = gr.Textbox(label="Path Errors", lines=4, value=path_errors) with gr.Accordion("Config (Game Spoiler and Example for llm to remix)", open=False): wacustom_config = gr.Textbox(label="Custom Configuration (JSON)", value=json.dumps(all_states, default=lambda o: o.__dict__, indent=2), lines=8) wacustom_configbtn = gr.Button("Load Custom Config") wacustom_configbtn.click( load_game, inputs=[wacustom_config, wamediabool], outputs=[waerror_box, wagame_log, wadescription, wachoices, wacustom_config, wagame_session, wamedia] ) geminiapidemo.queue().launch()