# 灵感点可视化工具

将灵感点分析数据（包括匹配结果、搜索结果等）生成交互式HTML可视化页面。

---

## 快速开始

```bash
python visualize_inspiration_points.py
```

生成的HTML文件位置：
```
data/阿里多多酱/out/人设_1110/how/灵感点可视化.html
```

在浏览器中打开该文件即可查看可视化结果。

---

## 功能特性

### 1. 步骤化展示

- **步骤1**：灵感点匹配灵感分类（基于step1数据）
  - 显示灵感点与各个灵感要素的匹配关系
  - 展示匹配分数、相同部分、增量部分、分数说明

- **步骤2**：搜索结果展示（基于search数据）
  - **2.1**：直接搜索灵感分类
    - 显示以灵感要素为关键词搜索到的小红书帖子
    - 展示每个帖子与原始灵感点的匹配分数（基于step4数据）

### 2. 双层匹配分数展示

#### 步骤1分数（灵感点 → 灵感要素）
- 数据来源：`all_step1_灵感人设匹配_gemini-2.5-pro.json`
- 显示位置：步骤1匹配项的顶部标题栏
- 含义：灵感点与某个灵感要素的语义匹配度

#### 步骤4分数（搜索帖子 → 灵感点）
- 数据来源：`all_step4_搜索结果匹配_gemini-2.5-pro.json`
- 显示位置：搜索结果帖子卡片的右上角徽章
- 含义：搜索到的帖子内容与原始灵感点的匹配度

### 3. 交互功能

- **可折叠面板**
  - 步骤1和步骤2可独立折叠
  - 匹配项列表可折叠（默认只展开第一个）

- **卡片点击详情**
  - 点击灵感点卡片：查看完整的灵感点信息
  - 点击分类卡片：查看该灵感要素下的所有帖子
  - 点击搜索结果卡片：查看帖子的完整详情

- **分数详情弹窗**
  - 点击步骤4的匹配分数徽章
  - 显示：分数、相同部分、增量部分、分数说明

- **图片轮播**
  - 搜索结果卡片支持多图轮播
  - 点击左右箭头切换图片

### 4. 智能排序

- 搜索结果按匹配分数降序排列
- 有匹配分数的帖子优先显示
- 无匹配分数的帖子排在最后

---

## 数据来源

### 输入文件

| 文件路径 | 用途 | 数据内容 |
|---------|------|---------|
| `data/阿里多多酱/out/人设_1110/how/灵感点/[灵感点名称]/all_summary_完整流程_gemini-2.5-pro.json` | 灵感点摘要 | 灵感点的基本信息、描述、维度等 |
| `data/阿里多多酱/out/人设_1110/how/灵感点/[灵感点名称]/all_step1_灵感人设匹配_gemini-2.5-pro.json` | 步骤1匹配 | 灵感点与灵感要素的匹配结果 |
| `data/阿里多多酱/out/人设_1110/how/灵感点/[灵感点名称]/search/all_search_*.json` | 搜索结果 | 以灵感要素为关键词搜索的小红书帖子 |
| `data/阿里多多酱/out/人设_1110/how/灵感点/[灵感点名称]/search/all_step4_搜索结果匹配_gemini-2.5-pro.json` | 步骤4匹配 | 搜索结果帖子与灵感点的匹配分数 |
| `data/阿里多多酱/out/人设_1110/分类索引_完整.json` | 分类索引 | 灵感分类、目的分类、关键点分类的完整索引 |
| `data/阿里多多酱/out/人设_1110/点到帖子映射.json` | 点映射 | 灵感点/目的点/关键点到帖子的映射 |
| `data/阿里多多酱/out/人设_1110/帖子到分类和点映射.json` | 帖子映射 | 帖子ID到分类和点的映射 |

### 输出文件

```
data/阿里多多酱/out/人设_1110/how/灵感点可视化.html
```

单个HTML文件包含所有数据和样式，可直接在浏览器中打开。

---

## 数据结构说明

### Step1 数据结构（灵感点 → 灵感要素）

**文件**: `all_step1_灵感人设匹配_gemini-2.5-pro.json`

```json
{
  "灵感": "内容植入品牌推广",
  "匹配结果列表": [
    {
      "输入信息": {
        "B": "内容植入品牌推广",
        "A": "将品牌/产品信息融入内容",
        "A_Context": "所属视角: 灵感触发源\n一级分类: 商业合作的要求"
      },
      "匹配结果": {
        "score": 0.9,
        "score说明": "...",
        "相同部分": {"内容": "...", "品牌": "..."},
        "增量部分": {"推广": "..."}
      },
      "业务信息": {
        "灵感": "内容植入品牌推广",
        "匹配要素": "将品牌/产品信息融入内容"
      }
    }
  ]
}
```

**关键字段**:
- `输入信息.A`: 灵感要素名称（用于展示和搜索）
- `输入信息.A_Context`: 灵感要素的分类层级
- `匹配结果.score`: 灵感点与灵感要素的匹配分数

### Step4 数据结构（搜索帖子 → 灵感点）

**文件**: `all_step4_搜索结果匹配_gemini-2.5-pro.json`

```json
{
  "输入信息": {
    "灵感": "内容植入品牌推广",
    "搜索关键词": "将品牌/产品信息融入内容",
    "搜索结果数": 20
  },
  "匹配结果列表": [
    {
      "输入信息": {
        "B": "内容植入品牌推广",
        "A": "🔥 Gpt 4o 将品牌符号融入场景，附步骤！",
        "A_Context": "..."
      },
      "匹配结果": {
        "score": 0.75,
        "score说明": "...",
        "相同部分": {"内容植入": "...", "品牌推广": "..."},
        "增量部分": {"品牌推广": "..."}
      },
      "业务信息": {
        "灵感": "内容植入品牌推广",
        "channel_content_id": "6842c7d3000000002001f6c4",
        "title": "🔥 Gpt 4o 将品牌符号融入场景，附步骤！",
        "likes": 801
      }
    }
  ]
}
```

**关键字段**:
- `输入信息.A`: 帖子标题
- `匹配结果.score`: 帖子与灵感点的匹配分数
- `业务信息.channel_content_id`: 帖子ID（用于关联搜索结果）

---

## 重要技术说明

### 变量命名隔离

**问题背景**：步骤1和步骤4使用相同的数据结构（相同部分、增量部分、score等），在同一个循环中处理时容易导致变量覆盖。

**解决方案**：使用不同的变量名前缀

**步骤1变量**（灵感点匹配）:
```python
score = match_result.get("score", 0)
score_explain = match_result.get("score说明", "")
same_parts = match_result.get("相同部分", {})
increment_parts = match_result.get("增量部分", {})
```

**步骤4变量**（搜索结果匹配）:
```python
note_score = score_info["score"]
note_score_explain = score_info.get("score说明", "")
note_same_parts = score_info.get("相同部分", {})
note_increment_parts = score_info.get("增量部分", {})
```

### None值处理

**问题**：JSON文件中某些字段可能为`null`，Python读取后为`None`，调用`.items()`或`.keys()`会报错。

**解决方案**：使用`or {}`或`or ""`确保默认值

```python
same_parts = match_result.get("相同部分", {}) or {}
score_explain = match_result.get("score说明", "") or ""
```

---

## 版本历史

### v1.1 (2025-11-13)
- **修复**: 变量命名冲突导致step1分数被step4数据覆盖
  - 步骤1和步骤4的变量现在完全隔离
  - step1显示正确的灵感匹配分数
  - step4显示正确的帖子匹配分数
- **修复**: None值处理
  - 添加`or {}`和`or ""`确保安全处理None值
  - 修复"object of type 'NoneType' has no len()"错误

### v1.0 (2025-11-13)
- 初始版本
- 支持步骤1和步骤2的可视化展示
- 支持搜索结果匹配分数展示
- 支持交互式卡片和弹窗

---

## 使用场景

### 场景1：分析灵感点匹配效果

打开可视化页面，查看：
1. 灵感点与哪些灵感要素匹配度最高
2. 匹配的相同部分和增量部分是什么
3. 为什么得到这个分数（查看分数说明）

### 场景2：评估搜索结果质量

在步骤2中查看：
1. 以灵感要素为关键词搜索到的帖子
2. 哪些帖子与原始灵感点匹配度最高
3. 为什么这些帖子匹配度高（点击分数查看详情）

### 场景3：发现内容机会

通过可视化页面：
1. 了解哪些灵感分类缺少内容（匹配分数低）
2. 查看高分搜索结果，学习内容创作方向
3. 识别内容创作的相同点和差异点

---

## 常见问题

### Q1: 为什么有些搜索结果没有分数？

**A**: 只有在`all_step4_搜索结果匹配_gemini-2.5-pro.json`文件中的帖子才有匹配分数。如果搜索结果较多，step4可能只对部分帖子进行了匹配分析。

### Q2: step1分数和step4分数有什么区别？

**A**:
- **step1分数**：灵感点与灵感要素的语义匹配度（概念级别）
- **step4分数**：实际小红书帖子与灵感点的内容匹配度（内容级别）

### Q3: 为什么有些灵感点没有搜索结果？

**A**: 搜索功能依赖于step1匹配到的灵感要素。如果某个灵感点没有匹配到合适的灵感要素，或者没有执行搜索步骤，就不会有搜索结果。

### Q4: 如何更新可视化？

**A**: 当数据文件更新后，重新运行脚本即可：
```bash
python visualize_inspiration_points.py
```

---

## 相关文档

- [索引构建 README](README_索引构建.md)
- [搜索模块 README](script/search/README.md)
- [详情模块 README](script/detail/README.md)
