pokemon-quiz / app.py
yoon-gu's picture
Update app.py
c0554b7
import os
import gradio as gr
import pandas as pd
import random
import json
import time
import wandb
from utils import Info
import logging
from typing import Optional
wandb.login(key=os.environ['WANDB_KEY'])
run = wandb.init(project="pokemon-quiz", entity="yoon-gu")
with open('pokemon.json', 'r') as f:
pokemons = json.load(f)
pokemons_types = sorted(set([t for poke in pokemons for t in poke['types']]))
df = pd.DataFrame(pokemons)
GEN_RANGE = {
"λͺ¨λ“  μ„ΈλŒ€": [1, 1017],
"1μ„ΈλŒ€": [1, 151],
"2μ„ΈλŒ€": [152, 251],
"3μ„ΈλŒ€": [252, 386],
"4μ„ΈλŒ€": [387, 493],
"5μ„ΈλŒ€": [494, 649],
"6μ„ΈλŒ€": [650, 721],
"7μ„ΈλŒ€": [722, 809],
"8μ„ΈλŒ€": [810, 905],
"9μ„ΈλŒ€": [906, 1017]
}
QUESTION_TEMPLATE = {"question": "λ‹€μŒ 포켓λͺ¬μ˜ 이름은 λ­˜κΉŒμš”?![]({img_url})", "answer": "{name}"}
def get_question_answer(pokemons_set, user):
chosen = random.choice(pokemons_set)
name = chosen['name']
image_path = chosen['image_path']
img_url = f"https://huggingface.co/spaces/yoon-gu/pokemon/resolve/main/{image_path}"
q = QUESTION_TEMPLATE["question"].format(img_url=img_url)
a = QUESTION_TEMPLATE['answer'].format(name=name)
candidates = random.choices([poke['name'] for poke in pokemons_set], k=3)
candidates.append(a)
random.shuffle(candidates)
infos[user].candidates = candidates
return q, a
initial_info = {"done" : True,
"score": 0, "count": 0,
"best_score": 0, "best_time": float("inf"),
"time": 0.0, "comment": "",
"history": [],
"candidates": ['1번', '2번', '3번', '4번']}
try:
folder = run.use_artifact("settings:latest").download()
with open(os.path.join(folder, "users.json"), "r") as f:
USERS = json.load(f)
with open(os.path.join(folder, "infos.json"), "r") as f:
infos = json.load(f)
for k, v in infos.items():
infos[k] = Info(**v)
except Exception as e:
logging.error(e)
USERS = ["κΉ€μ„œν˜„", "κΉ€μš°μ£Ό", "Anonymous"]
infos = {user: Info(name=user) for user in USERS}
MD = """# 포켓λͺ¬ ν€΄μ¦ˆ πŸ¦‘
## 곡뢀 방법 πŸ“š
μ•„λž˜ 포켓λͺ¬ 도감을 보고 κ³΅λΆ€ν•˜λ©΄ 도움이 λ©λ‹ˆλ‹€.
- https://huggingface.co/spaces/yoon-gu/pokemon
## μ‚¬μš©λ°©λ²• πŸ“–
1. μ‚¬μš©μžλ₯Ό μ„ νƒν•˜μ„Έμš”.
2. 총 ν€΄μ¦ˆ 개수λ₯Ό μ„ νƒν•˜μ„Έμš”.
3. 포켓λͺ¬ μ„ΈλŒ€λ₯Ό μ„ νƒν•˜μ„Έμš”.
4. 포켓λͺ¬ νƒ€μž…μ„ μ„ νƒν•˜μ„Έμš”.
## 점수판 πŸ“Š
"""
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
markdown = gr.Markdown(MD.format(content=''))
leader_board = gr.DataFrame(wrap=True, row_count=10)
with gr.Row():
gr.LoginButton()
gr.LogoutButton()
# user = gr.Dropdown(USERS, value="Anonymous", label="μ‚¬μš©μž", info="당신은 λˆ„κ΅¬μ‹ κ°€μš”?", allow_custom_value=True)
quiz_count = gr.Radio([10, 20, 30, 40, 50], value=10, label="총 ν€΄μ¦ˆ 개수", info="ν€΄μ¦ˆλ₯Ό λͺ‡ 개 ν’€ μ˜ˆμ •μΈκ°€μš”?")
with gr.Column():
with gr.Row():
with gr.Accordion("See Details", open=False):
generation = gr.CheckboxGroup(
[f"{k}μ„ΈλŒ€" for k in range(1, 10)],
value=[f"{k}μ„ΈλŒ€" for k in range(1, 10)],
label="포켓λͺ¬ μ„ΈλŒ€",
info="μ›ν•˜λŠ” 포켓λͺ¬ μ„ΈλŒ€λ₯Ό μ„ νƒν•˜μ„Έμš”."
)
poke_types = gr.CheckboxGroup(
pokemons_types, value=pokemons_types,
label="포켓λͺ¬ νƒ€μž…",
info="μ›ν•˜λŠ” 포켓λͺ¬ νƒ€μž…μ„ μ„ νƒν•˜μ„Έμš”."
)
with gr.Row():
play = gr.Button(value="ν€΄μ¦ˆ μ‹œμž‘", label="ν€΄μ¦ˆ μ‹œμž‘")
skip = gr.Button(value="문제 λ„˜μ–΄κ°€κΈ°", label="문제 μŠ€ν‚΅")
chatbot = gr.Chatbot(bubble_full_width=False,
height=600,
avatar_images=["https://huggingface.co/spaces/yoon-gu/pokemon/resolve/main/images/No_0001_이상해씨.png",
"https://huggingface.co/spaces/yoon-gu/pokemon/resolve/main/images/No_0155_λΈŒμΌ€μΈ.png"])
with gr.Row():
button1 = gr.Button(value="1번")
button2 = gr.Button(value="2번")
with gr.Row():
button3 = gr.Button(value="3번")
button4 = gr.Button(value="4번")
def respond(message, chat_history, quiz_count, gen, types, profile: Optional[gr.OAuthProfile]):
if profile:
user = profile.name
else:
raise gr.Error("μ‚¬μš©μž 이름을 μž…λ ₯ν•˜μ„Έμš”.")
message = message.strip()
done = infos[user].done
dfs = []
for g in gen:
start, end = GEN_RANGE[g]
dfs.append(df[start-1:end])
sdf = pd.concat(dfs)
pokemons_set = sdf[sdf['types'].apply(lambda x: any([t in x for t in types]))]
pokemons_set = pokemons_set.to_dict("records")
if done:
infos[user].history = []
if "ν€΄μ¦ˆμ‹œμž‘" == message.replace(" ", ""):
q, a = get_question_answer(pokemons_set, user)
bot_message = f"ν€΄μ¦ˆλ₯Ό μ‹œμž‘ν•©λ‹ˆλ‹€.\n{q}"
infos[user].answer = a
infos[user].done = False
infos[user].score = 0
infos[user].count = 0
infos[user].time = time.time()
infos[user].generations = gen
infos[user].types = types
else:
bot_message = "ν€΄μ¦ˆλ₯Ό μ‹œμž‘ν•˜κ³  μ‹ΆμœΌμ‹œλ©΄, **ν€΄μ¦ˆ μ‹œμž‘** λ²„νŠΌμ„ λˆ„λ₯΄μ„Έμš”."
else:
if infos[user].answer == message:
q, a = get_question_answer(pokemons_set, user)
infos[user].answer = a
infos[user].score += 10
infos[user].count += 1
bot_message = f"πŸŽ‰μ •λ‹΅μž…λ‹ˆλ‹€! λ‹€μŒ λ¬Έμ œμž…λ‹ˆλ‹€.\n{q}\n- ν˜„μž¬ 점수: {infos[user].score:3.1f}점\n- μ†Œμš” μ‹œκ°„: {time.time() - infos[user].time:4.3f}초"
elif "ν¬κΈ°ν•˜κΈ°" == message.replace(" ", ""):
bot_message = f"ν€΄μ¦ˆλ₯Ό κ°•μ œ μ’…λ£Œν•©λ‹ˆλ‹€."
infos[user].done = True
elif "문제 λ„˜μ–΄κ°€κΈ°" == message:
infos[user].count += 1
q, a = get_question_answer(pokemons_set, user)
infos[user].answer = a
bot_message = f"문제λ₯Ό λ„˜μ–΄κ°‘λ‹ˆλ‹€. λ‹€μŒλ¬Έμ œμž…λ‹ˆλ‹€.\n{q}"
else:
hint1 = ""
for i, y in enumerate(infos[user].answer):
if i < len(message):
if message[i] == y:
hint1 += y
else:
hint1 += "X"
else:
hint1 += "X"
bot_message = f"***{message}***!? 🧐 λ‹€μ‹œ ν•œλ²ˆ μƒκ°ν•΄λ³΄μ„Έμš”.\n힌트: {hint1}"
infos[user].score -= 1
# gr.Info(f"{user}λ‹˜, 총 {quiz_count}개 문제 쀑 {infos[user].count+1}번째 문제 진행 μ€‘μž…λ‹ˆλ‹€.")
if quiz_count == infos[user].count:
bot_message = f"λͺ¨λ“  ν€΄μ¦ˆλ₯Ό λ‹€ ν’€μ—ˆμŠ΅λ‹ˆλ‹€. μ μˆ˜λŠ” {infos[user].score:3.1f}점 μž…λ‹ˆλ‹€."
infos[user].done = True
if infos[user].score >= infos[user].best_score:
infos[user].best_score = infos[user].score
infos[user].best_time = min(time.time() - infos[user].time, infos[user].best_time)
infos[user].best_time = round(infos[user].best_time, 2)
infos[user].comment = f"{gen}+{types}"
infos[user].history = []
with open("infos.json", "w") as f:
json.dump({k: v.model_dump() for k, v in infos.items()}, f, indent=4, ensure_ascii=False)
with open("users.json", "w") as f:
json.dump(USERS, f, indent=4, ensure_ascii=False)
artifact = wandb.Artifact("settings", type="History")
artifact.add_file("infos.json")
artifact.add_file("users.json")
run.log_artifact(artifact)
infos[user].history.append((message, bot_message))
leader_board = sorted(infos.items(), key=lambda x: (x[1].best_score, -x[1].best_time), reverse=True)
lbdf = pd.DataFrame([dict(**a[1].model_dump()) for a in leader_board])
lbdf.rename(columns={'name': "이름", 'best_score': "졜고점수", 'best_time': "μ‹œκ°„κΈ°λ‘", 'comment': "ν€΄μ¦ˆμœ ν˜•"}, inplace=True)
lbdf.index += 1
md = lbdf[['이름', '졜고점수', 'μ‹œκ°„κΈ°λ‘', 'ν€΄μ¦ˆμœ ν˜•']]
if infos[user].done:
btn = gr.Button(value="ν€΄μ¦ˆ μ‹œμž‘", label="ν€΄μ¦ˆ μ‹œμž‘")
else:
btn = gr.Button(value="ν¬κΈ°ν•˜κΈ°", label="ν€΄μ¦ˆ 쀑단")
random_buttons = [gr.Button(value=c) for c in infos[user].candidates]
return btn, infos[user].history, md, *random_buttons
play.click(respond,
inputs=[play, chatbot, quiz_count, generation, poke_types],
outputs=[play, chatbot, leader_board, button1, button2, button3, button4])
skip.click(respond,
inputs=[skip, chatbot, quiz_count, generation, poke_types],
outputs=[play, chatbot, leader_board, button1, button2, button3, button4])
for btn in [button1, button2, button3, button4]:
btn.click(respond,
inputs=[btn, chatbot, quiz_count, generation, poke_types],
outputs=[play, chatbot, leader_board, button1, button2, button3, button4])
def update_table(profile: Optional[gr.OAuthProfile]):
user = profile.name
global USERS
if user not in USERS:
USERS += [user]
infos[user] = Info(name=user)
leader_board = sorted(infos.items(), key=lambda x: (x[1].best_score, -x[1].best_time), reverse=True)
lbdf = pd.DataFrame([dict(**a[1].model_dump()) for a in leader_board])
lbdf.rename(columns={'name': "이름", 'best_score': "졜고점수", 'best_time': "μ‹œκ°„κΈ°λ‘", 'comment': "ν€΄μ¦ˆμœ ν˜•"}, inplace=True)
lbdf.index += 1
md = lbdf[['이름', '졜고점수', 'μ‹œκ°„κΈ°λ‘', 'ν€΄μ¦ˆμœ ν˜•']]
if infos[user].done:
btn = gr.Button(value="ν€΄μ¦ˆ μ‹œμž‘", label="ν€΄μ¦ˆ μ‹œμž‘")
else:
btn = gr.Button(value="ν¬κΈ°ν•˜κΈ°", label="ν€΄μ¦ˆ 쀑단")
random_buttons = [gr.Button(value=c) for c in infos[user].candidates]
return btn, md, infos[user].history, *random_buttons
demo.load(update_table,
inputs=None,
outputs=[play, leader_board, chatbot, button1, button2, button3, button4])
demo.queue(concurrency_count=3)
demo.launch()