> ## Documentation Index
> Fetch the complete documentation index at: https://docs.senseaudio.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# 语音合成 HTTP 流式 (TTS-SSE)

> 基于 SSE 的流式 TTS 合成接口参考

## 说明

将文本通过 SSE 协议流式合成为语音，适用于低延迟、边合成边播放的实时场景。请求参数与 [语音合成 HTTP](/api-reference/endpoint/tts/synthesize) 完全相同，仅需将 `stream` 设为 `true`；响应为 `text/event-stream`。

* **接口地址**：`https://api.senseaudio.cn/v1/t2a_v2`
* **Content-Type（请求）**：`application/json`
* **Content-Type（响应）**：`text/event-stream; charset=utf-8`
* **鉴权方式**：Bearer Token，详见 [快速接入](/guides/account/quick-access)
* **语音合成**：参考 [语音合成 HTTP](/api-reference/endpoint/tts/synthesize)
* **WebSocket 合成**：参考 [语音合成 WebSocket](/api-reference/endpoint/tts/websocket)

<Note>
  流式模式要求 `stream` 固定为 `true`；响应采用 SSE 格式，每个事件以 `data: ` 前缀 + JSON 对象返回，`extra_info` 仅在最后一个 chunk 返回。
</Note>

## SSE 响应格式

响应 `Content-Type: text/event-stream; charset=utf-8`。每个数据块以 `data: ` 开头，后跟一个 JSON 对象，字段与同步返回的 `TTSResponse` 一致，`data.status` 用于标识分片顺序。

<ResponseField name="data" type="object">
  合成数据对象，可能为 null，需进行非空判断。

  <Expandable title="child attributes">
    <ResponseField name="data.audio" type="string">
      合成后的音频数据，hex 编码，格式与请求中指定的 `audio_setting.format` 一致。
    </ResponseField>

    <ResponseField name="data.status" type="integer">
      当前音频流状态：`1` 表示合成中，`2` 表示合成结束。
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="extra_info" type="object">
  音频附加信息，**仅在最后一个 chunk 返回**。

  <Expandable title="child attributes">
    <ResponseField name="extra_info.audio_length" type="integer">音频时长（毫秒）。</ResponseField>
    <ResponseField name="extra_info.audio_sample_rate" type="integer">音频采样率。</ResponseField>
    <ResponseField name="extra_info.audio_size" type="integer">音频文件大小（字节）。</ResponseField>
    <ResponseField name="extra_info.bitrate" type="integer">音频比特率。</ResponseField>
    <ResponseField name="extra_info.audio_format" type="string">音频格式：`mp3` / `pcm` / `flac` / `wav`。</ResponseField>
    <ResponseField name="extra_info.audio_channel" type="integer">声道数：`1` 单声道 / `2` 双声道。</ResponseField>
    <ResponseField name="extra_info.word_count" type="integer">字数：按 grapheme cluster 统计，排除纯空白/标点/控制符。</ResponseField>
    <ResponseField name="extra_info.usage_characters" type="integer">字符数：按 Unicode 码点统计。</ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="trace_id" type="string">链路追踪 ID。</ResponseField>

<ResponseField name="base_resp" type="object">
  本次请求的状态码和详情。

  <Expandable title="child attributes">
    <ResponseField name="base_resp.status_code" type="integer">状态码，`0` 表示成功。</ResponseField>
    <ResponseField name="base_resp.status_msg" type="string">状态详情。</ResponseField>
  </Expandable>
</ResponseField>

### 流式响应示例

```
data: {"data":{"audio":"49443304...","status":1},"extra_info":null,"trace_id":"69c20e38c8761996a85d57881fe4d817","base_resp":{"status_code":0,"status_msg":""}}

data: {"data":{"audio":"fffb9864...","status":1},"extra_info":null,"trace_id":"69c20e38c8761996a85d57881fe4d817","base_resp":{"status_code":0,"status_msg":""}}

data: {"data":{"audio":"fffb9864...","status":2},"extra_info":{"audio_length":2306,"audio_sample_rate":32000,"audio_size":36908,"bitrate":128000,"audio_format":"mp3","audio_channel":2,"word_count":24,"usage_characters":30},"trace_id":"69c20e38c8761996a85d57881fe4d817","base_resp":{"status_code":0,"status_msg":"success"}}
```

## 代码示例

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.senseaudio.cn/v1/t2a_v2 \
    -H "Authorization: Bearer $SENSEAUDIO_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "senseaudio-tts-1.5-260319",
      "text": "这是一个流式输出的例子。",
      "stream": true,
      "voice_setting": {
        "voice_id": "male_0004_a",
        "latex_read": false
      },
      "stream_options": {
        "exclude_aggregated_audio": true
      }
    }'
  ```

  ```python Python theme={null}
  import requests
  import json

  API_URL = "https://api.senseaudio.cn/v1/t2a_v2"
  HEADERS = {
      "Authorization": "Bearer SENSEAUDIO_API_KEY",
      "Content-Type": "application/json"
  }

  def tts_stream():
      payload = {
          "model": "senseaudio-tts-1.5-260319",
          "text": "这是一个流式输出的例子。",
          "stream": True,
          "voice_setting": {
              "voice_id": "male_0004_a",
              "latex_read": False
          },
          "stream_options": {
              "exclude_aggregated_audio": True
          }
      }
      with requests.post(API_URL, json=payload, headers=HEADERS, stream=True) as r:
          with open("stream_output.mp3", "wb") as f:
              for line in r.iter_lines():
                  if line:
                      line_str = line.decode('utf-8')
                      if line_str.startswith("data: "):
                          line_str = line_str[6:]
                      resp = json.loads(line_str)
                      if "data" in resp and "audio" in resp["data"]:
                          f.write(bytes.fromhex(resp["data"]["audio"]))
          print("流式合成完成")

  if __name__ == "__main__":
      tts_stream()
  ```

  ```javascript JavaScript theme={null}
  const axios = require('axios');
  const fs = require('fs');

  const API_URL = 'https://api.senseaudio.cn/v1/t2a_v2';
  const HEADERS = {
      'Authorization': 'Bearer SENSEAUDIO_API_KEY',
      'Content-Type': 'application/json'
  };

  async function ttsStream() {
      try {
          const payload = {
              model: 'senseaudio-tts-1.5-260319',
              text: '这是一个流式输出的例子。',
              stream: true,
              voice_setting: {
                  voice_id: 'male_0004_a',
                  latex_read: false
              },
              stream_options: {
                  exclude_aggregated_audio: true
              }
          };

          const res = await axios.post(API_URL, payload, {
              headers: HEADERS,
              responseType: 'stream'
          });

          const writeStream = fs.createWriteStream('stream_output.mp3');

          res.data.on('data', (chunk) => {
              const lines = chunk.toString().split('\n');
              for (const line of lines) {
                  if (line.startsWith('data: ')) {
                      try {
                          const json = JSON.parse(line.slice(6));
                          if (json.data && json.data.audio) {
                              writeStream.write(Buffer.from(json.data.audio, 'hex'));
                          }
                      } catch (e) {}
                  }
              }
          });

          res.data.on('end', () => {
              writeStream.end();
              console.log('流式合成完成');
          });
      } catch (err) {
          console.error('请求异常:', err.message);
      }
  }

  ttsStream();
  ```

  ```go Go theme={null}
  package main

  import (
      "bufio"
      "bytes"
      "encoding/hex"
      "encoding/json"
      "fmt"
      "net/http"
      "os"
      "strings"
  )

  const (
      APIURL             = "https://api.senseaudio.cn/v1/t2a_v2"
      SENSEAUDIO_API_KEY = "SENSEAUDIO_API_KEY"
  )

  type TTSRequest struct {
      Model         string        `json:"model"`
      Text          string        `json:"text"`
      Stream        bool          `json:"stream"`
      VoiceSetting  VoiceSetting  `json:"voice_setting"`
      StreamOptions StreamOptions `json:"stream_options"`
  }

  type StreamOptions struct {
      ExcludeAggregatedAudio bool `json:"exclude_aggregated_audio"`
  }

  type VoiceSetting struct {
      VoiceID   string `json:"voice_id"`
      LatexRead bool   `json:"latex_read"`
  }

  type SSEResponse struct {
      Data struct {
          Audio  string `json:"audio"`
          Status int    `json:"status"`
      } `json:"data"`
      BaseResp struct {
          StatusCode    int    `json:"status_code"`
          StatusMessage string `json:"status_msg"`
      } `json:"base_resp"`
  }

  func main() {
      payload := TTSRequest{
          Model:  "senseaudio-tts-1.5-260319",
          Text:   "这是一个流式输出的例子。",
          Stream: true,
          VoiceSetting: VoiceSetting{
              VoiceID:   "male_0004_a",
              LatexRead: false,
          },
          StreamOptions: StreamOptions{
              ExcludeAggregatedAudio: true,
          },
      }

      jsonData, _ := json.Marshal(payload)
      req, _ := http.NewRequest("POST", APIURL, bytes.NewBuffer(jsonData))
      req.Header.Set("Authorization", "Bearer "+SENSEAUDIO_API_KEY)
      req.Header.Set("Content-Type", "application/json")

      client := &http.Client{}
      resp, err := client.Do(req)
      if err != nil {
          fmt.Println("请求失败:", err)
          return
      }
      defer resp.Body.Close()

      file, _ := os.Create("stream_output.mp3")
      defer file.Close()

      scanner := bufio.NewScanner(resp.Body)
      for scanner.Scan() {
          line := scanner.Text()
          if strings.HasPrefix(line, "data: ") {
              var result SSEResponse
              json.Unmarshal([]byte(line[6:]), &result)
              if result.Data.Audio != "" {
                  audioData, _ := hex.DecodeString(result.Data.Audio)
                  file.Write(audioData)
              }
          }
      }
      fmt.Println("流式合成完成")
  }
  ```

  ```java Java theme={null}
  import java.io.*;
  import java.net.HttpURLConnection;
  import java.net.URL;
  import org.json.JSONObject;

  public class SenseAudioTTSStream {
      private static final String API_URL = "https://api.senseaudio.cn/v1/t2a_v2";
      private static final String SENSEAUDIO_API_KEY = "SENSEAUDIO_API_KEY";

      public static void main(String[] args) {
          try {
              JSONObject voiceSetting = new JSONObject();
              voiceSetting.put("voice_id", "male_0004_a");
              voiceSetting.put("latex_read", false);

              JSONObject payload = new JSONObject();
              payload.put("model", "senseaudio-tts-1.5-260319");
              payload.put("text", "这是一个流式输出的例子。");
              payload.put("stream", true);
              payload.put("voice_setting", voiceSetting);
              payload.put("stream_options", new JSONObject().put("exclude_aggregated_audio", true));

              URL url = new URL(API_URL);
              HttpURLConnection conn = (HttpURLConnection) url.openConnection();
              conn.setRequestMethod("POST");
              conn.setRequestProperty("Authorization", "Bearer " + SENSEAUDIO_API_KEY);
              conn.setRequestProperty("Content-Type", "application/json");
              conn.setDoOutput(true);

              try (OutputStream os = conn.getOutputStream()) {
                  byte[] input = payload.toString().getBytes("utf-8");
                  os.write(input, 0, input.length);
              }

              try (BufferedReader br = new BufferedReader(
                      new InputStreamReader(conn.getInputStream(), "utf-8"));
                   FileOutputStream fos = new FileOutputStream("stream_output.mp3")) {

                  String line;
                  while ((line = br.readLine()) != null) {
                      if (line.startsWith("data: ")) {
                          String jsonStr = line.substring(6);
                          JSONObject result = new JSONObject(jsonStr);
                          if (result.has("data")) {
                              JSONObject data = result.getJSONObject("data");
                              if (data.has("audio")) {
                                  String audioHex = data.getString("audio");
                                  byte[] audioData = new byte[audioHex.length() / 2];
                                  for (int i = 0; i < audioData.length; i++) {
                                      int index = i * 2;
                                      int val = Integer.parseInt(audioHex.substring(index, index + 2), 16);
                                      audioData[i] = (byte) val;
                                  }
                                  fos.write(audioData);
                              }
                          }
                      }
                  }
                  System.out.println("流式合成完成");
              }
          } catch (Exception e) {
              System.out.println("请求异常: " + e.getMessage());
              e.printStackTrace();
          }
      }
  }
  ```
</CodeGroup>

## 相关指南

* [语音合成 HTTP](/api-reference/endpoint/tts/synthesize)
* [语音合成 WebSocket](/api-reference/endpoint/tts/websocket)
* [语音合成与音色概览](/guides/tts/overview)
* [自定义音色（克隆与文生音色）](/guides/voice/custom)


## OpenAPI

````yaml api-reference/endpoint/tts/synthesize-stream.openapi.json POST /v1/t2a_v2
openapi: 3.1.0
info:
  title: SenseAudio - 语音合成 HTTP 流式
  version: 1.0.0
servers:
  - url: https://api.senseaudio.cn
    description: 生产环境
security:
  - bearerAuth: []
paths:
  /v1/t2a_v2:
    post:
      tags:
        - Text to Speech
      summary: 语音合成 HTTP 流式 (TTS-SSE)
      description: >-
        基于 SSE 的流式 TTS 合成接口。请求参数与同步合成一致，`stream` 固定为 `true`；响应 `Content-Type:
        text/event-stream; charset=utf-8`，每个事件以 `data: ` 前缀 + JSON
        对象返回，`extra_info` 仅在最后一个 chunk 返回。
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TTSStreamRequest'
            example:
              model: senseaudio-tts-1.5-260319
              text: 这是一个流式输出的例子。
              stream: true
              voice_setting:
                voice_id: male_0004_a
                latex_read: false
              stream_options:
                exclude_aggregated_audio: true
      responses:
        '200':
          description: 'SSE 流式响应。每行以 `data: ` 开头，后跟一个 `TTSStreamChunk` JSON 对象；事件之间以空行分隔。'
          content:
            text/event-stream:
              schema:
                $ref: '#/components/schemas/TTSStreamChunk'
              example:
                - data:
                    audio: 49443304...
                    status: 1
                  extra_info: null
                  trace_id: 69c20e38c8761996a85d57881fe4d817
                  base_resp:
                    status_code: 0
                    status_msg: ''
                - data:
                    audio: fffb9864...
                    status: 2
                  extra_info:
                    audio_length: 2306
                    audio_sample_rate: 32000
                    audio_size: 36908
                    bitrate: 128000
                    audio_format: mp3
                    audio_channel: 2
                    word_count: 24
                    usage_characters: 30
                  trace_id: 69c20e38c8761996a85d57881fe4d817
                  base_resp:
                    status_code: 0
                    status_msg: success
        '401':
          description: 鉴权失败
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    TTSStreamRequest:
      type: object
      required:
        - model
        - text
        - stream
        - voice_setting
      properties:
        model:
          type: string
          enum:
            - senseaudio-tts-1.5-260319
          default: senseaudio-tts-1.5-260319
          example: senseaudio-tts-1.5-260319
          description: >-
            TTS 模型 ID。`senseaudio-tts-1.5-260319`
            为推荐版本（情绪/多音字/公式朗读支持，且支持克隆与文生音色）；
        text:
          type: string
          description: >-
            合成文本，最大 10000 字符，支持 停顿符。其中time 单位为毫秒（ms）、500 表示停顿 500 毫秒、最小值为 100
            毫秒，最大值无限制。
          example: 你好，这是来自 <break time=500> SenseAudio 的第一条语音
        stream:
          type: boolean
          enum:
            - true
          default: true
          example: true
          description: 流式模式必须为 `true`
        voice_setting:
          $ref: '#/components/schemas/VoiceSetting'
        audio_setting:
          $ref: '#/components/schemas/AudioSetting'
        dictionary:
          type: array
          items:
            $ref: '#/components/schemas/DictionaryItem'
          example:
            - original: 好干净
              replacement: '[hao4]干净'
        stream_options:
          $ref: '#/components/schemas/StreamOptions'
    TTSStreamChunk:
      type: object
      description: 'SSE 单个事件的 JSON 载荷（去除 `data: ` 前缀后的内容）。'
      properties:
        data:
          type: object
          nullable: true
          properties:
            audio:
              type: string
              description: hex 编码音频分片
            status:
              type: integer
              description: 1 合成中 2 合成结束
        extra_info:
          type: object
          nullable: true
          description: 仅在最后一个 chunk（`data.status=2`）返回。
          properties:
            audio_length:
              type: integer
            audio_sample_rate:
              type: integer
            audio_size:
              type: integer
            bitrate:
              type: integer
            audio_format:
              type: string
            audio_channel:
              type: integer
            word_count:
              type: integer
            usage_characters:
              type: integer
        trace_id:
          type: string
        base_resp:
          $ref: '#/components/schemas/BaseResp'
    ErrorResponse:
      type: object
      properties:
        code:
          type: string
        message:
          type: string
    VoiceSetting:
      type: object
      required:
        - voice_id
      properties:
        voice_id:
          type: string
          description: 系统/克隆/文生音色 ID
          example: male_0004_a
        speed:
          type: number
          default: 1
          description: 语速 [0.5, 2.0]
        vol:
          type: number
          default: 1
          description: 音量 [0.01, 10.0]
        pitch:
          type: integer
          default: 0
          description: 音调 [-12, 12]
        latex_read:
          type: boolean
          default: false
          description: >-
            控制是否朗读 latex 公式，默认为 false。


            - 请求中的公式需要在公式的首尾加上 `$$`。

            - 请求中公式若有 `\`，需转义成 `\\`。


            示例：动能公式


            <img src="/images/tts/latex-read-example.png" alt="动能公式" width="128"
            />


            表示为：`$$E_k = \\frac{1}{2} m v^2$$`
    AudioSetting:
      type: object
      properties:
        format:
          type: string
          enum:
            - mp3
            - wav
            - pcm
            - flac
          default: mp3
        sample_rate:
          type: integer
          enum:
            - 8000
            - 16000
            - 22050
            - 24000
            - 32000
            - 44100
          default: 32000
        bitrate:
          type: integer
          enum:
            - 32000
            - 64000
            - 128000
            - 256000
          default: 128000
        channel:
          type: integer
          enum:
            - 1
            - 2
          default: 2
    DictionaryItem:
      type: object
      properties:
        original:
          type: string
          example: 好干净
        replacement:
          type: string
          example: '[hao4]干净'
    StreamOptions:
      type: object
      properties:
        exclude_aggregated_audio:
          type: boolean
          default: false
          description: 是否在最后一个 chunk 中排除聚合音频
    BaseResp:
      type: object
      description: 通用状态结构
      properties:
        status_code:
          type: integer
          description: 0 表示成功，非 0 表示失败
        status_msg:
          type: string
          description: 状态详情
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API_KEY
      description: 格式：`Bearer <API_KEY>`

````