ai 7.0.149 → 7.0.151
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/CHANGELOG.md +21 -0
- package/dist/index.d.ts +163 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +279 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/index.js +1 -1
- package/dist/test/index.d.ts +17 -2
- package/dist/test/index.d.ts.map +1 -1
- package/dist/test/index.js +12 -1
- package/dist/test/index.js.map +1 -1
- package/docs/03-ai-sdk-core/18-tools.mdx +181 -9
- package/docs/03-ai-sdk-core/37-speech.mdx +65 -0
- package/docs/07-reference/01-ai-sdk-core/12-stream-speech.mdx +195 -0
- package/docs/07-reference/01-ai-sdk-core/index.mdx +5 -0
- package/package.json +12 -12
- package/src/error/no-speech-generated-error.ts +5 -1
- package/src/generate-speech/index.ts +7 -0
- package/src/generate-speech/is-streaming-speech-model.ts +17 -0
- package/src/generate-speech/stream-speech-result.ts +95 -0
- package/src/generate-speech/stream-speech.ts +569 -0
- package/src/test/mock-streaming-speech-model-v4.ts +28 -0
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: experimental_streamSpeech
|
|
3
|
+
description: API Reference for experimental_streamSpeech.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# `experimental_streamSpeech()`
|
|
7
|
+
|
|
8
|
+
<Note type="warning">
|
|
9
|
+
`experimental_streamSpeech` is an experimental feature.
|
|
10
|
+
</Note>
|
|
11
|
+
|
|
12
|
+
Streams speech audio from text, or from an array or stream of text deltas and
|
|
13
|
+
text parts, using a speech model with streaming support.
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { experimental_streamSpeech as streamSpeech } from 'ai';
|
|
17
|
+
import { elevenLabs } from '@ai-sdk/elevenlabs';
|
|
18
|
+
|
|
19
|
+
const result = streamSpeech({
|
|
20
|
+
model: elevenLabs.speech('eleven_flash_v2_5'),
|
|
21
|
+
text: 'Hello, world!',
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
for await (const chunk of result.audioStream) {
|
|
25
|
+
// Uint8Array audio bytes
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Import
|
|
30
|
+
|
|
31
|
+
<Snippet
|
|
32
|
+
text={`import { experimental_streamSpeech as streamSpeech } from "ai"`}
|
|
33
|
+
prompt={false}
|
|
34
|
+
/>
|
|
35
|
+
|
|
36
|
+
## API Signature
|
|
37
|
+
|
|
38
|
+
### Parameters
|
|
39
|
+
|
|
40
|
+
<PropertiesTable
|
|
41
|
+
content={[
|
|
42
|
+
{
|
|
43
|
+
name: 'model',
|
|
44
|
+
type: 'SpeechModel',
|
|
45
|
+
description:
|
|
46
|
+
'The speech model to use. The model must implement the experimental streaming speech extension (`Experimental_StreamingSpeechModelV4`).',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'text',
|
|
50
|
+
type: 'string | Iterable<string | Experimental_SpeechTextPart> | AsyncIterable<string | Experimental_SpeechTextPart> | ReadableStream<string | Experimental_SpeechTextPart>',
|
|
51
|
+
description:
|
|
52
|
+
"The text to convert to speech: a complete string, or an array, iterable, or stream of text deltas (e.g. the `textStream` of `streamText`) and/or text parts `{ type: 'text', text, voice?, providerOptions? }`. A part's `voice` selects its speaker on providers that support several voices per stream; single-voice providers error the stream when a part's voice differs from the call's voice. The end of the stream ends the input.",
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
name: 'voice',
|
|
56
|
+
type: 'string',
|
|
57
|
+
isOptional: true,
|
|
58
|
+
description: 'The voice to use for speech generation.',
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'outputFormat',
|
|
62
|
+
type: '{ type: string; rate?: number }',
|
|
63
|
+
isOptional: true,
|
|
64
|
+
description:
|
|
65
|
+
"The format of the output audio chunks, e.g. `{ type: 'audio/pcm', rate: 24000 }` or `{ type: 'audio/mpeg' }`. Supported formats are provider-specific.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: 'instructions',
|
|
69
|
+
type: 'string',
|
|
70
|
+
isOptional: true,
|
|
71
|
+
description: 'Instructions for the speech generation.',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: 'speed',
|
|
75
|
+
type: 'number',
|
|
76
|
+
isOptional: true,
|
|
77
|
+
description: 'The speed of the speech generation.',
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: 'language',
|
|
81
|
+
type: 'string',
|
|
82
|
+
isOptional: true,
|
|
83
|
+
description:
|
|
84
|
+
'The language for speech generation (ISO 639-1 code), or "auto". Provider support varies.',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
name: 'providerOptions',
|
|
88
|
+
type: 'Record<string, JSONObject>',
|
|
89
|
+
isOptional: true,
|
|
90
|
+
description: 'Additional provider-specific options.',
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'abortSignal',
|
|
94
|
+
type: 'AbortSignal',
|
|
95
|
+
isOptional: true,
|
|
96
|
+
description: 'An optional abort signal to cancel the call.',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
name: 'headers',
|
|
100
|
+
type: 'Record<string, string>',
|
|
101
|
+
isOptional: true,
|
|
102
|
+
description:
|
|
103
|
+
'Additional HTTP/WebSocket headers, if supported by the provider.',
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: 'includeRawChunks',
|
|
107
|
+
type: 'boolean',
|
|
108
|
+
isOptional: true,
|
|
109
|
+
description:
|
|
110
|
+
'When true, the provider includes raw provider chunks in `fullStream` as `raw` parts.',
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
name: 'onError',
|
|
114
|
+
type: '(event: { error: unknown }) => void | PromiseLike<void>',
|
|
115
|
+
isOptional: true,
|
|
116
|
+
description:
|
|
117
|
+
'Called for each `error` part the provider reports. Defaults to `console.error`.',
|
|
118
|
+
},
|
|
119
|
+
]}
|
|
120
|
+
/>
|
|
121
|
+
|
|
122
|
+
### Returns
|
|
123
|
+
|
|
124
|
+
<PropertiesTable
|
|
125
|
+
content={[
|
|
126
|
+
{
|
|
127
|
+
name: 'audioStream',
|
|
128
|
+
type: 'AsyncIterableStream<Uint8Array>',
|
|
129
|
+
description:
|
|
130
|
+
'Audio bytes in generation order. Shares one live stream with `fullStream`: only one of them can be accessed, once, before any result promise. `error` parts are skipped (they are reported via `onError`); the stream errors only when the speech stream itself fails.',
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
name: 'fullStream',
|
|
134
|
+
type: 'AsyncIterableStream<Experimental_SpeechStreamPart>',
|
|
135
|
+
description:
|
|
136
|
+
'A single-consumer live stream of `audio` (with `audio: Uint8Array` and `audioFormat`), `raw`, and `error` parts. Error parts are not fatal; the stream continues after them.',
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
name: 'usage',
|
|
140
|
+
type: 'Promise<{ inputCharacters?: number; inputTokens?: number; outputTokens?: number; raw?: JSONObject }>',
|
|
141
|
+
description: 'Usage information for the call, if known.',
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'warnings',
|
|
145
|
+
type: 'Promise<Warning[]>',
|
|
146
|
+
description:
|
|
147
|
+
'Warnings for the call, e.g. unsupported settings. Resolves when the provider emits the stream start.',
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: 'responses',
|
|
151
|
+
type: 'Promise<Array<SpeechModelResponseMetadata>>',
|
|
152
|
+
description: 'Response metadata (timestamp, model ID, headers, body).',
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: 'providerMetadata',
|
|
156
|
+
type: 'Promise<Record<string, JSONObject>>',
|
|
157
|
+
description: 'Additional provider-specific metadata.',
|
|
158
|
+
},
|
|
159
|
+
]}
|
|
160
|
+
/>
|
|
161
|
+
|
|
162
|
+
<Note>
|
|
163
|
+
The result promises settle as the stream is consumed. If you cancel the stream
|
|
164
|
+
early (for example by breaking out of a `for await` loop) or abort the call,
|
|
165
|
+
pending result promises reject immediately and the provider is signalled to
|
|
166
|
+
close its connection. A stream that is not read stalls under backpressure and
|
|
167
|
+
keeps the provider call open.
|
|
168
|
+
</Note>
|
|
169
|
+
|
|
170
|
+
## Errors
|
|
171
|
+
|
|
172
|
+
- `UnsupportedFunctionalityError` is thrown synchronously when the model does
|
|
173
|
+
not support streaming speech.
|
|
174
|
+
- `InvalidArgumentError` is thrown synchronously when `text` is not a string,
|
|
175
|
+
an iterable or async iterable, or a readable stream.
|
|
176
|
+
- Provider `error` parts are not fatal. They appear in `fullStream`, are
|
|
177
|
+
skipped by `audioStream`, and are passed to `onError`.
|
|
178
|
+
- If the stream ends without audio, the result rejects with
|
|
179
|
+
`NoSpeechGeneratedError`, whose `cause` is the last provider error part.
|
|
180
|
+
- If the stream stops after audio but before it finished, the result rejects
|
|
181
|
+
with the last provider error part, or with a `StreamProviderError`.
|
|
182
|
+
- If the provider call fails (for example an authentication error), the result
|
|
183
|
+
rejects with that error. Cancelling or aborting rejects with the
|
|
184
|
+
cancellation or abort reason.
|
|
185
|
+
|
|
186
|
+
## Wire format (experimental)
|
|
187
|
+
|
|
188
|
+
Streaming speech over WebSocket is serialized with the experimental
|
|
189
|
+
speech-stream envelope defined in `@ai-sdk/provider-utils`
|
|
190
|
+
(`experimental_parseSpeechStreamClientFrame`,
|
|
191
|
+
`experimental_serializeSpeechStreamPart`, `experimental_parseSpeechStreamPart`):
|
|
192
|
+
the client sends one `speech-stream.start` TEXT frame, input text as
|
|
193
|
+
`speech-stream.text-delta` TEXT frames (each carrying its text part's `voice`
|
|
194
|
+
and `providerOptions`), and a `speech-stream.text-done` TEXT frame; each server TEXT frame is one JSON-serialized speech stream part with
|
|
195
|
+
base64 audio. AI Gateway implements the server side of this envelope.
|
|
@@ -98,6 +98,11 @@ AI SDK Core contains the following main functions:
|
|
|
98
98
|
description: 'Generate speech audio from text.',
|
|
99
99
|
href: '/docs/reference/ai-sdk-core/generate-speech',
|
|
100
100
|
},
|
|
101
|
+
{
|
|
102
|
+
title: 'experimental_streamSpeech()',
|
|
103
|
+
description: 'Stream speech audio from text or a text stream.',
|
|
104
|
+
href: '/docs/reference/ai-sdk-core/stream-speech',
|
|
105
|
+
},
|
|
101
106
|
{
|
|
102
107
|
title: 'uploadFile()',
|
|
103
108
|
description: 'Upload a file to a provider and get a provider reference.',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.151",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI SDK by Vercel - build apps like ChatGPT, Claude, Gemini, and more with a single interface for any model using the Vercel AI Gateway or go direct to OpenAI, Anthropic, Google, or any other model provider.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,20 +42,20 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@ai-sdk/gateway": "4.0.
|
|
46
|
-
"@ai-sdk/provider": "4.0.
|
|
47
|
-
"@ai-sdk/provider-utils": "5.0.
|
|
45
|
+
"@ai-sdk/gateway": "4.0.124",
|
|
46
|
+
"@ai-sdk/provider": "4.0.33",
|
|
47
|
+
"@ai-sdk/provider-utils": "5.0.67"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
|
-
"@ai-sdk/amazon-bedrock": "5.0.
|
|
51
|
-
"@ai-sdk/deepseek": "3.0.
|
|
52
|
-
"@ai-sdk/google": "4.0.
|
|
53
|
-
"@ai-sdk/groq": "4.0.
|
|
54
|
-
"@ai-sdk/huggingface": "2.0.
|
|
55
|
-
"@ai-sdk/moonshotai": "3.0.
|
|
56
|
-
"@ai-sdk/openai": "4.0.
|
|
50
|
+
"@ai-sdk/amazon-bedrock": "5.0.123",
|
|
51
|
+
"@ai-sdk/deepseek": "3.0.72",
|
|
52
|
+
"@ai-sdk/google": "4.0.104",
|
|
53
|
+
"@ai-sdk/groq": "4.0.69",
|
|
54
|
+
"@ai-sdk/huggingface": "2.0.77",
|
|
55
|
+
"@ai-sdk/moonshotai": "3.0.76",
|
|
56
|
+
"@ai-sdk/openai": "4.0.101",
|
|
57
57
|
"@ai-sdk/test-server": "2.0.4",
|
|
58
|
-
"@ai-sdk/xai": "5.0.
|
|
58
|
+
"@ai-sdk/xai": "5.0.29",
|
|
59
59
|
"@edge-runtime/vm": "^5.0.0",
|
|
60
60
|
"@smithy/eventstream-codec": "^4.3.3",
|
|
61
61
|
"@smithy/util-utf8": "^4.3.3",
|
|
@@ -13,10 +13,14 @@ export class NoSpeechGeneratedError extends AISDKError {
|
|
|
13
13
|
|
|
14
14
|
readonly responses: Array<SpeechModelResponseMetadata>;
|
|
15
15
|
|
|
16
|
-
constructor(options: {
|
|
16
|
+
constructor(options: {
|
|
17
|
+
responses: Array<SpeechModelResponseMetadata>;
|
|
18
|
+
cause?: unknown;
|
|
19
|
+
}) {
|
|
17
20
|
super({
|
|
18
21
|
name,
|
|
19
22
|
message: 'No speech audio generated.',
|
|
23
|
+
...(options.cause !== undefined && { cause: options.cause }),
|
|
20
24
|
});
|
|
21
25
|
|
|
22
26
|
this.responses = options.responses;
|
|
@@ -3,6 +3,13 @@ import { generateSpeech } from './generate-speech';
|
|
|
3
3
|
import { logWarnings } from '../logger/log-warnings';
|
|
4
4
|
|
|
5
5
|
export { generateSpeech } from './generate-speech';
|
|
6
|
+
export { streamSpeech as experimental_streamSpeech } from './stream-speech';
|
|
7
|
+
export type {
|
|
8
|
+
SpeechStreamPart as Experimental_SpeechStreamPart,
|
|
9
|
+
SpeechStreamUsage as Experimental_SpeechStreamUsage,
|
|
10
|
+
SpeechTextPart as Experimental_SpeechTextPart,
|
|
11
|
+
StreamSpeechResult as Experimental_StreamSpeechResult,
|
|
12
|
+
} from './stream-speech-result';
|
|
6
13
|
export type { SpeechResult } from './generate-speech-result';
|
|
7
14
|
export type { GeneratedAudioFile } from './generated-audio-file';
|
|
8
15
|
export type {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_StreamingSpeechModelV4,
|
|
3
|
+
SpeechModelV4,
|
|
4
|
+
} from '@ai-sdk/provider';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Whether a resolved speech model implements the experimental streaming
|
|
8
|
+
* speech extension (`Experimental_StreamingSpeechModelV4`).
|
|
9
|
+
*/
|
|
10
|
+
export function isStreamingSpeechModel(
|
|
11
|
+
model: SpeechModelV4,
|
|
12
|
+
): model is Experimental_StreamingSpeechModelV4 {
|
|
13
|
+
return (
|
|
14
|
+
typeof (model as Partial<Experimental_StreamingSpeechModelV4>).doStream ===
|
|
15
|
+
'function'
|
|
16
|
+
);
|
|
17
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Experimental_SpeechModelV4StreamUsage,
|
|
3
|
+
JSONObject,
|
|
4
|
+
SharedV4AudioFormat,
|
|
5
|
+
SharedV4ProviderMetadata,
|
|
6
|
+
} from '@ai-sdk/provider';
|
|
7
|
+
import type { ProviderOptions } from '@ai-sdk/provider-utils';
|
|
8
|
+
import type { SpeechModelResponseMetadata } from '../types/speech-model-response-metadata';
|
|
9
|
+
import type { Warning } from '../types/warning';
|
|
10
|
+
import type { AsyncIterableStream } from '../util/async-iterable-stream';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* A piece of text to synthesize. Pass a stream of these (or mix them with
|
|
14
|
+
* plain strings) to give parts their own voice, e.g. for dialogue.
|
|
15
|
+
*/
|
|
16
|
+
export type SpeechTextPart = {
|
|
17
|
+
type: 'text';
|
|
18
|
+
text: string;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* The voice that speaks this part (provider-specific, like the call's
|
|
22
|
+
* `voice`). Single-voice providers reject a voice that differs from the
|
|
23
|
+
* call's voice.
|
|
24
|
+
*/
|
|
25
|
+
voice?: string;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Additional provider-specific options for this part.
|
|
29
|
+
*/
|
|
30
|
+
providerOptions?: ProviderOptions;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type SpeechStreamPart =
|
|
34
|
+
| {
|
|
35
|
+
/**
|
|
36
|
+
* Audio chunk in generation order. Chunks are not necessarily
|
|
37
|
+
* standalone files; concatenate them to reconstruct the audio. A chunk
|
|
38
|
+
* is empty only when it carries `providerMetadata` (e.g. a turn marker).
|
|
39
|
+
*/
|
|
40
|
+
type: 'audio';
|
|
41
|
+
id?: string;
|
|
42
|
+
audio: Uint8Array;
|
|
43
|
+
audioFormat: SharedV4AudioFormat;
|
|
44
|
+
providerMetadata?: SharedV4ProviderMetadata;
|
|
45
|
+
}
|
|
46
|
+
| {
|
|
47
|
+
type: 'raw';
|
|
48
|
+
rawValue: unknown;
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
type: 'error';
|
|
52
|
+
error: unknown;
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export type SpeechStreamUsage = Experimental_SpeechModelV4StreamUsage;
|
|
56
|
+
|
|
57
|
+
export interface StreamSpeechResult {
|
|
58
|
+
/**
|
|
59
|
+
* Usage information reported for the call, if available.
|
|
60
|
+
*/
|
|
61
|
+
readonly usage: PromiseLike<SpeechStreamUsage>;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Warnings for the call, e.g. unsupported settings.
|
|
65
|
+
*/
|
|
66
|
+
readonly warnings: PromiseLike<Array<Warning>>;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Response metadata.
|
|
70
|
+
*/
|
|
71
|
+
readonly responses: PromiseLike<Array<SpeechModelResponseMetadata>>;
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Additional provider-specific metadata.
|
|
75
|
+
*/
|
|
76
|
+
readonly providerMetadata: PromiseLike<Record<string, JSONObject>>;
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Stream of audio bytes in generation order.
|
|
80
|
+
*
|
|
81
|
+
* `audioStream` and `fullStream` share one live stream: only one of them
|
|
82
|
+
* can be accessed, and only once. Access it before any result promise;
|
|
83
|
+
* accessing a result promise first consumes the stream internally.
|
|
84
|
+
*/
|
|
85
|
+
readonly audioStream: AsyncIterableStream<Uint8Array>;
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Full stream of speech parts (audio, raw, and error parts).
|
|
89
|
+
*
|
|
90
|
+
* `audioStream` and `fullStream` share one live stream: only one of them
|
|
91
|
+
* can be accessed, and only once. Access it before any result promise;
|
|
92
|
+
* accessing a result promise first consumes the stream internally.
|
|
93
|
+
*/
|
|
94
|
+
readonly fullStream: AsyncIterableStream<SpeechStreamPart>;
|
|
95
|
+
}
|