Skip to content

TTS (Text-to-Speech) ​

An AI Pod has been deployed with the Kokoro tts service, which offers fast performance.

If you need an OpenAI-compatible multi-voice TTS service, please refer to Qwen3TTS API.

The entry point for the qwen3tts-ai service can be accessed via . .

Online Demo ​

You can access the online demo at . .

The API of tts service can be accessed via .

The API interface of Qwen3TTS is documented in Qwen3TTS API.

If you need OpenAI-style POST /v1/audio/speech, or require querying /v1/audio/voices, using extended parameters instruct / language, or performing startup validation based on /health's ready=true, you should use qwen3tts-ai instead of the tts-ai described in this page.

qwen3tts-ai This document explicitly states:

  • OpenAI-style interface supports request-level language
  • OpenAI-style interface supports request-level instruct
  • OpenAI interface now supports request-level seed
  • Under the same container image version, model, and request parameters, fixed seed ensures reproducible audio output
  • This document only includes request fields actually recommended for public use; parameters like speed that are compatible but not effective are omitted from formal parameter descriptions

Standalone Deployment ​

  1. Save the following content into a docker-compose.yml file
yml
services:
  tts:
    image: registry.lazycat.cloud/x/lzc-aipod-tts:763ebf7
    ports:
      - 8880:8880
    environment:
      - PYTHONPATH=/app:/app/api
      - USE_GPU=true
      - PYTHONUNBUFFERED=1
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8880/health"]
      interval: 30s
      timeout: 5s
      retries: 100
      start_period: 1s
  1. Run docker-compose up -d to start the AI Pod in the current directory
  2. After startup, access http://127.0.0.1:8880/docs
Example
vue
<template>
  <div class="tts-player">
    <div class="input-section">
      <textarea
        v-model="text"
        placeholder="请输入要转换的文本..."
        class="text-input"
        rows="4"
      ></textarea>
      <button
        @click="synthesizeSpeech"
        :disabled="isLoading"
        class="synthesize-btn"
      >
        {{ isLoading ? "转换中..." : "转换为语音" }}
      </button>
    </div>

    <div class="player-section" v-if="audioUrl">
      <audio
        ref="audioPlayer"
        :src="audioUrl"
        controls
        class="audio-player"
      ></audio>
    </div>
  </div>
</template>

<script setup>
import { ref } from "vue";

const text = ref("欢迎使用算力舱,玩的开心。welcome use AI pod, happy hack!");
const audioUrl = ref("");
const isLoading = ref(false);
const audioPlayer = ref(null);

const domain = () => {
  const currentHost = window.location.host;
  const host = currentHost.replace(/^([^.]+)/, "tts-ai");
  const protocol = window.location.protocol;
  return `${protocol}//${host}`;
};

const synthesizeSpeech = async () => {
  if (!text.value.trim()) {
    alert("请输入要转换的文本");
    return;
  }

  isLoading.value = true;
  try {
    const response = await fetch(`${domain()}/v1/audio/speech`, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        input: text.value,
        voice: "zf_044",
        response_format: "mp3",
        download_format: "wav",
        stream: true,
        speed: 1,
        return_download_link: true,
      }),
    });

    if (!response.ok) {
      throw new Error("语音合成请求失败");
    }

    const blob = await response.blob();
    audioUrl.value = URL.createObjectURL(blob);

    // 自动播放
    if (audioPlayer.value) {
      audioPlayer.value.play();
    }
  } catch (error) {
    console.error("语音合成错误:", error);
    alert("语音合成失败,请重试");
  } finally {
    isLoading.value = false;
  }
};
</script>

<style>
.tts-player {
  margin: 0 auto;
}

.input-section {
  margin-bottom: 20px;
}

.text-input {
  width: 100%;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 4px;
  margin-bottom: 10px;
  font-size: 16px;
  resize: vertical;
}

.synthesize-btn {
  background-color: #4caf50;
  color: white;
  padding: 10px 20px;
  border: none;
  border-radius: 4px;
  cursor: pointer;
  font-size: 16px;
  transition: background-color 0.3s;
}

.synthesize-btn:hover {
  background-color: #45a049;
}

.synthesize-btn:disabled {
  background-color: #cccccc;
  cursor: not-allowed;
}

.player-section {
  margin-top: 20px;
}

.audio-player {
  width: 100%;
}
</style>