# 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
**修复状态**: ✅ 实时流式显示已实现
**测试状态**: ⏳ 待验证