parley / app.py
jonpreamble's picture
Fix random.choice only being run once per reboot
9ad6c07
raw
history blame
7.33 kB
# formatted with python black, line length 200
import os, random
import openai
import gradio as gr
from game_content import INITIAL_WELCOME_TEXT
from game_content import GAME_INTRO_CHOICES, NOTES_TO_THE_NARRATOR_AT_START, AWAITING_INPUT, NOTES_TO_THE_NARRATOR_EVERY_TIME
from game_content import game_over_victory_txt, game_over_fail_txt, S_GAME_OVER
from game_content import N_TURNS_REQUIRED_TO_PASS_FIRST_BANDIT_ENCOUNTER, N_TURNS_REQUIRED_TO_REACH_HOME
import decider_utils
from decider_utils import YES, NO
from decider_questions import * # QUESTION_IS_USER_HOME, QUESTION_IS_USER_ENGAGED_WITH_BANDITS, etc.
from webpage import PAGE_STYLING_JS, PLEASE_BE_PATIENT_DIV, TOP_OF_SCREEN_PADDING_DIV
N_COMPLETIONS_WHEN_ELABORATING = 1 # I previously had this set to 3, but that made the program very slow.
MINIMUM_COMPLETION_LENGTH_CHARS_WHEN_ELABORATING = 7
def elaborate(
str_beginning,
prevent_user_from_reaching_home=True,
require_user_to_be_still_engaged_with_bandits=False,
):
longest_completion = ""
while len(longest_completion) < MINIMUM_COMPLETION_LENGTH_CHARS_WHEN_ELABORATING:
completions = openai.Completion.create(
engine="text-davinci-003",
prompt=str_beginning,
temperature=0.5,
max_tokens=4000 - int(len(str_beginning) / 4),
frequency_penalty=0.5,
presence_penalty=0.5,
n=N_COMPLETIONS_WHEN_ELABORATING,
)["choices"]
for i in range(0, N_COMPLETIONS_WHEN_ELABORATING):
completion = completions[i]["text"]
# debug_print(completion)
allowed = True
if prevent_user_from_reaching_home:
does_the_user_reach_home = decider_utils.yesno(QUESTION_IS_USER_HOME, str_beginning + completion, default=YES)
allowed = not does_the_user_reach_home
if require_user_to_be_still_engaged_with_bandits:
is_user_engaged_with_bandits = decider_utils.yesno(
QUESTION_IS_USER_ENGAGED_WITH_BANDITS,
str_beginning + completion,
default=YES,
)
allowed = allowed and is_user_engaged_with_bandits
if allowed and len(completion) > len(longest_completion):
longest_completion = completion
return str_beginning + longest_completion
def run_1_game_turn(s_narr_transcript, s_n_turns_elapsed, s_user_transcript, s_user_input):
n_turns_elapsed = int(s_n_turns_elapsed)
finally_add2_both_tscripts = ""
if n_turns_elapsed == 0 and s_narr_transcript == "":
# New game.
# I learned the hard way that we have to do the random choice thing from within the game code;
# because if we just put it inside the "with demo:" block,
# then the gradio server only runs the random choice once per reboot.
game_intro = random.choice(GAME_INTRO_CHOICES)
s_narr_transcript = game_intro + NOTES_TO_THE_NARRATOR_AT_START
s_user_transcript = game_intro
elif s_user_input == "":
s_user_transcript += "You must choose an action.\n"
elif S_GAME_OVER in s_narr_transcript:
s_user_transcript += "Sorry, the game is already over. To play again, please refresh the page.\n"
elif decider_utils.yesno(QUESTION_IS_ACTION_LIKELY_LETHAL, s_user_input, default=NO):
finally_add2_both_tscripts += game_over_fail_txt("You have taken an action that is likely to result in killing someone.")
elif decider_utils.yesno(QUESTION_IS_USER_ENGAGED_WITH_BANDITS, s_narr_transcript, default=NO) and decider_utils.yesno(QUESTION_IS_ACTION_RUNNING_AWAY, s_user_input, default=NO):
finally_add2_both_tscripts += "Invalid entry. You cannot outrun these bandits.\n"
elif decider_utils.yesno(QUESTION_IS_ACTION_MAGIC, s_user_input, default=NO):
finally_add2_both_tscripts += "Invalid entry. You are not a spellcaster and have no magic items except your revolver.\n"
else:
# User input accepted.
n_turns_elapsed += 1
s_user_transcript += s_user_input + "\n"
s_narr_transcript += s_user_input + "\n"
s_narr_transcript += NOTES_TO_THE_NARRATOR_EVERY_TIME
s_new_narr_transcript = elaborate(
s_narr_transcript,
prevent_user_from_reaching_home=n_turns_elapsed < N_TURNS_REQUIRED_TO_REACH_HOME,
require_user_to_be_still_engaged_with_bandits=n_turns_elapsed < N_TURNS_REQUIRED_TO_PASS_FIRST_BANDIT_ENCOUNTER,
)
s_new_part = s_new_narr_transcript.replace(s_narr_transcript, "")
s_narr_transcript += s_new_part + "\n"
s_user_transcript += s_new_part + "\n"
did_user_kill = decider_utils.yesno(QUESTION_DID_PROTAGONIST_KILL, s_new_part, default=NO)
did_user_kill = did_user_kill or decider_utils.yesno(QUESTION_DID_PROTAGONIST_KILL, s_narr_transcript, default=NO)
if did_user_kill:
finally_add2_both_tscripts += game_over_fail_txt("You have taken a life.")
else:
is_user_home = decider_utils.yesno(QUESTION_IS_USER_HOME, s_narr_transcript, default=NO)
if is_user_home:
has_at_least_30_gold = decider_utils.yesno(QUESTION_DOES_USER_STILL_HAVE_AT_LEAST_30_GOLD, s_narr_transcript, default=NO)
if has_at_least_30_gold:
finally_add2_both_tscripts += game_over_victory_txt("You made it home with 30+ gold! Your family is grateful and you all hug in celebration.")
else:
finally_add2_both_tscripts += game_over_fail_txt("You reached home with less than 30 gold - too little for your family to live on.")
# End of code block User input accepted.
s_n_turns_elapsed = str(n_turns_elapsed)
s_user_input = ""
if S_GAME_OVER not in finally_add2_both_tscripts and S_GAME_OVER not in s_narr_transcript:
finally_add2_both_tscripts += AWAITING_INPUT
s_narr_transcript += finally_add2_both_tscripts
s_user_transcript += finally_add2_both_tscripts
return [s_narr_transcript, s_n_turns_elapsed, s_user_transcript, s_user_input]
openai.organization = os.environ.get("OPENAI_ORGANIZATION")
openai.api_key = os.environ.get("OPENAI_KEY")
demo = gr.Blocks()
with demo:
gr_top_of_scr_padding = gr.HTML(TOP_OF_SCREEN_PADDING_DIV)
gr_narr_transcript = gr.Textbox(label="", value="", interactive=False, max_lines=9999, visible=False)
gr_user_transcript = gr.Textbox(label="", value=INITIAL_WELCOME_TEXT, interactive=False, max_lines=9999, elem_classes="parleygame")
gr_pls_be_patient = gr.HTML(PLEASE_BE_PATIENT_DIV)
gr_user_input = gr.Textbox(label="", value="", placeholder="Describe your next action here...", interactive=True)
gr_button1 = gr.Button(value="Run Next Turn")
gr_n_turns_elapsed = gr.Textbox(label="N Turns Elapsed", value="0", interactive=False)
gr_button1.click(
fn=run_1_game_turn, inputs=[gr_narr_transcript, gr_n_turns_elapsed, gr_user_transcript, gr_user_input], outputs=[gr_narr_transcript, gr_n_turns_elapsed, gr_user_transcript, gr_user_input]
)
# See https://discuss.huggingface.co/t/gradio-html-component-with-javascript-code-dont-work/37316/2
demo.load(None, None, None, _js=PAGE_STYLING_JS)
demo.launch()