app.py
CHANGED
|
@@ -122,7 +122,6 @@ def create_ui():
|
|
| 122 |
q_disp = gr.Text(label="问题内容", lines=2)
|
| 123 |
a_disp = gr.Text(label="标准答案")
|
| 124 |
|
| 125 |
-
# 【修复关键点1】移除 Tuple 选项,规避底层 Schema 渲染崩溃 Bug
|
| 126 |
status_opt = gr.Radio(
|
| 127 |
label="审核结论",
|
| 128 |
choices=["正确", "错误", "优化"],
|
|
@@ -132,17 +131,21 @@ def create_ui():
|
|
| 132 |
|
| 133 |
comment = gr.Text(label="审核备注")
|
| 134 |
save_status = gr.Text(label="操作反馈", interactive=False)
|
| 135 |
-
save_btn = gr.Button("💾 提交
|
| 136 |
|
| 137 |
with gr.Row():
|
| 138 |
prev_btn = gr.Button("⬅️ 上一个图表")
|
| 139 |
next_btn = gr.Button("➡️ 下一个图表")
|
| 140 |
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 146 |
|
| 147 |
# --- 事件绑定 ---
|
| 148 |
demo.load(
|
|
@@ -178,12 +181,12 @@ def create_ui():
|
|
| 178 |
prev_btn.click(lambda: navigate(-1), outputs=[src_dd, typ_dd, id_dd, mdl_dd, save_status])
|
| 179 |
next_btn.click(lambda: navigate(1), outputs=[src_dd, typ_dd, id_dd, mdl_dd, save_status])
|
| 180 |
|
| 181 |
-
#
|
| 182 |
-
def
|
| 183 |
if not qid:
|
| 184 |
-
return "⚠️ 无效操作:未选择题目", gr.update()
|
| 185 |
|
| 186 |
-
#
|
| 187 |
status_map = {
|
| 188 |
"正确": "correct",
|
| 189 |
"错误": "incorrect",
|
|
@@ -196,33 +199,52 @@ def create_ui():
|
|
| 196 |
"status": mapped_status, "comment": cmt
|
| 197 |
})
|
| 198 |
|
|
|
|
| 199 |
stats = data_manager.get_review_stats()
|
| 200 |
stats_str = f"✅{stats['correct']} | ❌{stats['incorrect']} | 总{stats['total']}"
|
|
|
|
| 201 |
|
| 202 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
|
|
|
|
| 204 |
save_btn.click(
|
| 205 |
-
|
| 206 |
-
inputs=[curr_qid, id_dd, src_dd, status_opt, comment],
|
| 207 |
-
outputs=[save_status, stats_txt]
|
| 208 |
)
|
| 209 |
|
| 210 |
-
#
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
export_btn.click(
|
| 216 |
-
handle_export,
|
| 217 |
-
inputs=[],
|
| 218 |
-
outputs=[download_file]
|
| 219 |
)
|
| 220 |
|
| 221 |
return demo
|
| 222 |
|
| 223 |
if __name__ == "__main__":
|
| 224 |
app = create_ui()
|
| 225 |
-
# show_api=False 依然保留,同时移除了所有容易触发 Schema 崩溃的类型定义
|
| 226 |
app.launch(
|
| 227 |
server_name="0.0.0.0",
|
| 228 |
server_port=7860,
|
|
|
|
| 122 |
q_disp = gr.Text(label="问题内容", lines=2)
|
| 123 |
a_disp = gr.Text(label="标准答案")
|
| 124 |
|
|
|
|
| 125 |
status_opt = gr.Radio(
|
| 126 |
label="审核结论",
|
| 127 |
choices=["正确", "错误", "优化"],
|
|
|
|
| 131 |
|
| 132 |
comment = gr.Text(label="审核备注")
|
| 133 |
save_status = gr.Text(label="操作反馈", interactive=False)
|
| 134 |
+
save_btn = gr.Button("💾 提交本题并下一题", variant="primary")
|
| 135 |
|
| 136 |
with gr.Row():
|
| 137 |
prev_btn = gr.Button("⬅️ 上一个图表")
|
| 138 |
next_btn = gr.Button("➡️ 下一个图表")
|
| 139 |
|
| 140 |
+
gr.Markdown("---")
|
| 141 |
+
gr.Markdown("### 📦 记录导出与预览")
|
| 142 |
+
# 【新增替代方案】使用 gr.Code 展示所有记录,自带右上角复制按钮
|
| 143 |
+
records_code = gr.Code(
|
| 144 |
+
label="当前所有审核记录 JSON (光标悬浮至代码块右上角可一键复制)",
|
| 145 |
+
language="json",
|
| 146 |
+
interactive=False,
|
| 147 |
+
lines=15
|
| 148 |
+
)
|
| 149 |
|
| 150 |
# --- 事件绑定 ---
|
| 151 |
demo.load(
|
|
|
|
| 181 |
prev_btn.click(lambda: navigate(-1), outputs=[src_dd, typ_dd, id_dd, mdl_dd, save_status])
|
| 182 |
next_btn.click(lambda: navigate(1), outputs=[src_dd, typ_dd, id_dd, mdl_dd, save_status])
|
| 183 |
|
| 184 |
+
# 【核心逻辑升级】保存 + 自动跳转 + 刷新记录展示
|
| 185 |
+
def quick_save_and_next(qid, cid, src, status_label, cmt, current_qa_selection, qa_json_str):
|
| 186 |
if not qid:
|
| 187 |
+
return "⚠️ 无效操作:未选择题目", gr.update(), gr.update(), gr.update()
|
| 188 |
|
| 189 |
+
# 1. 状态映射与保存
|
| 190 |
status_map = {
|
| 191 |
"正确": "correct",
|
| 192 |
"错误": "incorrect",
|
|
|
|
| 199 |
"status": mapped_status, "comment": cmt
|
| 200 |
})
|
| 201 |
|
| 202 |
+
# 2. 刷新统计
|
| 203 |
stats = data_manager.get_review_stats()
|
| 204 |
stats_str = f"✅{stats['correct']} | ❌{stats['incorrect']} | 总{stats['total']}"
|
| 205 |
+
feedback = f"✅ 保存成功 (ID: {qid})"
|
| 206 |
|
| 207 |
+
# 3. 提取所有记录并格式化为 JSON 字符串给代码块展示
|
| 208 |
+
all_reviews = data_manager.get_all_reviews()
|
| 209 |
+
reviews_json_text = json.dumps(all_reviews, ensure_ascii=False, indent=2)
|
| 210 |
+
|
| 211 |
+
# 4. 自动跳转下一题逻辑
|
| 212 |
+
next_qa_update = gr.update()
|
| 213 |
+
try:
|
| 214 |
+
qas = json.loads(qa_json_str)
|
| 215 |
+
# 解析当前选中的题号,比如 "Q1: xxx..." 提取数字 1
|
| 216 |
+
curr_q_num = int(current_qa_selection.split(":")[0][1:])
|
| 217 |
+
next_idx = curr_q_num # 下一题的索引正好等于当前题号(基于0的索引)
|
| 218 |
+
|
| 219 |
+
if next_idx < len(qas):
|
| 220 |
+
next_q = qas[next_idx]
|
| 221 |
+
next_choice = f"Q{next_idx+1}: {next_q['q'][:20]}..."
|
| 222 |
+
# 通知 Radio 组件切换到下一题,这会自动触发 qa_radio.change 事件刷新题目内容
|
| 223 |
+
next_qa_update = gr.update(value=next_choice)
|
| 224 |
+
else:
|
| 225 |
+
feedback += " (当前图表题目已全部审核完毕)"
|
| 226 |
+
except Exception as e:
|
| 227 |
+
pass
|
| 228 |
+
|
| 229 |
+
return feedback, stats_str, next_qa_update, reviews_json_text
|
| 230 |
|
| 231 |
+
# 绑定升级后的保存事件
|
| 232 |
save_btn.click(
|
| 233 |
+
quick_save_and_next,
|
| 234 |
+
inputs=[curr_qid, id_dd, src_dd, status_opt, comment, qa_radio, qa_store],
|
| 235 |
+
outputs=[save_status, stats_txt, qa_radio, records_code]
|
| 236 |
)
|
| 237 |
|
| 238 |
+
# 初始化时也加载一次记录
|
| 239 |
+
demo.load(
|
| 240 |
+
fn=lambda: json.dumps(data_manager.get_all_reviews(), ensure_ascii=False, indent=2),
|
| 241 |
+
outputs=[records_code]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 242 |
)
|
| 243 |
|
| 244 |
return demo
|
| 245 |
|
| 246 |
if __name__ == "__main__":
|
| 247 |
app = create_ui()
|
|
|
|
| 248 |
app.launch(
|
| 249 |
server_name="0.0.0.0",
|
| 250 |
server_port=7860,
|