@mingxy/ocosay 1.0.3 → 1.0.4
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.
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +1 -1
- package/package.json +1 -1
- package/TECH_PLAN.md +0 -352
- package/__mocks__/@opencode-ai/plugin.ts +0 -32
- package/jest.config.js +0 -15
- package/src/config.ts +0 -183
- package/src/core/backends/afplay-backend.ts +0 -162
- package/src/core/backends/aplay-backend.ts +0 -160
- package/src/core/backends/base.ts +0 -117
- package/src/core/backends/index.ts +0 -128
- package/src/core/backends/naudiodon-backend.ts +0 -164
- package/src/core/backends/powershell-backend.ts +0 -173
- package/src/core/player.ts +0 -322
- package/src/core/speaker.ts +0 -283
- package/src/core/stream-player.ts +0 -326
- package/src/core/stream-reader.ts +0 -190
- package/src/core/streaming-synthesizer.ts +0 -123
- package/src/core/types.ts +0 -185
- package/src/index.ts +0 -236
- package/src/plugin.ts +0 -178
- package/src/providers/base.ts +0 -150
- package/src/providers/minimax.ts +0 -515
- package/src/tools/tts.ts +0 -277
- package/src/types/config.ts +0 -38
- package/src/types/naudiodon.d.ts +0 -19
- package/tests/__mocks__/@opencode-ai/plugin.ts +0 -32
- package/tests/backends.test.ts +0 -831
- package/tests/config.test.ts +0 -327
- package/tests/index.test.ts +0 -201
- package/tests/integration-test.d.ts +0 -6
- package/tests/integration-test.d.ts.map +0 -1
- package/tests/integration-test.js +0 -84
- package/tests/integration-test.js.map +0 -1
- package/tests/integration-test.ts +0 -93
- package/tests/p1-fixes.test.ts +0 -160
- package/tests/plugin.test.ts +0 -312
- package/tests/provider.test.d.ts +0 -2
- package/tests/provider.test.d.ts.map +0 -1
- package/tests/provider.test.js +0 -69
- package/tests/provider.test.js.map +0 -1
- package/tests/provider.test.ts +0 -87
- package/tests/speaker.test.d.ts +0 -2
- package/tests/speaker.test.d.ts.map +0 -1
- package/tests/speaker.test.js +0 -63
- package/tests/speaker.test.js.map +0 -1
- package/tests/speaker.test.ts +0 -232
- package/tests/stream-player.test.ts +0 -303
- package/tests/stream-reader.test.ts +0 -269
- package/tests/streaming-synthesizer.test.ts +0 -225
- package/tests/tts-tools.test.ts +0 -270
- package/tests/types.test.d.ts +0 -2
- package/tests/types.test.d.ts.map +0 -1
- package/tests/types.test.js +0 -61
- package/tests/types.test.js.map +0 -1
- package/tests/types.test.ts +0 -63
- package/tsconfig.json +0 -22
package/src/tools/tts.ts
DELETED
|
@@ -1,277 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* OpenCode TTS 工具定义
|
|
3
|
-
* 用于 OpenCode Plugin 注册
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { speak, stop, pause, resume, listVoices, getDefaultSpeaker } from '../core/speaker'
|
|
7
|
-
import { TTSError, TTSErrorCode } from '../core/types'
|
|
8
|
-
import {
|
|
9
|
-
isStreamEnabled,
|
|
10
|
-
isAutoReadEnabled,
|
|
11
|
-
getStreamStatus,
|
|
12
|
-
getStreamReader,
|
|
13
|
-
getStreamingSynthesizer,
|
|
14
|
-
getStreamPlayer
|
|
15
|
-
} from '../index'
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* OpenCode TTS 工具定义
|
|
19
|
-
* 用于 OpenCode Plugin 注册
|
|
20
|
-
*/
|
|
21
|
-
export const ttsTools = [
|
|
22
|
-
{
|
|
23
|
-
name: 'tts_speak',
|
|
24
|
-
description: '将文本转换为语音并播放',
|
|
25
|
-
input: {
|
|
26
|
-
type: 'object',
|
|
27
|
-
properties: {
|
|
28
|
-
text: {
|
|
29
|
-
type: 'string',
|
|
30
|
-
description: '要转换的文本内容'
|
|
31
|
-
},
|
|
32
|
-
provider: {
|
|
33
|
-
type: 'string',
|
|
34
|
-
description: 'TTS 提供商名称',
|
|
35
|
-
default: 'minimax'
|
|
36
|
-
},
|
|
37
|
-
voice: {
|
|
38
|
-
type: 'string',
|
|
39
|
-
description: '音色 ID'
|
|
40
|
-
},
|
|
41
|
-
model: {
|
|
42
|
-
type: 'string',
|
|
43
|
-
enum: ['sync', 'async', 'stream'],
|
|
44
|
-
description: '合成模式',
|
|
45
|
-
default: 'stream'
|
|
46
|
-
},
|
|
47
|
-
speed: {
|
|
48
|
-
type: 'number',
|
|
49
|
-
description: '语速 0.5-2.0'
|
|
50
|
-
},
|
|
51
|
-
volume: {
|
|
52
|
-
type: 'number',
|
|
53
|
-
description: '音量 0-100'
|
|
54
|
-
},
|
|
55
|
-
pitch: {
|
|
56
|
-
type: 'number',
|
|
57
|
-
description: '音调 0.5-2.0'
|
|
58
|
-
}
|
|
59
|
-
},
|
|
60
|
-
required: ['text']
|
|
61
|
-
}
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
name: 'tts_stop',
|
|
65
|
-
description: '停止当前 TTS 播放'
|
|
66
|
-
},
|
|
67
|
-
{
|
|
68
|
-
name: 'tts_pause',
|
|
69
|
-
description: '暂停当前 TTS 播放'
|
|
70
|
-
},
|
|
71
|
-
{
|
|
72
|
-
name: 'tts_resume',
|
|
73
|
-
description: '恢复暂停的 TTS 播放'
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
name: 'tts_list_voices',
|
|
77
|
-
description: '列出可用的音色',
|
|
78
|
-
input: {
|
|
79
|
-
type: 'object',
|
|
80
|
-
properties: {
|
|
81
|
-
provider: {
|
|
82
|
-
type: 'string',
|
|
83
|
-
description: 'TTS 提供商名称',
|
|
84
|
-
default: 'minimax'
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
{
|
|
90
|
-
name: 'tts_list_providers',
|
|
91
|
-
description: '列出所有已注册的 TTS 提供商'
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
name: 'tts_status',
|
|
95
|
-
description: '获取当前 TTS 播放状态',
|
|
96
|
-
output: {
|
|
97
|
-
type: 'object',
|
|
98
|
-
properties: {
|
|
99
|
-
isPlaying: { type: 'boolean' },
|
|
100
|
-
isPaused: { type: 'boolean' }
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
},
|
|
104
|
-
{
|
|
105
|
-
name: 'tts_stream_speak',
|
|
106
|
-
description: '启动流式朗读(豆包模式),订阅AI回复并边生成边朗读',
|
|
107
|
-
input: {
|
|
108
|
-
type: 'object',
|
|
109
|
-
properties: {
|
|
110
|
-
text: {
|
|
111
|
-
type: 'string',
|
|
112
|
-
description: '初始文本(可选)'
|
|
113
|
-
},
|
|
114
|
-
voice: {
|
|
115
|
-
type: 'string',
|
|
116
|
-
description: '音色ID'
|
|
117
|
-
},
|
|
118
|
-
model: {
|
|
119
|
-
type: 'string',
|
|
120
|
-
enum: ['sync', 'async', 'stream'],
|
|
121
|
-
default: 'stream'
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
},
|
|
126
|
-
{
|
|
127
|
-
name: 'tts_stream_stop',
|
|
128
|
-
description: '停止当前流式朗读'
|
|
129
|
-
},
|
|
130
|
-
{
|
|
131
|
-
name: 'tts_stream_status',
|
|
132
|
-
description: '获取当前流式朗读状态',
|
|
133
|
-
output: {
|
|
134
|
-
type: 'object',
|
|
135
|
-
properties: {
|
|
136
|
-
isActive: { type: 'boolean' },
|
|
137
|
-
bytesWritten: { type: 'number' },
|
|
138
|
-
state: { type: 'string' }
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
]
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* 工具执行处理器
|
|
146
|
-
*/
|
|
147
|
-
export async function handleToolCall(
|
|
148
|
-
toolName: string,
|
|
149
|
-
args?: Record<string, any>
|
|
150
|
-
): Promise<any> {
|
|
151
|
-
try {
|
|
152
|
-
switch (toolName) {
|
|
153
|
-
case 'tts_speak':
|
|
154
|
-
await speak(args?.text, {
|
|
155
|
-
provider: args?.provider,
|
|
156
|
-
voice: args?.voice,
|
|
157
|
-
model: args?.model,
|
|
158
|
-
speed: args?.speed,
|
|
159
|
-
volume: args?.volume,
|
|
160
|
-
pitch: args?.pitch
|
|
161
|
-
})
|
|
162
|
-
return { success: true, message: 'Speech completed' }
|
|
163
|
-
|
|
164
|
-
case 'tts_stop':
|
|
165
|
-
await stop()
|
|
166
|
-
return { success: true, message: 'Stopped' }
|
|
167
|
-
|
|
168
|
-
case 'tts_pause':
|
|
169
|
-
pause()
|
|
170
|
-
return { success: true, message: 'Paused' }
|
|
171
|
-
|
|
172
|
-
case 'tts_resume':
|
|
173
|
-
resume()
|
|
174
|
-
return { success: true, message: 'Resumed' }
|
|
175
|
-
|
|
176
|
-
case 'tts_list_voices':
|
|
177
|
-
const voices = await listVoices(args?.provider as string | undefined)
|
|
178
|
-
return { success: true, voices }
|
|
179
|
-
|
|
180
|
-
case 'tts_list_providers':
|
|
181
|
-
const speaker = getDefaultSpeaker()
|
|
182
|
-
const providers = speaker.getProviders()
|
|
183
|
-
return { success: true, providers }
|
|
184
|
-
|
|
185
|
-
case 'tts_status':
|
|
186
|
-
const s = getDefaultSpeaker()
|
|
187
|
-
return {
|
|
188
|
-
success: true,
|
|
189
|
-
isPlaying: s.isPlaying(),
|
|
190
|
-
isPaused: s.isPausedState()
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
case 'tts_stream_speak':
|
|
194
|
-
if (!isAutoReadEnabled()) {
|
|
195
|
-
throw new TTSError(
|
|
196
|
-
'Stream mode is not enabled. autoRead must be enabled in configuration to use tts_stream_speak.',
|
|
197
|
-
TTSErrorCode.UNKNOWN,
|
|
198
|
-
'tts_stream'
|
|
199
|
-
)
|
|
200
|
-
}
|
|
201
|
-
if (!isStreamEnabled()) {
|
|
202
|
-
throw new TTSError(
|
|
203
|
-
'Stream components not initialized. Please initialize with autoRead enabled.',
|
|
204
|
-
TTSErrorCode.UNKNOWN,
|
|
205
|
-
'tts_stream'
|
|
206
|
-
)
|
|
207
|
-
}
|
|
208
|
-
const streamReader = getStreamReader()
|
|
209
|
-
const synthesizer = getStreamingSynthesizer()
|
|
210
|
-
if (streamReader && synthesizer) {
|
|
211
|
-
streamReader.start()
|
|
212
|
-
if (args?.text) {
|
|
213
|
-
synthesizer.synthesize(args.text)
|
|
214
|
-
}
|
|
215
|
-
return { success: true, message: 'Stream speak started' }
|
|
216
|
-
}
|
|
217
|
-
throw new TTSError(
|
|
218
|
-
'Stream components not available',
|
|
219
|
-
TTSErrorCode.UNKNOWN,
|
|
220
|
-
'tts_stream'
|
|
221
|
-
)
|
|
222
|
-
|
|
223
|
-
case 'tts_stream_stop':
|
|
224
|
-
if (!isStreamEnabled()) {
|
|
225
|
-
throw new TTSError(
|
|
226
|
-
'Stream mode is not enabled. Please enable autoRead in configuration.',
|
|
227
|
-
TTSErrorCode.UNKNOWN,
|
|
228
|
-
'tts_stream'
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
const player = getStreamPlayer()
|
|
232
|
-
if (player) {
|
|
233
|
-
player.stop()
|
|
234
|
-
return { success: true, message: 'Stream stopped' }
|
|
235
|
-
}
|
|
236
|
-
throw new TTSError(
|
|
237
|
-
'Stream player not available',
|
|
238
|
-
TTSErrorCode.UNKNOWN,
|
|
239
|
-
'tts_stream'
|
|
240
|
-
)
|
|
241
|
-
|
|
242
|
-
case 'tts_stream_status':
|
|
243
|
-
if (!isStreamEnabled()) {
|
|
244
|
-
return {
|
|
245
|
-
success: true,
|
|
246
|
-
isActive: false,
|
|
247
|
-
bytesWritten: 0,
|
|
248
|
-
state: 'not_initialized'
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
return {
|
|
252
|
-
success: true,
|
|
253
|
-
...getStreamStatus()
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
default:
|
|
257
|
-
throw new TTSError(
|
|
258
|
-
`Unknown tool: ${toolName}`,
|
|
259
|
-
TTSErrorCode.UNKNOWN,
|
|
260
|
-
'tools'
|
|
261
|
-
)
|
|
262
|
-
}
|
|
263
|
-
} catch (error) {
|
|
264
|
-
if (error instanceof TTSError) {
|
|
265
|
-
return {
|
|
266
|
-
success: false,
|
|
267
|
-
error: error.message,
|
|
268
|
-
code: error.code,
|
|
269
|
-
provider: error.provider
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return {
|
|
273
|
-
success: false,
|
|
274
|
-
error: String(error)
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
}
|
package/src/types/config.ts
DELETED
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Ocosay Configuration Types
|
|
3
|
-
* 配置文件类型定义
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
export interface OcosayConfig {
|
|
7
|
-
enabled: boolean
|
|
8
|
-
autoPlay: boolean
|
|
9
|
-
autoRead: boolean
|
|
10
|
-
streamMode: boolean
|
|
11
|
-
streamBufferSize: number
|
|
12
|
-
streamBufferTimeout: number
|
|
13
|
-
speed: number
|
|
14
|
-
volume: number
|
|
15
|
-
pitch: number
|
|
16
|
-
providers: {
|
|
17
|
-
minimax: {
|
|
18
|
-
apiKey: string
|
|
19
|
-
baseURL: string
|
|
20
|
-
voiceId: string
|
|
21
|
-
model: 'sync' | 'async' | 'stream'
|
|
22
|
-
ttsModel: string
|
|
23
|
-
audioFormat: 'mp3' | 'wav' | 'flac'
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export const DEFAULT_CONFIG: Omit<OcosayConfig, 'providers'> = {
|
|
29
|
-
enabled: true,
|
|
30
|
-
autoPlay: false,
|
|
31
|
-
autoRead: false,
|
|
32
|
-
streamMode: true,
|
|
33
|
-
streamBufferSize: 30,
|
|
34
|
-
streamBufferTimeout: 2000,
|
|
35
|
-
speed: 1.0,
|
|
36
|
-
volume: 80,
|
|
37
|
-
pitch: 1.0
|
|
38
|
-
}
|
package/src/types/naudiodon.d.ts
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
declare module 'naudiodon' {
|
|
2
|
-
interface NaudiodonAudioOutput {
|
|
3
|
-
start(): void
|
|
4
|
-
write(chunk: Buffer): void
|
|
5
|
-
end(): void
|
|
6
|
-
quit(): void
|
|
7
|
-
on(event: string, callback: (error: Error) => void): void
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
interface Naudiodon {
|
|
11
|
-
new (options: {
|
|
12
|
-
sampleRate?: number
|
|
13
|
-
channels?: number
|
|
14
|
-
bitDepth?: number
|
|
15
|
-
}): NaudiodonAudioOutput
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
export = Naudiodon
|
|
19
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
const schema = {
|
|
2
|
-
string: () => ({
|
|
3
|
-
describe: (desc: string) => ({ describe: desc }),
|
|
4
|
-
optional: () => ({
|
|
5
|
-
describe: (desc: string) => ({ describe: desc })
|
|
6
|
-
}),
|
|
7
|
-
number: () => ({
|
|
8
|
-
describe: (desc: string) => ({ describe: desc }),
|
|
9
|
-
optional: () => ({
|
|
10
|
-
describe: (desc: string) => ({ describe: desc })
|
|
11
|
-
})
|
|
12
|
-
}),
|
|
13
|
-
enum: (values: string[]) => ({
|
|
14
|
-
describe: (desc: string) => ({ describe: desc }),
|
|
15
|
-
optional: () => ({
|
|
16
|
-
describe: (desc: string) => ({ describe: desc })
|
|
17
|
-
})
|
|
18
|
-
})
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
function tool({ description, args, execute }: any) {
|
|
23
|
-
return {
|
|
24
|
-
description,
|
|
25
|
-
args,
|
|
26
|
-
execute,
|
|
27
|
-
schema
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export { tool, schema }
|
|
32
|
-
export const Plugin = jest.fn()
|