@mingxy/ocosay 1.1.0 → 1.1.2

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.
Files changed (73) hide show
  1. package/README.md +43 -653
  2. package/dist/config.js +2 -1
  3. package/dist/core/logger.d.ts +46 -0
  4. package/dist/core/logger.js +126 -0
  5. package/dist/core/notification.d.ts +27 -0
  6. package/dist/core/notification.js +86 -0
  7. package/dist/core/speaker.js +5 -35
  8. package/dist/core/stream-reader.js +2 -1
  9. package/dist/index.d.ts +1 -0
  10. package/dist/index.js +1 -0
  11. package/dist/package.json +7 -4
  12. package/dist/plugin.js +220 -197
  13. package/dist/tools/tts.js +2 -1
  14. package/dist/utils/logger.d.ts +6 -0
  15. package/dist/utils/logger.js +42 -6
  16. package/package.json +4 -2
  17. package/scripts/compile-native.cjs +48 -0
  18. package/scripts/install-portaudio.cjs +117 -0
  19. package/.idea/UniappTool.xml +0 -10
  20. package/.idea/inspectionProfiles/profiles_settings.xml +0 -5
  21. package/.idea/modules.xml +0 -8
  22. package/.idea/ocosay.iml +0 -12
  23. package/.idea/vcs.xml +0 -6
  24. package/.sisyphus/boulder.json +0 -23
  25. package/dist/config.d.ts.map +0 -1
  26. package/dist/config.js.map +0 -1
  27. package/dist/core/backends/afplay-backend.d.ts.map +0 -1
  28. package/dist/core/backends/afplay-backend.js.map +0 -1
  29. package/dist/core/backends/aplay-backend.d.ts.map +0 -1
  30. package/dist/core/backends/aplay-backend.js.map +0 -1
  31. package/dist/core/backends/base.d.ts.map +0 -1
  32. package/dist/core/backends/base.js.map +0 -1
  33. package/dist/core/backends/howler-backend.d.ts.map +0 -1
  34. package/dist/core/backends/howler-backend.js.map +0 -1
  35. package/dist/core/backends/index.d.ts.map +0 -1
  36. package/dist/core/backends/index.js.map +0 -1
  37. package/dist/core/backends/naudiodon-backend.d.ts.map +0 -1
  38. package/dist/core/backends/naudiodon-backend.js.map +0 -1
  39. package/dist/core/backends/powershell-backend.d.ts.map +0 -1
  40. package/dist/core/backends/powershell-backend.js.map +0 -1
  41. package/dist/core/player.d.ts.map +0 -1
  42. package/dist/core/player.js.map +0 -1
  43. package/dist/core/speaker.d.ts.map +0 -1
  44. package/dist/core/speaker.js.map +0 -1
  45. package/dist/core/stream-player.d.ts.map +0 -1
  46. package/dist/core/stream-player.js.map +0 -1
  47. package/dist/core/stream-reader.d.ts.map +0 -1
  48. package/dist/core/stream-reader.js.map +0 -1
  49. package/dist/core/streaming-synthesizer.d.ts.map +0 -1
  50. package/dist/core/streaming-synthesizer.js.map +0 -1
  51. package/dist/core/types.d.ts.map +0 -1
  52. package/dist/core/types.js.map +0 -1
  53. package/dist/index.d.ts.map +0 -1
  54. package/dist/index.js.map +0 -1
  55. package/dist/plugin.d.ts.map +0 -1
  56. package/dist/plugin.js.map +0 -7
  57. package/dist/providers/base.d.ts.map +0 -1
  58. package/dist/providers/base.js.map +0 -1
  59. package/dist/providers/minimax.d.ts.map +0 -1
  60. package/dist/providers/minimax.js.map +0 -1
  61. package/dist/services/notification-service.d.ts.map +0 -1
  62. package/dist/services/notification-service.js.map +0 -1
  63. package/dist/services/speaker-service.d.ts.map +0 -1
  64. package/dist/services/speaker-service.js.map +0 -1
  65. package/dist/services/streaming-service.d.ts.map +0 -1
  66. package/dist/services/streaming-service.js.map +0 -1
  67. package/dist/tools/tts.d.ts.map +0 -1
  68. package/dist/tools/tts.js.map +0 -1
  69. package/dist/types/config.d.ts.map +0 -1
  70. package/dist/types/config.js.map +0 -1
  71. package/dist/utils/logger.d.ts.map +0 -1
  72. package/dist/utils/logger.js.map +0 -1
  73. package/tsconfig.jest.json +0 -21
package/README.md CHANGED
@@ -1,693 +1,83 @@
1
- # ocosay - OpenCode TTS 播放插件
1
+ # @mingxy/ocosay
2
2
 
3
- > 🎙️ 让 AI 开口说话 — 支持豆包模式边接收边朗读的 TTS 插件
3
+ OpenCode MiniMax TTS 插件,支持语音合成与播放。
4
4
 
5
- [![npm version](https://img.shields.io/npm/v/@mingxy/ocosay.svg)](https://www.npmjs.com/package/@mingxy/ocosay)
6
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
5
+ ## 安装
7
6
 
8
- ## Why This Exists
9
-
10
- 在 AI 助手对话场景中,文字回复往往显得生硬。**ocosay** 让 AI 能够"开口说话",通过流式 TTS 技术实现边接收边朗读的豆包模式,极大提升对话交互体验。
11
-
12
- **解决的问题:**
13
- - 长文本等待焦虑 — 流式播放,首包延迟低
14
- - 缺乏情感反馈 — 多种音色选择,支持语速/音调调节
15
- - 交互体验单一 — 从"看"升级到"听"
16
-
17
- ## Features
18
-
19
- - 🎙️ **多 TTS 模型支持** - MiniMax 作为第一个实现,可扩展其他提供商
20
- - 🔊 **多种合成模式** - 同步、异步、流式三种模式可选
21
- - 🎭 **音色克隆** - 支持音色快速复刻
22
- - 🎛️ **播放控制** - 暂停、恢复、停止
23
- - 📋 **音色列表** - 查询可用音色
24
- - 🔌 **OpenCode Plugin** - 无缝集成 OpenCode
25
- - 📡 **豆包模式** - autoRead + TuiEventBus,边接收边朗读
26
- - 📝 **日志系统** - 使用 pino 统一日志格式,写入 `~/.ocosay/ocosay.log`
27
- - 🔔 **Toast 提示** - 播放成功/失败显示 Toast 通知
28
-
29
- ## Platform Support
30
-
31
- | 平台 | 支持状态 | 说明 |
32
- |------|----------|------|
33
- | macOS | ✅ 完全支持 | howler.js 跨平台音频后端 |
34
- | Linux | ✅ 完全支持 | howler.js 跨平台音频后端 |
35
- | Windows | ✅ 完全支持 | howler.js 跨平台音频后端 |
36
-
37
- ### 音频后端
7
+ ```bash
8
+ npm install -g @mingxy/ocosay
9
+ ```
38
10
 
39
- ocosay 使用统一的 `AudioBackend` 架构:
11
+ > 安装过程自动完成 PortAudio 依赖检测与编译
40
12
 
41
- | 后端 | 类型 | 说明 |
42
- |------|------|------|
43
- | **howler** | 跨平台 | 基于 howler.js,纯 JavaScript 实现,npm 直接安装无需编译 |
44
- | naudiodon | 流式 | native 模块,支持真正的流式播放(需 npm install) |
45
- | afplay | macOS | 系统命令 afplay |
46
- | aplay | Linux | 系统命令 aplay |
47
- | powershell | Windows | PowerShell PlaySync |
13
+ ---
48
14
 
49
- > **注意**: 流式播放(豆包模式)需要 naudiodon 后端支持。请执行 `npm install naudiodon` 安装。
15
+ ## ⚠️ 自动安装失败时
50
16
 
51
- ## 安装方式
17
+ 如果终端出现 PortAudio 相关错误,请手动安装:
52
18
 
53
- ### 方式一:ocx 安装(推荐)
19
+ ### macOS
54
20
 
55
21
  ```bash
56
- ocx install @mingxy/ocosay
22
+ brew install portaudio
57
23
  ```
58
24
 
59
- ### 方式二:手动配置
25
+ ### Windows WSL
60
26
 
61
27
  ```bash
62
- npm install @mingxy/ocosay
28
+ sudo apt-get install -y libportaudio-dev portaudio
63
29
  ```
64
30
 
65
- OpenCode 配置文件中添加插件:
31
+ ### Windows 原生
66
32
 
67
- ```jsonc
68
- {
69
- "plugin": [
70
- "@mingxy/ocosay"
71
- ]
72
- }
33
+ ```powershell
34
+ choco install portaudio
73
35
  ```
74
36
 
75
- > **首次安装**:重启 OpenCode 后,插件会自动在 `~/.config/opencode/ocosay.jsonc` 生成默认配置文件。
76
- > 请编辑该文件,填写您的 `apiKey` 和 `baseURL`。
37
+ 安装完成后重新运行:
77
38
 
78
- ## 快速开始
39
+ ```bash
40
+ npm install -g @mingxy/ocosay
41
+ ```
79
42
 
80
- ### 1. 添加插件
43
+ ---
81
44
 
82
- `~/.config/opencode/opencode.jsonc` 中添加:
45
+ ## 验证
83
46
 
84
- ```jsonc
85
- {
86
- "plugin": [
87
- "@mingxy/ocosay"
88
- ]
89
- }
47
+ ```bash
48
+ node -e "require('naudiodon')"
90
49
  ```
91
50
 
92
- ### 2. 重启 OpenCode
93
-
94
- 插件会自动下载并初始化。
51
+ 无报错即成功。
95
52
 
96
- ### 3. 填写配置
53
+ ---
97
54
 
98
- 首次启动后,插件会自动生成 `~/.config/opencode/ocosay.jsonc` 配置文件。
55
+ ## 配置
99
56
 
100
- 编辑该文件,填写必填项:
57
+ 在 OpenCode 配置文件中添加:
101
58
 
102
- ```jsonc
59
+ ```json
103
60
  {
104
- "providers": {
105
- "minimax": {
106
- "apiKey": "您的API_KEY", // ⚠️ 必填
107
- "baseURL": "https://api.minimaxi.com" // ⚠️ 必填
108
- }
109
- }
61
+ "plugins": ["@mingxy/ocosay"]
110
62
  }
111
63
  ```
112
64
 
113
- ### 4. 重启 OpenCode 使配置生效
114
-
115
- ## 快速开始
116
-
117
- ### 初始化
118
-
119
- ```typescript
120
- import { initialize } from 'ocosay'
121
-
122
- await initialize({
123
- providers: {
124
- minimax: {
125
- apiKey: 'your-api-key',
126
- voiceId: 'male-qn-qingse',
127
- model: 'stream'
128
- }
129
- }
130
- })
131
- ```
132
-
133
- ### 基本使用
134
-
135
- ```typescript
136
- import { speak, stop, pause, resume } from 'ocosay'
137
-
138
- // 说话
139
- await speak('你好,世界!')
140
-
141
- // 暂停
142
- pause()
143
-
144
- // 恢复
145
- resume()
146
-
147
- // 停止
148
- await stop()
149
- ```
150
-
151
- ### 指定音色和模式
152
-
153
- ```typescript
154
- await speak('你好,世界!', {
155
- provider: 'minimax',
156
- voice: 'female-shaonv',
157
- model: 'sync',
158
- speed: 1.0,
159
- volume: 80
160
- })
161
- ```
162
-
163
- ## 豆包模式
164
-
165
- 豆包模式是 ocosay 的核心特性 — 开启后,AI 助手的回复会**边接收边朗读**,实现类似豆包 App 的流畅播报体验。
166
-
167
- ### 核心组件
168
-
169
- | 组件 | 说明 |
170
- |------|------|
171
- | `StreamReader` | 文本缓冲器,收集并缓冲流式文本 |
172
- | `StreamingSynthesizer` | 流式合成器,边接收边合成音频 |
173
- | `StreamPlayer` | 流式播放器,边收边播 |
174
- | `TuiEventBus` | 事件总线,监听 OpenCode 事件流 |
175
-
176
- > **注意**:`autoRead` 是 `initialize()` 的配置选项(`autoRead: true`),而非独立组件。
177
-
178
- ### 启用豆包模式
179
-
180
- 豆包模式通过 `initialize()` 的 `autoRead: true` 配置选项启用:
181
-
182
- ```typescript
183
- import { initialize } from 'ocosay'
184
-
185
- // 启用豆包模式
186
- await initialize({
187
- providers: {
188
- minimax: {
189
- apiKey: 'your-api-key',
190
- voiceId: 'male-qn-qingse'
191
- }
192
- },
193
- autoRead: true // 开启边接收边朗读
194
- })
195
- ```
196
-
197
- ### 数据流与事件
198
-
199
- 豆包模式的数据流如下:
200
-
201
- ```
202
- TuiEventBus (message.part.delta)
203
- → StreamReader (缓冲文本)
204
- → StreamingSynthesizer (流式合成)
205
- → StreamPlayer (边收边播)
206
- → TuiEventBus (message.part.end)
207
- ```
208
-
209
- | 事件 | 说明 |
210
- |------|------|
211
- | `message.part.delta` | AI回复文本增量事件,携带 `delta` 字段 |
212
- | `message.part.end` | AI回复片段结束事件 |
213
-
214
- ### TuiEventBus 事件监听
215
-
216
- TuiEventBus 负责监听 OpenCode 的事件流,实现边接收边朗读:
217
-
218
- ```typescript
219
- import { TuiEventBus } from 'ocosay'
220
-
221
- const bus = new TuiEventBus()
222
-
223
- // 监听文本增量事件
224
- bus.on('message.part.delta', (event) => {
225
- // event.properties.delta 包含新增的文本
226
- console.log('收到文本:', event.properties.delta)
227
- })
228
-
229
- // 监听回复片段结束
230
- bus.on('message.part.end', () => {
231
- console.log('回复片段结束')
232
- })
233
- ```
234
-
235
- ## 工具列表
236
-
237
- ocosay 提供 10 个工具用于 OpenCode 集成:
238
-
239
- | 工具名 | 描述 | 参数 |
240
- |--------|------|------|
241
- | `tts_speak` | 将文本转换为语音并播放 | `text` (必填),其他参数从配置文件读取 |
242
- | `tts_stop` | 停止当前 TTS 播放 | - |
243
- | `tts_pause` | 暂停当前 TTS 播放 | - |
244
- | `tts_resume` | 恢复暂停的 TTS 播放 | - |
245
- | `tts_list_voices` | 列出可用的音色 | `provider` |
246
- | `tts_list_providers` | 列出所有已注册的 TTS 提供商 | - |
247
- | `tts_status` | 获取当前 TTS 播放状态 | - |
248
- | `tts_stream_speak` | 启动流式朗读(豆包模式) | `text`, `voice`, `model` |
249
- | `tts_stream_stop` | 停止当前流式朗读 | - |
250
- | `tts_stream_status` | 获取当前流式朗读状态 | - |
251
-
252
- ### tts_speak
253
-
254
- 将文本转换为语音并播放。其他参数(provider、voice、model、speed等)从配置文件读取。
255
-
256
- ```typescript
257
- // 工具调用
258
- await tts_speak({
259
- text: '这是要播放的文本内容'
260
- })
261
- ```
262
-
263
- ### tts_stop
264
-
265
- 停止当前 TTS 播放。
266
-
267
- ```typescript
268
- // 工具调用
269
- await tts_stop()
270
- ```
271
-
272
- ### tts_pause
273
-
274
- 暂停当前 TTS 播放。
275
-
276
- ```typescript
277
- // 工具调用
278
- await tts_pause()
279
- ```
280
-
281
- ### tts_resume
282
-
283
- 恢复暂停的 TTS 播放。
284
-
285
- ```typescript
286
- // 工具调用
287
- await tts_resume()
288
- ```
289
-
290
- ### tts_list_voices
291
-
292
- 列出可用的音色。
293
-
294
- ```typescript
295
- // 工具调用
296
- const result = await tts_list_voices({ provider: 'minimax' })
297
- // 返回: { success: true, voices: [...] }
298
- ```
299
-
300
- ### tts_list_providers
301
-
302
- 列出所有已注册的 TTS 提供商。
303
-
304
- ```typescript
305
- // 工具调用
306
- const result = await tts_list_providers()
307
- // 返回: { success: true, providers: ['minimax'] }
308
- ```
309
-
310
- ### tts_status
311
-
312
- 获取当前 TTS 播放状态。
313
-
314
- ```typescript
315
- // 工具调用
316
- const status = await tts_status()
317
- // 返回: { success: true, isPlaying: boolean, isPaused: boolean }
318
- ```
319
-
320
- ### tts_stream_speak
321
-
322
- 启动流式朗读(豆包模式),订阅AI回复并边生成边朗读。
323
-
324
- ```typescript
325
- // 工具调用
326
- await tts_stream_speak({
327
- text: '初始文本(可选)',
328
- voice: 'female-shaonv',
329
- model: 'stream'
330
- })
331
- ```
332
-
333
- ### tts_stream_stop
334
-
335
- 停止当前流式朗读。
336
-
337
- ```typescript
338
- // 工具调用
339
- await tts_stream_stop()
340
- ```
341
-
342
- ### tts_stream_status
343
-
344
- 获取当前流式朗读状态。
345
-
346
- ```typescript
347
- // 工具调用
348
- const status = await tts_stream_status()
349
- // 返回: { success: true, isActive: boolean, bytesWritten: number, state: string }
350
- ```
351
-
352
- ## API 参考
65
+ ---
353
66
 
354
- ### initialize(config?)
67
+ ## 故障排除
355
68
 
356
- 初始化 ocosay 插件。**必须首先调用此方法。**
357
-
358
- | 参数 | 类型 | 说明 |
359
- |------|------|------|
360
- | config.defaultProvider | string | 默认 TTS 提供商,默认 minimax |
361
- | config.defaultModel | 'sync' \| 'async' \| 'stream' | 默认合成模式,默认 stream |
362
- | config.defaultVoice | string | 默认音色 ID |
363
- | config.providers.minimax | MiniMaxConfig | MiniMax 提供商配置 |
364
- | config.autoRead | boolean | 启用豆包模式(边接收边朗读) |
365
- | config.streamBufferSize | number | 流式缓冲大小,默认 30 |
366
- | config.streamBufferTimeout | number | 流式缓冲超时(ms),默认 2000 |
367
-
368
- ```typescript
369
- import { initialize } from 'ocosay'
370
-
371
- await initialize({
372
- providers: {
373
- minimax: {
374
- apiKey: 'your-api-key',
375
- voiceId: 'male-qn-qingse',
376
- model: 'stream'
377
- }
378
- },
379
- autoRead: true // 启用豆包模式
380
- })
381
- ```
382
-
383
- ### destroy()
384
-
385
- 释放所有资源,清理插件状态。应在插件卸载或会话结束时调用。
386
-
387
- ```typescript
388
- import { destroy } from 'ocosay'
389
-
390
- await destroy()
391
- ```
392
-
393
- ### TuiEventBus
394
-
395
- 事件总线类,用于监听 OpenCode 事件流。
396
-
397
- | 方法 | 说明 |
69
+ | 问题 | 解决 |
398
70
  |------|------|
399
- | `on(event, handler)` | 注册事件监听器 |
400
- | `off(event, handler)` | 注销事件监听器 |
401
-
402
- **可用事件:**
71
+ | Cannot find module 'naudiodon' | 运行 `npm rebuild naudiodon` |
72
+ | 音频播放无声 | 检查系统音频设备 |
73
+ | 其他错误 | 运行诊断:`node scripts/verify-audio.js` |
403
74
 
404
- | 事件名 | 说明 | 事件属性 |
405
- |--------|------|----------|
406
- | `message.part.delta` | AI回复文本增量 | `sessionId`, `messageId`, `partId`, `properties.delta` |
407
- | `message.part.end` | AI回复片段结束 | - |
408
-
409
- ### speak(text, options?)
410
-
411
- 将文本转换为语音并播放。
412
-
413
- | 参数 | 类型 | 说明 |
414
- |------|------|------|
415
- | text | string | 要转换的文本 |
416
- | options.provider | string | TTS 提供商,默认 minimax |
417
- | options.voice | string | 音色 ID |
418
- | options.model | 'sync' \| 'async' \| 'stream' | 合成模式,默认 stream |
419
- | options.speed | number | 语速 0.5-2.0 |
420
- | options.volume | number | 音量 0-100 |
421
- | options.pitch | number | 音调 0.5-2.0 |
422
-
423
- ### stop()
424
-
425
- 停止当前播放。
426
-
427
- ### pause()
428
-
429
- 暂停当前播放。
430
-
431
- ### resume()
432
-
433
- 恢复暂停的播放。
434
-
435
- ### listVoices(provider?)
436
-
437
- 列出可用的音色。
438
-
439
- ```typescript
440
- const voices = await listVoices('minimax')
441
- console.log(voices)
442
- // [{ id: 'male-qn-qingse', name: '青年清澈', ... }]
443
- ```
75
+ ---
444
76
 
445
- ### isAutoReadEnabled()
77
+ ## 平台支持
446
78
 
447
- 检查豆包模式是否已启用。
448
-
449
- ```typescript
450
- import { isAutoReadEnabled } from 'ocosay'
451
-
452
- const enabled = isAutoReadEnabled() // 返回: boolean
453
- ```
454
-
455
- ### isStreamEnabled()
456
-
457
- 检查流式组件是否已初始化。
458
-
459
- ```typescript
460
- import { isStreamEnabled } from 'ocosay'
461
-
462
- const enabled = isStreamEnabled() // 返回: boolean
463
- ```
464
-
465
- ### getStreamStatus()
466
-
467
- 获取流式播放状态。
468
-
469
- ```typescript
470
- import { getStreamStatus } from 'ocosay'
471
-
472
- const status = getStreamStatus()
473
- // 返回: { isActive: boolean, bytesWritten: number, state: string }
474
- ```
475
-
476
- ## MiniMax 音色列表
477
-
478
- | ID | 名称 | 语言 | 性别 |
479
- |----|------|------|------|
480
- | male-qn-qingse | 青年清澈 | zh-CN | male |
481
- | male-qn-qingse_2 | 青年清澈v2 | zh-CN | male |
482
- | female-shaonv | 少女 | zh-CN | female |
483
- | male-baiming | 成熟男声 | zh-CN | male |
484
- | female-tianmei | 甜美女声 | zh-CN | female |
485
-
486
- ## 合成模式
487
-
488
- | 模式 | 说明 | 适用场景 |
489
- |------|----------|----------|
490
- | stream | 流式合成,边生成边播放 | 长文本,首包延迟低 |
491
- | sync | 同步合成,等待完整音频 | 短文本,一体化返回 |
492
- | async | 异步合成,轮询获取结果 | 长文本,需要任务队列 |
493
-
494
- ## 架构设计
495
-
496
- ```
497
- ┌─────────────────────────────────────────────────────────────────────┐
498
- │ OpenCode │
499
- │ ┌─────────────────────────────────────────────────────────────────┐ │
500
- │ │ Plugin (ocosay) │ │
501
- │ │ ┌───────────────────────────────────────────────────────────┐ │ │
502
- │ │ │ Speaker │ │ │
503
- │ │ │ ┌───────────────────────┐ ┌───────────────────────────┐ │ │ │
504
- │ │ │ │ StreamReader │ │ StreamingSynthesizer │ │ │ │
505
- │ │ │ │ (文本缓冲) │ │ (流式合成) │ │ │ │
506
- │ │ │ └───────────────────────┘ └───────────────────────────┘ │ │ │
507
- │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │
508
- │ │ │ │ StreamPlayer (边收边播) │ │ │ │
509
- │ │ │ └─────────────────────────────────────────────────────┘ │ │ │
510
- │ │ │ │ │ │ │
511
- │ │ │ ┌─────────────────────────────────────────────────────┐ │ │ │
512
- │ │ │ │ TuiEventBus │ │ │ │
513
- │ │ │ │ (监听 OpenCode 事件流) │ │ │ │
514
- │ │ │ └─────────────────────────────────────────────────────┘ │ │ │
515
- │ │ └───────────────────────────────────────────────────────────┘ │ │
516
- │ └─────────────────────────────────────────────────────────────────┘ │
517
- │ │ │
518
- │ ┌─────────────────────────────────────────────────────────────────┐ │
519
- │ │ TTS Providers (可扩展) │ │
520
- │ │ ┌──────────────────┐ ┌────────────────────────────────────┐ │ │
521
- │ │ │ MiniMax │ │ (Future) │ │ │
522
- │ │ └──────────────────┘ └────────────────────────────────────┘ │ │
523
- │ └─────────────────────────────────────────────────────────────────┘ │
524
- └─────────────────────────────────────────────────────────────────────┘
525
- ```
526
-
527
- ## 错误处理
528
-
529
- ```typescript
530
- import { speak } from 'ocosay'
531
- import { TTSError, TTSErrorCode } from 'ocosay'
532
-
533
- try {
534
- await speak('你好')
535
- } catch (error) {
536
- if (error instanceof TTSError) {
537
- console.error(`[${error.code}] ${error.message}`)
538
- console.error(`Provider: ${error.provider}`)
539
- }
540
- }
541
- ```
542
-
543
- ### 错误码
544
-
545
- | 错误码 | 说明 |
546
- |--------|------|
547
- | NETWORK | 网络错误 |
548
- | AUTH | 认证失败 |
549
- | QUOTA | 配额超限 |
550
- | INVALID_VOICE | 无效音色 |
551
- | INVALID_PARAMS | 无效参数 |
552
- | PLAYER_ERROR | 播放错误 |
553
- | UNKNOWN | 未知错误 |
554
-
555
- ## Troubleshooting / FAQ
556
-
557
- ### Q: 首包延迟太长怎么办?
558
-
559
- **A:** 切换到 `stream` 模式,并选择较短的音色如 `female-shaonv`。
560
-
561
- ### Q: 播放出现卡顿?
562
-
563
- **A:** 检查网络状况,或降低语速 `speed: 0.8`。
564
-
565
- ### Q: 如何切换不同音色?
566
-
567
- **A:** 使用 `listVoices()` 查看可用音色,通过 `speak(text, { voice: 'voice-id' })` 指定。
568
-
569
- ### Q: 豆包模式不工作?
570
-
571
- **A:** 确认 TuiEventBus 已正确初始化,并检查 `autoRead` 开关状态。
572
-
573
- ### Q: 报错 AUTH?
574
-
575
- **A:** 检查 API Key 是否正确配置,或密钥是否过期。
576
-
577
- ## 日志系统
578
-
579
- ocosay 使用 pino 作为日志库,提供统一的日志格式。
580
-
581
- ### 日志位置
582
-
583
- ```
584
- ~/.ocosay/ocosay.log
585
- ```
586
-
587
- ### 日志级别
588
-
589
- | 级别 | 说明 |
79
+ | 平台 | 状态 |
590
80
  |------|------|
591
- | `error` | 错误信息 |
592
- | `warn` | 警告信息 |
593
- | `info` | 一般信息 |
594
- | `debug` | 调试信息 |
595
-
596
- ### 示例
597
-
598
- ```bash
599
- # 查看实时日志
600
- tail -f ~/.ocosay/ocosay.log
601
-
602
- # 查看错误日志
603
- grep "error" ~/.ocosay/ocosay.log
604
- ```
605
-
606
- ## 开发
607
-
608
- ```bash
609
- # 安装依赖
610
- npm install
611
-
612
- # 构建
613
- npm run build
614
-
615
- # 运行测试
616
- npm test
617
-
618
- # 监听模式
619
- npm run watch
620
- ```
621
-
622
- ## Changelog
623
-
624
- ### v1.0.13 (2026-04-06)
625
- **New Features:**
626
- - ✨ Toast通知:插件加载成功/失败显示Toast (success/error)
627
- - ✨ Toast通知:语音播放成功/失败显示Toast (success/error)
628
- - 🔄 初始化重试机制:session创建时自动重试初始化
629
- - 🌐 所有Toast内容改为英文
630
- - 🔒 错误信息脱敏,不暴露内部细节
631
-
632
- **Bug Fix:**
633
- - 🐛 修复showToast调用方式(添加延迟+防御性检查)
634
-
635
- ### v1.0.10 (2026-04-05)
636
- **Bug Fix:**
637
- - 🐛 修复 showToast 时序问题(初始化成功后才显示 toast)
638
- - 🐛 添加初始化失败时 error toast 提示
639
-
640
- ### v1.0.8 (2026-04-05)
641
- **New Features:**
642
- - ✨ 新增 OpenCode 启动成功弹窗,显示插件版本号和 autoRead 模式状态
643
-
644
- ### v1.0.4 (2026-04-05)
645
- **Bug Fix & Improvements:**
646
- - 🐛 修复 npm 包包含源码和测试文件问题(添加 .npmignore)
647
- - 🎵 默认 voiceId 改为 `female-chengshu`(成熟女性音色)
648
- - 🔧 默认 baseURL: `https://api.minimaxi.com`
649
-
650
- ### v1.0.5 (2026-04-05)
651
- **Bug Fix:**
652
- - 🐛 修复 OpenCode 加载失败 `Plugin export is not a function`
653
- - 根因:`export default { server }` 让 module.default 是对象不是函数
654
- - 修复:使用 named export `export const server = OcosayPlugin; export default server`
655
-
656
- ### v1.0.3 (2026-04-05)
657
- **Bug Fix:**
658
- - 🐛 修复 OpenCode 加载失败 `Plugin export is not a function`
659
- - 根因:TypeScript ESM 导入缺少 .js 扩展名
660
- - 修复:使用 esbuild 打包 plugin.ts
661
-
662
- ### v1.0.2 (2026-04-05)
663
- **Bug Fix:**
664
- - 🐛 修复 OpenCode 加载失败 `Plugin export is not a function`
665
- - 根因:OpenCode 插件加载器期望 `{ server: Plugin }` 格式导出
666
- - 修复:`export default { server: OcosayPlugin }`
667
- - 🎵 默认 TTS 模型改为 `speech-2.8-hd`
668
-
669
- ### v1.0.1 (2026-04-05)
670
- - 📚 多平台 AudioBackend 架构(6 种后端)
671
- - 🔌 OpenCode 插件标准集成
672
- - 📋 完整测试覆盖(304 测试)
673
-
674
- ### v1.0.0 (2026-04-05)
675
- - 🎙️ 初始版本
676
- - 🔊 多 TTS 模型支持
677
- - 🎭 多种音色选择
678
- - 🎛️ 播放控制(暂停、恢复、停止)
679
- - 📡 豆包模式(边接收边朗读)
680
-
681
- ## Contributing
682
-
683
- 欢迎提交 Issue 和 PR!
684
-
685
- 1. Fork 本仓库
686
- 2. 创建特性分支 (`git checkout -b feature/amazing`)
687
- 3. 提交更改 (`git commit -m 'Add amazing feature'`)
688
- 4. 推送分支 (`git push origin feature/amazing`)
689
- 5. 提交 Pull Request
690
-
691
- ## License
692
-
693
- MIT
81
+ | macOS | |
82
+ | Windows WSL | |
83
+ | Windows 原生 | ⚠️ |