@ai-sdk/mistral
Advanced tools
| import { z } from 'zod/v4'; | ||
| export type MistralSpeechModelId = 'voxtral-mini-tts-2603' | (string & {}); | ||
| export const mistralSpeechModelOptions = z.object({ | ||
| /** | ||
| * Base64-encoded reference audio for one-off voice cloning. | ||
| * | ||
| * When provided, this takes precedence over the standard `voice` option. | ||
| */ | ||
| refAudio: z.string().min(1).optional(), | ||
| }); | ||
| export type MistralSpeechModelOptions = z.infer< | ||
| typeof mistralSpeechModelOptions | ||
| >; |
| import type { SharedV4Warning, SpeechModelV4 } from '@ai-sdk/provider'; | ||
| import { | ||
| combineHeaders, | ||
| createJsonResponseHandler, | ||
| parseProviderOptions, | ||
| postToApi, | ||
| serializeModelOptions, | ||
| WORKFLOW_DESERIALIZE, | ||
| WORKFLOW_SERIALIZE, | ||
| type FetchFunction, | ||
| } from '@ai-sdk/provider-utils'; | ||
| import { z } from 'zod/v4'; | ||
| import { mistralFailedResponseHandler } from './mistral-error'; | ||
| import { | ||
| mistralSpeechModelOptions, | ||
| type MistralSpeechModelId, | ||
| } from './mistral-speech-model-options'; | ||
| interface MistralSpeechModelConfig { | ||
| provider: string; | ||
| baseURL: string; | ||
| headers?: () => Record<string, string | undefined>; | ||
| fetch?: FetchFunction; | ||
| _internal?: { | ||
| currentDate?: () => Date; | ||
| }; | ||
| } | ||
| type MistralSpeechOutputFormat = 'pcm' | 'wav' | 'mp3' | 'flac' | 'opus'; | ||
| export class MistralSpeechModel implements SpeechModelV4 { | ||
| readonly specificationVersion = 'v4'; | ||
| static [WORKFLOW_SERIALIZE](model: MistralSpeechModel) { | ||
| return serializeModelOptions({ | ||
| modelId: model.modelId, | ||
| config: model.config, | ||
| }); | ||
| } | ||
| static [WORKFLOW_DESERIALIZE](options: { | ||
| modelId: MistralSpeechModelId; | ||
| config: MistralSpeechModelConfig; | ||
| }) { | ||
| return new MistralSpeechModel(options.modelId, options.config); | ||
| } | ||
| get provider(): string { | ||
| return this.config.provider; | ||
| } | ||
| constructor( | ||
| readonly modelId: MistralSpeechModelId, | ||
| private readonly config: MistralSpeechModelConfig, | ||
| ) {} | ||
| private async getArgs({ | ||
| text, | ||
| voice, | ||
| outputFormat = 'mp3', | ||
| instructions, | ||
| speed, | ||
| language, | ||
| providerOptions, | ||
| }: Parameters<SpeechModelV4['doGenerate']>[0]) { | ||
| const warnings: SharedV4Warning[] = []; | ||
| const mistralOptions = await parseProviderOptions({ | ||
| provider: 'mistral', | ||
| providerOptions, | ||
| schema: mistralSpeechModelOptions, | ||
| }); | ||
| let responseFormat: MistralSpeechOutputFormat = 'mp3'; | ||
| if (['pcm', 'wav', 'mp3', 'flac', 'opus'].includes(outputFormat)) { | ||
| responseFormat = outputFormat as MistralSpeechOutputFormat; | ||
| } else { | ||
| warnings.push({ | ||
| type: 'unsupported', | ||
| feature: 'outputFormat', | ||
| details: `Unsupported output format: ${outputFormat}. Using mp3 instead.`, | ||
| }); | ||
| } | ||
| if (instructions != null) { | ||
| warnings.push({ | ||
| type: 'unsupported', | ||
| feature: 'instructions', | ||
| details: | ||
| 'Mistral speech models do not support the `instructions` option. ' + | ||
| 'Use a reference audio clip to guide delivery.', | ||
| }); | ||
| } | ||
| if (speed != null) { | ||
| warnings.push({ | ||
| type: 'unsupported', | ||
| feature: 'speed', | ||
| details: | ||
| 'Mistral speech models do not support the `speed` option. It was ignored.', | ||
| }); | ||
| } | ||
| if (language != null) { | ||
| warnings.push({ | ||
| type: 'unsupported', | ||
| feature: 'language', | ||
| details: | ||
| 'Mistral speech models do not support the `language` option. ' + | ||
| 'Language is inferred from the input text and voice.', | ||
| }); | ||
| } | ||
| const refAudio = mistralOptions?.refAudio; | ||
| const requestBody = { | ||
| model: this.modelId, | ||
| input: text, | ||
| voice_id: refAudio == null ? voice : undefined, | ||
| ref_audio: refAudio, | ||
| response_format: responseFormat, | ||
| stream: false, | ||
| }; | ||
| const requestBodyValues = { | ||
| ...requestBody, | ||
| ref_audio: refAudio == null ? undefined : '[redacted]', | ||
| }; | ||
| return { requestBody, requestBodyValues, warnings }; | ||
| } | ||
| async doGenerate( | ||
| options: Parameters<SpeechModelV4['doGenerate']>[0], | ||
| ): Promise<Awaited<ReturnType<SpeechModelV4['doGenerate']>>> { | ||
| const currentDate = this.config._internal?.currentDate?.() ?? new Date(); | ||
| const { requestBody, requestBodyValues, warnings } = | ||
| await this.getArgs(options); | ||
| const { | ||
| value: response, | ||
| responseHeaders, | ||
| rawValue: rawResponse, | ||
| } = await postToApi({ | ||
| url: `${this.config.baseURL}/audio/speech`, | ||
| headers: combineHeaders( | ||
| { 'Content-Type': 'application/json' }, | ||
| this.config.headers?.(), | ||
| options.headers, | ||
| ), | ||
| body: { | ||
| content: JSON.stringify(requestBody), | ||
| values: requestBodyValues, | ||
| }, | ||
| failedResponseHandler: mistralFailedResponseHandler, | ||
| successfulResponseHandler: createJsonResponseHandler( | ||
| mistralSpeechResponseSchema, | ||
| ), | ||
| abortSignal: options.abortSignal, | ||
| fetch: this.config.fetch, | ||
| }); | ||
| return { | ||
| audio: response.audio_data, | ||
| warnings, | ||
| request: { | ||
| body: JSON.stringify(requestBodyValues), | ||
| }, | ||
| response: { | ||
| timestamp: currentDate, | ||
| modelId: this.modelId, | ||
| headers: responseHeaders, | ||
| body: rawResponse, | ||
| }, | ||
| }; | ||
| } | ||
| } | ||
| const mistralSpeechResponseSchema = z.object({ | ||
| audio_data: z.string(), | ||
| }); |
+6
-0
| # @ai-sdk/mistral | ||
| ## 4.0.12 | ||
| ### Patch Changes | ||
| - ba433f7: Add non-streaming Voxtral text-to-speech generation with saved voice IDs and one-off reference audio. | ||
| ## 4.0.11 | ||
@@ -4,0 +10,0 @@ |
+16
-2
@@ -1,2 +0,2 @@ | ||
| import { ProviderV4, LanguageModelV4, EmbeddingModelV4 } from '@ai-sdk/provider'; | ||
| import { ProviderV4, LanguageModelV4, EmbeddingModelV4, SpeechModelV4 } from '@ai-sdk/provider'; | ||
| import { FetchFunction } from '@ai-sdk/provider-utils'; | ||
@@ -34,2 +34,8 @@ import { z } from 'zod/v4'; | ||
| type MistralSpeechModelId = 'voxtral-mini-tts-2603' | (string & {}); | ||
| declare const mistralSpeechModelOptions: z.ZodObject<{ | ||
| refAudio: z.ZodOptional<z.ZodString>; | ||
| }, z.core.$strip>; | ||
| type MistralSpeechModelOptions = z.infer<typeof mistralSpeechModelOptions>; | ||
| interface MistralProvider extends ProviderV4 { | ||
@@ -54,2 +60,10 @@ (modelId: MistralChatModelId): LanguageModelV4; | ||
| /** | ||
| * Creates a model for speech generation (text-to-speech). | ||
| */ | ||
| speech(modelId: MistralSpeechModelId): SpeechModelV4; | ||
| /** | ||
| * Creates a model for speech generation (text-to-speech). | ||
| */ | ||
| speechModel(modelId: MistralSpeechModelId): SpeechModelV4; | ||
| /** | ||
| * @deprecated Use `embedding` instead. | ||
@@ -96,2 +110,2 @@ */ | ||
| export { type MistralEmbeddingModelOptions, type MistralLanguageModelChatOptions, type MistralLanguageModelChatOptions as MistralLanguageModelOptions, type MistralProvider, type MistralProviderSettings, VERSION, createMistral, mistral }; | ||
| export { type MistralEmbeddingModelOptions, type MistralLanguageModelChatOptions, type MistralLanguageModelChatOptions as MistralLanguageModelOptions, type MistralProvider, type MistralProviderSettings, type MistralSpeechModelId, type MistralSpeechModelOptions, VERSION, createMistral, mistral }; |
+157
-1
@@ -941,4 +941,152 @@ // src/mistral-provider.ts | ||
| // src/mistral-speech-model.ts | ||
| import { | ||
| combineHeaders as combineHeaders3, | ||
| createJsonResponseHandler as createJsonResponseHandler3, | ||
| parseProviderOptions as parseProviderOptions3, | ||
| postToApi, | ||
| serializeModelOptions as serializeModelOptions3, | ||
| WORKFLOW_DESERIALIZE as WORKFLOW_DESERIALIZE3, | ||
| WORKFLOW_SERIALIZE as WORKFLOW_SERIALIZE3 | ||
| } from "@ai-sdk/provider-utils"; | ||
| import { z as z7 } from "zod/v4"; | ||
| // src/mistral-speech-model-options.ts | ||
| import { z as z6 } from "zod/v4"; | ||
| var mistralSpeechModelOptions = z6.object({ | ||
| /** | ||
| * Base64-encoded reference audio for one-off voice cloning. | ||
| * | ||
| * When provided, this takes precedence over the standard `voice` option. | ||
| */ | ||
| refAudio: z6.string().min(1).optional() | ||
| }); | ||
| // src/mistral-speech-model.ts | ||
| var MistralSpeechModel = class _MistralSpeechModel { | ||
| constructor(modelId, config) { | ||
| this.modelId = modelId; | ||
| this.config = config; | ||
| this.specificationVersion = "v4"; | ||
| } | ||
| static [WORKFLOW_SERIALIZE3](model) { | ||
| return serializeModelOptions3({ | ||
| modelId: model.modelId, | ||
| config: model.config | ||
| }); | ||
| } | ||
| static [WORKFLOW_DESERIALIZE3](options) { | ||
| return new _MistralSpeechModel(options.modelId, options.config); | ||
| } | ||
| get provider() { | ||
| return this.config.provider; | ||
| } | ||
| async getArgs({ | ||
| text, | ||
| voice, | ||
| outputFormat = "mp3", | ||
| instructions, | ||
| speed, | ||
| language, | ||
| providerOptions | ||
| }) { | ||
| const warnings = []; | ||
| const mistralOptions = await parseProviderOptions3({ | ||
| provider: "mistral", | ||
| providerOptions, | ||
| schema: mistralSpeechModelOptions | ||
| }); | ||
| let responseFormat = "mp3"; | ||
| if (["pcm", "wav", "mp3", "flac", "opus"].includes(outputFormat)) { | ||
| responseFormat = outputFormat; | ||
| } else { | ||
| warnings.push({ | ||
| type: "unsupported", | ||
| feature: "outputFormat", | ||
| details: `Unsupported output format: ${outputFormat}. Using mp3 instead.` | ||
| }); | ||
| } | ||
| if (instructions != null) { | ||
| warnings.push({ | ||
| type: "unsupported", | ||
| feature: "instructions", | ||
| details: "Mistral speech models do not support the `instructions` option. Use a reference audio clip to guide delivery." | ||
| }); | ||
| } | ||
| if (speed != null) { | ||
| warnings.push({ | ||
| type: "unsupported", | ||
| feature: "speed", | ||
| details: "Mistral speech models do not support the `speed` option. It was ignored." | ||
| }); | ||
| } | ||
| if (language != null) { | ||
| warnings.push({ | ||
| type: "unsupported", | ||
| feature: "language", | ||
| details: "Mistral speech models do not support the `language` option. Language is inferred from the input text and voice." | ||
| }); | ||
| } | ||
| const refAudio = mistralOptions == null ? void 0 : mistralOptions.refAudio; | ||
| const requestBody = { | ||
| model: this.modelId, | ||
| input: text, | ||
| voice_id: refAudio == null ? voice : void 0, | ||
| ref_audio: refAudio, | ||
| response_format: responseFormat, | ||
| stream: false | ||
| }; | ||
| const requestBodyValues = { | ||
| ...requestBody, | ||
| ref_audio: refAudio == null ? void 0 : "[redacted]" | ||
| }; | ||
| return { requestBody, requestBodyValues, warnings }; | ||
| } | ||
| async doGenerate(options) { | ||
| var _a, _b, _c, _d, _e; | ||
| const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date(); | ||
| const { requestBody, requestBodyValues, warnings } = await this.getArgs(options); | ||
| const { | ||
| value: response, | ||
| responseHeaders, | ||
| rawValue: rawResponse | ||
| } = await postToApi({ | ||
| url: `${this.config.baseURL}/audio/speech`, | ||
| headers: combineHeaders3( | ||
| { "Content-Type": "application/json" }, | ||
| (_e = (_d = this.config).headers) == null ? void 0 : _e.call(_d), | ||
| options.headers | ||
| ), | ||
| body: { | ||
| content: JSON.stringify(requestBody), | ||
| values: requestBodyValues | ||
| }, | ||
| failedResponseHandler: mistralFailedResponseHandler, | ||
| successfulResponseHandler: createJsonResponseHandler3( | ||
| mistralSpeechResponseSchema | ||
| ), | ||
| abortSignal: options.abortSignal, | ||
| fetch: this.config.fetch | ||
| }); | ||
| return { | ||
| audio: response.audio_data, | ||
| warnings, | ||
| request: { | ||
| body: JSON.stringify(requestBodyValues) | ||
| }, | ||
| response: { | ||
| timestamp: currentDate, | ||
| modelId: this.modelId, | ||
| headers: responseHeaders, | ||
| body: rawResponse | ||
| } | ||
| }; | ||
| } | ||
| }; | ||
| var mistralSpeechResponseSchema = z7.object({ | ||
| audio_data: z7.string() | ||
| }); | ||
| // src/version.ts | ||
| var VERSION = true ? "4.0.11" : "0.0.0-test"; | ||
| var VERSION = true ? "4.0.12" : "0.0.0-test"; | ||
@@ -973,2 +1121,8 @@ // src/mistral-provider.ts | ||
| }); | ||
| const createSpeechModel = (modelId) => new MistralSpeechModel(modelId, { | ||
| provider: "mistral.speech", | ||
| baseURL, | ||
| headers: getHeaders, | ||
| fetch: options.fetch | ||
| }); | ||
| const provider = function(modelId) { | ||
@@ -989,2 +1143,4 @@ if (new.target) { | ||
| provider.textEmbeddingModel = createEmbeddingModel; | ||
| provider.speech = createSpeechModel; | ||
| provider.speechModel = createSpeechModel; | ||
| provider.imageModel = (modelId) => { | ||
@@ -991,0 +1147,0 @@ throw new NoSuchModelError({ modelId, modelType: "imageModel" }); |
+1
-1
| { | ||
| "name": "@ai-sdk/mistral", | ||
| "version": "4.0.11", | ||
| "version": "4.0.12", | ||
| "type": "module", | ||
@@ -5,0 +5,0 @@ "license": "Apache-2.0", |
+1
-1
| # AI SDK - Mistral Provider | ||
| The **[Mistral provider](https://ai-sdk.dev/providers/ai-sdk-providers/mistral)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model support for the Mistral chat API. | ||
| The **[Mistral provider](https://ai-sdk.dev/providers/ai-sdk-providers/mistral)** for the [AI SDK](https://ai-sdk.dev/docs) contains language model, embedding model, and speech model support for Mistral APIs. | ||
@@ -5,0 +5,0 @@ > **Deploying to Vercel?** With Vercel's AI Gateway you can access Mistral (and hundreds of models from other providers) — no additional packages, API keys, or extra cost. [Get started with AI Gateway](https://vercel.com/ai-gateway). |
+4
-0
@@ -12,2 +12,6 @@ export { createMistral, mistral } from './mistral-provider'; | ||
| export type { MistralEmbeddingModelOptions } from './mistral-embedding-model-options'; | ||
| export type { | ||
| MistralSpeechModelId, | ||
| MistralSpeechModelOptions, | ||
| } from './mistral-speech-model-options'; | ||
| export { VERSION } from './version'; |
@@ -6,2 +6,3 @@ import { | ||
| type ProviderV4, | ||
| type SpeechModelV4, | ||
| } from '@ai-sdk/provider'; | ||
@@ -18,2 +19,4 @@ import { | ||
| import type { MistralEmbeddingModelId } from './mistral-embedding-model-options'; | ||
| import { MistralSpeechModel } from './mistral-speech-model'; | ||
| import type { MistralSpeechModelId } from './mistral-speech-model-options'; | ||
| import { VERSION } from './version'; | ||
@@ -45,2 +48,12 @@ | ||
| /** | ||
| * Creates a model for speech generation (text-to-speech). | ||
| */ | ||
| speech(modelId: MistralSpeechModelId): SpeechModelV4; | ||
| /** | ||
| * Creates a model for speech generation (text-to-speech). | ||
| */ | ||
| speechModel(modelId: MistralSpeechModelId): SpeechModelV4; | ||
| /** | ||
| * @deprecated Use `embedding` instead. | ||
@@ -122,2 +135,10 @@ */ | ||
| const createSpeechModel = (modelId: MistralSpeechModelId) => | ||
| new MistralSpeechModel(modelId, { | ||
| provider: 'mistral.speech', | ||
| baseURL, | ||
| headers: getHeaders, | ||
| fetch: options.fetch, | ||
| }); | ||
| const provider = function (modelId: MistralChatModelId) { | ||
@@ -140,2 +161,4 @@ if (new.target) { | ||
| provider.textEmbeddingModel = createEmbeddingModel; | ||
| provider.speech = createSpeechModel; | ||
| provider.speechModel = createSpeechModel; | ||
@@ -142,0 +165,0 @@ provider.imageModel = (modelId: string) => { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
224142
11.55%24
9.09%2743
15.3%33
37.5%