Spaces:
Running
Running
init commit
Browse files- README.md +3 -3
- app.py +137 -0
- data/vocab.json +123 -0
README.md
CHANGED
@@ -1,8 +1,8 @@
|
|
1 |
---
|
2 |
title: JpVocab
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
-
colorTo:
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.15.0
|
8 |
app_file: app.py
|
|
|
1 |
---
|
2 |
title: JpVocab
|
3 |
+
emoji: ✏️
|
4 |
+
colorFrom: gray
|
5 |
+
colorTo: red
|
6 |
sdk: gradio
|
7 |
sdk_version: 5.15.0
|
8 |
app_file: app.py
|
app.py
ADDED
@@ -0,0 +1,137 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import random
|
3 |
+
|
4 |
+
import gradio as gr
|
5 |
+
|
6 |
+
|
7 |
+
def main():
|
8 |
+
app = App()
|
9 |
+
app.launch()
|
10 |
+
|
11 |
+
|
12 |
+
class App:
|
13 |
+
def __init__(self):
|
14 |
+
vocab = load_json("data/vocab.json")
|
15 |
+
ch = [f"Ch. {i:02d}" for i, _ in enumerate(vocab, 1)]
|
16 |
+
self.vocab = dict(zip(ch, vocab))
|
17 |
+
self.__init_app()
|
18 |
+
|
19 |
+
def __init_app(self):
|
20 |
+
with self.__init_blocks() as self.app:
|
21 |
+
self.__init_states()
|
22 |
+
self.__init_layout()
|
23 |
+
self.__init_events()
|
24 |
+
|
25 |
+
def __init_blocks(self):
|
26 |
+
font = gr.themes.GoogleFont("Noto Sans Mono")
|
27 |
+
text_size = gr.themes.sizes.text_md
|
28 |
+
theme = gr.themes.Soft(font=font, text_size=text_size)
|
29 |
+
return gr.Blocks(title="Demo", theme=theme)
|
30 |
+
|
31 |
+
def __init_states(self):
|
32 |
+
self.question_list = gr.State(None)
|
33 |
+
self.curr_item = gr.State(None)
|
34 |
+
self.correct = gr.State(0)
|
35 |
+
self.total = gr.State(0)
|
36 |
+
|
37 |
+
def __init_layout(self):
|
38 |
+
with gr.Tabs() as self.tabs:
|
39 |
+
with gr.Tab("設定", id=0):
|
40 |
+
self.__init_chapters()
|
41 |
+
with gr.Tab("測驗", id=1):
|
42 |
+
self.__init_quiz()
|
43 |
+
with gr.Tab("紀錄", id=2):
|
44 |
+
self.__init_record()
|
45 |
+
|
46 |
+
def __init_chapters(self):
|
47 |
+
with gr.Row():
|
48 |
+
with gr.Tab("N5"):
|
49 |
+
ch = sorted(list(self.vocab.keys()))
|
50 |
+
self.chapters = gr.CheckboxGroup(ch, value=ch[:1], label="章節")
|
51 |
+
with gr.Row():
|
52 |
+
self.start_btn = gr.Button("開始測驗")
|
53 |
+
|
54 |
+
def __init_quiz(self):
|
55 |
+
desc = "完成設定後按下「開始測驗」"
|
56 |
+
|
57 |
+
with gr.Row():
|
58 |
+
self.question = gr.Textbox(placeholder=desc, label="題目", interactive=False)
|
59 |
+
self.score = gr.Textbox("0/0", label="分數")
|
60 |
+
|
61 |
+
with gr.Row():
|
62 |
+
self.answer = gr.Textbox(label="作答")
|
63 |
+
|
64 |
+
def __init_record(self):
|
65 |
+
with gr.Row():
|
66 |
+
self.record = gr.TextArea(show_label=False)
|
67 |
+
|
68 |
+
with gr.Row():
|
69 |
+
self.again_btn = gr.Button("再次測驗")
|
70 |
+
self.back_to_setting_btn = gr.Button("回到設定")
|
71 |
+
|
72 |
+
def __init_events(self):
|
73 |
+
init_inns = [self.chapters]
|
74 |
+
init_outs = [self.question_list, self.tabs]
|
75 |
+
init_args = gr_args(self.init_questions, init_inns, init_outs)
|
76 |
+
|
77 |
+
reset_outs = [self.score, self.correct, self.total]
|
78 |
+
reset_args = gr_args(self.reset_score, None, reset_outs)
|
79 |
+
|
80 |
+
next_inns = [self.question_list]
|
81 |
+
next_outs = [self.curr_item, self.question, self.question_list, self.answer]
|
82 |
+
next_args = gr_args(self.next_question, next_inns, next_outs)
|
83 |
+
|
84 |
+
check_inns = [self.answer, self.curr_item, self.correct, self.total]
|
85 |
+
check_outs = [self.score, self.correct, self.total]
|
86 |
+
check_args = gr_args(self.check, check_inns, check_outs)
|
87 |
+
|
88 |
+
self.start_btn.click(**init_args).then(**reset_args).then(**next_args)
|
89 |
+
self.answer.submit(**check_args).then(**next_args)
|
90 |
+
|
91 |
+
def init_questions(self, chapters):
|
92 |
+
question_list = [v for ch in chapters for v in self.vocab[ch]]
|
93 |
+
random.shuffle(question_list)
|
94 |
+
selected_tab = gr.Tabs(selected=1) if question_list else gr.Tabs(selected=0)
|
95 |
+
return question_list, selected_tab
|
96 |
+
|
97 |
+
def next_question(self, question_list):
|
98 |
+
if question_list:
|
99 |
+
item = list.pop(question_list)
|
100 |
+
return item, item["meaning"], question_list, None
|
101 |
+
return None, None, None, None
|
102 |
+
|
103 |
+
def check(self, answer, item, correct, total):
|
104 |
+
total += 1
|
105 |
+
if answer == item["kana"]:
|
106 |
+
correct += 1
|
107 |
+
info = f"{correct}/{total} - 正確"
|
108 |
+
elif item["kanji"] is not None and answer == item["kanji"]:
|
109 |
+
correct += 1
|
110 |
+
info = f"{correct}/{total} - 正確"
|
111 |
+
else:
|
112 |
+
kana = item["kana"]
|
113 |
+
kanji = item["kanji"]
|
114 |
+
meaning = item["meaning"]
|
115 |
+
info = f"{correct}/{total} - 錯誤 {meaning} - {kana}"
|
116 |
+
info += f" - {kanji}" if kanji is not None else ""
|
117 |
+
|
118 |
+
return info, correct, total
|
119 |
+
|
120 |
+
def reset_score(self):
|
121 |
+
return "0/0", 0, 0
|
122 |
+
|
123 |
+
def launch(self):
|
124 |
+
self.app.launch()
|
125 |
+
|
126 |
+
|
127 |
+
def gr_args(fn, inputs=None, outputs=None, show_progress="minimal"):
|
128 |
+
return dict(fn=fn, inputs=inputs, outputs=outputs, show_progress=show_progress)
|
129 |
+
|
130 |
+
|
131 |
+
def load_json(path):
|
132 |
+
with open(path, "rt", encoding="UTF-8") as fp:
|
133 |
+
return json.load(fp)
|
134 |
+
|
135 |
+
|
136 |
+
if __name__ == "__main__":
|
137 |
+
main()
|
data/vocab.json
ADDED
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
[
|
2 |
+
[
|
3 |
+
{"kana": "あさ", "kanji": "朝", "meaning": "早上"},
|
4 |
+
{"kana": "いま", "kanji": "今", "meaning": "現在"},
|
5 |
+
{"kana": "えき", "kanji": "駅", "meaning": "車站"},
|
6 |
+
{"kana": "くるま", "kanji": "車", "meaning": "車"},
|
7 |
+
{"kana": "はい", "kanji": null, "meaning": "是的;好的"},
|
8 |
+
{"kana": "すき", "kanji": "好き", "meaning": "喜歡"},
|
9 |
+
{"kana": "たべる", "kanji": "食べる", "meaning": "吃"},
|
10 |
+
{"kana": "ひと", "kanji": "人", "meaning": "人"},
|
11 |
+
{"kana": "ねこ", "kanji": "猫", "meaning": "貓"}
|
12 |
+
],
|
13 |
+
[
|
14 |
+
{"kana": "あした", "kanji": "明日", "meaning": "明天"},
|
15 |
+
{"kana": "うみ", "kanji": "海", "meaning": "海"},
|
16 |
+
{"kana": "でんしゃ", "kanji": "電車", "meaning": "電車"},
|
17 |
+
{"kana": "にく", "kanji": "肉", "meaning": "肉"},
|
18 |
+
{"kana": "いいえ", "kanji": null, "meaning": "不是"},
|
19 |
+
{"kana": "おおい", "kanji": "多い", "meaning": "多的"},
|
20 |
+
{"kana": "おいしい", "kanji": null, "meaning": "好吃的"},
|
21 |
+
{"kana": "しごと", "kanji": "仕事", "meaning": "工作"},
|
22 |
+
{"kana": "どうぞ", "kanji": null, "meaning": "請"}
|
23 |
+
],
|
24 |
+
[
|
25 |
+
{"kana": "あお", "kanji": "青", "meaning": "藍色"},
|
26 |
+
{"kana": "おおきい", "kanji": "大きい", "meaning": "大的"},
|
27 |
+
{"kana": "きょう", "kanji": "今日", "meaning": "今天"},
|
28 |
+
{"kana": "でんわ", "kanji": "電話", "meaning": "電話"},
|
29 |
+
{"kana": "カメラ", "kanji": null, "meaning": "相機"},
|
30 |
+
{"kana": "たべもの", "kanji": "食べ物", "meaning": "食物"},
|
31 |
+
{"kana": "はやい", "kanji": "早い", "meaning": "早的"},
|
32 |
+
{"kana": "ひとり", "kanji": "一人", "meaning": "一人"},
|
33 |
+
{"kana": "ほん", "kanji": "本", "meaning": "書"}
|
34 |
+
],
|
35 |
+
[
|
36 |
+
{"kana": "はな", "kanji": "花", "meaning": "花"},
|
37 |
+
{"kana": "なつ", "kanji": "夏", "meaning": "夏天"},
|
38 |
+
{"kana": "テレビ", "kanji": null, "meaning": "電視"},
|
39 |
+
{"kana": "すこし", "kanji": "少し", "meaning": "稍微"},
|
40 |
+
{"kana": "たかい", "kanji": "高い", "meaning": "高的;貴的"},
|
41 |
+
{"kana": "しろ", "kanji": "白", "meaning": "白"},
|
42 |
+
{"kana": "きらい", "kanji": "嫌い", "meaning": "討厭的"},
|
43 |
+
{"kana": "ない", "kanji": null, "meaning": "沒有"},
|
44 |
+
{"kana": "うえ", "kanji": "上", "meaning": "上面"}
|
45 |
+
],
|
46 |
+
[
|
47 |
+
{"kana": "はる", "kanji": "春", "meaning": "春天"},
|
48 |
+
{"kana": "ねる", "kanji": "寝る", "meaning": "睡覺"},
|
49 |
+
{"kana": "なまえ", "kanji": "名前", "meaning": "名字"},
|
50 |
+
{"kana": "だれ", "kanji": "誰", "meaning": "誰"},
|
51 |
+
{"kana": "くろ", "kanji": "黒", "meaning": "黑色"},
|
52 |
+
{"kana": "カレー", "kanji": null, "meaning": "咖哩"},
|
53 |
+
{"kana": "おとこ", "kanji": "男", "meaning": "男人"},
|
54 |
+
{"kana": "あつい", "kanji": "暑い", "meaning": "熱的"},
|
55 |
+
{"kana": "あなた", "kanji": null, "meaning": "你"}
|
56 |
+
],
|
57 |
+
[
|
58 |
+
{"kana": "おふろ", "kanji": "お風呂", "meaning": "浴室;洗澡"},
|
59 |
+
{"kana": "あまい", "kanji": "甘い", "meaning": "甜的"},
|
60 |
+
{"kana": "いたい", "kanji": "痛い", "meaning": "疼痛的"},
|
61 |
+
{"kana": "ここ", "kanji": null, "meaning": "這裡"},
|
62 |
+
{"kana": "さき", "kanji": "先", "meaning": "首先"},
|
63 |
+
{"kana": "する", "kanji": null, "meaning": "做(某事)"},
|
64 |
+
{"kana": "つかう", "kanji": "使う", "meaning": "使用"},
|
65 |
+
{"kana": "てんき", "kanji": "天気", "meaning": "天氣"},
|
66 |
+
{"kana": "なか", "kanji": "中", "meaning": "裡面;中間"}
|
67 |
+
],
|
68 |
+
[
|
69 |
+
{"kana": "あめ", "kanji": "雨", "meaning": "雨"},
|
70 |
+
{"kana": "いい", "kanji": null, "meaning": "好的"},
|
71 |
+
{"kana": "おそい", "kanji": "遅い", "meaning": "慢的"},
|
72 |
+
{"kana": "これ", "kanji": null, "meaning": "這個"},
|
73 |
+
{"kana": "ちいさい", "kanji": "小さい", "meaning": "小的"},
|
74 |
+
{"kana": "ニュース", "kanji": null, "meaning": "新聞"},
|
75 |
+
{"kana": "のる", "kanji": "乗る", "meaning": "搭乘"},
|
76 |
+
{"kana": "かう", "kanji": "買う", "meaning": "買"},
|
77 |
+
{"kana": "くる", "kanji": "来る", "meaning": "來"}
|
78 |
+
],
|
79 |
+
[
|
80 |
+
{"kana": "いす", "kanji": "椅子", "meaning": "椅子"},
|
81 |
+
{"kana": "した", "kanji": "下", "meaning": "下面"},
|
82 |
+
{"kana": "きる", "kanji": "切る", "meaning": "切"},
|
83 |
+
{"kana": "すう", "kanji": "吸う", "meaning": "吸"},
|
84 |
+
{"kana": "せんせい", "kanji": "先生", "meaning": "老師"},
|
85 |
+
{"kana": "ちかい", "kanji": "近い", "meaning": "近的"},
|
86 |
+
{"kana": "トイレ", "kanji": null, "meaning": "廁所"},
|
87 |
+
{"kana": "ながい", "kanji": "長い", "meaning": "長的"},
|
88 |
+
{"kana": "はじめで", "kanji": "初めて", "meaning": "第一次"}
|
89 |
+
],
|
90 |
+
[
|
91 |
+
{"kana": "あう", "kanji": "会う", "meaning": "見面"},
|
92 |
+
{"kana": "うしろ", "kanji": "後ろ", "meaning": "後面"},
|
93 |
+
{"kana": "いえ", "kanji": "家", "meaning": "家"},
|
94 |
+
{"kana": "おとうと", "kanji": null, "meaning": "弟弟"},
|
95 |
+
{"kana": "いくら", "kanji": null, "meaning": "多少"},
|
96 |
+
{"kana": "こえ", "kanji": "声", "meaning": "聲音"},
|
97 |
+
{"kana": "しかし", "kanji": null, "meaning": "但是"},
|
98 |
+
{"kana": "そこ", "kanji": null, "meaning": "那裡(較近)"},
|
99 |
+
{"kana": "とぶ", "kanji": "飛ぶ", "meaning": "飛行"}
|
100 |
+
],
|
101 |
+
[
|
102 |
+
{"kana": "いくつ", "kanji": null, "meaning": "幾個"},
|
103 |
+
{"kana": "おかあさん", "kanji": "お母さん", "meaning": "媽媽"},
|
104 |
+
{"kana": "おとうさん", "kanji": "お父さん", "meaning": "爸爸"},
|
105 |
+
{"kana": "きく", "kanji": "聞く", "meaning": "聽"},
|
106 |
+
{"kana": "かぎ", "kanji": "鍵", "meaning": "鑰匙"},
|
107 |
+
{"kana": "あれ", "kanji": null, "meaning": "那個"},
|
108 |
+
{"kana": "くに", "kanji": "国", "meaning": "國"},
|
109 |
+
{"kana": "しる", "kanji": "知る", "meaning": "知道"},
|
110 |
+
{"kana": "せまい", "kanji": "狭い", "meaning": "狹小的"}
|
111 |
+
],
|
112 |
+
[
|
113 |
+
{"kana": "かるい", "kanji": "軽い", "meaning": "輕的"},
|
114 |
+
{"kana": "いく", "kanji": "行く", "meaning": "去"},
|
115 |
+
{"kana": "おばさん", "kanji": null, "meaning": "阿姨"},
|
116 |
+
{"kana": "おじさん", "kanji": null, "meaning": "叔叔"},
|
117 |
+
{"kana": "あか", "kanji": "赤", "meaning": "紅色"},
|
118 |
+
{"kana": "うた", "kanji": "歌", "meaning": "歌"},
|
119 |
+
{"kana": "かさ", "kanji": "傘", "meaning": "雨傘"},
|
120 |
+
{"kana": "とおい", "kanji": "遠い", "meaning": "遠的"},
|
121 |
+
{"kana": "とる", "kanji": "撮る", "meaning": "拍照"}
|
122 |
+
]
|
123 |
+
]
|