growork 1.0.1 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,539 +0,0 @@
1
- # Bloomo AI 客户端对接文档
2
-
3
- ## 概述
4
-
5
-
6
- Bloomo AI 是一个基于 LiveKit 的实时语音塔罗解读助手。系统包含三个核心 Agent,通过智能状态管理实现问题澄清、牌阵选择、抽牌、解读的完整流程。**支持单个 Session 内无限轮次的塔罗解读。**
7
-
8
-
9
- ## 多轮会话设计
10
-
11
-
12
- ### 轮次 (Round) 概念
13
-
14
-
15
- - **Session**:用户与 AI 的一次完整会话,包含多个轮次
16
- - **Round**:单次问题澄清 + 抽牌 + 解读的完整流程
17
- - **round_id 格式**:`{session_id}_round_{n}`,如 `session-abc-123_round_0`、`session-abc-123_round_1`
18
-
19
- ### 轮次生命周期
20
-
21
-
22
- | 阶段 | 动作 | round_id 状态 |
23
- | --- | --- | --- |
24
- | Session 创建 | 初始化 | `{session_id}_round_0` |
25
- | 问题澄清 | pushMessage | 使用当前 round_id |
26
- | 抽牌解读 | pushMessage | 使用当前 round_id |
27
- | 解读完成 | 推送推荐问题 + 创建摘要 | 使用当前 round_id |
28
- | 用户新问题 | 自动开启新轮次 | `{session_id}_round_1` |
29
-
30
-
31
- ### 多轮流程图
32
-
33
-
34
- ```plaintext
35
- Session 开始
36
-
37
- ┌─────────────────────────────────────┐
38
- │ Round N │
39
- │ ┌─────────────────────────────┐ │
40
- │ │ 1. CLARIFYING(问题澄清) │ │
41
- │ │ 2. SPREAD_CHOOSING(牌阵选择)│ │
42
- │ │ 3. DRAWING_CARDS(抽牌) │ │
43
- │ │ 4. READING(解读) │ │
44
- │ └─────────────────────────────┘ │
45
- │ ↓ │
46
- │ 解读完成,Agent 进入 LISTENING │
47
- │ ↓ │
48
- │ 用户发送新问题 │
49
- │ ↓ │
50
- │ 自动开启 Round N+1 │
51
- └─────────────────────────────────────┘
52
-
53
- Session 结束
54
- ```
55
-
56
-
57
- ## Agent 说明
58
-
59
-
60
- ### 1. QuestionClarificationAssistant(问题澄清助手)
61
-
62
- **作用**:通过引导式对话帮助用户明确塔罗咨询问题
63
-
64
- - 与用户进行语音对话
65
- - 理解和澄清用户的咨询意图
66
- - 完成后触发牌阵选择流程
67
-
68
- ### 2. SpreadChoosingAssistant(牌阵选择助手)
69
-
70
- **作用**:根据用户问题智能选择合适的塔罗牌阵
71
-
72
- - 分析用户问题的类型和需求
73
- - 从多种牌阵中选择最合适的牌阵
74
- - 通知客户端选择的牌阵类型
75
-
76
- ### 3. TarotReadingAssistant(塔罗解读助手)
77
-
78
- **作用**:基于用户问题和抽取的塔罗牌提供专业解读
79
-
80
- - 接收用户问题和牌面信息
81
- - 生成结构化的塔罗解读
82
- - 支持分段发送解读内容
83
-
84
- ## 工作流程
85
-
86
-
87
- ### 抽牌流程对比
88
-
89
-
90
- | 步骤 | 旧流程 | 新流程 |
91
- | --- | --- | --- |
92
- | 1 | 问题澄清完成 | 问题澄清完成 |
93
- | 2 | AI 发送 `draw_cards_ready` | AI **立即**切换到牌阵选择 Agent |
94
- | 3 | 客户端展示"是/不是我的问题" | AI 发送 `spread_chosen` |
95
- | 4 | 用户选择"是" → 发送 | 客户端展示牌阵外化 + "开始抽牌/不是我的问题" |
96
- | 5 | AI 切换到牌阵选择 Agent | 用户选择"开始抽牌" → 抽牌 |
97
- | 6 | AI 发送 `spread_chosen` | 用户选择"不是我的问题" → 发送 `not_my_question` |
98
- | 7 | 客户端抽牌 → 发送 `cards_drawn` | 抽牌完成 → 发送 `cards_drawn` |
99
-
100
-
101
- **主要变化**:
102
-
103
- - 移除了 `draw_cards_ready` 和 `start_draw_cards` 消息
104
- - 问题澄清完成后立即进入牌阵选择,减少一次交互
105
- - "不是我的问题"的判断时机从问题澄清后移到牌阵选择后
106
-
107
- ### 当前流程(新流程)
108
-
109
-
110
- ```plaintext
111
- - 单轮阶段流程
112
- 1. CLARIFYING(问题澄清)
113
- ↓ AI 确认是一个有效问题
114
- ↓ AI 立即切换到牌阵选择 Agent
115
- 2. SPREAD_CHOOSING(牌阵选择,AI 自动处理)
116
- ↓ AI 发送:spread_chosen + 牌阵类型
117
- ↓ 客户端可展示牌阵外化消息
118
- 3. DRAWING_CARDS(用户选择阶段)
119
- - 用户选择"开始抽牌":客户端处理抽牌
120
- ↓ 客户端发送:cards_drawn + 牌面信息 + 牌阵类型
121
- - 用户选择"不是我的问题":
122
- ↓ 客户端发送:not_my_question
123
- ↓ 回到步骤 1
124
- 4. READING(塔罗解读)
125
- - AI 发送第一段解读
126
- ↓ AI 发送:reading_paragraph_sent
127
- ↓ 客户端发送:continue_reading(语音模式)
128
- - AI 发送下一段解读
129
- ↓ 重复直到完成
130
- 5. 解读完成
131
- ↓ Agent 状态变为 LISTENING
132
- ↓ AI 发送:text_reading_completed(文本解读完成,仅文本模式)
133
- ↓ AI 发送:recommended_questions(推荐问题,仅文本模式)
134
- ↓ 用户发送新问题
135
- ↓ 自动开启新轮次,回到步骤 1
136
-
137
- - 其他
138
- 1. 会话创建完成
139
- ↓ AI 发送:session_created
140
- 2. Agent 状态变化
141
- ↓ AI 发送:agent_state_changed
142
- 3. 按句转录发送句子文本
143
- ↓ AI 发送:sentence_text
144
- ↓ 客户端发送:stream_text_output_finished(仅文本模式下文本动画播放完成)
145
- 4. 过渡提示语
146
- ↓ 客户端发送:hint_speech
147
- ↓ AI 发送:hint_speech_played
148
- 5. 推荐问题(仅文本模式)
149
- ↓ AI 发送:recommended_questions
150
- ```
151
-
152
-
153
- ## 消息通信协议
154
-
155
-
156
- ### AI → 客户端(接收)
157
-
158
-
159
- 通过 `room.on("data_received")` 接收 JSON 格式消息:
160
-
161
-
162
- #### 1. 牌阵选择通知
163
-
164
- ```json
165
- {
166
- "type": "spread_chosen",
167
- "spread_type": "three_card"
168
- }
169
- ```
170
-
171
- **说明**:问题澄清完成后,AI 立即选择合适的牌阵并发送此消息。客户端收到后:
172
-
173
- 1. 可展示牌阵外化消息(解释为什么选择这个牌阵)
174
- 1. 展示两个选项:"开始抽牌" 和 "不是我的问题"
175
-
176
- **牌阵类型枚举**:
177
-
178
- - `three_card` - 三牌阵/时间之流牌阵(3张牌)
179
- - `general_fortune` - 综合运势牌阵(3张牌)
180
- - `root_cause` - 追本溯源牌阵(4张牌)
181
- - `relation_cross` - 关系十字牌阵/大十字牌阵(5张牌)
182
- - `two_choose_one` - 二择一牌阵(6张牌)
183
-
184
- #### 2. 段落发送完成通知
185
-
186
- ```json
187
- {
188
- "type": "reading_paragraph_sent",
189
- "paragraph_index": 1,
190
- "total_paragraphs": 3,
191
- "is_last": false
192
- }
193
- ```
194
-
195
- **说明**:每段解读发送完成后的通知,客户端可据此展示"继续"按钮
196
-
197
- #### 3. 会话创建完成通知
198
-
199
- ```json
200
- {
201
- "type": "session_created",
202
- "session_id": "str"
203
- }
204
- ```
205
-
206
- **说明**:每次创建会话,由 Agent 生成 session_id 通知客户端,客户端可在此时根据当前 session_id 查询历史 session
207
-
208
- #### 4. Agent 状态变化通知
209
-
210
- ```json
211
- {
212
- "type": "agent_state_changed",
213
- "state": "str",
214
- "old_state": "str",
215
- "reason": "str"
216
- }
217
- ```
218
-
219
- **说明**:Agent 状态变化时,枚举如下
220
-
221
- ```plaintext
222
- class AgentState(Enum):
223
- """Agent 状态枚举"""
224
- IDLE = "idle" # 空闲状态
225
- THINKING = "thinking" # 思考/生成回复中
226
- SPEAKING = "speaking" # 正在说话
227
- LISTENING = "listening" # 正在聆听
228
- ```
229
-
230
- #### 5. 按句转录发送句子文本
231
-
232
- ```json
233
- {
234
- "type": "sentence_text",
235
- "text": "str",
236
- "sentence_index": 0,
237
- "total_sentences": 3,
238
- "stage": "str", //clarification/reading
239
- "message_id": "str" //当前整段 message_id
240
- }
241
- ```
242
-
243
- **说明**:自定义按句转录逻辑,需要将 LLM 生成的 message 按句拆分,顺序转录到客户端展示
244
-
245
- #### 6. 提示语发送完成通知
246
-
247
- ```json
248
- {
249
- "type": "hint_speech_played",
250
- "id": "str"
251
- }
252
- ```
253
-
254
- **说明**:客户端调用 tts 播放提示语,AI 播放完成后通知客户端
255
-
256
-
257
- #### 7. 推荐问题通知(仅文本模式)
258
-
259
- ```json
260
- {
261
- "type": "recommended_questions",
262
- "questions": ["问题1", "问题2", "问题3"]
263
- }
264
- ```
265
-
266
- **说明**:解读完成后,AI 推送 3-5 个推荐问题引导用户继续探索。客户端可展示为可点击的问题列表,用户点击后直接发送该问题开启新轮次。
267
-
268
-
269
- #### 8. 文本解读完成通知(仅文本模式)
270
-
271
- ```json
272
- {
273
- "type": "text_reading_completed",
274
- "round_id": "session-abc-123_round_0"
275
- }
276
- ```
277
-
278
- **说明**:文本模式下塔罗解读完成后发送,包含当前轮次的 `round_id`。客户端可据此标识本轮解读已结束,准备接收用户新问题开启下一轮。
279
-
280
-
281
-
282
- ### 客户端 → AI(发送)
283
-
284
-
285
- 通过 `room.local_participant.publish_data()` 发送 JSON 格式消息:
286
-
287
-
288
- #### 1. 不是想要的问题
289
-
290
- ```json
291
- {
292
- "type": "not_my_question"
293
- }
294
- ```
295
-
296
- **说明**:在牌阵选择完成后(收到 `spread_chosen`),用户选择"不是我的问题",系统会返回问题澄清阶段重新开始
297
-
298
-
299
- #### 2. 抽牌完成
300
-
301
- ```json
302
- {
303
- "type": "cards_drawn",
304
- "spread_type": "three_card",
305
- "cards": [
306
- {
307
- "card_name": "The Fool",
308
- "reversed": false
309
- },
310
- {
311
- "card_name": "The Magician",
312
- "reversed": true
313
- },
314
- {
315
- "card_name": "The High Priestess",
316
- "reversed": false
317
- }
318
- ]
319
- }
320
- ```
321
-
322
- **说明**:用户完成抽牌后发送,必须包含 `spread_type` 字段(与 AI 发送的 `spread_chosen` 中的值不一定一致,超时客户端会兜底 three_card 牌阵),触发 AI 开始解读
323
-
324
-
325
- #### 3. 继续解读
326
-
327
- ```json
328
- {
329
- "type": "continue_reading"
330
- }
331
- ```
332
-
333
- **说明**:用户准备听下一段解读时发送
334
-
335
-
336
- #### 4. 文本动画播放完成
337
-
338
- ```json
339
- {
340
- "type": "stream_text_output_finished",
341
- "message_id": "str"
342
- }
343
- ```
344
-
345
- **说明**:**仅在文本模式 (TEXT) 下使用**。客户端收到 `sentence_text` 后,在文本动画播放完成时发送此消息通知 AI,AI 会继续发送下一句。语音模式 (VOICE) 下不需要发送此消息,AI 会在语音播放完成后自动继续。
346
-
347
-
348
- #### 5. tts 播放提示语
349
-
350
- ```json
351
- {
352
- "type": "hint_speech",
353
- "text": "str",
354
- "id": "str"
355
- }
356
- ```
357
-
358
- **说明**:客户端通知 AI tts 播放提示语
359
-
360
-
361
-
362
- ## 会话配置 (Metadata)
363
-
364
-
365
- 客户端可通过 LiveKit 的 participant metadata 传递会话配置给 AI:
366
-
367
-
368
- ### Metadata 字段
369
-
370
-
371
- | 字段 | 类型 | 必填 | 说明 |
372
- | --- | --- | --- | --- |
373
- | `interaction_mode` | string | 否 | 交互模式,`voice` 或 `text`,默认 `voice` |
374
- | `default_spread` | string | 否 | 默认牌阵类型,首次解读时跳过 LLM 选择直接使用 |
375
-
376
-
377
- ### Metadata 示例
378
-
379
-
380
- ```json
381
- {
382
- "interaction_mode": "voice",
383
- "default_spread": "relation_cross"
384
- }
385
- ```
386
-
387
-
388
- ### default_spread 说明
389
-
390
-
391
- - **作用**:用户在进入会话前已选择牌阵时,可通过此字段指定首次解读使用的牌阵
392
- - **生效范围**:仅对 Session 中的**第一次解读**生效,使用后自动清空
393
- - **后续轮次**:第二轮及之后的解读会通过 LLM 自动选择牌阵
394
- - **无效值处理**:如果传入无效的牌阵类型,会回退到 LLM 选择
395
-
396
- **牌阵类型枚举**:
397
-
398
- - `three_card` - 三牌阵/时间之流牌阵(3张牌)
399
- - `general_fortune` - 综合运势牌阵(3张牌)
400
- - `root_cause` - 追本溯源牌阵(4张牌)
401
- - `relation_cross` - 关系十字牌阵/大十字牌阵(5张牌)
402
- - `two_choose_one` - 二择一牌阵(6张牌)
403
-
404
-
405
- ## 交互模式 (InteractionModeType)
406
-
407
-
408
- 系统支持两种交互模式,通过 LiveKit 的 participant attributes 或 metadata 传递给 AI:
409
-
410
-
411
- ### 模式类型
412
-
413
-
414
- ```rpm
415
- class InteractionModeType(Enum):
416
- VOICE = "voice" # 语音模式
417
- TEXT = "text" # 文本模式
418
- ```
419
-
420
-
421
- ### 模式差异
422
-
423
-
424
- | 特性 | 语音模式 (VOICE) | 文本模式 (TEXT) |
425
- | --- | --- | --- |
426
- | **文本发送方式** | 按句发送 + 播放语音 | 一次性发送完整文本 |
427
- | **sentence_text** | 逐句发送,每句播放语音 | 一次性发送全部文本,不播放语音 |
428
- | **stream_text_output_finished** | ❌ 不需要(AI 根据语音播放完成自动继续) | ✅ **必须发送**(AI 等待客户端文本动画完成) |
429
- | **语音播放** | ✅ AI 自动播放 TTS | ❌ 不播放 |
430
- | **用户输入** | 🎤 语音输入 | ⌨️ 文本输入 |
431
- | **Agent 音频订阅** | ✅ 订阅用户麦克风 | ❌ 不订阅 |
432
-
433
-
434
-
435
- ## 注意事项
436
-
437
-
438
- 1. **可靠传输**:数据消息可使用 `reliable: true` 确保送达
439
- 1. **状态同步**:客户端应根据接收到的消息类型维护当前状态
440
- 1. **错误处理**:网络异常时应有重试机制或友好提示
441
- 1. **语音交互**:系统通过 LiveKit 的 STT/TTS 自动处理语音,客户端只需处理数据消息
442
- 1. **交互模式**:
443
- - 语音模式下,客户端无需发送 `stream_text_output_finished`
444
- - 文本模式下,**必须**在文本动画完成后发送 `stream_text_output_finished`
445
- 1. **message_id 匹配**:`stream_text_output_finished` 中的 `message_id` 必须与对应的 `sentence_text` 消息一致
446
- 1. **多轮会话**:
447
- - 单个 Session 支持无限轮次解读
448
- - 解读完成后 Agent 进入 `LISTENING` 状态,用户发送新问题自动开启新轮次
449
- - 每轮解读独立生成摘要,历史记录按轮次分组展示
450
- - 推荐问题仅在文本模式下推送
451
- 1. **新抽牌流程**:
452
- - 问题澄清完成后,AI 立即选择牌阵并发送 `spread_chosen`
453
- - 客户端收到后展示牌阵外化消息和选项按钮
454
- - 用户选择"开始抽牌"后完成抽牌发送 `cards_drawn`
455
- - 用户选择"不是我的问题"则发送 `not_my_question` 返回问题澄清
456
-
457
- ## Agent 与业务后端 (Java) 交互
458
-
459
-
460
- Agent 会在特定时机向 Java 业务后端推送事件,用于同步状态和触发业务逻辑。
461
-
462
-
463
- ### 事件推送接口
464
-
465
-
466
- **路径**:`POST /agent/event`
467
-
468
-
469
- **请求参数**:
470
-
471
-
472
- | 字段 | 类型 | 必填 | 说明 |
473
- | --- | --- | --- | --- |
474
- | `eventType` | string | 是 | 事件类型 |
475
- | `businessId` | string | 否 | 业务ID,通常为 `round_id` |
476
- | `extra` | object | 否 | 扩展数据 |
477
-
478
-
479
- ### 事件类型
480
-
481
-
482
- #### 1. deep_dive_start(深度解读开始)
483
-
484
-
485
- **触发时机**:塔罗解读 LLM 生成完成后
486
-
487
-
488
- **参数**:
489
-
490
- ```json
491
- {
492
- "eventType": "deep_dive_start",
493
- "businessId": "session-abc-123_round_0",
494
- "extra": {}
495
- }
496
- ```
497
-
498
-
499
- **说明**:通知业务后端开始深度解读,用于状态同步。
500
-
501
-
502
- #### 2. start_draw_cards(牌阵确认)
503
-
504
-
505
- **触发时机**:塔罗解读 LLM 生成完成后(与 `deep_dive_start` 同时发送)
506
-
507
-
508
- **参数**:
509
-
510
- ```json
511
- {
512
- "eventType": "start_draw_cards",
513
- "businessId": "session-abc-123_round_0",
514
- "extra": {
515
- "spreadType": "relation_cross"
516
- }
517
- }
518
- ```
519
-
520
-
521
- **说明**:通知业务后端牌阵确认,Java 端可据此累计次数。`spreadType` 为本次解读使用的牌阵类型。
522
-
523
-
524
- **牌阵类型枚举**:
525
-
526
- - `three_card` - 三牌阵/时间之流牌阵
527
- - `general_fortune` - 综合运势牌阵
528
- - `root_cause` - 追本溯源牌阵
529
- - `relation_cross` - 关系十字牌阵/大十字牌阵
530
- - `two_choose_one` - 二择一牌阵
531
-
532
-
533
- ## 完整示例
534
-
535
-
536
- 参考官方 LiveKit 前端模板:
537
-
538
- - iOS: [agent-starter-swift](https%3A%2F%2Fgithub.com%2Flivekit-examples%2Fagent-starter-swift)
539
- - Flutter: [agent-starter-flutter](https%3A%2F%2Fgithub.com%2Flivekit-examples%2Fagent-starter-flutter)