# Python x Gradio
日文五十音大進擊 Day 5
[Colab Demo](https://colab.research.google.com/drive/1ABh2sU7lOn2Qm1X_1GkYSvvcT7Qnf420)
---
## 應用收尾
再加上幾個元件來完善整體應用:
1. 提示資訊
2. 計算正確題數 & 正確率
3. 答錯的歷史紀錄
4. (Optional) 重構
---
# 提示欄位
----
## 增加提示元件
用來提示使用者正確、錯誤以及答案是什麼:
```python
with gr.Row():
txt_test = gr.Textbox(label="題目", interactive=False)
txt_info = gr.Textbox(label="資訊", interactive=False)
txt_input = gr.Textbox(label="作答", submit_btn=True)
```
----
在檢查答案時,回傳相關的提示資訊:
```python
def check_answer(...):
# ...
if txt_input in spell[txt_test]:
# ...
txt_info = "正確!"
else:
# ...
answer = ", ".join(spell[txt_test])
txt_info = f"錯誤,正確答案為 {answer}"
# ...
return ..., txt_info, ...
```
---
# 正確率
----
增加**答對題數**、**總答題數**和**答對比率**的元件:
```python
n_correct = gr.Number(label="答對題數", interactive=False)
n_total = gr.Number(label="總答題數", interactive=False)
txt_accuracy = gr.Textbox("100.00%", label="答對比率", interactive=False)
```
設定 `interactive=False` 避免被使用者竄改
因為答對比率要顯示 `%` 所以要是 `gr.Textbox` 元件
----
在 `check_answer()` 時順便統計正確率:
```python
def check_answer(..., n_correct, n_total):
# ...
if txt_input in spell[txt_test]:
n_correct += 1
# ...
n_total += 1
accuracy = n_correct / n_total
return ..., n_correct, n_total, f"{accuracy:.2%}"
```
---
# 歷史紀錄
----
放一個 `gr.TextArea` 在新的分頁:
```python
with gr.Tab(label="紀錄", id=2):
txt_records = gr.TextArea(show_label=False, interactive=False)
btn_again = gr.Button("再次測驗")
btn_back = gr.Button("回到設定")
```
在這個分頁順便放上**再次測驗**與**回到設定**兩個按鈕
方便使用者跳轉到不同分頁進行行動
----
在使用者答錯時記錄下來:
```python
def check_answer(..., txt_records):
if txt_input in spell[txt_test]:
# ...
else:
answer = ", ".join(spell[txt_test])
txt_info = f"錯誤,正確答案為 {answer}"
txt_records += f"題目:{txt_test}、正解:{answer}、輸入:{txt_input}\n"
# ...
return ..., txt_records
```
----
在測驗結束時,計算正確率並跳轉到紀錄分頁:
```python
def next_char(st_queue, n_correct, n_total, txt_record):
if not st_queue:
gr.Info("測驗結束!")
accuracy = n_correct / n_total
txt_record += f"正確率 {accuracy:.2%} ({n_correct}/{n_total})"
return None, None, None, txt_record, gr.Tabs(selected=2)
# ...
```
----
當使用者點擊**再次測驗**時
其實與點擊第一個分頁的**開始測驗**按鈕一樣
```python
btn_start.click(...)
btn_again.click(...)
```
----
點擊**回到設定**時,只要跳轉分頁即可:
```python
def back():
return gr.Tabs(selected=0)
btn_back.click(back, outputs=tabs)
```
----
在重新進行測驗時,記得重置狀態紀錄:
```python
def reset():
return 0, 0, "100.00%", None, None
btn_again.click(
reset, outputs=[n_correct, n_total, txt_accuracy, txt_info, txt_records]
).then(...)
```
---
# 重構
----
Gradio 的事件註冊往往有很多重複性的參數
這時很適合進行簡單的重構
----
宣告一個取得 Keyword Arguments 的函式:
```python
def gr_args(fn=None, inputs=None, outputs=None, show_progress="hidden", **kwargs):
return dict(
fn=fn,
inputs=inputs,
outputs=outputs,
show_progress=show_progress,
**kwargs,
)
```
----
將輸入、輸出、參數各自獨立成變數:
```python
reset_outputs = [n_correct, n_total, txt_accuracy, txt_info, txt_records]
reset_args = gr_args(reset, outputs=reset_outputs)
start_inputs = [chk_kana, chk_seion, chk_dakuon, chk_handakuon, chk_youon]
start_outputs = [txt_test, st_queue, debug, tabs]
start_args = gr_args(start_test, start_inputs, start_outputs)
```
----
這樣就能對重複或相似的事件做大幅度的精簡:
```python
btn_start.click(**reset_args).then(**start_args)
btn_again.click(**reset_args).then(**start_args)
```
{"title":"Python x Gradio Day 5","slideOptions":"{\"transition\":\"slide\"}","description":"日文五十音大進擊 Day 5","contributors":"[{\"id\":\"c7cbb212-2c41-4dfa-8d85-f8e7fa769bf1\",\"add\":3581,\"del\":0}]"}