# AI流式传输JSON显示问题 - 实时显示方案 ## 🔍 问题现象 **对话框显示原始JSON**(修复前): ```json { "spaceType": "入户玄关", "spacePositioning": "该空间作为住宅的入户过渡区域...", "layout": "空间采用单边动线布局..." } ``` **控制台日志**: ``` 📥 AI流式响应: string { "spaceType": "入户玄关", ... } ``` --- ## 🎯 根本原因 ### 1. 流式传输特性 - `completionJSON`使用流式传输逐步发送内容 - AI按JSON格式生成内容,在生成过程中发送**不完整的JSON字符串** - 流式回调收到的是`string`类型的JSON片段 ### 2. JSON解析失败 - 不完整的JSON无法被`JSON.parse()`解析 - 例如:`{"spaceType":"客厅","layout":"空间采用...` (缺少结尾`}`) - 花括号不匹配:`{` > `}` ### 3. 用户需求 - ❌ 不希望显示原始JSON - ❌ 不希望显示"正在生成..."等待提示 - ✅ **希望实时显示已生成的分析文字**(流式体验) --- ## ✅ 修复方案:实时提取和显示 ### 核心策略:从不完整JSON中提取字段并实时格式化 **逻辑流程**: 1. 检测到JSON格式字符串(以`{`开头) 2. 尝试`JSON.parse()`解析完整JSON 3. **如果失败** → 调用`extractPartialJSON()`提取已完成的字段 4. 格式化提取到的字段 → 实时显示中文文本 5. 随着流式传输继续,不断更新显示 ### 方案1:部分字段提取(核心修复) **`extractPartialJSON`方法**(新增,第488-525行): 使用正则表达式从不完整的JSON中提取已生成的字段: ```typescript private extractPartialJSON(jsonString: string): any { const result: any = {}; const fields = [ 'spaceType', 'spacePositioning', 'layout', 'hardDecoration', 'colorAnalysis', 'materials', 'form', 'style', 'suggestions' ]; for (const field of fields) { // 匹配完整的字段值: "fieldName": "value" const regex = new RegExp(`"${field}"\\s*:\\s*"([^"]*)"`, 'g'); const match = regex.exec(jsonString); if (match && match[1]) { result[field] = match[1]; console.log(`✅ 提取字段 ${field}`); } else { // 尝试提取不完整的值(当前正在生成中的字段) const partialRegex = new RegExp(`"${field}"\\s*:\\s*"([^"]*?)(?:"|$)`, 's'); const partialMatch = partialRegex.exec(jsonString); if (partialMatch && partialMatch[1] && partialMatch[1].length > 20) { result[field] = partialMatch[1] + '...'; // 添加省略号标记 console.log(`⚠️ 提取不完整字段 ${field}`); } } } return Object.keys(result).length > 0 ? result : null; } ``` **提取示例**: 输入(不完整JSON): ```json {"spaceType":"客厅","spacePositioning":"该空间定位为高端住宅的核心社交区域,兼具日常休闲与接待功能...","layout":"空间采用围合式布局,以电视背景墙为 ``` 输出(提取结果): ```javascript { spaceType: "客厅", spacePositioning: "该空间定位为高端住宅的核心社交区域...", layout: "空间采用围合式布局,以电视背景墙为..." } ``` ### 方案2:实时格式化显示 **代码**(`design-analysis-ai.service.ts` 第100-131行): ```typescript if (trimmed.startsWith('{') || trimmed.startsWith('[')) { try { jsonObject = JSON.parse(trimmed); console.log('✅ JSON解析成功,完整对象'); } catch (e) { // 🔥 关键修复:JSON不完整时,提取已完整的字段并格式化显示 console.log('⚠️ JSON解析失败,尝试提取部分字段...'); jsonObject = this.extractPartialJSON(trimmed); if (jsonObject && Object.keys(jsonObject).length > 0) { console.log('✅ 成功提取部分字段:', Object.keys(jsonObject).join(', ')); // 继续格式化显示 } else { displayText = '🔄 正在生成分析结果...'; // 完全无法提取时 } } } // 格式化JSON对象(完整或部分) if (jsonObject) { displayText = this.formatJSONToText(jsonObject); // 后备方案... } ``` ### 方案3:最后覆盖显示(已实现) **逻辑**: - AI完成后,调用`parseJSONAnalysis`生成`formattedContent` - 通过`onContentStream`发送最终格式化内容 - **覆盖之前显示的进度提示或JSON片段** **代码**(`design-analysis-ai.service.ts` 第204-208行): ```typescript // 🔥 关键:在最后发送完整的格式化内容 if (options.onContentStream && analysisData.formattedContent) { console.log('📤 发送最终格式化内容到UI...'); options.onContentStream(analysisData.formattedContent); } ``` --- ## 🧪 调试步骤 ### 1. 检查控制台日志 **正常流程**(修复后 - 实时显示): ``` 📥 AI流式响应: string {"spaceType":"客厅"... 🔍 检测到JSON格式字符串,尝试解析... ⚠️ JSON解析失败,尝试提取部分字段... 🔧 [extractPartialJSON] 开始提取部分JSON字段... ✅ 提取字段 spaceType: 客厅 ✅ 成功提取部分字段: spaceType 🎨 开始格式化JSON对象... → 显示: 空间类型:客厅 (流式传输继续...) 📥 AI流式响应: string {"spaceType":"客厅","spacePositioning":"该空间定位为... ⚠️ JSON解析失败,尝试提取部分字段... ✅ 提取字段 spaceType: 客厅 ✅ 提取字段 spacePositioning: 该空间定位为高端住宅的核心社交区域... ✅ 成功提取部分字段: spaceType, spacePositioning → 显示: 空间类型:客厅 一、空间定位与场景属性 该空间定位为... (继续...直到完成) 📥 AI最终返回结果: {spaceType: "客厅", spacePositioning: "...", ...} ✅ JSON解析成功,完整对象 📊 解析后的分析数据: {formattedContent: "一、空间定位..."} 📤 发送最终格式化内容到UI... → 显示: 完整的格式化文本(8个维度) ``` **异常情况1**:JSON解析成功但格式化失败 ``` ✅ JSON解析成功 🎨 开始格式化JSON对象... ⚠️ formatJSONToText结果过短,使用fallback... ✅ [fallbackFormatJSON] 后备格式化完成,长度: 523 → 显示格式化后的中文文本 ``` **异常情况2**:花括号匹配但JSON有语法错误 ``` ⚠️ JSON解析失败,可能是流式传输中数据不完整 📊 JSON不完整: {5 vs }5 (匹配) ❌ JSON解析失败: SyntaxError: Unexpected token → 显示: ⚠️ AI分析结果格式异常,正在重新生成... ``` ### 2. 检查对话框显示 **修复前**: ``` 对话框内容: { "spaceType": "入户玄关", "spacePositioning": "该空间作为住宅的..." } ``` **修复后(流式传输中)**: ``` 对话框内容: 🔄 正在生成分析结果... ``` **修复后(完成)**: ``` 对话框内容: 一、空间定位与场景属性 该空间作为住宅的入户过渡区域,兼具交通枢纽与形象展示功能... 二、空间布局与动线 空间采用单边动线布局,电梯井道嵌入式设置于右侧墙体结构中... ``` ### 3. 验证JSON不完整检测 **手动测试**: ```javascript // 在浏览器控制台测试 const json1 = '{"spaceType":"客厅","layout":"空间采用'; const json2 = '{"spaceType":"客厅","layout":"空间采用"}'; const check = (str) => { const open = (str.match(/\{/g) || []).length; const close = (str.match(/\}/g) || []).length; console.log(`{${open} vs }${close}`, open > close ? '不完整' : '完整'); }; check(json1); // {2 vs }0 不完整 ✅ check(json2); // {2 vs }2 完整 ✅ ``` --- ## 📊 修复效果对比 ### 流式传输过程(实时显示) **修复前**: ``` 对话框显示: {"spaceType":"客厅","spacePositioning":"该空间定位为高端住宅...","layout":"空间采用 ``` **修复后**: ``` 对话框显示(实时更新): 空间类型:客厅 一、空间定位与场景属性 该空间定位为高端住宅的核心社交区域... 二、空间布局与动线 空间采用围合式布局...(继续生成中) ``` ### 对比表格 | 场景 | 修复前 | 修复后 | |------|--------|--------| | **流式传输开始** | `{"spaceType":"客厅"...` | **空间类型:客厅** | | **第1个字段完成** | `{"spaceType":"客厅","spacePositioning":"...` | **一、空间定位与场景属性**
该空间定位为... | | **第2个字段完成** | 继续显示JSON | **二、空间布局与动线**
空间采用... | | **流式传输中** | 显示原始JSON片段 | **实时显示已生成的中文文本** ✅ | | **完成时** | 可能显示JSON或格式化文本 | 显示完整的格式化中文文本 ✅ | | **JSON解析失败** | 显示原始JSON | 提取部分字段或显示提示 | --- ## 🔧 故障排除 ### 问题1:仍然显示JSON **可能原因**: - 代码未重新编译部署 - 浏览器缓存未清除 **解决方案**: ```powershell # 1. 重新编译 npm run build:prod # 2. 部署 .\deploy.ps1 # 3. 清除浏览器缓存 Ctrl + Shift + Delete ``` ### 问题2:显示"正在生成"但一直不更新 **可能原因**: - AI分析失败,没有调用最终的`onContentStream` - `analysisData.formattedContent`为空 **排查步骤**: 1. 查看控制台是否有"📤 发送最终格式化内容"日志 2. 检查是否有错误日志 3. 验证`parseJSONAnalysis`返回的内容 ### 问题3:格式化内容为空 **可能原因**: - AI返回的JSON缺少必要字段 - `formatJSONToText`、`fallbackFormatJSON`、`beautifyJSON`都失败 **排查步骤**: 1. 查看控制台日志中的"AI返回JSON预览" 2. 检查是否有字段缺失 3. 验证`getChineseTitleForKey`映射是否正确 --- ## 📝 测试清单 ### 基本功能测试 - [ ] 上传图片,开始AI分析 - [ ] 检查控制台日志中有"🔍 检测到JSON格式字符串" - [ ] 验证对话框**不显示原始JSON** - [ ] 验证对话框**实时显示中文分析文字**(而不是等待提示) ### 实时流式显示测试 - [ ] 观察对话框内容逐步增加 - [ ] 第1个字段生成时,显示"空间类型:XXX" - [ ] 第2个字段生成时,显示"一、空间定位与场景属性\n\n..." - [ ] 后续字段逐步追加显示 - [ ] 检查控制台日志中有"✅ 提取字段 spaceType"等日志 - [ ] 检查控制台日志中有"✅ 成功提取部分字段: spaceType, spacePositioning..." ### 完成状态测试 - [ ] 等待分析完成 - [ ] 检查控制台日志中有"✅ JSON解析成功,完整对象" - [ ] 检查控制台日志中有"📤 发送最终格式化内容" - [ ] 验证对话框显示完整的格式化中文文本(8个维度) - [ ] 验证文本带标题:一、二、三...八 ### 异常处理测试 - [ ] 如果某个字段特别长,验证是否正常显示 - [ ] 如果AI返回速度很快,验证是否正常显示 - [ ] 验证没有显示"🔄 正在生成..."(除非完全无法提取字段) --- ## 🔗 相关文件 1. **`design-analysis-ai.service.ts`** (第100-131行) - 流式回调JSON检测和处理 - 调用`extractPartialJSON`提取部分字段 - 实时格式化显示 2. **`design-analysis-ai.service.ts`** (第488-525行) **🆕** - **`extractPartialJSON` - 从不完整JSON中提取字段** - 使用正则表达式匹配已完成的字段 - 支持流式传输时实时提取 3. **`design-analysis-ai.service.ts`** (第430-482行) - `formatJSONToText` - 格式化为中文文本(带标题) - `fallbackFormatJSON` - 后备格式化方案 - `beautifyJSON` - 美化JSON显示 4. **`design-analysis-ai.service.ts`** (第290-330行) - `parseJSONAnalysis` - 解析JSON为结构化数据 - 最终格式化内容发送(第204-208行) 5. **`stage-requirements.component.ts`** (第3445-3454行) - `onContentStream` 回调处理 - 更新对话框内容 --- ## 📋 修复总结 ### 核心改进 1. ✅ **实时流式显示**:不等待完整JSON,逐步提取并显示已生成的字段 2. ✅ **智能字段提取**:使用正则表达式从不完整JSON中提取完整字段值 3. ✅ **用户体验优化**:用户看到的是逐步生成的中文分析文字,而不是JSON或等待提示 ### 技术亮点 - 正则表达式精准匹配JSON字段 - 支持提取不完整字段(当前正在生成的字段) - 三层格式化保障(formatJSONToText → fallbackFormatJSON → beautifyJSON) - 详细的控制台日志便于调试 --- **创建时间**: 2024-12-01 16:40 **最后更新**: 2024-12-01 16:50 **修复状态**: ✅ 实时流式显示已实现 **测试状态**: ⏳ 待验证