@amaster.ai/tts-client 1.1.8 → 1.1.10
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/index.cjs +959 -130
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +106 -46
- package/dist/index.d.ts +106 -46
- package/dist/index.js +955 -129
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/tts-client.ts"],"sourcesContent":["import type { TTSClient, TTSClientConfig } from \"./tts-client\";\nimport createTTSClient from \"./tts-client\";\nexport { createTTSClient, type TTSClient, type TTSClientConfig };\n","/**\n * TTS Realtime WebSocket Client\n *\n * WebSocket-based real-time text-to-speech synthesis with multiple voice options.\n * Built-in playback only supports PCM format.\n *\n * @example\n * ```typescript\n * const client = createTTSClient({\n * voice: \"Cherry\",\n * autoPlay: true,\n * onReady() {\n * console.log(\"TTS ready\");\n * },\n * onAudioStart() {\n * console.log(\"Playing audio\");\n * },\n * onAudioEnd() {\n * console.log(\"Playback ended\");\n * },\n * });\n *\n * await client.connect();\n * await client.speak(\"Hello, this is a test.\");\n * // client.close();\n * ```\n */\n\nconst TTS_PATH = \"/api/proxy/builtin/platform/qwen-tts/api-ws/v1/realtime\";\n\nexport interface TTSClientConfig {\n /** Get access token for WebSocket authentication */\n getAccessToken?: () => string | null;\n /** Voice name, default 'Cherry' */\n voice?: string;\n /** Auto play audio, default true */\n autoPlay?: boolean;\n /** Audio format, default 'pcm' */\n audioFormat?: \"pcm\" | \"mp3\" | \"wav\" | \"opus\";\n /** Sample rate, default 24000 */\n sampleRate?: number;\n /** Called when connection is ready */\n onReady?: () => void;\n /** Called when audio playback starts */\n onAudioStart?: () => void;\n /** Called when audio playback ends */\n onAudioEnd?: () => void;\n /** Called on each audio chunk received */\n onAudioChunk?: (chunk: string[]) => void;\n /** Called on error */\n onError?: (error: Error) => void;\n}\n\nexport interface TTSClient {\n /** Connect to TTS service */\n connect(): Promise<void>;\n /** Synthesize speech from text */\n speak(text: string): Promise<void>;\n /** Play audio from chunks */\n play(): void;\n /** Stop audio playback */\n stop(): void;\n /** Close connection */\n close(): void;\n}\n\nfunction createTTSClient(config: TTSClientConfig): TTSClient {\n const {\n getAccessToken,\n voice = \"Cherry\",\n autoPlay = true,\n audioFormat = \"pcm\",\n sampleRate = 24000,\n onReady,\n onAudioStart,\n onAudioEnd,\n onAudioChunk,\n onError,\n } = config;\n\n let ws: WebSocket | null = null;\n let audioChunks: string[] = [];\n let audioContext: AudioContext | null = null;\n let audioSource: AudioBufferSourceNode | null = null;\n\n async function connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n // Build WebSocket URL with optional token parameter\n let wsUrl = TTS_PATH;\n if (getAccessToken) {\n const token = getAccessToken();\n if (token) {\n const separator = wsUrl.includes(\"?\") ? \"&\" : \"?\";\n wsUrl = `${wsUrl}${separator}token=${encodeURIComponent(token)}`;\n }\n }\n\n ws = new WebSocket(wsUrl);\n\n ws.onopen = () => {};\n\n ws.onmessage = (event) => {\n const data = JSON.parse(event.data);\n\n if (data.type === \"session.created\") {\n ws!.send(\n JSON.stringify({\n type: \"session.update\",\n session: {\n mode: \"server_commit\",\n voice,\n response_format: audioFormat,\n sample_rate: sampleRate,\n },\n })\n );\n }\n\n if (data.type === \"session.updated\") {\n onReady?.();\n resolve();\n }\n\n if (data.type === \"response.audio.delta\") {\n audioChunks.push(data.delta);\n onAudioChunk?.(audioChunks);\n }\n\n if (data.type === \"response.audio.done\") {\n onAudioChunk?.(audioChunks);\n if (autoPlay && typeof window !== \"undefined\") {\n playAudio();\n }\n }\n\n if (data.type === \"response.done\") {\n ws!.send(JSON.stringify({ type: \"session.finish\" }));\n }\n\n if (data.type === \"error\") {\n const err = new Error(data.error?.message || \"Unknown error\");\n onError?.(err);\n reject(err);\n }\n };\n\n ws.onerror = () => {\n const err = new Error(\"WebSocket connection error\");\n onError?.(err);\n reject(err);\n };\n\n ws.onclose = () => {\n ws = null;\n };\n });\n }\n\n async function speak(text: string): Promise<void> {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error(\"WebSocket not connected\");\n }\n\n audioChunks = [];\n\n ws.send(\n JSON.stringify({\n type: \"input_text_buffer.append\",\n text,\n })\n );\n\n setTimeout(() => {\n ws!.send(\n JSON.stringify({\n type: \"input_text_buffer.commit\",\n })\n );\n }, 100);\n }\n\n function playAudio() {\n let chunks: string[] = audioChunks;\n if (typeof window === \"undefined\") return;\n\n try {\n if (!audioContext) {\n audioContext = new AudioContext();\n }\n\n onAudioStart?.();\n\n let totalBytes = 0;\n const allBytes: Uint8Array[] = [];\n\n for (const chunk of chunks) {\n const binaryString = atob(chunk);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n allBytes.push(bytes);\n totalBytes += bytes.length;\n }\n\n const combined = new Uint8Array(totalBytes);\n let offset = 0;\n for (const bytes of allBytes) {\n combined.set(bytes, offset);\n offset += bytes.length;\n }\n\n const numSamples = combined.length / 2;\n const audioBuffer = audioContext.createBuffer(1, numSamples, sampleRate);\n const channelData = audioBuffer.getChannelData(0);\n\n const dataView = new DataView(combined.buffer);\n for (let i = 0; i < numSamples; i++) {\n const int16 = dataView.getInt16(i * 2, true);\n channelData[i] = int16 / 32768.0;\n }\n\n const source = audioContext.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(audioContext.destination);\n source.onended = () => onAudioEnd?.();\n source.start(0);\n audioSource = source;\n } catch (err) {\n onError?.(err as Error);\n }\n }\n\n function stopAudio() {\n if (audioSource) {\n audioSource.stop();\n audioSource = null;\n }\n if (audioContext) {\n audioContext.close();\n audioContext = null;\n }\n }\n\n function close() {\n if (ws) {\n ws.close();\n ws = null;\n }\n stopAudio();\n }\n\n return {\n connect,\n speak,\n close,\n play: playAudio,\n stop: stopAudio,\n };\n}\n\nexport default (\n authConfig: Pick<TTSClientConfig, \"getAccessToken\">\n): ((config: TTSClientConfig) => TTSClient) => {\n return (config: TTSClientConfig) => {\n return createTTSClient({ ...authConfig, ...config });\n };\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/tts-client.ts"],"sourcesContent":["import createTTSClient from \"./tts-client\";\nexport { createTTSClient };\nexport {\n createTTSSpeakController,\n preprocessTTSContent,\n splitTextIntoFragments,\n type TTSClient,\n type TTSClientConfig,\n type TTSSnapshot,\n type TTSSpeakController,\n type TTSSpeakControllerOptions,\n type TTSSpeakOptions,\n type TTSStreamOptions,\n type TTSRuntime,\n type TTSStorageAdapter,\n} from \"./tts-client\";\n","const TTS_PATH = \"/api/proxy/builtin/platform/qwen-tts/api-ws/v1/realtime\";\nconst TTS_MAX_FRAGMENT_LENGTH = 2000;\n\nexport type TTSAudioFormat = \"pcm\" | \"mp3\" | \"wav\" | \"opus\";\n\nexport interface TTSStorageAdapter {\n getItem(key: string): string | null | undefined;\n setItem(key: string, value: string): void;\n removeItem?(key: string): void;\n}\n\nexport interface TTSRuntime {\n Taro?: {\n createInnerAudioContext?: () => {\n src: string;\n autoplay?: boolean;\n obeyMuteSwitch?: boolean;\n play?: () => void;\n stop?: () => void;\n destroy?: () => void;\n onPlay?: (callback: () => void) => void;\n onEnded?: (callback: () => void) => void;\n onStop?: (callback: () => void) => void;\n onError?: (callback: (error: { errMsg?: string }) => void) => void;\n };\n getFileSystemManager?: () => {\n writeFile?: (options: {\n filePath: string;\n data: ArrayBuffer;\n encoding?: string;\n success?: () => void;\n fail?: (error: unknown) => void;\n }) => void;\n unlink?: (options: {\n filePath: string;\n success?: () => void;\n fail?: () => void;\n }) => void;\n };\n env?: {\n USER_DATA_PATH?: string;\n };\n getEnv?: () => unknown;\n ENV_TYPE?: Record<string, unknown>;\n };\n}\n\nexport interface TTSClientConfig {\n getAccessToken?: () => string | null;\n voice?: string;\n autoPlay?: boolean;\n audioFormat?: TTSAudioFormat;\n sampleRate?: number;\n runtime?: TTSRuntime;\n onReady?: () => void;\n onAudioStart?: () => void;\n onAudioEnd?: () => void;\n onAudioChunk?: (chunks: string[]) => void;\n onError?: (error: Error) => void;\n onClose?: () => void;\n}\n\nexport interface TTSClient {\n connect(): Promise<void>;\n speak(text: string): Promise<void>;\n startStream(): void;\n appendText(text: string): void;\n commitText(): void;\n play(): void;\n stop(): void;\n close(): void;\n isConnected(): boolean;\n hasAudio(): boolean;\n isResponseDone(): boolean;\n isPlaying(): boolean;\n isStreamingPlayback(): boolean;\n}\n\nexport interface TTSSpeakOptions {\n id?: string;\n text: string;\n voice?: string;\n audioFormat?: TTSAudioFormat;\n sampleRate?: number;\n}\n\nexport interface TTSStreamOptions {\n id?: string;\n voice?: string;\n audioFormat?: TTSAudioFormat;\n sampleRate?: number;\n}\n\nexport interface TTSSnapshot {\n status: \"idle\" | \"connecting\" | \"speaking\" | \"error\";\n activeId: string | null;\n error: string | null;\n requestId: number;\n text: string | null;\n voice: string | null;\n fallbackMode: \"none\" | \"system\";\n}\n\nexport interface TTSSpeakController {\n getSnapshot(): TTSSnapshot;\n subscribe(listener: (snapshot: TTSSnapshot) => void): () => void;\n speak(options: TTSSpeakOptions): Promise<void>;\n startStream(options: TTSStreamOptions): Promise<void>;\n appendStreamText(options: TTSSpeakOptions): Promise<void>;\n commitStream(): void;\n finishStream(): void;\n stop(options?: { preserveClient?: boolean }): void;\n release(): void;\n toggle(options: TTSSpeakOptions): Promise<void>;\n isActive(id?: string | null): boolean;\n setVoice(voice: string | null): void;\n getVoice(): string | null;\n}\n\nexport interface TTSSpeakControllerOptions {\n storage?: TTSStorageAdapter;\n voiceStorageKey?: string;\n runtime?: TTSRuntime;\n fallbackToSystemSpeech?: boolean;\n}\n\ntype AudioPlaybackBackend = {\n kind: \"browser\" | \"mini-program\";\n hasStreamingPlayback: boolean;\n isPlaying(): boolean;\n stop(): void;\n playBuffered(input: { chunks: string[]; sampleRate: number; audioFormat: TTSAudioFormat }): Promise<void> | void;\n scheduleStreamingChunk?(input: { chunk: string; sampleRate: number; audioFormat: TTSAudioFormat }): Promise<void> | void;\n finalizeStreaming?(): void;\n close(): void;\n};\n\ntype TTSFactory = (config: TTSClientConfig) => TTSClient;\n\nfunction isBrowserEnvironment() {\n return typeof window !== \"undefined\";\n}\n\nfunction getWeightedTextLength(text: string) {\n let length = 0;\n\n for (const char of text) {\n length += /[\\u3400-\\u4dbf\\u4e00-\\u9fff\\uf900-\\ufaff]/.test(char) ? 2 : 1;\n }\n\n return length;\n}\n\nfunction splitOversizedSegment(segment: string, maxLength: number) {\n const fragments: string[] = [];\n let current = \"\";\n let currentLength = 0;\n\n for (const char of segment) {\n const charLength = getWeightedTextLength(char);\n\n if (current && currentLength + charLength > maxLength) {\n fragments.push(current);\n current = char;\n currentLength = charLength;\n continue;\n }\n\n current += char;\n currentLength += charLength;\n }\n\n if (current) {\n fragments.push(current);\n }\n\n return fragments;\n}\n\nexport function splitTextIntoFragments(text: string, maxLength = TTS_MAX_FRAGMENT_LENGTH) {\n const fragments: string[] = [];\n const segments = text.match(/.+?(?:\\r?\\n+|$)/gs) ?? [];\n const softBreakPattern = /(?<=[。!?;.!?;])|(?<=[,、,::])|(?<=\\s)/;\n\n let current = \"\";\n\n const pushFragment = (fragment: string) => {\n const trimmed = fragment.trim();\n if (trimmed) {\n fragments.push(trimmed);\n }\n };\n\n const appendPart = (part: string) => {\n if (!part.trim()) {\n return;\n }\n\n if (getWeightedTextLength(part) > maxLength) {\n for (const fragment of splitOversizedSegment(part, maxLength)) {\n pushFragment(fragment);\n }\n current = \"\";\n return;\n }\n\n const next = current ? `${current}${part}` : part;\n if (getWeightedTextLength(next) <= maxLength) {\n current = next;\n return;\n }\n\n pushFragment(current);\n current = part;\n };\n\n for (const segment of segments) {\n const parts = segment.split(softBreakPattern).filter((part) => part.trim());\n\n if (!parts.length) {\n continue;\n }\n\n for (const part of parts) {\n appendPart(part);\n }\n }\n\n pushFragment(current);\n return fragments;\n}\n\nfunction normalizeWhitespace(text: string) {\n return text.replace(/\\r\\n/g, \"\\n\").replace(/\\n{3,}/g, \"\\n\\n\").replace(/[ \\t]{2,}/g, \" \");\n}\n\nfunction stripMarkdownTables(text: string) {\n return text.replace(/^\\|(.+)\\|$/gm, (_, row: string) =>\n row\n .split(\"|\")\n .map((cell) => cell.trim())\n .filter(Boolean)\n .join(\",\")\n );\n}\n\nfunction stripMarkdown(text: string) {\n return text\n .replace(/```[\\s\\S]*?```/g, \" \")\n .replace(/`([^`]+)`/g, \"$1\")\n .replace(/!\\[([^\\]]*)\\]\\([^)]+\\)/g, \"$1\")\n .replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, \"$1\")\n .replace(/^#{1,6}\\s+/gm, \"\")\n .replace(/^\\s*>\\s?/gm, \"\")\n .replace(/^\\s*[-*+]\\s+/gm, \"\")\n .replace(/^\\s*\\d+\\.\\s+/gm, \"\")\n .replace(/[*_~#>]+/g, \"\");\n}\n\nfunction stripUrls(text: string) {\n return text.replace(/https?:\\/\\/\\S+/gi, \" \");\n}\n\nfunction stripEmojiAndSymbols(text: string) {\n return text.replace(/[\\u{1F000}-\\u{1FAFF}\\u{2600}-\\u{27BF}]/gu, \" \");\n}\n\nexport function preprocessTTSContent(text: string) {\n const normalized = normalizeWhitespace(text);\n const withoutTables = stripMarkdownTables(normalized);\n const withoutMarkdown = stripMarkdown(withoutTables);\n const withoutUrls = stripUrls(withoutMarkdown);\n const withoutEmoji = stripEmojiAndSymbols(withoutUrls);\n\n return withoutEmoji\n .replace(/[|]/g, \",\")\n .replace(/[ \\t]+\\n/g, \"\\n\")\n .replace(/\\n+/g, \"\\n\")\n .replace(/[ ]{2,}/g, \" \")\n .trim();\n}\n\nfunction decodeBase64Chunk(chunk: string) {\n const binaryString = atob(chunk);\n const bytes = new Uint8Array(binaryString.length);\n\n for (let index = 0; index < binaryString.length; index += 1) {\n bytes[index] = binaryString.charCodeAt(index);\n }\n\n return bytes;\n}\n\nfunction concatUint8Arrays(items: Uint8Array[]) {\n let totalLength = 0;\n\n for (const item of items) {\n totalLength += item.length;\n }\n\n const result = new Uint8Array(totalLength);\n let offset = 0;\n for (const item of items) {\n result.set(item, offset);\n offset += item.length;\n }\n\n return result;\n}\n\nfunction pcmToWav(pcmBytes: Uint8Array, sampleRate: number) {\n const header = new ArrayBuffer(44);\n const view = new DataView(header);\n const dataSize = pcmBytes.byteLength;\n\n const writeString = (offset: number, value: string) => {\n for (let index = 0; index < value.length; index += 1) {\n view.setUint8(offset + index, value.charCodeAt(index));\n }\n };\n\n writeString(0, \"RIFF\");\n view.setUint32(4, 36 + dataSize, true);\n writeString(8, \"WAVE\");\n writeString(12, \"fmt \");\n view.setUint32(16, 16, true);\n view.setUint16(20, 1, true);\n view.setUint16(22, 1, true);\n view.setUint32(24, sampleRate, true);\n view.setUint32(28, sampleRate * 2, true);\n view.setUint16(32, 2, true);\n view.setUint16(34, 16, true);\n writeString(36, \"data\");\n view.setUint32(40, dataSize, true);\n\n return concatUint8Arrays([new Uint8Array(header), pcmBytes]);\n}\n\nfunction bytesToDataUri(bytes: Uint8Array, mimeType: string) {\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n\n return `data:${mimeType};base64,${btoa(binary)}`;\n}\n\nfunction createBrowserPlaybackBackend(config: {\n sampleRate: number;\n onAudioStart?: () => void;\n onAudioEnd?: () => void;\n onError?: (error: Error) => void;\n}) {\n const { sampleRate, onAudioStart, onAudioEnd, onError } = config;\n\n let audioContext: AudioContext | null = null;\n const audioSources = new Set<AudioBufferSourceNode>();\n let nextScheduleTime = 0;\n let streamEndHandled = false;\n let streamingStarted = false;\n\n const ensureAudioContext = () => {\n if (!audioContext && typeof AudioContext !== \"undefined\") {\n audioContext = new AudioContext({ sampleRate });\n }\n\n return audioContext;\n };\n\n const createAudioBufferFromPCM = (bytes: Uint8Array) => {\n const numSamples = Math.floor(bytes.length / 2);\n const buffer = new AudioBuffer({ length: numSamples, sampleRate });\n const channelData = buffer.getChannelData(0);\n const dataView = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);\n\n for (let index = 0; index < numSamples; index += 1) {\n const int16 = dataView.getInt16(index * 2, true);\n channelData[index] = int16 / 32768;\n }\n\n return buffer;\n };\n\n const stop = () => {\n for (const source of audioSources) {\n try {\n source.onended = null;\n source.stop();\n } catch {}\n source.disconnect();\n }\n\n audioSources.clear();\n nextScheduleTime = 0;\n streamEndHandled = false;\n streamingStarted = false;\n };\n\n return {\n kind: \"browser\" as const,\n hasStreamingPlayback: true,\n isPlaying() {\n return audioSources.size > 0;\n },\n stop,\n async playBuffered(input: { chunks: string[]; sampleRate: number; audioFormat: TTSAudioFormat }) {\n if (input.audioFormat !== \"pcm\") {\n onError?.(new Error(`Built-in playback only supports pcm, got ${input.audioFormat}`));\n return;\n }\n\n const context = ensureAudioContext();\n if (!context || !input.chunks.length) {\n return;\n }\n\n stop();\n\n const chunkBytes = input.chunks.map((chunk) => decodeBase64Chunk(chunk));\n const combined = concatUint8Arrays(chunkBytes);\n const buffer = createAudioBufferFromPCM(combined);\n const source = context.createBufferSource();\n\n if (context.state === \"suspended\") {\n await context.resume();\n }\n\n source.buffer = buffer;\n source.connect(context.destination);\n audioSources.add(source);\n source.onended = () => {\n audioSources.delete(source);\n source.disconnect();\n onAudioEnd?.();\n };\n\n onAudioStart?.();\n source.start(0);\n },\n async scheduleStreamingChunk(input: { chunk: string; sampleRate: number; audioFormat: TTSAudioFormat }) {\n if (input.audioFormat !== \"pcm\") {\n onError?.(new Error(`Built-in playback only supports pcm, got ${input.audioFormat}`));\n return;\n }\n\n const context = ensureAudioContext();\n if (!context) {\n return;\n }\n\n if (context.state === \"suspended\") {\n await context.resume();\n }\n\n const chunkBytes = decodeBase64Chunk(input.chunk);\n const chunkBuffer = createAudioBufferFromPCM(chunkBytes);\n const source = context.createBufferSource();\n const leadTime = 0.05;\n\n if (!nextScheduleTime) {\n nextScheduleTime = Math.max(context.currentTime + leadTime, leadTime);\n }\n\n source.buffer = chunkBuffer;\n source.connect(context.destination);\n audioSources.add(source);\n source.onended = () => {\n audioSources.delete(source);\n source.disconnect();\n if (streamEndHandled && audioSources.size === 0) {\n nextScheduleTime = 0;\n streamEndHandled = false;\n streamingStarted = false;\n onAudioEnd?.();\n }\n };\n\n if (!streamingStarted) {\n streamingStarted = true;\n onAudioStart?.();\n }\n\n source.start(nextScheduleTime);\n nextScheduleTime += chunkBuffer.duration;\n },\n finalizeStreaming() {\n streamEndHandled = true;\n if (audioSources.size === 0 && streamingStarted) {\n nextScheduleTime = 0;\n streamEndHandled = false;\n streamingStarted = false;\n onAudioEnd?.();\n }\n },\n close() {\n stop();\n if (audioContext) {\n void audioContext.close().catch(() => {});\n audioContext = null;\n }\n },\n } satisfies AudioPlaybackBackend;\n}\n\nfunction createMiniProgramPlaybackBackend(config: {\n runtime?: TTSRuntime;\n onAudioStart?: () => void;\n onAudioEnd?: () => void;\n onError?: (error: Error) => void;\n}) {\n const { runtime, onAudioStart, onAudioEnd, onError } = config;\n const taro = runtime?.Taro;\n const createInnerAudioContext = taro?.createInnerAudioContext;\n const getFileSystemManager = taro?.getFileSystemManager;\n const userDataPath = taro?.env?.USER_DATA_PATH;\n\n let innerAudio:\n | ReturnType<NonNullable<NonNullable<TTSRuntime[\"Taro\"]>[\"createInnerAudioContext\"]>>\n | null = createInnerAudioContext?.() ?? null;\n let currentTempFile: string | null = null;\n let playing = false;\n\n const bindEvents = () => {\n innerAudio?.onPlay?.(() => {\n playing = true;\n onAudioStart?.();\n });\n innerAudio?.onEnded?.(() => {\n playing = false;\n onAudioEnd?.();\n });\n innerAudio?.onStop?.(() => {\n playing = false;\n });\n innerAudio?.onError?.((error) => {\n playing = false;\n onError?.(new Error(error?.errMsg || \"Mini-program audio playback failed\"));\n });\n };\n\n bindEvents();\n\n const cleanupTempFile = () => {\n if (!currentTempFile) {\n return;\n }\n\n const pathToDelete = currentTempFile;\n currentTempFile = null;\n getFileSystemManager?.()?.unlink?.({\n filePath: pathToDelete,\n fail: () => {},\n });\n };\n\n const writeTempAudioFile = async (bytes: Uint8Array) => {\n if (!userDataPath || !getFileSystemManager) {\n return bytesToDataUri(bytes, \"audio/wav\");\n }\n\n const filePath = `${userDataPath}/amaster-tts-${Date.now()}-${Math.random().toString(16).slice(2)}.wav`;\n const fsManager = getFileSystemManager();\n\n if (!fsManager?.writeFile) {\n return bytesToDataUri(bytes, \"audio/wav\");\n }\n\n await new Promise<void>((resolve, reject) => {\n fsManager.writeFile?.({\n filePath,\n data: bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer,\n success: () => resolve(),\n fail: (error) => reject(error),\n });\n });\n\n cleanupTempFile();\n currentTempFile = filePath;\n return filePath;\n };\n\n return {\n kind: \"mini-program\" as const,\n hasStreamingPlayback: false,\n isPlaying() {\n return playing;\n },\n stop() {\n innerAudio?.stop?.();\n playing = false;\n },\n async playBuffered(input: { chunks: string[]; sampleRate: number; audioFormat: TTSAudioFormat }) {\n if (input.audioFormat !== \"pcm\") {\n onError?.(new Error(`Mini-program built-in playback only supports pcm, got ${input.audioFormat}`));\n return;\n }\n\n const pcmChunks = input.chunks.map((chunk) => decodeBase64Chunk(chunk));\n const wavBytes = pcmToWav(concatUint8Arrays(pcmChunks), input.sampleRate);\n const source = await writeTempAudioFile(wavBytes);\n\n if (!innerAudio && createInnerAudioContext) {\n innerAudio = createInnerAudioContext();\n bindEvents();\n }\n\n if (!innerAudio?.play) {\n onError?.(new Error(\"Mini-program audio context is unavailable\"));\n return;\n }\n\n innerAudio.src = source;\n innerAudio.autoplay = false;\n innerAudio.obeyMuteSwitch = false;\n innerAudio.play();\n },\n close() {\n innerAudio?.stop?.();\n innerAudio?.destroy?.();\n innerAudio = null;\n playing = false;\n cleanupTempFile();\n },\n } satisfies AudioPlaybackBackend;\n}\n\nfunction resolvePlaybackBackend(config: {\n runtime?: TTSRuntime;\n sampleRate: number;\n onAudioStart?: () => void;\n onAudioEnd?: () => void;\n onError?: (error: Error) => void;\n}) {\n if (config.runtime?.Taro?.createInnerAudioContext && !isBrowserEnvironment()) {\n return createMiniProgramPlaybackBackend(config);\n }\n\n if (typeof AudioContext !== \"undefined\") {\n return createBrowserPlaybackBackend(config);\n }\n\n return null;\n}\n\nfunction createRawTTSClient(config: TTSClientConfig): TTSClient {\n const {\n getAccessToken,\n voice = \"Cherry\",\n autoPlay = true,\n audioFormat = \"pcm\",\n sampleRate = 24000,\n runtime,\n onReady,\n onAudioStart,\n onAudioEnd,\n onAudioChunk,\n onError,\n onClose,\n } = config;\n void getAccessToken;\n\n let ws: WebSocket | null = null;\n let connected = false;\n let audioChunks: string[] = [];\n let responseDone = false;\n let autoPlayed = false;\n let playbackSuppressed = false;\n let playbackBackend = resolvePlaybackBackend({\n runtime,\n sampleRate,\n onAudioStart,\n onAudioEnd,\n onError,\n });\n\n function buildWsUrl() {\n let path = TTS_PATH;\n \n // TODO:携带 token 返回会导致报错\n // const token = getAccessToken?.();\n // if (token) {\n // const separator = path.includes(\"?\") ? \"&\" : \"?\";\n // path = `${path}${separator}token=${encodeURIComponent(token)}`;\n // }\n\n return path;\n }\n\n function play() {\n playbackSuppressed = false;\n\n if (!audioChunks.length || !playbackBackend) {\n return;\n }\n\n if (!responseDone && playbackBackend.hasStreamingPlayback) {\n return;\n }\n\n void playbackBackend.playBuffered({\n chunks: [...audioChunks],\n sampleRate,\n audioFormat,\n });\n }\n\n function stop() {\n playbackSuppressed = true;\n playbackBackend?.stop();\n }\n\n function close() {\n stop();\n\n if (ws) {\n ws.close();\n ws = null;\n }\n\n connected = false;\n playbackBackend?.close();\n playbackBackend = resolvePlaybackBackend({\n runtime,\n sampleRate,\n onAudioStart,\n onAudioEnd,\n onError,\n });\n onClose?.();\n }\n\n async function connect() {\n if (connected && ws?.readyState === WebSocket.OPEN) {\n return;\n }\n\n await new Promise<void>((resolve, reject) => {\n const socket = new WebSocket(buildWsUrl());\n ws = socket;\n\n let settled = false;\n\n const settleResolve = () => {\n if (settled) {\n return;\n }\n\n settled = true;\n connected = true;\n resolve();\n };\n\n const settleReject = (error: Error) => {\n if (settled) {\n return;\n }\n\n settled = true;\n connected = false;\n reject(error);\n };\n\n socket.onmessage = async (event) => {\n try {\n const data = JSON.parse(event.data);\n\n if (data.type === \"session.created\") {\n socket.send(\n JSON.stringify({\n type: \"session.update\",\n session: {\n mode: \"server_commit\",\n voice,\n response_format: audioFormat,\n sample_rate: sampleRate,\n },\n })\n );\n }\n\n if (data.type === \"session.updated\") {\n onReady?.();\n settleResolve();\n return;\n }\n\n if (data.type === \"response.audio.delta\") {\n audioChunks.push(data.delta);\n onAudioChunk?.([...audioChunks]);\n\n if (autoPlay && !playbackSuppressed && playbackBackend?.hasStreamingPlayback) {\n autoPlayed = true;\n await playbackBackend.scheduleStreamingChunk?.({\n chunk: data.delta,\n sampleRate,\n audioFormat,\n });\n }\n\n return;\n }\n\n if (data.type === \"response.audio.done\") {\n responseDone = true;\n onAudioChunk?.([...audioChunks]);\n\n if (playbackBackend?.hasStreamingPlayback) {\n playbackBackend.finalizeStreaming?.();\n return;\n }\n\n if (autoPlay && !playbackSuppressed && !autoPlayed) {\n autoPlayed = true;\n await playbackBackend?.playBuffered({\n chunks: [...audioChunks],\n sampleRate,\n audioFormat,\n });\n }\n\n return;\n }\n\n if (data.type === \"error\") {\n const error = new Error(data.error?.message || \"Unknown TTS error\");\n onError?.(error);\n settleReject(error);\n }\n } catch (error) {\n const parsedError =\n error instanceof Error ? error : new Error(String(error));\n onError?.(parsedError);\n settleReject(parsedError);\n }\n };\n\n socket.onerror = () => {\n const error = new Error(\"WebSocket connection error\");\n onError?.(error);\n settleReject(error);\n };\n\n socket.onclose = () => {\n connected = false;\n ws = null;\n };\n });\n }\n\n function resetSynthesisState() {\n stop();\n audioChunks = [];\n responseDone = false;\n autoPlayed = false;\n playbackSuppressed = false;\n }\n\n function ensureSocketReady() {\n if (!ws || ws.readyState !== WebSocket.OPEN) {\n throw new Error(\"WebSocket not connected\");\n }\n }\n\n function appendText(text: string) {\n const normalizedText = preprocessTTSContent(text);\n const fragments = splitTextIntoFragments(normalizedText);\n\n if (!fragments.length) {\n return;\n }\n\n ensureSocketReady();\n const socket = ws;\n\n for (const fragment of fragments) {\n socket?.send(\n JSON.stringify({\n type: \"input_text_buffer.append\",\n text: fragment,\n })\n );\n }\n }\n\n function commitText() {\n ensureSocketReady();\n const socket = ws;\n\n socket?.send(\n JSON.stringify({\n type: \"input_text_buffer.commit\",\n })\n );\n }\n\n function startStream() {\n resetSynthesisState();\n }\n\n async function speak(text: string) {\n startStream();\n appendText(text);\n commitText();\n }\n\n return {\n connect,\n speak,\n startStream,\n appendText,\n commitText,\n play,\n stop,\n close,\n isConnected() {\n return connected && ws?.readyState === WebSocket.OPEN;\n },\n hasAudio() {\n return audioChunks.length > 0;\n },\n isResponseDone() {\n return responseDone;\n },\n isPlaying() {\n return playbackBackend?.isPlaying() ?? false;\n },\n isStreamingPlayback() {\n return playbackBackend?.hasStreamingPlayback ?? false;\n },\n };\n}\n\nfunction defaultSnapshot(voice: string | null): TTSSnapshot {\n return {\n status: \"idle\",\n activeId: null,\n error: null,\n requestId: 0,\n text: null,\n voice,\n fallbackMode: \"none\",\n };\n}\n\nfunction canUseSystemSpeech() {\n return isBrowserEnvironment() && \"speechSynthesis\" in window && \"SpeechSynthesisUtterance\" in window;\n}\n\nfunction systemSpeak(text: string, options: { onStart?: () => void; onEnd?: () => void; onError?: (error: Error) => void }) {\n if (!canUseSystemSpeech()) {\n throw new Error(\"SpeechSynthesis is not supported\");\n }\n\n const utterance = new SpeechSynthesisUtterance(text);\n utterance.onstart = () => {\n options.onStart?.();\n };\n utterance.onerror = (event) => {\n options.onError?.(new Error(event.error || \"Speech synthesis failed\"));\n };\n utterance.onend = () => {\n options.onEnd?.();\n };\n window.speechSynthesis.cancel();\n window.speechSynthesis.speak(utterance);\n}\n\nfunction stopSystemSpeech() {\n if (canUseSystemSpeech()) {\n window.speechSynthesis.cancel();\n }\n}\n\nexport function createTTSSpeakController(\n createClient: TTSFactory,\n options: TTSSpeakControllerOptions = {}\n): TTSSpeakController {\n const listeners = new Set<(snapshot: TTSSnapshot) => void>();\n const persistedVoice =\n options.voiceStorageKey && options.storage\n ? options.storage.getItem(options.voiceStorageKey) || null\n : null;\n\n let client: TTSClient | null = null;\n let snapshot = defaultSnapshot(persistedVoice);\n let streamActive = false;\n let streamId: string | null = null;\n\n const emit = () => {\n for (const listener of listeners) {\n listener(snapshot);\n }\n };\n\n const setSnapshot = (next: Partial<TTSSnapshot>) => {\n snapshot = {\n ...snapshot,\n ...next,\n };\n emit();\n };\n\n const persistVoice = (voice: string | null) => {\n if (!options.voiceStorageKey || !options.storage) {\n return;\n }\n\n if (!voice) {\n options.storage.removeItem?.(options.voiceStorageKey);\n return;\n }\n\n options.storage.setItem(options.voiceStorageKey, voice);\n };\n\n const reset = (requestId: number, preserved?: Partial<Pick<TTSSnapshot, \"text\" | \"voice\">>) => {\n snapshot = {\n status: \"idle\",\n activeId: null,\n error: null,\n requestId,\n text: preserved?.text ?? null,\n voice: preserved?.voice ?? snapshot.voice,\n fallbackMode: \"none\",\n };\n emit();\n };\n\n const stop = (stopOptions?: { preserveClient?: boolean }) => {\n const preserveClient = stopOptions?.preserveClient ?? true;\n const nextRequestId = snapshot.requestId + 1;\n streamActive = false;\n streamId = null;\n\n client?.stop();\n stopSystemSpeech();\n\n if (!preserveClient || !client || !snapshot.text) {\n client?.close();\n client = null;\n reset(nextRequestId, { voice: snapshot.voice });\n return;\n }\n\n reset(nextRequestId, {\n text: snapshot.text,\n voice: snapshot.voice,\n });\n };\n\n const createManagedClient = (\n input: Pick<TTSSpeakOptions, \"id\" | \"voice\" | \"audioFormat\" | \"sampleRate\">,\n requestId: number,\n content: string | null,\n ) => {\n const nextVoice = input.voice ?? snapshot.voice ?? undefined;\n const nextClient = createClient({\n voice: nextVoice,\n autoPlay: true,\n audioFormat: input.audioFormat,\n sampleRate: input.sampleRate,\n runtime: options.runtime,\n onReady: () => {\n if (client !== nextClient) {\n return;\n }\n\n setSnapshot({\n status: \"connecting\",\n error: null,\n });\n },\n onAudioStart: () => {\n if (client !== nextClient) {\n return;\n }\n\n setSnapshot({\n status: \"speaking\",\n error: null,\n fallbackMode: \"none\",\n });\n },\n onAudioEnd: () => {\n if (client !== nextClient) {\n return;\n }\n\n setSnapshot({\n status: streamActive ? \"connecting\" : \"idle\",\n activeId: streamActive ? streamId : null,\n error: null,\n fallbackMode: \"none\",\n });\n },\n onError: (error) => {\n if (client !== nextClient) {\n return;\n }\n\n streamActive = false;\n streamId = null;\n setSnapshot({\n status: \"error\",\n error: error.message,\n fallbackMode: \"none\",\n });\n },\n onClose: () => {\n if (client !== nextClient) {\n return;\n }\n\n client = null;\n },\n });\n\n client = nextClient;\n setSnapshot({\n status: \"connecting\",\n activeId: input.id ?? null,\n error: null,\n requestId,\n text: content,\n voice: nextVoice ?? null,\n fallbackMode: \"none\",\n });\n\n return {\n nextClient,\n nextVoice,\n };\n };\n\n const ensureStreamClient = async (streamOptions: TTSStreamOptions) => {\n const nextRequestId = snapshot.requestId + 1;\n const nextVoice = streamOptions.voice ?? snapshot.voice ?? undefined;\n\n if (client && snapshot.voice === (nextVoice ?? null)) {\n streamActive = true;\n streamId = streamOptions.id ?? null;\n setSnapshot({\n status: client.isPlaying() ? \"speaking\" : \"connecting\",\n activeId: streamId,\n error: null,\n requestId: nextRequestId,\n voice: nextVoice ?? null,\n fallbackMode: \"none\",\n });\n client.startStream();\n return;\n }\n\n stop({ preserveClient: false });\n const { nextClient } = createManagedClient(\n {\n id: streamOptions.id,\n voice: streamOptions.voice,\n audioFormat: streamOptions.audioFormat,\n sampleRate: streamOptions.sampleRate,\n },\n nextRequestId,\n \"\",\n );\n\n streamActive = true;\n streamId = streamOptions.id ?? null;\n await nextClient.connect();\n nextClient.startStream();\n };\n\n const speak = async (speakOptions: TTSSpeakOptions) => {\n const content = preprocessTTSContent(speakOptions.text);\n if (!content) {\n stop({ preserveClient: false });\n return;\n }\n\n const nextRequestId = snapshot.requestId + 1;\n const nextVoice = speakOptions.voice ?? snapshot.voice ?? undefined;\n\n if (client && snapshot.text === content && snapshot.voice === (nextVoice ?? null) && client.hasAudio()) {\n setSnapshot({\n status: \"speaking\",\n activeId: speakOptions.id ?? null,\n error: null,\n requestId: nextRequestId,\n text: content,\n voice: nextVoice ?? null,\n fallbackMode: \"none\",\n });\n client.play();\n return;\n }\n\n stop({ preserveClient: false });\n streamActive = false;\n streamId = null;\n const { nextClient } = createManagedClient(\n {\n id: speakOptions.id,\n voice: speakOptions.voice,\n audioFormat: speakOptions.audioFormat,\n sampleRate: speakOptions.sampleRate,\n },\n nextRequestId,\n content,\n );\n\n try {\n await nextClient.connect();\n await nextClient.speak(content);\n } catch (error) {\n if (client !== nextClient) {\n return;\n }\n\n if (options.fallbackToSystemSpeech !== false && canUseSystemSpeech()) {\n client?.close();\n client = null;\n\n systemSpeak(content, {\n onStart: () => {\n setSnapshot({\n status: \"speaking\",\n error: null,\n activeId: speakOptions.id ?? null,\n requestId: nextRequestId,\n text: content,\n voice: nextVoice ?? null,\n fallbackMode: \"system\",\n });\n },\n onEnd: () => {\n setSnapshot({\n status: \"idle\",\n activeId: null,\n error: null,\n fallbackMode: \"none\",\n });\n },\n onError: (fallbackError) => {\n setSnapshot({\n status: \"error\",\n error: fallbackError.message,\n fallbackMode: \"none\",\n });\n },\n });\n return;\n }\n\n client?.close();\n client = null;\n setSnapshot({\n status: \"error\",\n error: error instanceof Error ? error.message : String(error),\n fallbackMode: \"none\",\n });\n }\n };\n\n return {\n getSnapshot() {\n return snapshot;\n },\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n speak,\n async startStream(streamOptions) {\n await ensureStreamClient(streamOptions);\n },\n async appendStreamText(streamOptions) {\n const content = preprocessTTSContent(streamOptions.text);\n\n if (!content) {\n return;\n }\n\n if (!streamActive || streamId !== (streamOptions.id ?? null) || !client) {\n await ensureStreamClient(streamOptions);\n }\n\n client?.appendText(content);\n setSnapshot({\n status: snapshot.status === \"speaking\" ? \"speaking\" : \"connecting\",\n activeId: streamOptions.id ?? null,\n error: null,\n text: `${snapshot.text || \"\"}${content}`,\n fallbackMode: \"none\",\n });\n },\n commitStream() {\n if (!client || !streamActive) {\n return;\n }\n\n client.commitText();\n setSnapshot({\n status: snapshot.status === \"speaking\" ? \"speaking\" : \"connecting\",\n activeId: streamId,\n error: null,\n fallbackMode: \"none\",\n });\n },\n finishStream() {\n streamActive = false;\n streamId = null;\n setSnapshot({\n status: client?.isPlaying() ? \"speaking\" : \"idle\",\n activeId: client?.isPlaying() ? snapshot.activeId : null,\n error: null,\n fallbackMode: \"none\",\n });\n },\n stop,\n release() {\n stop({ preserveClient: false });\n },\n async toggle(toggleOptions) {\n if (this.isActive(toggleOptions.id)) {\n stop();\n return;\n }\n\n await speak(toggleOptions);\n },\n isActive(id) {\n if (!id) {\n return snapshot.status === \"connecting\" || snapshot.status === \"speaking\";\n }\n\n return (\n snapshot.activeId === id &&\n (snapshot.status === \"connecting\" || snapshot.status === \"speaking\")\n );\n },\n setVoice(voice) {\n setSnapshot({ voice });\n persistVoice(voice);\n },\n getVoice() {\n return snapshot.voice;\n },\n };\n}\n\nexport default function createTTSClient(\n authConfig: Pick<TTSClientConfig, \"getAccessToken\" | \"runtime\">\n): (config: TTSClientConfig) => TTSClient {\n return (config: TTSClientConfig) => createRawTTSClient({ ...authConfig, ...config });\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,64 +1,124 @@
|
|
|
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
|
-
|
|
1
|
+
type TTSAudioFormat = "pcm" | "mp3" | "wav" | "opus";
|
|
2
|
+
interface TTSStorageAdapter {
|
|
3
|
+
getItem(key: string): string | null | undefined;
|
|
4
|
+
setItem(key: string, value: string): void;
|
|
5
|
+
removeItem?(key: string): void;
|
|
6
|
+
}
|
|
7
|
+
interface TTSRuntime {
|
|
8
|
+
Taro?: {
|
|
9
|
+
createInnerAudioContext?: () => {
|
|
10
|
+
src: string;
|
|
11
|
+
autoplay?: boolean;
|
|
12
|
+
obeyMuteSwitch?: boolean;
|
|
13
|
+
play?: () => void;
|
|
14
|
+
stop?: () => void;
|
|
15
|
+
destroy?: () => void;
|
|
16
|
+
onPlay?: (callback: () => void) => void;
|
|
17
|
+
onEnded?: (callback: () => void) => void;
|
|
18
|
+
onStop?: (callback: () => void) => void;
|
|
19
|
+
onError?: (callback: (error: {
|
|
20
|
+
errMsg?: string;
|
|
21
|
+
}) => void) => void;
|
|
22
|
+
};
|
|
23
|
+
getFileSystemManager?: () => {
|
|
24
|
+
writeFile?: (options: {
|
|
25
|
+
filePath: string;
|
|
26
|
+
data: ArrayBuffer;
|
|
27
|
+
encoding?: string;
|
|
28
|
+
success?: () => void;
|
|
29
|
+
fail?: (error: unknown) => void;
|
|
30
|
+
}) => void;
|
|
31
|
+
unlink?: (options: {
|
|
32
|
+
filePath: string;
|
|
33
|
+
success?: () => void;
|
|
34
|
+
fail?: () => void;
|
|
35
|
+
}) => void;
|
|
36
|
+
};
|
|
37
|
+
env?: {
|
|
38
|
+
USER_DATA_PATH?: string;
|
|
39
|
+
};
|
|
40
|
+
getEnv?: () => unknown;
|
|
41
|
+
ENV_TYPE?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
28
44
|
interface TTSClientConfig {
|
|
29
|
-
/** Get access token for WebSocket authentication */
|
|
30
45
|
getAccessToken?: () => string | null;
|
|
31
|
-
/** Voice name, default 'Cherry' */
|
|
32
46
|
voice?: string;
|
|
33
|
-
/** Auto play audio, default true */
|
|
34
47
|
autoPlay?: boolean;
|
|
35
|
-
|
|
36
|
-
audioFormat?: "pcm" | "mp3" | "wav" | "opus";
|
|
37
|
-
/** Sample rate, default 24000 */
|
|
48
|
+
audioFormat?: TTSAudioFormat;
|
|
38
49
|
sampleRate?: number;
|
|
39
|
-
|
|
50
|
+
runtime?: TTSRuntime;
|
|
40
51
|
onReady?: () => void;
|
|
41
|
-
/** Called when audio playback starts */
|
|
42
52
|
onAudioStart?: () => void;
|
|
43
|
-
/** Called when audio playback ends */
|
|
44
53
|
onAudioEnd?: () => void;
|
|
45
|
-
|
|
46
|
-
onAudioChunk?: (chunk: string[]) => void;
|
|
47
|
-
/** Called on error */
|
|
54
|
+
onAudioChunk?: (chunks: string[]) => void;
|
|
48
55
|
onError?: (error: Error) => void;
|
|
56
|
+
onClose?: () => void;
|
|
49
57
|
}
|
|
50
58
|
interface TTSClient {
|
|
51
|
-
/** Connect to TTS service */
|
|
52
59
|
connect(): Promise<void>;
|
|
53
|
-
/** Synthesize speech from text */
|
|
54
60
|
speak(text: string): Promise<void>;
|
|
55
|
-
|
|
61
|
+
startStream(): void;
|
|
62
|
+
appendText(text: string): void;
|
|
63
|
+
commitText(): void;
|
|
56
64
|
play(): void;
|
|
57
|
-
/** Stop audio playback */
|
|
58
65
|
stop(): void;
|
|
59
|
-
/** Close connection */
|
|
60
66
|
close(): void;
|
|
67
|
+
isConnected(): boolean;
|
|
68
|
+
hasAudio(): boolean;
|
|
69
|
+
isResponseDone(): boolean;
|
|
70
|
+
isPlaying(): boolean;
|
|
71
|
+
isStreamingPlayback(): boolean;
|
|
72
|
+
}
|
|
73
|
+
interface TTSSpeakOptions {
|
|
74
|
+
id?: string;
|
|
75
|
+
text: string;
|
|
76
|
+
voice?: string;
|
|
77
|
+
audioFormat?: TTSAudioFormat;
|
|
78
|
+
sampleRate?: number;
|
|
79
|
+
}
|
|
80
|
+
interface TTSStreamOptions {
|
|
81
|
+
id?: string;
|
|
82
|
+
voice?: string;
|
|
83
|
+
audioFormat?: TTSAudioFormat;
|
|
84
|
+
sampleRate?: number;
|
|
85
|
+
}
|
|
86
|
+
interface TTSSnapshot {
|
|
87
|
+
status: "idle" | "connecting" | "speaking" | "error";
|
|
88
|
+
activeId: string | null;
|
|
89
|
+
error: string | null;
|
|
90
|
+
requestId: number;
|
|
91
|
+
text: string | null;
|
|
92
|
+
voice: string | null;
|
|
93
|
+
fallbackMode: "none" | "system";
|
|
94
|
+
}
|
|
95
|
+
interface TTSSpeakController {
|
|
96
|
+
getSnapshot(): TTSSnapshot;
|
|
97
|
+
subscribe(listener: (snapshot: TTSSnapshot) => void): () => void;
|
|
98
|
+
speak(options: TTSSpeakOptions): Promise<void>;
|
|
99
|
+
startStream(options: TTSStreamOptions): Promise<void>;
|
|
100
|
+
appendStreamText(options: TTSSpeakOptions): Promise<void>;
|
|
101
|
+
commitStream(): void;
|
|
102
|
+
finishStream(): void;
|
|
103
|
+
stop(options?: {
|
|
104
|
+
preserveClient?: boolean;
|
|
105
|
+
}): void;
|
|
106
|
+
release(): void;
|
|
107
|
+
toggle(options: TTSSpeakOptions): Promise<void>;
|
|
108
|
+
isActive(id?: string | null): boolean;
|
|
109
|
+
setVoice(voice: string | null): void;
|
|
110
|
+
getVoice(): string | null;
|
|
111
|
+
}
|
|
112
|
+
interface TTSSpeakControllerOptions {
|
|
113
|
+
storage?: TTSStorageAdapter;
|
|
114
|
+
voiceStorageKey?: string;
|
|
115
|
+
runtime?: TTSRuntime;
|
|
116
|
+
fallbackToSystemSpeech?: boolean;
|
|
61
117
|
}
|
|
62
|
-
|
|
118
|
+
type TTSFactory = (config: TTSClientConfig) => TTSClient;
|
|
119
|
+
declare function splitTextIntoFragments(text: string, maxLength?: number): string[];
|
|
120
|
+
declare function preprocessTTSContent(text: string): string;
|
|
121
|
+
declare function createTTSSpeakController(createClient: TTSFactory, options?: TTSSpeakControllerOptions): TTSSpeakController;
|
|
122
|
+
declare function createTTSClient(authConfig: Pick<TTSClientConfig, "getAccessToken" | "runtime">): (config: TTSClientConfig) => TTSClient;
|
|
63
123
|
|
|
64
|
-
export { type TTSClient, type TTSClientConfig,
|
|
124
|
+
export { type TTSClient, type TTSClientConfig, type TTSRuntime, type TTSSnapshot, type TTSSpeakController, type TTSSpeakControllerOptions, type TTSSpeakOptions, type TTSStorageAdapter, type TTSStreamOptions, createTTSClient, createTTSSpeakController, preprocessTTSContent, splitTextIntoFragments };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,64 +1,124 @@
|
|
|
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
|
-
|
|
1
|
+
type TTSAudioFormat = "pcm" | "mp3" | "wav" | "opus";
|
|
2
|
+
interface TTSStorageAdapter {
|
|
3
|
+
getItem(key: string): string | null | undefined;
|
|
4
|
+
setItem(key: string, value: string): void;
|
|
5
|
+
removeItem?(key: string): void;
|
|
6
|
+
}
|
|
7
|
+
interface TTSRuntime {
|
|
8
|
+
Taro?: {
|
|
9
|
+
createInnerAudioContext?: () => {
|
|
10
|
+
src: string;
|
|
11
|
+
autoplay?: boolean;
|
|
12
|
+
obeyMuteSwitch?: boolean;
|
|
13
|
+
play?: () => void;
|
|
14
|
+
stop?: () => void;
|
|
15
|
+
destroy?: () => void;
|
|
16
|
+
onPlay?: (callback: () => void) => void;
|
|
17
|
+
onEnded?: (callback: () => void) => void;
|
|
18
|
+
onStop?: (callback: () => void) => void;
|
|
19
|
+
onError?: (callback: (error: {
|
|
20
|
+
errMsg?: string;
|
|
21
|
+
}) => void) => void;
|
|
22
|
+
};
|
|
23
|
+
getFileSystemManager?: () => {
|
|
24
|
+
writeFile?: (options: {
|
|
25
|
+
filePath: string;
|
|
26
|
+
data: ArrayBuffer;
|
|
27
|
+
encoding?: string;
|
|
28
|
+
success?: () => void;
|
|
29
|
+
fail?: (error: unknown) => void;
|
|
30
|
+
}) => void;
|
|
31
|
+
unlink?: (options: {
|
|
32
|
+
filePath: string;
|
|
33
|
+
success?: () => void;
|
|
34
|
+
fail?: () => void;
|
|
35
|
+
}) => void;
|
|
36
|
+
};
|
|
37
|
+
env?: {
|
|
38
|
+
USER_DATA_PATH?: string;
|
|
39
|
+
};
|
|
40
|
+
getEnv?: () => unknown;
|
|
41
|
+
ENV_TYPE?: Record<string, unknown>;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
28
44
|
interface TTSClientConfig {
|
|
29
|
-
/** Get access token for WebSocket authentication */
|
|
30
45
|
getAccessToken?: () => string | null;
|
|
31
|
-
/** Voice name, default 'Cherry' */
|
|
32
46
|
voice?: string;
|
|
33
|
-
/** Auto play audio, default true */
|
|
34
47
|
autoPlay?: boolean;
|
|
35
|
-
|
|
36
|
-
audioFormat?: "pcm" | "mp3" | "wav" | "opus";
|
|
37
|
-
/** Sample rate, default 24000 */
|
|
48
|
+
audioFormat?: TTSAudioFormat;
|
|
38
49
|
sampleRate?: number;
|
|
39
|
-
|
|
50
|
+
runtime?: TTSRuntime;
|
|
40
51
|
onReady?: () => void;
|
|
41
|
-
/** Called when audio playback starts */
|
|
42
52
|
onAudioStart?: () => void;
|
|
43
|
-
/** Called when audio playback ends */
|
|
44
53
|
onAudioEnd?: () => void;
|
|
45
|
-
|
|
46
|
-
onAudioChunk?: (chunk: string[]) => void;
|
|
47
|
-
/** Called on error */
|
|
54
|
+
onAudioChunk?: (chunks: string[]) => void;
|
|
48
55
|
onError?: (error: Error) => void;
|
|
56
|
+
onClose?: () => void;
|
|
49
57
|
}
|
|
50
58
|
interface TTSClient {
|
|
51
|
-
/** Connect to TTS service */
|
|
52
59
|
connect(): Promise<void>;
|
|
53
|
-
/** Synthesize speech from text */
|
|
54
60
|
speak(text: string): Promise<void>;
|
|
55
|
-
|
|
61
|
+
startStream(): void;
|
|
62
|
+
appendText(text: string): void;
|
|
63
|
+
commitText(): void;
|
|
56
64
|
play(): void;
|
|
57
|
-
/** Stop audio playback */
|
|
58
65
|
stop(): void;
|
|
59
|
-
/** Close connection */
|
|
60
66
|
close(): void;
|
|
67
|
+
isConnected(): boolean;
|
|
68
|
+
hasAudio(): boolean;
|
|
69
|
+
isResponseDone(): boolean;
|
|
70
|
+
isPlaying(): boolean;
|
|
71
|
+
isStreamingPlayback(): boolean;
|
|
72
|
+
}
|
|
73
|
+
interface TTSSpeakOptions {
|
|
74
|
+
id?: string;
|
|
75
|
+
text: string;
|
|
76
|
+
voice?: string;
|
|
77
|
+
audioFormat?: TTSAudioFormat;
|
|
78
|
+
sampleRate?: number;
|
|
79
|
+
}
|
|
80
|
+
interface TTSStreamOptions {
|
|
81
|
+
id?: string;
|
|
82
|
+
voice?: string;
|
|
83
|
+
audioFormat?: TTSAudioFormat;
|
|
84
|
+
sampleRate?: number;
|
|
85
|
+
}
|
|
86
|
+
interface TTSSnapshot {
|
|
87
|
+
status: "idle" | "connecting" | "speaking" | "error";
|
|
88
|
+
activeId: string | null;
|
|
89
|
+
error: string | null;
|
|
90
|
+
requestId: number;
|
|
91
|
+
text: string | null;
|
|
92
|
+
voice: string | null;
|
|
93
|
+
fallbackMode: "none" | "system";
|
|
94
|
+
}
|
|
95
|
+
interface TTSSpeakController {
|
|
96
|
+
getSnapshot(): TTSSnapshot;
|
|
97
|
+
subscribe(listener: (snapshot: TTSSnapshot) => void): () => void;
|
|
98
|
+
speak(options: TTSSpeakOptions): Promise<void>;
|
|
99
|
+
startStream(options: TTSStreamOptions): Promise<void>;
|
|
100
|
+
appendStreamText(options: TTSSpeakOptions): Promise<void>;
|
|
101
|
+
commitStream(): void;
|
|
102
|
+
finishStream(): void;
|
|
103
|
+
stop(options?: {
|
|
104
|
+
preserveClient?: boolean;
|
|
105
|
+
}): void;
|
|
106
|
+
release(): void;
|
|
107
|
+
toggle(options: TTSSpeakOptions): Promise<void>;
|
|
108
|
+
isActive(id?: string | null): boolean;
|
|
109
|
+
setVoice(voice: string | null): void;
|
|
110
|
+
getVoice(): string | null;
|
|
111
|
+
}
|
|
112
|
+
interface TTSSpeakControllerOptions {
|
|
113
|
+
storage?: TTSStorageAdapter;
|
|
114
|
+
voiceStorageKey?: string;
|
|
115
|
+
runtime?: TTSRuntime;
|
|
116
|
+
fallbackToSystemSpeech?: boolean;
|
|
61
117
|
}
|
|
62
|
-
|
|
118
|
+
type TTSFactory = (config: TTSClientConfig) => TTSClient;
|
|
119
|
+
declare function splitTextIntoFragments(text: string, maxLength?: number): string[];
|
|
120
|
+
declare function preprocessTTSContent(text: string): string;
|
|
121
|
+
declare function createTTSSpeakController(createClient: TTSFactory, options?: TTSSpeakControllerOptions): TTSSpeakController;
|
|
122
|
+
declare function createTTSClient(authConfig: Pick<TTSClientConfig, "getAccessToken" | "runtime">): (config: TTSClientConfig) => TTSClient;
|
|
63
123
|
|
|
64
|
-
export { type TTSClient, type TTSClientConfig,
|
|
124
|
+
export { type TTSClient, type TTSClientConfig, type TTSRuntime, type TTSSnapshot, type TTSSpeakController, type TTSSpeakControllerOptions, type TTSSpeakOptions, type TTSStorageAdapter, type TTSStreamOptions, createTTSClient, createTTSSpeakController, preprocessTTSContent, splitTextIntoFragments };
|