fix(ai): 修复分析结果 JSON 嵌套 bug
- replay_cached 直接回放纯文本,不再包装 JSON 壳 - complete_analysis 跳过已完成的记录,防止缓存命中时覆写 - 前端 AnalysisContent 增加 extractPlainText 递归解析 JSON
This commit is contained in:
@@ -60,9 +60,23 @@ const SUGGESTION_STATUS_CONFIG: Record<string, { color: string; text: string }>
|
||||
// 分析结果渲染(Markdown 风格)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** 递归提取 JSON 嵌套中的实际文本内容 */
|
||||
function extractPlainText(raw: string): string {
|
||||
try {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (typeof parsed === 'object' && parsed !== null && typeof parsed.content === 'string') {
|
||||
return extractPlainText(parsed.content);
|
||||
}
|
||||
return raw;
|
||||
} catch {
|
||||
return raw;
|
||||
}
|
||||
}
|
||||
|
||||
function AnalysisContent({ content, isDark }: { content: string; isDark: boolean }) {
|
||||
const text = extractPlainText(content);
|
||||
// 简单的 Markdown 风格渲染
|
||||
const lines = content.split('\n');
|
||||
const lines = text.split('\n');
|
||||
const rendered = lines.map((line, i) => {
|
||||
// 标题行
|
||||
if (line.startsWith('### ')) {
|
||||
|
||||
@@ -128,20 +128,14 @@ impl AnalysisService {
|
||||
Ok((stream, analysis_id, provider_name))
|
||||
}
|
||||
|
||||
/// 将缓存结果构造为一次性 Stream(模拟 SSE 单条返回)
|
||||
/// 将缓存结果构造为一次性 Stream(直接回放纯文本,不额外包装 JSON)
|
||||
fn replay_cached(
|
||||
&self,
|
||||
content: String,
|
||||
metadata: serde_json::Value,
|
||||
_metadata: serde_json::Value,
|
||||
) -> Pin<Box<dyn Stream<Item = AiResult<String>> + Send>> {
|
||||
use futures::stream;
|
||||
let payload = serde_json::json!({
|
||||
"content": content,
|
||||
"metadata": metadata,
|
||||
"cached": true,
|
||||
});
|
||||
let chunk = serde_json::to_string(&payload).unwrap_or_default();
|
||||
Box::pin(stream::once(async move { Ok(chunk) }))
|
||||
Box::pin(stream::once(async move { Ok(content) }))
|
||||
}
|
||||
|
||||
/// 更新分析记录为完成
|
||||
@@ -156,6 +150,11 @@ impl AnalysisService {
|
||||
.await?
|
||||
.ok_or_else(|| AiError::AnalysisNotFound(analysis_id.to_string()))?;
|
||||
|
||||
// 缓存回放时记录已是 completed,跳过重复更新
|
||||
if entity.status == "completed" {
|
||||
tracing::debug!(analysis = %analysis_id, "分析已完成,跳过重复 complete");
|
||||
return Ok(());
|
||||
}
|
||||
let mut active: ai_analysis::ActiveModel = entity.into();
|
||||
active.status = Set("completed".into());
|
||||
active.result_content = Set(Some(content));
|
||||
|
||||
Reference in New Issue
Block a user