app.py
CHANGED
|
@@ -7,6 +7,7 @@ from data_manager import DataManager, data_manager
|
|
| 7 |
from typing import Dict, List, Optional, Tuple, Any
|
| 8 |
import json
|
| 9 |
import os
|
|
|
|
| 10 |
|
| 11 |
# ============== 全局状态 ==============
|
| 12 |
|
|
@@ -123,6 +124,40 @@ def update_chart_dropdown(source: str, chart_type: str):
|
|
| 123 |
)
|
| 124 |
|
| 125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
| 127 |
"""
|
| 128 |
加载图表数据并返回所有 UI 更新
|
|
@@ -132,13 +167,14 @@ def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
|
| 132 |
"""
|
| 133 |
if not all([source, chart_type, chart_id, model]):
|
| 134 |
return [
|
| 135 |
-
"", # html_display
|
| 136 |
-
"", # label_info
|
| 137 |
"[]", # qa_data (JSON string)
|
| 138 |
"等待加载数据...", # status_text
|
| 139 |
"请在左侧选择图表", # progress_text
|
| 140 |
"{}", # current_qa_reviews (JSON string)
|
| 141 |
-
gr.Radio(choices=[], value=None) # qa_selector
|
|
|
|
| 142 |
]
|
| 143 |
|
| 144 |
# 更新状态
|
|
@@ -149,6 +185,12 @@ def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
|
| 149 |
html_content = chart_data.get('html_content', '')
|
| 150 |
label_info = chart_data.get('label_info', {})
|
| 151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 152 |
# 格式化标签信息
|
| 153 |
if label_info:
|
| 154 |
label_text = f"""
|
|
@@ -164,7 +206,7 @@ def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
|
| 164 |
| **链接** | [查看原图]({label_info.get('Weblink', '#')}) |
|
| 165 |
"""
|
| 166 |
else:
|
| 167 |
-
label_text = "暂无标签信息"
|
| 168 |
|
| 169 |
# 获取 QA 列表
|
| 170 |
qa_list = data_manager.get_qa_list(source, chart_type, model, chart_id)
|
|
@@ -185,13 +227,14 @@ def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
|
| 185 |
qa_choices = [f"Q{i+1}: {qa.question[:50]}..." for i, qa in enumerate(qa_list)] if qa_list else []
|
| 186 |
|
| 187 |
return [
|
| 188 |
-
|
| 189 |
label_text, # label_info
|
| 190 |
json.dumps([{"id": qa.id, "question": qa.question, "answer": qa.answer} for qa in qa_list]), # qa_data (JSON string)
|
| 191 |
status_text, # status_text
|
| 192 |
progress_text, # progress_text
|
| 193 |
json.dumps(existing_reviews), # current_qa_reviews (JSON string)
|
| 194 |
-
gr.Radio(choices=qa_choices, value=qa_choices[0] if qa_choices else None) # qa_selector
|
|
|
|
| 195 |
]
|
| 196 |
|
| 197 |
|
|
@@ -279,12 +322,7 @@ def create_ui():
|
|
| 279 |
# 自定义 CSS
|
| 280 |
custom_css = """
|
| 281 |
.chart-container {
|
| 282 |
-
height:
|
| 283 |
-
overflow: auto;
|
| 284 |
-
border: 1px solid #e0e0e0;
|
| 285 |
-
border-radius: 8px;
|
| 286 |
-
padding: 10px;
|
| 287 |
-
background: #fafafa;
|
| 288 |
}
|
| 289 |
|
| 290 |
.control-panel {
|
|
@@ -293,6 +331,15 @@ def create_ui():
|
|
| 293 |
border-radius: 8px;
|
| 294 |
margin-bottom: 10px;
|
| 295 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 296 |
"""
|
| 297 |
|
| 298 |
with gr.Blocks(
|
|
@@ -376,12 +423,21 @@ def create_ui():
|
|
| 376 |
value="default",
|
| 377 |
interactive=True
|
| 378 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 379 |
|
| 380 |
# ===== 中间:图表展示 =====
|
| 381 |
with gr.Column(scale=2, min_width=400):
|
| 382 |
gr.Markdown("### 📈 图表展示")
|
| 383 |
|
| 384 |
-
# HTML 图表展示
|
| 385 |
html_display = gr.HTML(
|
| 386 |
value="<div style='text-align:center;padding:50px;color:#999;'>请选择图表</div>",
|
| 387 |
elem_classes=["chart-container"]
|
|
@@ -517,7 +573,7 @@ def create_ui():
|
|
| 517 |
inputs=[source_dropdown, chart_type_dropdown, chart_dropdown, model_dropdown],
|
| 518 |
outputs=[
|
| 519 |
html_display, label_display, qa_data_json, status_text, progress_text,
|
| 520 |
-
current_reviews_json, qa_selector
|
| 521 |
]
|
| 522 |
)
|
| 523 |
|
|
@@ -526,7 +582,7 @@ def create_ui():
|
|
| 526 |
inputs=[source_dropdown, chart_type_dropdown, chart_dropdown, model_dropdown],
|
| 527 |
outputs=[
|
| 528 |
html_display, label_display, qa_data_json, status_text, progress_text,
|
| 529 |
-
current_reviews_json, qa_selector
|
| 530 |
]
|
| 531 |
)
|
| 532 |
|
|
@@ -624,4 +680,4 @@ if __name__ == "__main__":
|
|
| 624 |
server_name="0.0.0.0",
|
| 625 |
server_port=7860,
|
| 626 |
share=False
|
| 627 |
-
)
|
|
|
|
| 7 |
from typing import Dict, List, Optional, Tuple, Any
|
| 8 |
import json
|
| 9 |
import os
|
| 10 |
+
import base64
|
| 11 |
|
| 12 |
# ============== 全局状态 ==============
|
| 13 |
|
|
|
|
| 124 |
)
|
| 125 |
|
| 126 |
|
| 127 |
+
def create_embedded_html(html_content: str, chart_id: str = "") -> str:
|
| 128 |
+
"""
|
| 129 |
+
创建嵌入式的 HTML 显示
|
| 130 |
+
|
| 131 |
+
使用 data URI 方式嵌入 HTML 内容到 iframe 中
|
| 132 |
+
"""
|
| 133 |
+
if not html_content:
|
| 134 |
+
return f"""
|
| 135 |
+
<div style="display:flex;flex-direction:column;align-items:center;justify-content:center;
|
| 136 |
+
min-height:400px;color:#999;border:2px dashed #ddd;border-radius:12px;background:#fafafa;">
|
| 137 |
+
<div style="font-size:48px;margin-bottom:16px;">📭</div>
|
| 138 |
+
<div style="font-size:18px;font-weight:500;">暂无图表内容</div>
|
| 139 |
+
<div style="font-size:14px;margin-top:8px;">图表 ID: {chart_id or '未知'}</div>
|
| 140 |
+
<div style="font-size:12px;margin-top:16px;color:#888;">请检查数据集目录中是否存在该图表的 HTML 文件</div>
|
| 141 |
+
</div>
|
| 142 |
+
"""
|
| 143 |
+
|
| 144 |
+
# 使用 base64 编码 HTML 内容,避免引号转义问题
|
| 145 |
+
html_bytes = html_content.encode('utf-8')
|
| 146 |
+
html_base64 = base64.b64encode(html_bytes).decode('utf-8')
|
| 147 |
+
|
| 148 |
+
# 使用 data URI
|
| 149 |
+
iframe_html = f"""
|
| 150 |
+
<iframe
|
| 151 |
+
src="data:text/html;base64,{html_base64}"
|
| 152 |
+
style="width:100%;height:500px;border:1px solid #e0e0e0;border-radius:8px;background:#fff;"
|
| 153 |
+
sandbox="allow-scripts allow-same-origin"
|
| 154 |
+
loading="lazy"
|
| 155 |
+
></iframe>
|
| 156 |
+
"""
|
| 157 |
+
|
| 158 |
+
return iframe_html
|
| 159 |
+
|
| 160 |
+
|
| 161 |
def load_chart_data(source: str, chart_type: str, chart_id: str, model: str):
|
| 162 |
"""
|
| 163 |
加载图表数据并返回所有 UI 更新
|
|
|
|
| 167 |
"""
|
| 168 |
if not all([source, chart_type, chart_id, model]):
|
| 169 |
return [
|
| 170 |
+
create_embedded_html(""), # html_display
|
| 171 |
+
"### 请在左侧选择图表", # label_info
|
| 172 |
"[]", # qa_data (JSON string)
|
| 173 |
"等待加载数据...", # status_text
|
| 174 |
"请在左侧选择图表", # progress_text
|
| 175 |
"{}", # current_qa_reviews (JSON string)
|
| 176 |
+
gr.Radio(choices=[], value=None), # qa_selector
|
| 177 |
+
"" # debug_info
|
| 178 |
]
|
| 179 |
|
| 180 |
# 更新状态
|
|
|
|
| 185 |
html_content = chart_data.get('html_content', '')
|
| 186 |
label_info = chart_data.get('label_info', {})
|
| 187 |
|
| 188 |
+
# 创建嵌入式 HTML
|
| 189 |
+
embedded_html = create_embedded_html(html_content, chart_id)
|
| 190 |
+
|
| 191 |
+
# 调试信息
|
| 192 |
+
debug_info = f"📁 {source}/{chart_type}/{chart_id} | HTML: {len(html_content)} 字符"
|
| 193 |
+
|
| 194 |
# 格式化标签信息
|
| 195 |
if label_info:
|
| 196 |
label_text = f"""
|
|
|
|
| 206 |
| **链接** | [查看原图]({label_info.get('Weblink', '#')}) |
|
| 207 |
"""
|
| 208 |
else:
|
| 209 |
+
label_text = "### ⚠️ 暂无标签信息"
|
| 210 |
|
| 211 |
# 获取 QA 列表
|
| 212 |
qa_list = data_manager.get_qa_list(source, chart_type, model, chart_id)
|
|
|
|
| 227 |
qa_choices = [f"Q{i+1}: {qa.question[:50]}..." for i, qa in enumerate(qa_list)] if qa_list else []
|
| 228 |
|
| 229 |
return [
|
| 230 |
+
embedded_html, # html_display
|
| 231 |
label_text, # label_info
|
| 232 |
json.dumps([{"id": qa.id, "question": qa.question, "answer": qa.answer} for qa in qa_list]), # qa_data (JSON string)
|
| 233 |
status_text, # status_text
|
| 234 |
progress_text, # progress_text
|
| 235 |
json.dumps(existing_reviews), # current_qa_reviews (JSON string)
|
| 236 |
+
gr.Radio(choices=qa_choices, value=qa_choices[0] if qa_choices else None), # qa_selector
|
| 237 |
+
debug_info # debug_info
|
| 238 |
]
|
| 239 |
|
| 240 |
|
|
|
|
| 322 |
# 自定义 CSS
|
| 323 |
custom_css = """
|
| 324 |
.chart-container {
|
| 325 |
+
min-height: 520px;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
}
|
| 327 |
|
| 328 |
.control-panel {
|
|
|
|
| 331 |
border-radius: 8px;
|
| 332 |
margin-bottom: 10px;
|
| 333 |
}
|
| 334 |
+
|
| 335 |
+
.debug-panel {
|
| 336 |
+
font-size: 12px;
|
| 337 |
+
color: #666;
|
| 338 |
+
padding: 8px;
|
| 339 |
+
background: #f5f5f5;
|
| 340 |
+
border-radius: 4px;
|
| 341 |
+
margin-top: 10px;
|
| 342 |
+
}
|
| 343 |
"""
|
| 344 |
|
| 345 |
with gr.Blocks(
|
|
|
|
| 423 |
value="default",
|
| 424 |
interactive=True
|
| 425 |
)
|
| 426 |
+
|
| 427 |
+
# 调试信息
|
| 428 |
+
debug_info = gr.Textbox(
|
| 429 |
+
label="调试信息",
|
| 430 |
+
value="",
|
| 431 |
+
interactive=False,
|
| 432 |
+
show_label=False,
|
| 433 |
+
elem_classes=["debug-panel"]
|
| 434 |
+
)
|
| 435 |
|
| 436 |
# ===== 中间:图表展示 =====
|
| 437 |
with gr.Column(scale=2, min_width=400):
|
| 438 |
gr.Markdown("### 📈 图表展示")
|
| 439 |
|
| 440 |
+
# HTML 图表展示(使用 iframe)
|
| 441 |
html_display = gr.HTML(
|
| 442 |
value="<div style='text-align:center;padding:50px;color:#999;'>请选择图表</div>",
|
| 443 |
elem_classes=["chart-container"]
|
|
|
|
| 573 |
inputs=[source_dropdown, chart_type_dropdown, chart_dropdown, model_dropdown],
|
| 574 |
outputs=[
|
| 575 |
html_display, label_display, qa_data_json, status_text, progress_text,
|
| 576 |
+
current_reviews_json, qa_selector, debug_info
|
| 577 |
]
|
| 578 |
)
|
| 579 |
|
|
|
|
| 582 |
inputs=[source_dropdown, chart_type_dropdown, chart_dropdown, model_dropdown],
|
| 583 |
outputs=[
|
| 584 |
html_display, label_display, qa_data_json, status_text, progress_text,
|
| 585 |
+
current_reviews_json, qa_selector, debug_info
|
| 586 |
]
|
| 587 |
)
|
| 588 |
|
|
|
|
| 680 |
server_name="0.0.0.0",
|
| 681 |
server_port=7860,
|
| 682 |
share=False
|
| 683 |
+
)
|