如何用 AI SDK 的 generateSpeech 生成语音并获取音频数据
【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai
当你需要在 TypeScript 应用中把一段文本转成音频时,AI SDK(The AI Toolkit for TypeScript)提供的generateSpeech函数可以直接完成这件事:调用语音模型生成语音,返回结果中的audio对象提供二进制数据(Uint8Array)和 base64 字符串两种访问方式,还可以按mediaType把音频写入磁盘。本文以 OpenAI 的tts-1模型为例,走通从配置密钥、调用函数到验证产出文件的完整路径。
准备依赖与 API Key
仓库自带的示例位于examples/ai-functions,其 README(examples/ai-functions/README.md)说明了三步:
- 在
examples/ai-functions下创建.env文件,写入对应服务商的密钥。以 OpenAI 为例,按文档原样填写(引号内替换为你自己的密钥):
OPENAI_API_KEY="YOUR_OPENAI_API_KEY"- 从 AI SDK 仓库根目录安装并构建:
pnpm install pnpm build- 之后可以从
examples/ai-functions目录用pnpm tsx运行任意示例脚本,格式为:
pnpm tsx src/path/to/example.ts调用 generateSpeech 生成语音
generateSpeech从ai包导入(参考 API 文档)。必填参数是model和text,可选参数包括voice、outputFormat、speed、language、providerOptions等。仓库内置的 OpenAI 基础示例 examples/ai-functions/src/generate-speech/openai/basic.ts 展示了最短可行调用:
import { openai } from '@ai-sdk/openai'; import { generateSpeech } from 'ai'; const result = await generateSpeech({ model: openai.speech('tts-1'), text: 'Hello from the AI SDK!', });如果需要通过 OpenAI 的voice参数指定声音,可选值在 OpenAI Provider 文档 中列明:alloy、ash、coral、echo、fable、onyx、nova、sage、shimmer:
import { generateSpeech } from 'ai'; import { openai } from '@ai-sdk/openai'; const result = await generateSpeech({ model: openai.speech('tts-1'), text: 'Hello, world!', voice: 'alloy', // OpenAI voice ID });除 OpenAI 外,generateSpeech还支持其他服务商的语音模型(Speech 概览文档 列出了可用子集),例如 ElevenLabs 的eleven_multilingual_v2:
import { generateSpeech } from 'ai'; import { elevenLabs } from '@ai-sdk/elevenlabs'; const { audio } = await generateSpeech({ model: elevenLabs.speech('eleven_multilingual_v2'), text: 'Hello from the AI SDK!', voice: 'your-voice-id', // Required: get this from your ElevenLabs account });注意voice的值含义依赖服务商:OpenAI 使用固定声音名,ElevenLabs 要求填自己账户中的 voice id(文档原文标注为 Required,需从 ElevenLabs 账户获取)。
获取音频数据:uint8Array、base64 与元数据
generateSpeech的返回值(API 参考)包含以下字段:
| 字段 | 类型 | 说明 |
|---|---|---|
audio | GeneratedAudioFile | 生成的音频 |
warnings | Warning[] | 来自服务商的警告(如不支持的设置项) |
providerMetadata | Record<string, JSONObject> | 可选,服务商元数据,外层 key 为服务商名 |
responses | Array<SpeechModelResponseMetadata> | 响应元数据,包含timestamp、modelId、headers等 |
其中audio(GeneratedAudioFile)提供四种访问方式:
| 属性 | 类型 | 用途 |
|---|---|---|
base64 | string | 音频的 base64 编码字符串 |
uint8Array | Uint8Array | 音频二进制数据 |
mediaType | string | 媒体类型,如"audio/mpeg" |
format | string | 音频格式,如"mp3" |
根据 Speech 文档 的写法,两种取数方式分别是:
const audioData = audio.uint8Array; // audio data as Uint8Array const audioBase64 = audio.base64; // audio data as base64 string可选分支:按 mediaType 保存为文件
仓库示例提供了 save-audio 辅助函数,演示了如何根据mediaType选择扩展名并把uint8Array写入磁盘:
import type { GeneratedAudioFile } from 'ai'; import fs from 'node:fs'; import path from 'node:path'; const OUTPUT_DIR = 'output'; const audioFormatMap = { 'audio/mpeg': 'mp3', 'audio/wav': 'wav', 'audio/flac': 'flac', 'audio/aac': 'aac', 'audio/ogg': 'ogg', }; export async function saveAudioFile(audio: GeneratedAudioFile) { const timestamp = Date.now(); const extension = audio.mediaType in audioFormatMap ? audioFormatMap[audio.mediaType as keyof typeof audioFormatMap] : 'mp3'; // Save the audio file to disk. fs.mkdirSync(OUTPUT_DIR, { recursive: true }); const filePath = path.join(OUTPUT_DIR, `audio-${timestamp}.${extension}`); await fs.promises.writeFile(filePath, audio.uint8Array); console.log(`Saved audio to ${filePath}`); }运行示例并验证结果
在examples/ai-functions目录下运行 OpenAI 基础示例:
pnpm tsx src/generate-speech/openai/basic.ts该示例(见 basic.ts)在调用后会打印四个部分,并调用saveAudioFile落盘:
console.log('Audio:', result.audio); console.log('Warnings:', result.warnings); console.log('Responses:', result.responses); console.log('Provider Metadata:', result.providerMetadata); await saveAudioFile(result.audio);成功的判断依据是:控制台依次输出上述字段,最后一行打印Saved audio to output/audio-<时间戳>.<扩展名>(路径与时间戳为运行时实际值,示例中的audio-${timestamp}由代码动态生成),并且output/目录下出现对应的音频文件。
处理 AI_NoSpeechGeneratedError 与常见设置
无音频产出时的错误处理
当generateSpeech无法生成有效音频时会抛出AI_NoSpeechGeneratedError(错误参考)。文档说明该错误出现在 "no audio could be generated from the input" 的情况,Speech 文档 进一步列出两类原因:模型未能生成响应,或模型生成的响应无法解析。错误对象保留两个属性用于排查日志:
responses:语音模型响应元数据,含时间戳、模型和 headers;cause:错误原因,可用于更细粒度的错误处理。
判断与捕获方式:
import { generateSpeech, NoSpeechGeneratedError } from 'ai'; import { openai } from '@ai-sdk/openai'; try { await generateSpeech({ model: openai.speech('tts-1'), text: 'Hello, world!', }); } catch (error) { if (NoSpeechGeneratedError.isInstance(error)) { console.log('AI_NoSpeechGeneratedError'); console.log('Cause:', error.cause); console.log('Responses:', error.responses); } }providerOptions、超时与自定义 Header
providerOptions:传递服务商特有参数。OpenAI 示例见 Provider 文档:
import { generateSpeech } from 'ai'; import { openai, type OpenAISpeechModelOptions } from '@ai-sdk/openai'; const result = await generateSpeech({ model: openai.speech('tts-1'), text: 'Hello, world!', voice: 'alloy', providerOptions: { openai: { speed: 1.2, } satisfies OpenAISpeechModelOptions, }, });abortSignal:传入AbortSignal可中止生成或设置超时,文档给出的示例是 1 秒超时:
abortSignal: AbortSignal.timeout(1000), // Abort after 1 secondheaders:传入Record<string, string>为请求附加自定义 HTTP header,例如:
headers: { 'X-Custom-Header': 'custom-value' },warnings:调用成功后通过audio.warnings(即返回值的warnings字段)读取服务商警告,例如某个参数不被当前模型支持时:
const warnings = result.warnings;另外,API 参考中还列出了maxRetries(最大重试次数,文档标注 Default: 2)、outputFormat(如"mp3"、"wav")和language(ISO 639-1 语言码,如"en"、"es",或"auto"自动检测,文档注明 Provider support varies)等可选参数,可按需查阅 generateSpeech API 参考。
小结
完成该场景需要三步:在examples/ai-functions配好.env密钥并pnpm install+pnpm build,用generateSpeech({ model, text, ... })发起调用,再从result.audio中取uint8Array或base64消费音频数据、按mediaType落盘。运行pnpm tsx src/generate-speech/openai/basic.ts后,以控制台输出的Saved audio to ...和output/目录下的音频文件作为成功标志;若调用抛错,用NoSpeechGeneratedError.isInstance判断并通过cause与responses定位原因。
【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考