|
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() |