textgames / play_with_hf.py
fhudi's picture
Update play_with_hf.py
24463e1 verified
from __future__ import annotations
#%%
import os
# os.environ.setdefault("GRADIO_SERVER_PORT", "1080")
# os.environ.setdefault("TEXTGAMES_SHOW_HIDDEN_LEVEL", "1")
os.environ.setdefault("TEXTGAMES_LOADGAME_DIR", "problemsets")
os.environ.setdefault("TEXTGAMES_LOADGAME_ID", "42")
os.environ.setdefault("TEXTGAMES_MOCKUSER", "")
os.environ.setdefault("TEXTGAMES_OUTPUT_DIR", "user_outputs")
favicon_path = "textgames-scrabble-black2-ss.png"
#%%
from play_helper import css, declare_components, start_new_game, check_played_game, download_from_drive, upload_to_drive, _leaderboards
import pandas as pd
import gradio as gr
import random
import json
from textgames import GAME_NAMES
#%%
os.makedirs(os.getenv('TEXTGAMES_OUTPUT_DIR', '.'), exist_ok=True)
#%%
def generate_sid(fp):
rand_int = random.randint(0, 1000)
with open(fp, "w", encoding="utf8") as f:
f.write(f"session_{rand_int:04}\n")
upload_to_drive(fp, mime_type="text/plain", update=True)
#%%
def get_sid(uid, force_generate_sid=False):
fp = f"{os.getenv('TEXTGAMES_OUTPUT_DIR')}/{uid}_sid.txt"
if force_generate_sid:
generate_sid(fp)
if not os.path.exists(fp):
download_from_drive(fp, mime_type="text/plain", compare_checksum=False)
if not os.path.exists(fp):
generate_sid(fp)
with open(fp, "r", encoding="utf8") as f:
sid = [_ for _ in f][-1]
return sid.strip()
#%%
def greet(request: gr.OAuthProfile | None):
user = {'email': os.getenv('TEXTGAMES_MOCKUSER', ''), 'name': ""}
if request is not None:
user = {'email': request.username, 'name': request.name, 'sid': get_sid(request.username)}
return f"""
Welcome to TextGames, {user['name'] or 'please login'}!
""", user, user['email']
#%%
with gr.Blocks(title="TextGames", css=css, delete_cache=(3600, 3600)) as demo:
((m, logout_btn, solved_games_df, game_radio, level_radio, new_game_btn, render_toggle, reset_sid_btn),
(session_state, is_solved, solved_games, user_state, uid_state),
) = declare_components(demo, greet, use_login_button=True)
logout_btn.activate()
reset_sid_checkbox = gr.Checkbox(False, visible=False, interactive=False)
reset_sid_btn.click(
# lambda: [gr.update(interactive=False)]*2, None, [reset_sid_btn, new_game_btn]
# ).then(
lambda x: x, [reset_sid_checkbox], [reset_sid_checkbox],
js="(x) => confirm('Only your best session is recorded on the leaderboard. Are you sure you want to start from the beginning? (cannot be undone)')"
# ).then(
# lambda: [gr.update(interactive=True)]*2, None, [reset_sid_btn, new_game_btn]
)
def _resetting(confirmed, user):
uid = user.get('email', None) if isinstance(user, dict) else None
if not uid:
gr.Warning("You need to log in first!")
elif confirmed:
user['sid'] = get_sid(uid, force_generate_sid=True)
gr.Info("Successfully resets the game with new session. Enjoy the game! πŸ’ͺ")
return user, False
reset_sid_checkbox.change(
lambda: [gr.update(interactive=False)]*3, None, [logout_btn, reset_sid_btn, new_game_btn]
).then(
_resetting, [reset_sid_checkbox, user_state], [user_state, reset_sid_checkbox]
).then(
check_played_game, [user_state, solved_games, solved_games_df], [solved_games, solved_games_df]
).then(
lambda: [gr.update(interactive=True)]*3, None, [logout_btn, reset_sid_btn, new_game_btn]
)
@gr.render(inputs=[game_radio, level_radio, user_state, session_state, uid_state], triggers=[render_toggle.change])
def _start_new_game(game_name, level, user, _session_state, _uid_state):
if _session_state in [1, 2]:
start_new_game(game_name, level, session_state, is_solved, solved_games, user=user, uid=_uid_state)
#%%
with (demo.route("Leaderboards", "/leaderboards") as demo_leaderboard):
# gr.Markdown("Under Construction. Will be available soon.")
def reload_leaderboard():
ret_leaderboards = {}
def add_dummies():
return pd.DataFrame({
'User': ['dummy'],
'Solved': [sorted([g.split('\t', 1)[0] for g in GAME_NAMES])],
'Attempts': [888],
'Time': [8888.8888],
})
if not os.path.exists(_leaderboards):
for lv in ['1', '2', '3']:
ret_leaderboards[lv] = add_dummies()
else:
datas = []
with open(_leaderboards, "r", encoding="utf8") as f:
for line in f:
datas.append(json.loads(line))
concat = [{'Level': d['difficulty_level'], 'User': d['uid'], 'Session': d['sid'],
'Solved': d['game_name'].split('\t', 1)[0], 'Attempts': d['turns'], "Time": d['ed'] - d['st']
} for d in datas]
df_leaderboards_all = pd.DataFrame(concat)
def get_best(_cur_df):
def _per_session(_df):
best = _df.groupby("Solved").apply(
lambda _df: _df.sort_values(["Attempts", "Time"]).iloc[0]
).reset_index(drop=True)
ret = pd.DataFrame({
"Solved": [sorted(best.Solved.unique())], "Attempts": best.Attempts.sum(), "Time": best.Time.sum(),
})
return ret
flat = _cur_df.groupby("Session").apply(_per_session)
srt = flat.sort_values(["Solved", "Attempts", "Time"], key=lambda c: {
"Solved": lambda s: -s.apply(len),
}.get(c.name, lambda s: s)(c))
return srt.iloc[0]
for lv in ['1', '2', '3']:
cur_df = df_leaderboards_all.loc[df_leaderboards_all.Level.eq(lv)].groupby("User").apply(get_best)
ret_leaderboards[lv] = (cur_df.reset_index() if len(cur_df) else add_dummies()).rename({"Attempts": "Turns"}, axis=1)
return ret_leaderboards
df_leaderboards = {}
# for lv, tab_name in [('1', "πŸš… Easy"), ('2', "πŸš€ Medium"), ('3', "πŸ›Έ Hard")]:
with gr.Tab("πŸš… Easy") as tab1:
lb_df_1 = gr.DataFrame(label="Rankings", col_count=(4, 'fixed'), interactive=False, show_search='filter')
tab1.select(lambda: df_leaderboards['1'], None, [lb_df_1])
with gr.Tab("πŸš€ Medium") as tab2:
lb_df_2 = gr.DataFrame(label="Rankings", col_count=(4, 'fixed'), interactive=False, show_search='filter')
tab2.select(lambda: df_leaderboards['2'], None, [lb_df_2])
with gr.Tab("πŸ›Έ Hard") as tab3:
lb_df_3 = gr.DataFrame(label="Rankings", col_count=(4, 'fixed'), interactive=False, show_search='filter')
tab3.select(lambda: df_leaderboards['3'], None, [lb_df_3])
def onload(progress=gr.Progress()):
global df_leaderboards
df_leaderboards = reload_leaderboard()
return df_leaderboards['1']
demo_leaderboard.load(onload, None, [lb_df_1])
#%%
# demo.launch()
demo.launch(
favicon_path=favicon_path if os.path.exists(favicon_path) else None,
show_api=False, enable_monitoring=False, pwa=False,
)
#%%
#%%
#%%
#%%
#%%
#%%