| import gradio as gr |
| import re |
|
|
| from create_world.creator_gradio import create_custom_world, create_scenario, create_storyline |
| from create_world.utils import load_txt |
| from create_character.gradio import generate_character_creation_questions, create_character_profile, parse_character_data_to_json |
| from play_game.main import create_initial_conversation, create_round_description, create_round_result, create_bad_ending, create_good_ending, convert_to_image_prompt, generate_image |
| from play_game.formatter import player_profile_to_str, to_round_result |
|
|
| |
| |
| |
|
|
| def main(): |
| with gr.Blocks() as demo: |
| gr.Markdown("## LRPG") |
| game_topic = gr.State() |
| world_summary = gr.State() |
| stories = gr.State([]) |
| player_profile = gr.State() |
| |
| with gr.Tab("κ²μ μΈκ³ μμ±"): |
| theme_choices = gr.Radio(["Harry Potter", "μ§μ μμ±"], label="ν
λ§ μ ν", info="κ²μμ ν
λ§λ₯Ό μ ννμΈμ.") |
| |
| @gr.render(inputs=[theme_choices]) |
| def on_world_choices(theme): |
| if theme == "μ§μ μμ±": |
| topic = gr.Textbox("ex)λ§λ²μ¬ μΈκ³, μ°μ£Ό μ μ", label="μ£Όμ ", info="μΈκ³μ μ£Όμ λ₯Ό μλ €μ£ΌμΈμ.", interactive=True) |
| world_story = gr.Textbox(label="μ€λͺ
", info="ꡬ체μ μΈ μΈκ³κ΄ μ€λͺ
κ³Ό λ£°μ μκ°νμΈμ", interactive=True) |
| world_create_btn = gr.Button("μΈκ³κ΄ μλ μμ±") |
| create_story_btn = gr.Button("μ€ν 리 μμ±", visible=False) |
| result = gr.Markdown("## μ€ν 리 μμ±μ΄ μλ£λμμ΅λλ€. μΊλ¦ν° μμ± νμΌλ‘ μ΄λν΄μ£ΌμΈμ.", visible=False) |
| |
| |
| def click_world_create_btn(topic, world_story): |
| gr.Info("μΈκ³κ΄ μμ±μ€μ
λλ€...") |
| topic, summary = create_custom_world(topic, world_story) |
| gr.Info("μΈκ³κ΄ μμ± μλ£!") |
| return { game_topic: topic, world_summary: summary, create_story_btn: gr.Button(visible=True) } |
| world_create_btn.click(fn=click_world_create_btn, inputs=[ topic, world_story ], outputs=[ game_topic, world_summary, create_story_btn ]) |
|
|
| |
| def click_create_story_btn(topic, summary): |
| gr.Info("μ€ν 리 μμ±μ€μ
λλ€...") |
| scenario = create_scenario(topic, summary, output_count=1, save=False) |
| _stories = create_storyline(topic, scenario[0], save=False) |
| gr.Info("μ€ν 리 μμ± μλ£!") |
| return { stories: _stories, result: gr.Markdown(visible=True) } |
| create_story_btn.click(fn=click_create_story_btn, inputs=[ game_topic, world_summary ], outputs= [ stories, result ]) |
|
|
| elif theme == "Harry Potter": |
| create_story_btn = gr.Button("μ€ν 리 μμ±") |
| result = gr.Markdown("## μ€ν 리 μμ±μ΄ μλ£λμμ΅λλ€. μΊλ¦ν° μμ± νμΌλ‘ μ΄λν΄μ£ΌμΈμ.", visible=False) |
| def click_create_story_btn(): |
| gr.Info("μ€ν 리 μμ±μ€μ
λλ€...") |
| topic = "Harry Potter" |
| _world_summary = load_txt("harrypotter_scenario/world_summary.txt") |
| scenario = create_scenario(topic, _world_summary, output_count=1, save=False) |
| _stories = create_storyline(topic, scenario[0], save=False) |
| gr.Info("μ€ν 리 μμ± μλ£!") |
| return { game_topic: topic, world_summary: _world_summary, stories: _stories, result: gr.Markdown(visible=True) } |
| create_story_btn.click(fn=click_create_story_btn, outputs=[ game_topic, world_summary, stories, result ]) |
|
|
| with gr.Tab("μΊλ¦ν° μμ±"): |
| @gr.render(inputs=[world_summary]) |
| def on_game_topic(summary): |
| questions = generate_character_creation_questions(summary) |
| answers = [] |
| for question_idx, question in enumerate(questions): |
| answer = gr.Textbox(key=question_idx, label=question, placeholder="λΉμ μ λλ΅μ μ
λ ₯νμΈμ.", interactive=True) |
| answers.append(answer) |
| char_create_btn = gr.Button("μΊλ¦ν° μμ±") |
| result = gr.Markdown("## μΊλ¦ν° μμ±μ΄ μλ£λμμ΅λλ€. κ²μ μ§ν νμΌλ‘ μ΄λν΄μ£ΌμΈμ.", visible=False) |
|
|
| def click_char_create_btn(*_answers): |
| gr.Info("μΊλ¦ν° μμ±μ€μ
λλ€...") |
| character_profile = parse_character_data_to_json(create_character_profile(questions, _answers)) |
| profile_keys = [key for key in character_profile.keys()] |
| required_keys = ["name", "gender", "age", "race", "job", "background"] |
| params_keys = [key for key in character_profile["params"].keys()] |
| required_params_keys = ["stamina", "intelligence", "combat_power", "agility"] |
| if not all(item in profile_keys for item in required_keys) or not all(item in params_keys for item in required_params_keys): |
| gr.Error("μΊλ¦ν° μμ±μ μ€ν¨νμ΅λλ€. νλͺ©λ€μ μμΈνκ² λΉ μ§μμ΄ κΈ°μ
ν΄μ£ΌμΈμ.") |
| return |
| gr.Info("μΊλ¦ν° μμ± μλ£!") |
| return { player_profile: character_profile, result: gr.Markdown(visible=True) } |
| char_create_btn.click(fn=click_char_create_btn, inputs=answers, outputs=[player_profile, result]) |
| |
|
|
| with gr.Tab("κ²μ νλ μ΄"): |
| round = gr.State(0) |
| player_restriction = gr.State() |
| player_capability = gr.State() |
| previous_conversation = gr.State("") |
| previous_round_result = gr.State("") |
|
|
| @gr.render(inputs=[world_summary, stories, player_profile, round, player_restriction, player_capability, previous_conversation, previous_round_result, game_topic], triggers=[round.change, player_profile.change]) |
| def on_round(_world_summary, _stories, _player_profile, _round, _player_restriction, _player_capability, _previous_conversation, _previous_round_result, _game_topic): |
| entire_story = [f"{idx+1}. {scenario['title']}\n{scenario['story']}\n\n" for idx, scenario in enumerate(_stories)] |
| player_profile_str = player_profile_to_str({ **_player_profile, 'params': _player_capability }) |
|
|
| round_scenario = _stories[_round-1] |
| if _round == 0: |
| introduction = gr.Markdown(create_initial_conversation(_world_summary, player_profile_str, _player_restriction, _player_capability, entire_story)) |
| game_start_btn = gr.Button("κ²μ μμ") |
| |
| def click_game_start_btn(): |
| return { round: 1, player_restriction: { "life": 20, "money": 20 }, player_capability: _player_profile["params"] } |
| game_start_btn.click(fn=click_game_start_btn, outputs=[round, player_restriction, player_capability]) |
| else: |
| round_story = f"{_round}. {round_scenario['title']}: {round_scenario['story']}\n" |
| if _player_restriction["life"] <= 0 or _player_restriction["money"] <= 0: |
| gr.Markdown("## μμ½κ²λ κ²μ μ€λ²λμμ΅λλ€. λ€λ₯Έ μ νμ ν΅ν΄ μλ‘μ΄ μ΄μΌκΈ°μ κ²°λ§μ λ§λ€μ΄λ³΄μΈμ.") |
| bad_ending = create_bad_ending(_world_summary, player_profile_str, _player_restriction, _player_capability, entire_story, round_story, _previous_conversation, _previous_round_result) |
| display_bad_ending = gr.Markdown(bad_ending) |
| restart_button = gr.Button("λ€μ μμνκΈ°") |
| def click_restart_button(): |
| return { round: 0, player_restriction: {}, player_capability: {}, previous_conversation: "", previous_round_result: "" } |
| restart_button.click(fn=click_restart_button, outputs=[round, player_restriction, player_capability, previous_conversation, previous_round_result]) |
| |
| elif _round > len(_stories): |
| gr.Markdown("## μΆνν©λλ€! κ²μ ν΄λ¦¬μ΄μ μ±κ³΅νμ
¨μ΅λλ€") |
| good_ending = create_good_ending(_world_summary, player_profile_str, _player_restriction, _player_capability, entire_story, _previous_conversation) |
| display_good_ending = gr.Markdown(good_ending) |
| restart_button = gr.Button("λ€μ μμνκΈ°") |
| def click_restart_button(): |
| return { round: 0, player_restriction: {}, player_capability: {}, previous_conversation: "", previous_round_result: "" } |
| restart_button.click(fn=click_restart_button, outputs=[round, player_restriction, player_capability, previous_conversation, previous_round_result]) |
|
|
| else: |
| round_description = create_round_description(_world_summary, player_profile_str, _player_restriction, _player_capability, entire_story, round_story, _previous_conversation, _previous_round_result) |
| gr.Markdown(f"## {_round}. {round_scenario['title']}") |
| with gr.Row(): |
| gr.Markdown(round_description) |
| with gr.Column(): |
| image_output = gr.Image(interactive=False, scale=5) |
| generate_image_btn = gr.Button("μ΄λ―Έμ§ μμ±") |
| def click_generate_image_btn(): |
| gr.Info("μ΄λ―Έμ§ μμ±μ€μ
λλ€...") |
| image_generation_prompt = convert_to_image_prompt(_game_topic, _world_summary, _player_profile, round_description) |
| image_url = generate_image(image_generation_prompt) |
| gr.Info("μ΄λ―Έμ§ μμ± μλ£!") |
| return gr.Image(image_url) |
| generate_image_btn.click(fn=click_generate_image_btn, outputs=image_output) |
| |
| with gr.Row(): |
| player_response = gr.Textbox(label="λΉμ λ§μ κ²°μ μ λ΄λ €μ£ΌμΈμ!", info="νλμ λ¬Έμ₯μΌλ‘ λΉμ μ΄ ν νλκ³Ό κ·Έμ λν κ·Όκ±°μ μ΄μ λ₯Ό λͺ
ννκ² μ€λͺ
ν΄μ£ΌμΈμ", interactive=True, scale=10) |
| submit_btn = gr.Button("κ²°μ ", scale=1) |
|
|
| def click_submit_btn(_player_response, _previous_conversation, _player_restriction, _player_capability): |
| gr.Info("κ²°μ μ λ°μμ€μ
λλ€...") |
| __round = _round |
| _round_description = round_description |
|
|
| |
| round_result = create_round_result(_world_summary, player_profile_str, _player_restriction, _player_capability, _round_description, _player_response) |
| round_effect = round_result["effect"] |
| round_result_explanation = round_result["reason"] |
| for key, value in round_effect["player_restriction"].items(): |
| if _player_restriction.get(key) is not None: |
| modified_value = _player_restriction[key] + value |
| if modified_value > 10: |
| _player_restriction[key] = 10 |
| elif modified_value < -10: |
| _player_restriction[key] = -10 |
| else: |
| _player_restriction[key] = modified_value |
|
|
| for key, value in round_effect["player_capability"].items(): |
| if _player_capability.get(key) is not None: |
| modified_value = _player_capability[key] + value |
| if modified_value > 100: |
| _player_capability[key] = 100 |
| elif modified_value < -100: |
| _player_capability[key] = -100 |
| else: |
| _player_capability[key] = modified_value |
|
|
| return { |
| round: __round+1, |
| previous_conversation: _previous_conversation + f"Game Master: {_round_description}\nPlayer: {_player_response}\n", |
| previous_round_result: to_round_result(round_effect, round_result_explanation), |
| player_restriction: _player_restriction, |
| player_capability: _player_capability, |
| } |
| submit_btn.click( |
| fn=click_submit_btn, |
| inputs=[ player_response, previous_conversation, player_restriction, player_capability ], |
| outputs=[round, previous_conversation, previous_round_result, player_restriction, player_capability] |
| ) |
|
|
| player_name = re.sub(r'"', '', _player_profile['name']) |
| player_status_display = gr.Markdown(f"## {player_name}λμ μν") |
| with gr.Group(): |
| with gr.Row(): |
| gr.Textbox(_player_restriction['life'], interactive=False, label="λͺ©μ¨") |
| gr.Textbox(_player_restriction['money'], interactive=False, label="μμ§κΈ") |
| with gr.Row(): |
| gr.Textbox(_player_capability["stamina"], interactive=False, label="μ€νλ―Έλ") |
| gr.Textbox(_player_capability["intelligence"], interactive=False, label="μ§λ₯") |
| gr.Textbox(_player_capability["combat_power"], interactive=False, label="μ ν¬λ ₯") |
| gr.Textbox(_player_capability["agility"], interactive=False, label="민첩μ±") |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| demo.launch(share=True) |
|
|
|
|
| if __name__ == "__main__": |
| main() |