Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -320,6 +320,12 @@ CUSTOM_CSS = """
|
|
| 320 |
white-space: pre-wrap;
|
| 321 |
line-height: 1.6;
|
| 322 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 323 |
"""
|
| 324 |
|
| 325 |
|
|
@@ -508,7 +514,6 @@ def build_sample_brief_html(sample: Dict[str, Any], index: int, total: int) -> s
|
|
| 508 |
|
| 509 |
def create_app():
|
| 510 |
samples = build_pending_samples()
|
| 511 |
-
sample_map = {s["anon_id"]: s for s in samples}
|
| 512 |
|
| 513 |
with gr.Blocks(
|
| 514 |
title="VideoEval Movie-Level Evaluation",
|
|
@@ -526,6 +531,7 @@ def create_app():
|
|
| 526 |
|
| 527 |
current_idx = gr.State(0)
|
| 528 |
evaluator_state = gr.State("anonymous")
|
|
|
|
| 529 |
|
| 530 |
with gr.Row():
|
| 531 |
with gr.Column(scale=5, elem_classes=["panel"]):
|
|
@@ -550,7 +556,7 @@ def create_app():
|
|
| 550 |
if not samples else build_sample_brief_html(samples[0], 0, len(samples))
|
| 551 |
)
|
| 552 |
|
| 553 |
-
gr.Markdown("## 3)
|
| 554 |
gr.Markdown("<span class='hint'>请先完成 1-5 分评分,未打分无法提交。</span>")
|
| 555 |
|
| 556 |
score_widgets: Dict[str, gr.Radio] = {}
|
|
@@ -576,32 +582,34 @@ def create_app():
|
|
| 576 |
score_widgets[key] = gr.Radio(choices=[1, 2, 3, 4, 5], label=f"{key} Score")
|
| 577 |
|
| 578 |
final_summary = gr.Textbox(label="Final Summary(可选)", lines=4, placeholder="总结该视频的主要优缺点")
|
| 579 |
-
submit_btn = gr.Button("提交
|
| 580 |
|
| 581 |
-
def _sync_sample_from_dropdown(anon_id: str) -> Tuple[str, str, int]:
|
|
|
|
| 582 |
if not anon_id or anon_id not in sample_map:
|
| 583 |
return None, "<div class='sample-card'><p class='story-body'>未找到样本</p></div>", 0
|
| 584 |
-
idx = next(i for i, s in enumerate(
|
| 585 |
-
sample =
|
| 586 |
-
return sample["video_path"], build_sample_brief_html(sample, idx, len(
|
| 587 |
|
| 588 |
-
def _go_prev(idx: int) -> Tuple[str, str, str, int]:
|
| 589 |
-
if not
|
| 590 |
return None, "<div class='sample-card'><p class='story-body'>无可用样本</p></div>", None, 0
|
| 591 |
idx = max(0, idx - 1)
|
| 592 |
-
sample =
|
| 593 |
-
return sample["video_path"], build_sample_brief_html(sample, idx, len(
|
| 594 |
|
| 595 |
-
def _go_next(idx: int) -> Tuple[str, str, str, int]:
|
| 596 |
-
if not
|
| 597 |
return None, "<div class='sample-card'><p class='story-body'>无可用样本</p></div>", None, 0
|
| 598 |
-
idx = min(len(
|
| 599 |
-
sample =
|
| 600 |
-
return sample["video_path"], build_sample_brief_html(sample, idx, len(
|
| 601 |
|
| 602 |
-
def _submit(evaluator_id: str, anon_id: str, summary: str, *score_vals):
|
| 603 |
-
if not
|
| 604 |
return "❌ 没有可提交样本。"
|
|
|
|
| 605 |
if not anon_id or anon_id not in sample_map:
|
| 606 |
return "❌ 请先选择样本。"
|
| 607 |
sample = sample_map[anon_id]
|
|
@@ -627,19 +635,76 @@ def create_app():
|
|
| 627 |
|
| 628 |
return f"✅ 已保存: `{single_path}`\n\n✅ 已更新方法统计: `{agg_path}`"
|
| 629 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 630 |
sample_dropdown.change(
|
| 631 |
_sync_sample_from_dropdown,
|
| 632 |
-
inputs=[sample_dropdown],
|
| 633 |
outputs=[movie_video, sample_info, current_idx],
|
| 634 |
)
|
| 635 |
-
prev_btn.click(_go_prev, inputs=[current_idx], outputs=[movie_video, sample_info, sample_dropdown, current_idx])
|
| 636 |
-
next_btn.click(_go_next, inputs=[current_idx], outputs=[movie_video, sample_info, sample_dropdown, current_idx])
|
| 637 |
|
| 638 |
-
submit_inputs = [evaluator_input, sample_dropdown, final_summary]
|
| 639 |
for key in BASE_METRIC_KEYS:
|
| 640 |
submit_inputs.append(score_widgets[key])
|
| 641 |
-
submit_btn.click(_submit, inputs=submit_inputs, outputs=[status])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 642 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 643 |
app.load(lambda x: x, inputs=[evaluator_input], outputs=[evaluator_state])
|
| 644 |
|
| 645 |
return app
|
|
|
|
| 320 |
white-space: pre-wrap;
|
| 321 |
line-height: 1.6;
|
| 322 |
}
|
| 323 |
+
#submit-btn button {
|
| 324 |
+
min-height: 52px !important;
|
| 325 |
+
font-size: 1.08rem !important;
|
| 326 |
+
font-weight: 700 !important;
|
| 327 |
+
padding: 0.7rem 1.2rem !important;
|
| 328 |
+
}
|
| 329 |
"""
|
| 330 |
|
| 331 |
|
|
|
|
| 514 |
|
| 515 |
def create_app():
|
| 516 |
samples = build_pending_samples()
|
|
|
|
| 517 |
|
| 518 |
with gr.Blocks(
|
| 519 |
title="VideoEval Movie-Level Evaluation",
|
|
|
|
| 531 |
|
| 532 |
current_idx = gr.State(0)
|
| 533 |
evaluator_state = gr.State("anonymous")
|
| 534 |
+
samples_state = gr.State(samples)
|
| 535 |
|
| 536 |
with gr.Row():
|
| 537 |
with gr.Column(scale=5, elem_classes=["panel"]):
|
|
|
|
| 556 |
if not samples else build_sample_brief_html(samples[0], 0, len(samples))
|
| 557 |
)
|
| 558 |
|
| 559 |
+
gr.Markdown("## 3) 评分(1-5)")
|
| 560 |
gr.Markdown("<span class='hint'>请先完成 1-5 分评分,未打分无法提交。</span>")
|
| 561 |
|
| 562 |
score_widgets: Dict[str, gr.Radio] = {}
|
|
|
|
| 582 |
score_widgets[key] = gr.Radio(choices=[1, 2, 3, 4, 5], label=f"{key} Score")
|
| 583 |
|
| 584 |
final_summary = gr.Textbox(label="Final Summary(可选)", lines=4, placeholder="总结该视频的主要优缺点")
|
| 585 |
+
submit_btn = gr.Button("提交", variant="primary", elem_id="submit-btn")
|
| 586 |
|
| 587 |
+
def _sync_sample_from_dropdown(anon_id: str, curr_samples: List[Dict[str, Any]]) -> Tuple[str, str, int]:
|
| 588 |
+
sample_map = {s["anon_id"]: s for s in curr_samples}
|
| 589 |
if not anon_id or anon_id not in sample_map:
|
| 590 |
return None, "<div class='sample-card'><p class='story-body'>未找到样本</p></div>", 0
|
| 591 |
+
idx = next(i for i, s in enumerate(curr_samples) if s["anon_id"] == anon_id)
|
| 592 |
+
sample = curr_samples[idx]
|
| 593 |
+
return sample["video_path"], build_sample_brief_html(sample, idx, len(curr_samples)), idx
|
| 594 |
|
| 595 |
+
def _go_prev(idx: int, curr_samples: List[Dict[str, Any]]) -> Tuple[str, str, str, int]:
|
| 596 |
+
if not curr_samples:
|
| 597 |
return None, "<div class='sample-card'><p class='story-body'>无可用样本</p></div>", None, 0
|
| 598 |
idx = max(0, idx - 1)
|
| 599 |
+
sample = curr_samples[idx]
|
| 600 |
+
return sample["video_path"], build_sample_brief_html(sample, idx, len(curr_samples)), sample["anon_id"], idx
|
| 601 |
|
| 602 |
+
def _go_next(idx: int, curr_samples: List[Dict[str, Any]]) -> Tuple[str, str, str, int]:
|
| 603 |
+
if not curr_samples:
|
| 604 |
return None, "<div class='sample-card'><p class='story-body'>无可用样本</p></div>", None, 0
|
| 605 |
+
idx = min(len(curr_samples) - 1, idx + 1)
|
| 606 |
+
sample = curr_samples[idx]
|
| 607 |
+
return sample["video_path"], build_sample_brief_html(sample, idx, len(curr_samples)), sample["anon_id"], idx
|
| 608 |
|
| 609 |
+
def _submit(evaluator_id: str, anon_id: str, summary: str, curr_samples: List[Dict[str, Any]], *score_vals):
|
| 610 |
+
if not curr_samples:
|
| 611 |
return "❌ 没有可提交样本。"
|
| 612 |
+
sample_map = {s["anon_id"]: s for s in curr_samples}
|
| 613 |
if not anon_id or anon_id not in sample_map:
|
| 614 |
return "❌ 请先选择样本。"
|
| 615 |
sample = sample_map[anon_id]
|
|
|
|
| 635 |
|
| 636 |
return f"✅ 已保存: `{single_path}`\n\n✅ 已更新方法统计: `{agg_path}`"
|
| 637 |
|
| 638 |
+
def _refresh_on_load() -> Tuple[Any, Any, str, int, str, List[Dict[str, Any]]]:
|
| 639 |
+
refreshed_samples = build_pending_samples()
|
| 640 |
+
if not refreshed_samples:
|
| 641 |
+
return (
|
| 642 |
+
gr.update(choices=[], value=None),
|
| 643 |
+
None,
|
| 644 |
+
"<div class='sample-card'><p class='story-body'>无可用样本(可能都已评估)</p></div>",
|
| 645 |
+
0,
|
| 646 |
+
"当前无待评估样本。",
|
| 647 |
+
refreshed_samples,
|
| 648 |
+
)
|
| 649 |
+
|
| 650 |
+
first = refreshed_samples[0]
|
| 651 |
+
return (
|
| 652 |
+
gr.update(choices=[s["anon_id"] for s in refreshed_samples], value=first["anon_id"]),
|
| 653 |
+
first["video_path"],
|
| 654 |
+
build_sample_brief_html(first, 0, len(refreshed_samples)),
|
| 655 |
+
0,
|
| 656 |
+
f"已刷新样本池:{len(refreshed_samples)} 个待评估样本。",
|
| 657 |
+
refreshed_samples,
|
| 658 |
+
)
|
| 659 |
+
|
| 660 |
+
def _refresh_after_submit(submit_msg: str) -> Tuple[Any, Any, str, int, str, List[Dict[str, Any]]]:
|
| 661 |
+
refreshed_samples = build_pending_samples()
|
| 662 |
+
submit_msg = (submit_msg or "").strip()
|
| 663 |
+
if not refreshed_samples:
|
| 664 |
+
status_msg = f"{submit_msg}\n\n当前无待评估样本。" if submit_msg else "当前无待评估样本。"
|
| 665 |
+
return (
|
| 666 |
+
gr.update(choices=[], value=None),
|
| 667 |
+
None,
|
| 668 |
+
"<div class='sample-card'><p class='story-body'>无可用样本(可能都已评估)</p></div>",
|
| 669 |
+
0,
|
| 670 |
+
status_msg,
|
| 671 |
+
refreshed_samples,
|
| 672 |
+
)
|
| 673 |
+
|
| 674 |
+
first = refreshed_samples[0]
|
| 675 |
+
refresh_msg = f"已刷新样本池:{len(refreshed_samples)} 个待评估样本。"
|
| 676 |
+
status_msg = f"{submit_msg}\n\n{refresh_msg}" if submit_msg else refresh_msg
|
| 677 |
+
return (
|
| 678 |
+
gr.update(choices=[s["anon_id"] for s in refreshed_samples], value=first["anon_id"]),
|
| 679 |
+
first["video_path"],
|
| 680 |
+
build_sample_brief_html(first, 0, len(refreshed_samples)),
|
| 681 |
+
0,
|
| 682 |
+
status_msg,
|
| 683 |
+
refreshed_samples,
|
| 684 |
+
)
|
| 685 |
+
|
| 686 |
sample_dropdown.change(
|
| 687 |
_sync_sample_from_dropdown,
|
| 688 |
+
inputs=[sample_dropdown, samples_state],
|
| 689 |
outputs=[movie_video, sample_info, current_idx],
|
| 690 |
)
|
| 691 |
+
prev_btn.click(_go_prev, inputs=[current_idx, samples_state], outputs=[movie_video, sample_info, sample_dropdown, current_idx])
|
| 692 |
+
next_btn.click(_go_next, inputs=[current_idx, samples_state], outputs=[movie_video, sample_info, sample_dropdown, current_idx])
|
| 693 |
|
| 694 |
+
submit_inputs = [evaluator_input, sample_dropdown, final_summary, samples_state]
|
| 695 |
for key in BASE_METRIC_KEYS:
|
| 696 |
submit_inputs.append(score_widgets[key])
|
| 697 |
+
submit_evt = submit_btn.click(_submit, inputs=submit_inputs, outputs=[status])
|
| 698 |
+
submit_evt.then(
|
| 699 |
+
_refresh_after_submit,
|
| 700 |
+
inputs=[status],
|
| 701 |
+
outputs=[sample_dropdown, movie_video, sample_info, current_idx, status, samples_state],
|
| 702 |
+
)
|
| 703 |
|
| 704 |
+
app.load(
|
| 705 |
+
_refresh_on_load,
|
| 706 |
+
outputs=[sample_dropdown, movie_video, sample_info, current_idx, status, samples_state],
|
| 707 |
+
)
|
| 708 |
app.load(lambda x: x, inputs=[evaluator_input], outputs=[evaluator_state])
|
| 709 |
|
| 710 |
return app
|