Spaces:
Runtime error
Runtime error
| import gradio as gr | |
| import json | |
| import os | |
| import tempfile | |
| import shutil | |
| import zipfile | |
| from relatively_constant_variables import finished_product_demo, all_states | |
| 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 | |
| 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', new_states=all_states): | |
| global all_states | |
| game_session = GameSession(starting_location, starting_state) | |
| description, choices, game_log = game_session.get_current_state_info() | |
| all_states = new_states | |
| 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 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.") | |
| 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, gr.update(value=custom_config), None, None | |
| except Exception as e: | |
| error_message = f"Error loading custom configuration: {str(e)}" | |
| return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None | |
| def load_game_edit_version(custom_config=None, with_media=False, custom_starting_location=None, custom_starting_state=None): | |
| 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 | |
| if custom_starting_location and custom_starting_state: | |
| if custom_starting_location not in all_states or custom_starting_state not in all_states[custom_starting_location]: | |
| raise ValueError(f"Invalid custom starting point: {custom_starting_location}, {custom_starting_state}") | |
| starting_location = custom_starting_location | |
| starting_state = custom_starting_state | |
| else: | |
| 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: | |
| 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, gr.update(value=custom_config), None, None | |
| except Exception as e: | |
| error_message = f"Error loading custom configuration: {str(e)}" | |
| return gr.update(value=error_message), None, None, None, gr.update(value=custom_config), None, None | |
| media_folder = os.path.abspath("saved_media") #make sure same as SAVE_DIR below | |
| def export_config_with_media(config_json): | |
| global media_folder | |
| """ | |
| Export the config JSON and zip it along with any files referenced in the media fields. | |
| :param config_json: JSON string containing the config | |
| :param media_folder: Path to the folder containing media files | |
| :return: Path to the created zip file | |
| """ | |
| # Parse the JSON | |
| config = json.loads(config_json) | |
| # Create a temporary directory to store files for zipping | |
| with tempfile.TemporaryDirectory() as temp_dir: | |
| # Save the config JSON to the temp directory | |
| config_path = os.path.join(temp_dir, 'config.json') | |
| with open(config_path, 'w') as f: | |
| json.dump(config, f, indent=2) | |
| # Collect all media files | |
| media_files = set() | |
| for location in config.values(): | |
| if isinstance(location, dict): | |
| for sublocation in location.values(): | |
| if isinstance(sublocation, dict) and 'media' in sublocation: | |
| media_files.update(sublocation['media']) | |
| # Copy media files to the temp directory | |
| for media_file in media_files: | |
| src_path = os.path.join(media_folder, media_file) | |
| if os.path.exists(src_path): | |
| dst_path = os.path.join(temp_dir, media_file) | |
| shutil.copy2(src_path, dst_path) | |
| else: | |
| print(f"Warning: Media file not found: {media_file}") | |
| # Create a zip file | |
| zip_path = os.path.join(os.path.dirname(media_folder), 'config_with_media.zip') | |
| with zipfile.ZipFile(zip_path, 'w') as zipf: | |
| for root, _, files in os.walk(temp_dir): | |
| for file in files: | |
| file_path = os.path.join(root, file) | |
| arcname = os.path.relpath(file_path, temp_dir) | |
| zipf.write(file_path, arcname) | |
| return zip_path | |
| 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)}""" | |
| def display_website(link): | |
| html = f"<iframe src='{link}' width='100%' height='1000px'></iframe>" | |
| gr.Info("If 404 then the space/page has probably been disabled - normally due to a better alternative") | |
| return html | |
| initgameinfo = start_game() | |
| fpeinitgameinfo = start_game(new_states=finished_product_demo) |