File size: 6,243 Bytes
fbe1c8a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# Clare AI Agent:前后端配合说明 & Podcast 集成到独立网站

## 一、前后端需要配合做什么

整体上:**前端负责 UI 和用户操作,后端负责会话状态、RAG、LLM 调用和音频生成**。具体分工如下。

### 1. 会话与身份

| 能力 | 后端 | 前端 |
|------|------|------|
| 登录 | `POST /api/login` 校验并建立会话(内存里存 `user_id`) | 收集姓名/ID,调用 login,存 `user`(如 `user_id` = email) |
| 会话状态 | 按 `user_id` 存 history、course_outline、weaknesses、cognitive_state、上传文件等 | 所有需要会话的请求都带 `user_id`(如 `user.email`) |

### 2. 对话与内容

| 能力 | 后端 | 前端 |
|------|------|------|
| 对话 | `POST /api/chat`:RAG 检索 + LLM 生成,返回回复 + 可选 references | 发 message、learning_mode、language_preference,渲染回复和引用 |
| 上传 | `POST /api/upload`:解析文件、更新该用户的 course_outline / RAG chunks | 选文件、doc_type,上传后刷新侧边栏/状态 |
| 导出 | `POST /api/export`:根据当前会话 history 生成 Markdown 文本 | 调 export,展示或下载文本 |
| 总结 | `POST /api/summary`:对当前会话做总结,返回 Markdown | 调 summary,展示在右侧或弹窗 |

### 3. 音频(TTS / Podcast)

| 能力 | 后端 | 前端 |
|------|------|------|
| TTS | `POST /api/tts`:接收一段 text,调用 OpenAI TTS,返回 **MP3 二进制**`audio/mpeg`) | 传 `user_id` + `text`,用 `response.blob()` 得到 Blob → `URL.createObjectURL(blob)``<audio src>` 播放或下载 |
| Podcast | `POST /api/podcast`:根据 `source=summary|conversation` 用当前会话生成脚本,再 TTS 合成,返回 **MP3 二进制**`audio/mpeg`) | 传 `user_id` + `source`,同样用 Blob → Object URL 播放/下载 |

### 4. 其他

- Memory Line、Profile 状态、Quiz 等:前端按需调对应 API,后端按 `user_id` 读会话状态并返回。
- 前端需统一配置 **API 基地址**(如 `VITE_API_BASE`),保证请求发到 Clare 后端。

**小结**:后端不写前端 UI,只提供 REST API 和会话状态;前端负责所有展示、表单和把「当前用户」(`user_id`) 带到每次请求里。Podcast 当前是「请求一次、返回一段 MP3 流」,不落盘。

---

## 二、把 Podcast 集成到「独立网站」的两种方式

当前实现里,**Podcast 不会生成可下载的 MP3 文件链接**,而是接口**直接返回 MP3 字节流**,由调用方在内存里播放或触发下载。

若你要在**独立网站**(与当前 React 应用分离的站点)里集成 podcast,有两种常见做法。

### 方式 A:不落盘,直接用 API 返回的 MP3 流(当前能力即可)

**流程:**

1. 独立网站(同源或配置好 CORS 的后端代理)向 Clare 后端发:  
   `POST /api/podcast`,body:`{ "user_id": "...", "source": "summary" | "conversation", "voice": "nova" }`2. 后端生成 podcast,**直接在响应体里返回 MP3**`Content-Type: audio/mpeg`)。
3. 独立网站用 `fetch` 拿到 `response.blob()`,然后:
   - **播放**`URL.createObjectURL(blob)` 得到临时 URL,赋给 `<audio src="...">`   - **下载**:用 `<a download>` + Object URL,或 Blob 转成文件让用户保存。

**特点:**

- **不需要**在后端生成「可下载的 MP3 文件」再让网站访问;
- 不占磁盘、不涉及文件 URL;适合「当前会话、一次性听/下」;
- 独立网站只要能用 JavaScript 调 Clare 的 API(或通过自己的后端转发)即可。

**结论:**  
若独立网站可以发 POST 并处理 Blob,**不需要**先生成可下载的 MP3 文件再给网站访问;直接使用接口返回的 MP3 流即可播放和下载。

---

### 方式 B:生成可下载的 MP3 文件,网站用「链接」播放/下载

适用于:

- 需要**固定、可分享的链接**(例如发给别人、放 RSS、嵌入第三方播放器);
- 希望**缓存**同一脚本的 MP3,避免重复生成;
- 独立网站只能提供「一个 MP3 地址」,不能发 POST(例如纯静态页、外嵌 `<audio src="https://...">`)。

**做法:**

1. **后端**在生成完 podcast 后:
   - 把 MP3 写入**文件**(例如 `/static/podcasts/<session_id>_<timestamp>.mp3`)或对象存储(如 S3/OSS),
   - 返回一个**可访问的 URL**,例如:  
     `https://your-api.com/static/podcasts/xxx.mp3` 或存储的 public URL。
2. **独立网站**:
   - 用该 URL 做 `<audio src="...">` 播放;
   - 或用 `<a href="..." download>下载</a>` 提供下载。

这样就是「**生成可下载的 MP3,再让网站通过文件 URL 访问/播放**」。

若要采用方式 B,后端需要增加逻辑(例如):

-`POST /api/podcast` 里,生成 MP3 后写入指定目录或上传到存储;
- 在响应里不再只返回 `audio/mpeg` 流,而是返回 JSON,例如:  
  `{ "url": "https://.../podcasts/xxx.mp3", "expires_in": 3600 }`;  
  或保留当前「直接返回 MP3」的行为,并**额外**提供一个 `GET /api/podcast/<id>` 或静态路径,用于通过 URL 访问已生成的 MP3。

---

## 三、简要对比

| 维度 | 方式 A:直接用 API 返回的 MP3 流 | 方式 B:生成 MP3 文件 + URL |
|------|----------------------------------|-----------------------------|
| 是否需要生成可下载文件 | **否** | **是**(写盘或对象存储) |
| 网站如何播放/下载 | 用 Blob + Object URL 或 `<a download>` | 用返回的 URL 做 `<audio src>` / 下载链接 |
| 是否可分享/固定链接 | 否(每次请求新生成) | 是 |
| 是否适合纯静态页「只填 URL」 | 否(需能发 POST) | 是 |
| 当前 Clare 是否支持 | **是**(现有 `/api/podcast` 即可) | 需在后端增加「落盘/存储 + 返回 URL」 |

**总结:**

- **不需要**「先生成可下载的 MP3 再让网站访问」:用现有 `/api/podcast`,在独立网站里用 POST + Blob 即可播放和下载(方式 A)。
- **需要**「可分享链接、外嵌播放器、纯 URL 访问」时:再在后端增加「生成 MP3 文件并返回 URL」的能力(方式 B)。