Penut commited on
Commit
ec39379
·
1 Parent(s): c04a1c7

init commit

Browse files
Files changed (3) hide show
  1. README.md +3 -3
  2. app.py +137 -0
  3. data/vocab.json +123 -0
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
  title: JpVocab
3
- emoji: 🦀
4
- colorFrom: blue
5
- colorTo: pink
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
+ ]