> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# 流式文本转语音

本指南介绍 3 种方法：将语音生成为文件、直接流式传输音频响应，以及可选地将生成的音频上传到 AWS S3 存储桶，并通过签名 URL 分享。

> **Note**
>
> 本指南假设你已[设置 API 密钥和 SDK](/docs/zh/eleven-api/quickstart)。如果尚未完成，请先完成
> 快速入门。可选的 S3 上传部分还需要拥有可访问 S3 的 AWS 账户。

> **Tip**
>
> 想了解流式传输为何这样运作？[了解音频 流式传输](/docs/zh/eleven-api/concepts/audio-streaming)深入讲解了协议、缓冲和
> 延迟之间的权衡。

## 将文本转换为语音（文件）

要将文本转换为语音并保存为文件，我们将使用 ElevenLabs SDK 的 `convert` 方法，然后在本地将其保存为 `.mp3` 文件。

**`Python`**

```python Python

import os
import uuid
from dotenv import load_dotenv
from elevenlabs import VoiceSettings
from elevenlabs.client import ElevenLabs

load_dotenv()

ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
elevenlabs = ElevenLabs(
    api_key=ELEVENLABS_API_KEY,
)


def text_to_speech_file(text: str) -> str:
    # Calling the text_to_speech conversion API with detailed parameters
    response = elevenlabs.text_to_speech.convert(
        voice_id="pNInz6obpgDQGcFmaJgB", # Adam pre-made voice
        output_format="mp3_22050_32",
        text=text,
        model_id="eleven_flash_v2_5", # use the flash model for low latency
        # Optional voice settings that allow you to customize the output
        voice_settings=VoiceSettings(
            stability=0.0,
            similarity_boost=1.0,
            style=0.0,
            use_speaker_boost=True,
            speed=1.0,
        ),
    )

    # uncomment the line below to play the audio back
    # play(response)

    # Generating a unique file name for the output MP3 file
    save_file_path = f"{uuid.uuid4()}.mp3"

    # Writing the audio to a file
    with open(save_file_path, "wb") as f:
        for chunk in response:
            if chunk:
                f.write(chunk)

    print(f"{save_file_path}: A new audio file was saved successfully!")

    # Return the path of the saved audio file
    return save_file_path

```

**`TypeScript`**

```typescript TypeScript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import * as dotenv from "dotenv";
import { writeFile } from "node:fs/promises";
import { v4 as uuid } from "uuid";

dotenv.config();

const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;

const elevenlabs = new ElevenLabsClient({
  apiKey: ELEVENLABS_API_KEY,
});

export const createAudioFileFromText = async (text: string): Promise<string> => {
  const audio = await elevenlabs.textToSpeech.convert("JBFqnCBsd6RMkjVDRZzb", {
    modelId: "eleven_v4",
    text,
    outputFormat: "mp3_44100_128",
    // Optional voice settings that allow you to customize the output
    voiceSettings: {
      stability: 0,
      similarityBoost: 0,
      useSpeakerBoost: true,
      speed: 1.0,
    },
  });

  const fileName = `${uuid()}.mp3`;
  await writeFile(fileName, Buffer.from(await new Response(audio).arrayBuffer()));
  return fileName;
};
```

然后可以通过以下方式运行此函数：

**`Python`**

```python Python
text_to_speech_file("Hello World")
```

**`TypeScript`**

```typescript TypeScript
await createAudioFileFromText("Hello World");
```

## 将文本转换为语音（流式传输）

如果希望直接流式传输音频而不保存为文件，可以使用流式传输功能。

**`Python`**

```python Python

import os
from typing import IO
from io import BytesIO
from dotenv import load_dotenv
from elevenlabs import VoiceSettings
from elevenlabs.client import ElevenLabs

load_dotenv()

ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
elevenlabs = ElevenLabs(
    api_key=ELEVENLABS_API_KEY,
)


def text_to_speech_stream(text: str) -> IO[bytes]:
    # Perform the text-to-speech conversion
    response = elevenlabs.text_to_speech.stream(
        voice_id="pNInz6obpgDQGcFmaJgB", # Adam pre-made voice
        output_format="mp3_22050_32",
        text=text,
        model_id="eleven_multilingual_v2",
        # Optional voice settings that allow you to customize the output
        voice_settings=VoiceSettings(
            stability=0.0,
            similarity_boost=1.0,
            style=0.0,
            use_speaker_boost=True,
            speed=1.0,
        ),
    )

    # Create a BytesIO object to hold the audio data in memory
    audio_stream = BytesIO()

    # Write each chunk of audio data to the stream
    for chunk in response:
        if chunk:
            audio_stream.write(chunk)

    # Reset stream position to the beginning
    audio_stream.seek(0)

    # Return the stream for further use
    return audio_stream

```

**`TypeScript`**

```typescript TypeScript
import { ElevenLabsClient } from "@elevenlabs/elevenlabs-js";
import * as dotenv from "dotenv";

dotenv.config();

const ELEVENLABS_API_KEY = process.env.ELEVENLABS_API_KEY;

if (!ELEVENLABS_API_KEY) {
  throw new Error("Missing ELEVENLABS_API_KEY in environment variables");
}

const elevenlabs = new ElevenLabsClient({
  apiKey: ELEVENLABS_API_KEY,
});

export const createAudioStreamFromText = async (text: string): Promise<Buffer> => {
  const audioStream = await elevenlabs.textToSpeech.stream("JBFqnCBsd6RMkjVDRZzb", {
    modelId: "eleven_v4",
    text,
    outputFormat: "mp3_44100_128",
    // Optional voice settings that allow you to customize the output
    voiceSettings: {
      stability: 0,
      similarityBoost: 1.0,
      useSpeakerBoost: true,
      speed: 1.0,
    },
  });

  const chunks: Buffer[] = [];
  for await (const chunk of audioStream) {
    chunks.push(chunk);
  }

  const content = Buffer.concat(chunks);
  return content;
};
```

然后可以通过以下方式运行此函数：

**`Python`**

```python Python
text_to_speech_stream("This is James")
```

**`TypeScript`**

```typescript TypeScript
await createAudioStreamFromText("This is James");
```

## 额外内容：上传到 AWS S3 并获取安全分享链接

将音频数据创建为文件或流后，可能希望与用户分享。一个方法是将其上传到 AWS S3 存储桶，并生成安全分享链接。

#### 创建 AWS 凭证

要将数据上传到 S3，需要将 AWS 访问密钥 ID、私有访问密钥和 AWS 区域名称添加到 `.env` 文件。按照以下步骤查找凭证：

1. 登录 AWS 管理控制台：前往 AWS 主页并登录账户。

![](/docs/_fern-img/e9f1f1b1950962c3d67ea25a0593ca989d33c9f49b641e22eb3f861fc72735e3.webp)

2. 打开 IAM（身份和访问管理）控制面板：可在服务菜单的“安全、身份与合规性”下找到 IAM。IAM 控制面板可安全管理对 AWS 服务的访问权限。

![](/docs/_fern-img/d6fa7e75879e7537693c4edde16d0ac5face78d72b00de50743a754c0681a5e3.webp)

3. 创建新用户（如有需要）：在 IAM 控制面板中，选择“用户”，然后选择“添加用户”。输入用户名。

![](/docs/_fern-img/47b05ffda6925e4e14147aadc296d7c86cbd3340aaa1025083f1e1464b230f51.webp)

4. 设置权限：根据希望授予的访问级别，直接向用户附加策略。对于 S3 上传，可以使用 AmazonS3FullAccess 策略。但最佳做法是遵循最小权限原则，仅授予完成任务所需的最少权限。你可能需要创建自定义策略，只允许对 S3 存储桶执行必要操作。

![](/docs/_fern-img/4b88bba4f5bb1509aa087a1ab5cc8068a274b17d8887c563f050b77e8438bb94.webp)

5. 检查并创建用户：检查设置后创建用户。创建完成后，将看到访问密钥 ID 和私有访问密钥。务必下载并安全保存这些凭证；完成此步骤后，无法再次获取私有访问密钥。

![](/docs/_fern-img/27dcdff3681522cf936ff6bfb81cf216ada1fe401c7c1dbd10e58cead8a48abc.webp)

6. 获取 AWS 区域名称：例如 us-east-1

![](/docs/_fern-img/016bc11c2f040942b215366c5fc9ac8e01f6261f5ebd44a3456d4b7ba97e9ae8.webp)

如果没有 AWS S3 存储桶，需要按照以下步骤新建一个：

1. 打开 S3 控制面板：可在服务菜单的“存储”下找到 S3。

![](/docs/_fern-img/d2455fa92ce6dfa705c3b91144fe22539fae1611848cb8e3cc2dac20e57db4e7.webp)

2. 创建新存储桶：在 S3 控制面板中，点击“创建存储桶”按钮。

![](/docs/_fern-img/3b7d5bdb6559e8511445b41b1bbdeed3f6674791cf23021a30ccb5aa8143be28.webp)

3. 输入存储桶名称并点击“创建存储桶”按钮。其他存储桶选项可保留默认值。新添加的存储桶将显示在列表中。

![](/docs/_fern-img/68d23f21bec1e3aa70b18f09c40c9bdace5ff0dd63edc17c6807e7ddac75758d.webp)![](/docs/_fern-img/63f7af93d4a73fab3011853c8393c954400d9f344a5811ec90b86d6c69b2ec16.webp)

#### 安装 AWS SDK 并添加凭证

使用 `pip` 和 `npm` 安装用于与 AWS 服务交互的 `boto3`。

**`Python`**

```bash Python
pip install boto3
```

**`TypeScript`**

```bash TypeScript
npm install @aws-sdk/client-s3
npm install @aws-sdk/s3-request-presigner
```

然后按如下方式将环境变量添加到 `.env` 文件：

```
AWS_ACCESS_KEY_ID=your_aws_access_key_id_here
AWS_SECRET_ACCESS_KEY=your_aws_secret_access_key_here
AWS_REGION_NAME=your_aws_region_name_here
AWS_S3_BUCKET_NAME=your_s3_bucket_name_here
```

#### 上传到 AWS S3 并生成签名 URL

添加以下函数，将音频流上传到 S3 并生成签名 URL。

**`s3_uploader.py (Python)`**

```python s3_uploader.py (Python)

import os
import boto3
import uuid

AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_REGION_NAME = os.getenv("AWS_REGION_NAME")
AWS_S3_BUCKET_NAME = os.getenv("AWS_S3_BUCKET_NAME")

session = boto3.Session(
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name=AWS_REGION_NAME,
)
s3 = session.client("s3")


def generate_presigned_url(s3_file_name: str) -> str:
    signed_url = s3.generate_presigned_url(
        "get_object",
        Params={"Bucket": AWS_S3_BUCKET_NAME, "Key": s3_file_name},
        ExpiresIn=3600,
    )  # URL expires in 1 hour
    return signed_url


def upload_audiostream_to_s3(audio_stream) -> str:
    s3_file_name = f"{uuid.uuid4()}.mp3"  # Generates a unique file name using UUID
    s3.upload_fileobj(audio_stream, AWS_S3_BUCKET_NAME, s3_file_name)

    return s3_file_name

```

**`s3_uploader.ts (TypeScript)`**

```typescript s3_uploader.ts (TypeScript)
import { S3Client, PutObjectCommand, GetObjectCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import * as dotenv from "dotenv";
import { v4 as uuid } from "uuid";

dotenv.config();

const { AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION_NAME, AWS_S3_BUCKET_NAME } =
  process.env;

if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY || !AWS_REGION_NAME || !AWS_S3_BUCKET_NAME) {
  throw new Error("One or more environment variables are not set. Please check your .env file.");
}

const s3 = new S3Client({
  credentials: {
    accessKeyId: AWS_ACCESS_KEY_ID,
    secretAccessKey: AWS_SECRET_ACCESS_KEY,
  },
  region: AWS_REGION_NAME,
});

export const generatePresignedUrl = async (objectKey: string) => {
  const getObjectParams = {
    Bucket: AWS_S3_BUCKET_NAME,
    Key: objectKey,
    Expires: 3600,
  };
  const command = new GetObjectCommand(getObjectParams);
  const url = await getSignedUrl(s3, command, { expiresIn: 3600 });
  return url;
};

export const uploadAudioStreamToS3 = async (audioStream: Buffer) => {
  const remotePath = `${uuid()}.mp3`;
  await s3.send(
    new PutObjectCommand({
      Bucket: AWS_S3_BUCKET_NAME,
      Key: remotePath,
      Body: audioStream,
      ContentType: "audio/mpeg",
    })
  );
  return remotePath;
};
```

然后可以使用文本生成的音频流调用上传函数。

**`Python`**

```python Python
s3_file_name = upload_audiostream_to_s3(audio_stream)
```

**`TypeScript`**

```typescript TypeScript
const s3path = await uploadAudioStreamToS3(stream);
```

将音频文件上传到 S3 后，生成签名 URL 以分享文件访问权限。此 URL 有时间限制，会在一段时间后过期，因此适合临时安全分享。

现在可以通过以下方式从文件生成 URL：

**`Python`**

```python Python
signed_url = generate_presigned_url(s3_file_name)
print(f"Signed URL to access the file: {signed_url}")
```

**`TypeScript`**

```typescript TypeScript
const presignedUrl = await generatePresignedUrl(s3path);
console.log("Presigned URL:", presignedUrl);
```

如果要多次使用该文件，应在数据库中存储 S3 文件路径，并在每次需要时重新生成签名 URL，而不是直接保存会过期的签名 URL。

#### 整合起来

要将所有内容整合起来，可以使用以下脚本：

**`main.py (Python)`**

```python main.py (Python)

import os

from dotenv import load_dotenv

load_dotenv()

from text_to_speech_stream import text_to_speech_stream
from s3_uploader import upload_audiostream_to_s3, generate_presigned_url


def main():
    text = "This is James"

    audio_stream = text_to_speech_stream(text)
    s3_file_name = upload_audiostream_to_s3(audio_stream)
    signed_url = generate_presigned_url(s3_file_name)

    print(f"Signed URL to access the file: {signed_url}")


if __name__ == "__main__":
    main()

```

**`index.ts (Typescript)`**

```typescript index.ts (Typescript)
import "dotenv/config";

import { generatePresignedUrl, uploadAudioStreamToS3 } from "./s3_uploader";
import { createAudioFileFromText } from "./text_to_speech_file";
import { createAudioStreamFromText } from "./text_to_speech_stream";

(async () => {
  // save the audio file to disk
  const fileName = await createAudioFileFromText(
    "Today, the sky is exceptionally clear, and the sun shines brightly."
  );

  console.log("File name:", fileName);

  // OR stream the audio, upload to S3, and get a presigned URL
  const stream = await createAudioStreamFromText(
    "Today, the sky is exceptionally clear, and the sun shines brightly."
  );

  const s3path = await uploadAudioStreamToS3(stream);

  const presignedUrl = await generatePresignedUrl(s3path);

  console.log("Presigned URL:", presignedUrl);
})();
```

## 总结

现在你已了解如何将文本转换为语音，并生成签名 URL 来分享音频文件。此功能为动态创建和分享内容带来许多可能性。

以下是一些可以基于此构建的示例。

1. **教育播客**：创建学生可随时访问的个性化教育内容。教师可将课程转换为音频格式，上传到 S3，并与学生分享链接，让他们在传统课堂之外获得更具吸引力的学习体验。

2. **网站无障碍功能**：以音频格式提供文本内容，提升网站无障碍性。这能让视障人士或偏好听觉学习的用户更方便地获取网站信息。

3. **自动化客户支持消息**：为客户支持生成自动化、个性化的音频消息，例如常见问题解答或订单更新。与传统文本邮件相比，这可带来更具吸引力的客户体验。

4. **有声书和旁白配音**：将整本书或短篇故事转换为音频格式，为受众提供欣赏文学作品的新方式。作者和出版商可丰富内容形式，触达偏好聆听而非阅读的受众。

5. **语言学习工具**：开发为学习者提供音频课程和练习的语言学习辅助工具，从而有针对性地练习发音和听力技能。

## 后续步骤

#### [WebSocket 流式传输](/docs/zh/eleven-api/guides/how-to/websockets/realtime-tts)

使用 WebSocket，实时流式传输由 LLM 生成的文本转语音内容。

#### [了解延迟](/docs/zh/eleven-api/concepts/latency)

了解影响延迟的因素，以及如何缩短首段音频生成时间。