تبدیل متن به گفتار — Text-to-speech

آشا تبدیل متن به گفتار (TTS) را از طریق endpoint اختصاصیِ /v1/audio/speech که با OpenAI Audio Speech API سازگار است پشتیبانی می‌کند. متن بفرستید و خروجیِ صوت خام در فرمت دلخواه بگیرید.

کشف مدل‌ها

مدل‌های TTS را از چند راه می‌توانید پیدا کنید:

از طریق API

همهٔ مدل‌ها را با endpoint سازگار با OpenAI یعنی GET /v1/models فهرست کنید. مدل‌های سنتز گفتار با حالتِ text->audio در architecture.modality قابل شناسایی‌اند:

cURL GET /v1/models
curl "https://app.asha-ai.ir/v1/models"

در صفحهٔ مدل‌ها

در فهرست مدل‌ها با فیلتر «صوتی» (Audio) مدل‌های صوتی — از جمله سنتز گفتار — را ببینید. این فیلتر سمتِ کلاینت و بر اساس نوع مدل در داشبورد اعمال می‌شود.

استفاده از API

درخواست POST به /v1/audio/speech با متنی که می‌خواهید سنتز کنید بفرستید. پاسخ یک جریانِ بایت خامِ صوت است (نه JSON)، پس می‌توانید مستقیم در فایل یا پخش‌کننده صوتی استفاده کنید.

مثال ساده

import os

import requests

response = requests.post(
    url="https://app.asha-ai.ir/v1/audio/speech",
    headers={
        "Authorization": f"Bearer {os.environ['ASHA_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={
        "model": "~openai/gpt-4o-mini-tts",
        "input": "Hello! This is a text-to-speech test.",
        "voice": "alloy",
        "response_format": "mp3",
    },
)
response.raise_for_status()

with open("output.mp3", "wb") as f:
    f.write(response.content)

generation_id = response.headers.get("X-Generation-Id")
print(f"Audio saved. Generation ID: {generation_id}")
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	payload := map[string]any{
		"model":           "~openai/gpt-4o-mini-tts",
		"input":           "Hello! This is a text-to-speech test.",
		"voice":           "alloy",
		"response_format": "mp3",
	}
	body, _ := json.Marshal(payload)

	req, _ := http.NewRequest("POST", "https://app.asha-ai.ir/v1/audio/speech", bytes.NewReader(body))
	req.Header.Set("Authorization", "Bearer "+os.Getenv("ASHA_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	resp, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		raw, _ := io.ReadAll(resp.Body)
		panic(fmt.Sprintf("TTS error %d: %s", resp.StatusCode, raw))
	}

	out, _ := os.Create("output.mp3")
	defer out.Close()
	_, _ = io.Copy(out, resp.Body)

	fmt.Println("Generation ID:", resp.Header.Get("X-Generation-Id"))
}
const response = await fetch("https://app.asha-ai.ir/v1/audio/speech", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ASHA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "~openai/gpt-4o-mini-tts",
    input: "Hello! This is a text-to-speech test.",
    voice: "alloy",
    response_format: "mp3",
  }),
});

if (!response.ok) {
  const err = await response.json();
  throw new Error(`TTS error ${response.status}: ${JSON.stringify(err)}`);
}

const audioBuffer = await response.arrayBuffer();
const generationId = response.headers.get("X-Generation-Id");
console.log(`Generation ID: ${generationId}`);
// Save audioBuffer to a file or play it directly
const response = await fetch("https://app.asha-ai.ir/v1/audio/speech", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ASHA_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "~openai/gpt-4o-mini-tts",
    input: "Hello! This is a text-to-speech test.",
    voice: "alloy",
    response_format: "mp3",
  }),
});

if (!response.ok) {
  const err = await response.json();
  throw new Error(`TTS error ${response.status}: ${JSON.stringify(err)}`);
}

const audioBuffer = await response.arrayBuffer();
const generationId = response.headers.get("X-Generation-Id");
console.log(`Generation ID: ${generationId}`);
// Save audioBuffer to a file or play it directly
curl https://app.asha-ai.ir/v1/audio/speech 
  -H "Content-Type: application/json" 
  -H "Authorization: Bearer $ASHA_API_KEY" 
  --output output.mp3 
  -d '{
    "model": "~openai/gpt-4o-mini-tts",
    "input": "Hello! This is a text-to-speech test.",
    "voice": "alloy",
    "response_format": "mp3"
  }'

پارامترهای درخواست

پارامترنوعالزامیشرح
modelstringبلهمدل TTS (مثل ~openai/gpt-4o-mini-tts، ~mistralai/voxtral-mini-tts)
inputstringبلهمتنی که باید گفتار شود
voicestringوابسته به ارائه‌دهندهشناسهٔ صدا؛ صداها بسته به مدل متفاوت‌اند، پس در صفحهٔ همان مدل چک کنید. این پارامتر را فقط وقتی حذف کنید که ارائه‌دهندهٔ انتخاب‌شده صدا را مستند کرده باشد
response_formatstringخیرفرمت خروجی صدا: mp3 یا pcm؛ پیش‌فرض pcm
speednumberخیرضریب سرعت پخش؛ فقط مدل‌هایی که پشتیبانی می‌کنند (مثل OpenAI TTS)؛ پیش‌فرض 1.0
input_referencesarrayخیرمحتویات مرجع برای کلون‌سازی صدای بدون‌وضعیت: یک بخش input_audio با نمونهٔ صدا و اختیاری یک بخش text با رونوشت؛ به «کلون‌سازی صدا» مراجعه کنید
providerobjectخیرپیکربندی عبور پارامترهای مختص ارائه‌دهنده

وقتی voice حذف شود، آشا درخواست را فقط به ارائه‌دهنده‌هایی می‌فرستد که adapterشان صدای پیش‌فرضِ سمت ارائه‌دهنده را پشتیبانی می‌کند. برای بقیهٔ ارائه‌دهنده‌ها درخواست با خطای اعتبارسنجی رد می‌شود.

کلون‌سازی صدا

برخی مدل‌ها کلون‌سازی صدای بدون‌وضعیت را پشتیبانی می‌کنند: یک نمونهٔ کوتاه از صدای مرجع را مستقیم با درخواست TTS می‌فرستید و گفتارِ تولیدشده همان صدا را تقلید می‌کند. هیچ مرحلهٔ جداگانهٔ ساخت صدا یا آپلود لازم نیست.

صدای مرجع را به‌صورت بخش input_audio با base64 در input_references بفرستید (URI با data:audio/...;base64, هم کار می‌کند) و اختیاری رونوشتش را به‌صورت بخش text اضافه کنید:

JSON request
{
  "model": "~fish-audio/s2.1-pro",
  "input": "Hello from my cloned voice!",
  "response_format": "mp3",
  "input_references": [
    { "type": "input_audio", "input_audio": { "data": "data:audio/wav;base64,UklGRuQXDAB..." } },
    { "type": "text", "text": "This is the transcript of the reference audio." }
  ]
}

برخی ارائه‌دهنده‌های یک مدل کلون‌کنندهٔ صدا ممکن است کلون‌سازی را پشتیبانی نکنند؛ فیلدِ supports_voice_cloning را در endpoints API چک کنید.

  • فرمت‌های صوتی پشتیبانی‌شده برای نمونهٔ مرجع، به ارائه‌دهنده بستگی دارد.
  • input_references حداکثر یک بخش input_audio و یک بخش text می‌پذیرد و به input_audio نیاز دارد.
  • صدای مرجع به ۲۰ MiB base64 محدود است (۱۵ MiB صوت decodeشده)؛ درخواست‌های بزرگ‌تر با خطای 400 رد می‌شوند.

گزینه‌های مختص ارائه‌دهنده

با پارامتر provider گزینه‌های مختص ارائه‌دهنده را بفرستید؛ با نام ارائه‌دهنده کلید می‌خورند و فقط گزینه‌های ارائه‌دهندهٔ جورشده منتقل می‌شوند:

JSON request
{
  "model": "~openai/gpt-4o-mini-tts",
  "input": "Hello world",
  "voice": "alloy",
  "provider": {
    "options": {
      "openai": {
        "instructions": "Speak in a warm, friendly tone."
      }
    }
  }
}

Azure (MAI-Voice-2)

Azure TTS درون‌زمینه از SSML استفاده می‌کند اما کاملاً انتزاع شده است؛ فقط به پارامترهای استاندارد نیاز دارید. پارامتر voice نام صدای Azure را می‌گیرد (مثل en-US-Harper:MAI-Voice-2) و speed پشتیبانی می‌شود (بازه: 0.5 تا 2.0).

برای سنتز بیانی، style و اختیاری styledegree را از گزینه‌های provider بفرستید:

JSON request
{
  "model": "~microsoft/mai-voice-2",
  "input": "Welcome to the event!",
  "voice": "en-US-Harper:MAI-Voice-2",
  "response_format": "mp3",
  "speed": 1.0,
  "provider": {
    "options": {
      "azure": {
        "style": "cheerful",
        "styledegree": 1.2
      }
    }
  }
}
گزینهنوعشرح
stylestringسبک بیانی (مثل cheerful، sad، angry، excited). سبک‌های در دسترس به صدا بستگی دارد
styledegreenumberشدت اثر سبک؛ پیش‌فرض 1.0؛ مقدار بالاتر بیان را زیاد می‌کند

قالب پاسخ

endpoint TTS یک جریانِ بایتِ صوتِ خام برمی‌گرداند، نه JSON. پاسخ این هدرها را دارد:

هدرشرح
Content-Typeنوع MIME صدا: audio/mpeg برای mp3 و audio/pcm برای pcm
X-Generation-Idشناسهٔ یکتای تولید برای ردیابی و دیباگ

فرمت‌های خروجی

فرمتContent-Typeشرح
mp3audio/mpegصدای فشرده با حجم کمتر؛ برای ذخیره و پخش
pcmaudio/pcmصوت خامِ بدون فشرده‌سازی؛ تأخیر کمتر، مناسب خطوط جریان بلادرنگ

قیمت‌گذاری

مدل‌های TTS به‌ازای هر کاراکتر متنِ ورودی قیمت‌گذاری می‌شوند. قیمت بسته به مدل و ارائه‌دهنده متفاوت است. هزینهٔ هر کاراکتر را در فهرست مدل‌ها یا از طریق Models API ببینید.

سازگاری با OpenAI SDK

endpoint TTS کاملاً با SDK رسمی OpenAI سازگار است؛ فقط Base URL را عوض کنید:

import os

from openai import OpenAI

client = OpenAI(
    base_url="https://app.asha-ai.ir/v1",
    api_key=os.environ["ASHA_API_KEY"],
)

# Non-streaming: get the full audio response
response = client.audio.speech.create(
    model="~openai/gpt-4o-mini-tts",
    input="The quick brown fox jumps over the lazy dog.",
    voice="nova",
    response_format="mp3",
)
response.write_to_file("output.mp3")

# Streaming: process audio chunks as they arrive
with client.audio.speech.with_streaming_response.create(
    model="~openai/gpt-4o-mini-tts",
    input="The quick brown fox jumps over the lazy dog.",
    voice="nova",
    response_format="mp3",
) as response:
    response.stream_to_file("output.mp3")
import fs from "fs";
import OpenAI from "openai";

const client = new OpenAI({
  baseURL: "https://app.asha-ai.ir/v1",
  apiKey: process.env.ASHA_API_KEY,
});

const response = await client.audio.speech.create({
  model: "~openai/gpt-4o-mini-tts",
  input: "The quick brown fox jumps over the lazy dog.",
  voice: "nova",
  response_format: "mp3",
});

const buffer = Buffer.from(await response.arrayBuffer());
await fs.promises.writeFile("output.mp3", buffer);
console.log("Audio saved to output.mp3");

بهترین روش‌ها

  • فرمت درست را انتخاب کنید — برای ذخیره و پخش عمومی از mp3 و برای خطوط جریان بلادرنگِ حساس به تأخیر از pcm استفاده کنید.
  • انتخاب صدا — ارائه‌دهنده‌های مختلف صداهای متفاوتی دارند؛ مستندات مدل را ببینید یا صداها را آزمایش کنید.
  • طول ورودی — برای متن‌های خیلی بلند، ورودی را به بخش‌های کوچک‌تر تقسیم و خروجی‌ها را به‌هم بچسبانید؛ این کار قابلیت اطمینان را بالا و تأخیرِ اولین بخش صدا را کم می‌کند.
  • پارامتر speed — فقط برخی ارائه‌دهنده‌ها (مثل OpenAI) پشتیبانی می‌کنند؛ بقیه ساکت نادیده‌اش می‌گیرند.

عیب‌یابی

فایل صوتی خالی یا خراب؟

  • مطمئن شوید response_format با روش ذخیرهٔ فایل جور است (خروجی pcm را با پسوند .mp3 ذخیره نکنید)
  • کد وضعیت پاسخ را چک کنید؛ پاسخ‌های غیر-200 بدنهٔ JSON خطا دارند نه صوت

مدل پیدا نمی‌شود؟

  • از فهرست مدل‌ها مدل‌های TTS را پیدا کنید
  • درستی نام مدل را چک کنید (مثل ~openai/gpt-4o-mini-tts)

صدا در دسترس نیست؟

  • صداهای در دسترس بسته به ارائه‌دهنده متفاوت‌اند؛ مستندات ارائه‌دهنده را برای شناسه‌های صدا ببینید
  • هر مدل مجموعه صدای خودش را دارد؛ فهرست کامل را در صفحهٔ همان مدل ببینید

سؤالات متداول

خروجی TTS چه فرمتی دارد؟

خروجی یک جریان بایت خام صوتی است (نه JSON)؛ با response_format می‌توانید mp3 یا pcm بگیرید.

آیا می‌توانم صدای دلخواه را کلون کنم؟

بله؛ مدل‌های پشتیبان کلون‌سازی بدون‌وضعیت دارند: نمونهٔ صدا را با input_references بفرستید و همان صدا تقلید می‌شود.

قیمت TTS چگونه حساب می‌شود؟

به‌ازای هر کاراکتر متن ورودی؛ قیمت هر مدل در models یا Models API به تومان مشخص است.

آیا با OpenAI SDK کار می‌کند؟

بله؛ endpoint سازگار با OpenAI Audio Speech API است؛ فقط base_url را عوض کنید.

سرعت پخش را چطور تغییر دهم؟

با پارامتر speed؛ اما فقط مدل‌هایی که پشتیبانی می‌کنند (مثل OpenAI)؛ بقیه نادیده می‌گیرند.

برای متون خیلی بلند چه کنم؟

متن را به بخش‌های کوچک تقسیم کنید، هر بخش را جدا تولید و خروجی‌ها را به‌هم بچسبانید؛ هم مطمئن‌تر است هم اولین بخش صدا سریع‌تر می‌رسد.