File size: 11,161 Bytes
4f69797
e444e3b
9227ae5
e444e3b
 
efe5a1a
00166b0
f46bcc2
819ed62
f727e2a
00166b0
 
 
e444e3b
 
 
766c5e5
9227ae5
 
 
 
 
 
 
 
 
 
 
 
 
 
e444e3b
9227ae5
be55574
9227ae5
cad521e
9227ae5
 
 
 
ccdda9e
 
 
 
f46bcc2
be55574
9227ae5
78309aa
 
 
4272589
be55574
 
78309aa
00166b0
 
78309aa
 
f46bcc2
 
2661cef
 
819ed62
 
78309aa
f46bcc2
385222f
3323684
819ed62
b7ed881
 
 
 
3323684
59c23dd
 
 
 
 
 
3323684
9227ae5
385222f
e444e3b
9227ae5
 
3db7d02
2d81047
08450ff
 
 
 
819ed62
9227ae5
 
fbe4202
 
 
 
 
 
 
 
 
 
 
9227ae5
3db7d02
 
b7ed881
7f078c2
3b81ad0
e78b69f
 
ccdda9e
 
 
d42f23f
ccdda9e
 
9227ae5
08450ff
 
 
 
3b81ad0
716cd4d
f46bcc2
766c5e5
 
 
 
 
 
 
9227ae5
59c23dd
f46bcc2
6d1bed2
be55574
9227ae5
f46bcc2
 
 
 
 
766c5e5
 
e444e3b
37ab76b
e444e3b
f46bcc2
be55574
f46bcc2
d68e6a5
f46bcc2
 
21ef542
8a477cd
6d1bed2
f46bcc2
b7ed881
f46bcc2
be55574
f46bcc2
b7ed881
e444e3b
920014e
f46bcc2
4c88e5f
 
 
 
 
0195f76
 
920014e
f46bcc2
 
98a5323
f46bcc2
 
 
 
 
 
 
 
2c3cc27
04b5b70
f46bcc2
 
78309aa
f46bcc2
 
 
78309aa
00166b0
21ef542
f46bcc2
 
 
b7d38a9
21ef542
78309aa
f46bcc2
8a477cd
 
 
ccdda9e
f46bcc2
 
3db7d02
 
e653393
ccdda9e
4272589
e653393
ccdda9e
 
 
 
e653393
ccdda9e
78309aa
32d1b78
 
7cf82c3
 
 
5f8ce22
f46bcc2
 
b7d38a9
21ef542
78309aa
8a477cd
f46bcc2
8a477cd
 
 
1a5d841
f46bcc2
c0554b7
be55574
21ef542
32d1b78
dbcbadd
e444e3b
ccdda9e
55c3782
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
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()