Add four-tab interface for caching all stage results, enable Qwen3-8B thinking, and implement proper stage switching
Browse files
app.py
CHANGED
@@ -886,37 +886,63 @@ async def streaming_ai_analysis(text: str, keywords: List[str], country: str, la
|
|
886 |
except Exception as e:
|
887 |
yield f"分析出错:{str(e)}"
|
888 |
|
889 |
-
# 三次渐进式输出的审核函数 -
|
890 |
def comprehensive_text_audit_streaming(text, keywords="", country="China", language="简体中文", model="Qwen/Qwen3-8B (Free - SiliconFlow)"):
|
891 |
"""
|
892 |
-
三次渐进式输出的AI内容审核 -
|
893 |
"""
|
894 |
if not text.strip():
|
895 |
-
yield "❌ Please enter text content"
|
896 |
return
|
897 |
|
898 |
# Parse keywords
|
899 |
keyword_list = [k.strip() for k in keywords.split(",") if k.strip()] if keywords else []
|
900 |
|
901 |
-
#
|
902 |
messages = []
|
|
|
|
|
|
|
903 |
|
904 |
try:
|
905 |
-
# 第一阶段:基础分析
|
|
|
|
|
|
|
906 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=1):
|
907 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
908 |
|
909 |
-
|
910 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=2):
|
911 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
912 |
|
913 |
-
|
914 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=3):
|
915 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
916 |
|
917 |
except Exception as e:
|
918 |
print(f"Analysis error: {e}")
|
919 |
-
|
|
|
920 |
|
921 |
# 执行流式分析
|
922 |
def perform_streaming_analysis(text: str, keywords: List[str], country: str, language: str, model: str, messages: list, stage: int):
|
@@ -1044,13 +1070,20 @@ def perform_streaming_analysis(text: str, keywords: List[str], country: str, lan
|
|
1044 |
)
|
1045 |
|
1046 |
# 发送流式请求
|
1047 |
-
|
1048 |
-
model
|
1049 |
-
messages
|
1050 |
-
stream
|
1051 |
-
max_tokens
|
1052 |
-
temperature
|
1053 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1054 |
|
1055 |
# 逐步接收并处理响应
|
1056 |
for chunk in response:
|
@@ -1176,6 +1209,84 @@ def generate_streaming_stage_html(stage: int, title: str, content: str, reasonin
|
|
1176 |
</div>
|
1177 |
"""
|
1178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1179 |
# 执行reasoning分析
|
1180 |
def perform_reasoning_analysis(text: str, keywords: List[str], country: str, language: str, model: str, messages: list, stage: int) -> dict:
|
1181 |
"""执行带reasoning的AI分析"""
|
@@ -2475,11 +2586,31 @@ with gr.Blocks(
|
|
2475 |
clear_btn = gr.Button("🗑️ Clear", variant="secondary", scale=1)
|
2476 |
|
2477 |
with gr.Column(scale=2):
|
2478 |
-
# 输出区域
|
2479 |
-
|
2480 |
-
|
2481 |
-
|
2482 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2483 |
|
2484 |
# 示例区域
|
2485 |
gr.Markdown("### 📋 Examples")
|
@@ -2488,16 +2619,20 @@ with gr.Blocks(
|
|
2488 |
example2_btn = gr.Button("Example 2: English Product Ad", size="sm")
|
2489 |
example3_btn = gr.Button("Example 3: Mixed Content", size="sm")
|
2490 |
|
2491 |
-
# 事件处理 -
|
2492 |
submit_btn.click(
|
2493 |
fn=comprehensive_text_audit_streaming,
|
2494 |
inputs=[text_input, keywords_input, country_select, language_select, model_select],
|
2495 |
-
outputs=
|
2496 |
)
|
2497 |
|
2498 |
clear_btn.click(
|
2499 |
-
fn=lambda: ("", "", "China", "简体中文", "Qwen/Qwen3-8B (Free - SiliconFlow)",
|
2500 |
-
|
|
|
|
|
|
|
|
|
2501 |
)
|
2502 |
|
2503 |
# 示例按钮事件
|
|
|
886 |
except Exception as e:
|
887 |
yield f"分析出错:{str(e)}"
|
888 |
|
889 |
+
# 三次渐进式输出的审核函数 - 缓存结果并支持切换
|
890 |
def comprehensive_text_audit_streaming(text, keywords="", country="China", language="简体中文", model="Qwen/Qwen3-8B (Free - SiliconFlow)"):
|
891 |
"""
|
892 |
+
三次渐进式输出的AI内容审核 - 缓存所有阶段结果
|
893 |
"""
|
894 |
if not text.strip():
|
895 |
+
yield ("❌ Please enter text content", "", "", "")
|
896 |
return
|
897 |
|
898 |
# Parse keywords
|
899 |
keyword_list = [k.strip() for k in keywords.split(",") if k.strip()] if keywords else []
|
900 |
|
901 |
+
# 初始化对话历史和结果缓存
|
902 |
messages = []
|
903 |
+
stage1_result = ""
|
904 |
+
stage2_result = ""
|
905 |
+
stage3_result = ""
|
906 |
|
907 |
try:
|
908 |
+
# 第一阶段:基础分析
|
909 |
+
yield ("🔍 Stage 1: Basic Analysis in progress...", "", "", "")
|
910 |
+
|
911 |
+
stage1_final = None
|
912 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=1):
|
913 |
+
stage1_final = chunk
|
914 |
+
yield (chunk, "", "", "")
|
915 |
+
|
916 |
+
stage1_result = stage1_final
|
917 |
+
|
918 |
+
# 第二阶段:详细标注
|
919 |
+
yield (stage1_result, "🎨 Stage 2: Detailed Annotation in progress...", "", "")
|
920 |
|
921 |
+
stage2_final = None
|
922 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=2):
|
923 |
+
stage2_final = chunk
|
924 |
+
yield (stage1_result, chunk, "", "")
|
925 |
+
|
926 |
+
stage2_result = stage2_final
|
927 |
+
|
928 |
+
# 第三阶段:修改建议
|
929 |
+
yield (stage1_result, stage2_result, "✨ Stage 3: Revision Suggestions in progress...", "")
|
930 |
|
931 |
+
stage3_final = None
|
932 |
for chunk in perform_streaming_analysis(text, keyword_list, country, language, model, messages, stage=3):
|
933 |
+
stage3_final = chunk
|
934 |
+
yield (stage1_result, stage2_result, chunk, "")
|
935 |
+
|
936 |
+
stage3_result = stage3_final
|
937 |
+
|
938 |
+
# 生成摘要界面
|
939 |
+
summary_interface = generate_analysis_summary()
|
940 |
+
yield (stage1_result, stage2_result, stage3_result, summary_interface)
|
941 |
|
942 |
except Exception as e:
|
943 |
print(f"Analysis error: {e}")
|
944 |
+
error_msg = generate_error_card(str(e))
|
945 |
+
yield (error_msg, "", "", "")
|
946 |
|
947 |
# 执行流式分析
|
948 |
def perform_streaming_analysis(text: str, keywords: List[str], country: str, language: str, model: str, messages: list, stage: int):
|
|
|
1070 |
)
|
1071 |
|
1072 |
# 发送流式请求
|
1073 |
+
request_params = {
|
1074 |
+
"model": model_config["model"],
|
1075 |
+
"messages": current_messages,
|
1076 |
+
"stream": True,
|
1077 |
+
"max_tokens": 4096,
|
1078 |
+
"temperature": 0.1
|
1079 |
+
}
|
1080 |
+
|
1081 |
+
# 为Qwen3-8B启用thinking
|
1082 |
+
if model_config["model"] == "Qwen/Qwen3-8B":
|
1083 |
+
request_params["enable_thinking"] = True
|
1084 |
+
request_params["thinking_budget"] = 2048
|
1085 |
+
|
1086 |
+
response = client.chat.completions.create(**request_params)
|
1087 |
|
1088 |
# 逐步接收并处理响应
|
1089 |
for chunk in response:
|
|
|
1209 |
</div>
|
1210 |
"""
|
1211 |
|
1212 |
+
# 生成分析摘要
|
1213 |
+
def generate_analysis_summary() -> str:
|
1214 |
+
"""生成分析摘要界面"""
|
1215 |
+
return f"""
|
1216 |
+
<div style="
|
1217 |
+
max-width: 900px;
|
1218 |
+
margin: 0 auto;
|
1219 |
+
padding: 30px;
|
1220 |
+
background: linear-gradient(135deg, #E8E3DE 0%, #F2EDE9 100%);
|
1221 |
+
border-radius: 20px;
|
1222 |
+
font-family: 'Microsoft YaHei', 'Noto Sans SC', sans-serif;
|
1223 |
+
">
|
1224 |
+
<div style="
|
1225 |
+
background-color: #F2EDE9;
|
1226 |
+
border-radius: 15px;
|
1227 |
+
padding: 25px;
|
1228 |
+
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
|
1229 |
+
">
|
1230 |
+
<h2 style="
|
1231 |
+
color: #5B5B5B;
|
1232 |
+
margin-bottom: 20px;
|
1233 |
+
font-size: 28px;
|
1234 |
+
border-bottom: 3px solid #9A8F8F;
|
1235 |
+
padding-bottom: 10px;
|
1236 |
+
">📊 Analysis Summary</h2>
|
1237 |
+
|
1238 |
+
<div style="
|
1239 |
+
background-color: rgba(255,255,255,0.7);
|
1240 |
+
padding: 20px;
|
1241 |
+
border-radius: 10px;
|
1242 |
+
margin-bottom: 20px;
|
1243 |
+
">
|
1244 |
+
<h3 style="color: #5B5B5B; margin-bottom: 15px; font-size: 20px;">🎯 Three-Stage Analysis Complete</h3>
|
1245 |
+
|
1246 |
+
<div style="margin: 15px 0;">
|
1247 |
+
<h4 style="color: #4CAF50; margin-bottom: 10px;">🔍 Stage 1: Basic Analysis</h4>
|
1248 |
+
<p style="color: #5B5B5B; margin-left: 20px;">Initial risk assessment and compliance evaluation</p>
|
1249 |
+
</div>
|
1250 |
+
|
1251 |
+
<div style="margin: 15px 0;">
|
1252 |
+
<h4 style="color: #FF9800; margin-bottom: 10px;">🎨 Stage 2: Detailed Annotation</h4>
|
1253 |
+
<p style="color: #5B5B5B; margin-left: 20px;">Sentence-level risk marking with color coding</p>
|
1254 |
+
</div>
|
1255 |
+
|
1256 |
+
<div style="margin: 15px 0;">
|
1257 |
+
<h4 style="color: #9C27B0; margin-bottom: 10px;">✨ Stage 3: Revision Suggestions</h4>
|
1258 |
+
<p style="color: #5B5B5B; margin-left: 20px;">Corrected text with compliance improvements</p>
|
1259 |
+
</div>
|
1260 |
+
</div>
|
1261 |
+
|
1262 |
+
<div style="
|
1263 |
+
background-color: rgba(255,255,255,0.5);
|
1264 |
+
padding: 20px;
|
1265 |
+
border-radius: 10px;
|
1266 |
+
margin-bottom: 20px;
|
1267 |
+
">
|
1268 |
+
<h3 style="color: #5B5B5B; margin-bottom: 15px; font-size: 20px;">💡 How to Use</h3>
|
1269 |
+
<ul style="color: #5B5B5B; line-height: 1.8;">
|
1270 |
+
<li><strong>Switch between tabs</strong> to view different analysis stages</li>
|
1271 |
+
<li><strong>Click the reasoning sections</strong> to see AI's thought process</li>
|
1272 |
+
<li><strong>Compare original and revised text</strong> in Stage 3</li>
|
1273 |
+
<li><strong>Use color coding</strong> in Stage 2 to identify risk levels</li>
|
1274 |
+
</ul>
|
1275 |
+
</div>
|
1276 |
+
|
1277 |
+
<div style="
|
1278 |
+
text-align: center;
|
1279 |
+
color: #4A7C59;
|
1280 |
+
font-size: 18px;
|
1281 |
+
font-weight: bold;
|
1282 |
+
padding: 20px;
|
1283 |
+
background-color: rgba(74, 124, 89, 0.1);
|
1284 |
+
border-radius: 8px;
|
1285 |
+
">🎉 Content Audit Complete! Review all stages above.</div>
|
1286 |
+
</div>
|
1287 |
+
</div>
|
1288 |
+
"""
|
1289 |
+
|
1290 |
# 执行reasoning分析
|
1291 |
def perform_reasoning_analysis(text: str, keywords: List[str], country: str, language: str, model: str, messages: list, stage: int) -> dict:
|
1292 |
"""执行带reasoning的AI分析"""
|
|
|
2586 |
clear_btn = gr.Button("🗑️ Clear", variant="secondary", scale=1)
|
2587 |
|
2588 |
with gr.Column(scale=2):
|
2589 |
+
# 输出区域 - 四个标签页
|
2590 |
+
with gr.Tabs():
|
2591 |
+
with gr.TabItem("🔍 Stage 1: Basic Analysis"):
|
2592 |
+
stage1_output = gr.HTML(
|
2593 |
+
value="<div style='text-align: center; padding: 50px; color: #888;'>Stage 1 results will appear here...</div>",
|
2594 |
+
label="Stage 1 Results"
|
2595 |
+
)
|
2596 |
+
|
2597 |
+
with gr.TabItem("🎨 Stage 2: Detailed Annotation"):
|
2598 |
+
stage2_output = gr.HTML(
|
2599 |
+
value="<div style='text-align: center; padding: 50px; color: #888;'>Stage 2 results will appear here...</div>",
|
2600 |
+
label="Stage 2 Results"
|
2601 |
+
)
|
2602 |
+
|
2603 |
+
with gr.TabItem("✨ Stage 3: Revision Suggestions"):
|
2604 |
+
stage3_output = gr.HTML(
|
2605 |
+
value="<div style='text-align: center; padding: 50px; color: #888;'>Stage 3 results will appear here...</div>",
|
2606 |
+
label="Stage 3 Results"
|
2607 |
+
)
|
2608 |
+
|
2609 |
+
with gr.TabItem("📊 Summary"):
|
2610 |
+
summary_output = gr.HTML(
|
2611 |
+
value="<div style='text-align: center; padding: 50px; color: #888;'>Analysis summary will appear here...</div>",
|
2612 |
+
label="Summary"
|
2613 |
+
)
|
2614 |
|
2615 |
# 示例区域
|
2616 |
gr.Markdown("### 📋 Examples")
|
|
|
2619 |
example2_btn = gr.Button("Example 2: English Product Ad", size="sm")
|
2620 |
example3_btn = gr.Button("Example 3: Mixed Content", size="sm")
|
2621 |
|
2622 |
+
# 事件处理 - 使用四个输出
|
2623 |
submit_btn.click(
|
2624 |
fn=comprehensive_text_audit_streaming,
|
2625 |
inputs=[text_input, keywords_input, country_select, language_select, model_select],
|
2626 |
+
outputs=[stage1_output, stage2_output, stage3_output, summary_output]
|
2627 |
)
|
2628 |
|
2629 |
clear_btn.click(
|
2630 |
+
fn=lambda: ("", "", "China", "简体中文", "Qwen/Qwen3-8B (Free - SiliconFlow)",
|
2631 |
+
"<div style='text-align: center; padding: 50px; color: #888;'>Stage 1 results will appear here...</div>",
|
2632 |
+
"<div style='text-align: center; padding: 50px; color: #888;'>Stage 2 results will appear here...</div>",
|
2633 |
+
"<div style='text-align: center; padding: 50px; color: #888;'>Stage 3 results will appear here...</div>",
|
2634 |
+
"<div style='text-align: center; padding: 50px; color: #888;'>Analysis summary will appear here...</div>"),
|
2635 |
+
outputs=[text_input, keywords_input, country_select, language_select, model_select, stage1_output, stage2_output, stage3_output, summary_output]
|
2636 |
)
|
2637 |
|
2638 |
# 示例按钮事件
|