TR ▾

Ses pipeline'ları için sansürsüz metin API'si

uncensoredhttps://api.xtts.cc/v1

TTS API Python: SDK ile Metni Ses İçin Hazırlayın

Bu API ses döndürmez. OpenAI SDK'sı ile Python'dan çağrılan bir metin modelidir ve bir konuşma motorunun önünde yer alır: metni yazar, temizler ve ses aşamasının okuyabileceği cümlelere böler.

güncellendi

Terminalden ses dalgası kapısına akan metin bloklarının izometrik illüstrasyonu

Bu API'nin ne yapıp ne yapmadığı

Bir tts api python öğreticisi aradıysanız, koddan önce net olması gereken bir nokta var: bu hizmet sesi sentezlemez. Açık ağırlıklı bir metin modeli için POST /v1/chat/completions ve GET /v1/models uç noktalarını sunar; model kimliği uncensored'dir. Ses uç noktası, ses listesi veya yanıtta ses dosyası yoktur. Resim, video veya gömme çıktısı da yoktur.

Peki bir konuşma projesinde nerede yer alır? İş akışının metin kısmında. Bir ses motoru bir konuşma metnini okumadan önce birinin onu yazması, sayıları ve kısaltmaları konuşma sözcüklerine dönüştürmesi, biçimlendirmeyi temizlemesi ve uzun duraklamalar olmadan sentezlenebilecek parçalara bölmesi gerekir. Bir dil modeli bu işi iyi yapar ve Python'dan, diğer OpenAI uyumlu hizmetler için zaten kullandığınız SDK ile çağırabilirsiniz.

Model, yasal yetişkin kullanımı için içerik reddi olmadan cevap verecek şekilde ayarlanmıştır; bu, daha katı bir modelin sahneyi ortada kesebileceği kurgu, karakter diyalogları ve anlatım için önemlidir. Tek bir katı kural geçerlidir: reşit olmayanlar içeren cinsel içerik yok.

Bu makalenin geri kalanı dört adımda küçük bir Python modülü oluşturur: ilk çağrı, akışlı bir cümle bölen, JSON çıktılı bir metin normalleştirici ve hız limitlerine saygı gösteren bir yeniden deneme sarmalayıcısı.

SDK'yı yükleyin ve ilk çağrıyı yapın

Python 3.8 veya daha yenisi ve resmi openai paketi gerekir. Önce API anahtarı sayfasında bir anahtar oluşturun. Yeni hesaplar tek tıkla $0.50 deneme kredisi talep edebilir ve bunun için kart gerekmez.

pip install openai

Anahtarı kaynak kodunuzda bırakmayın. Onu bir ortam değişkeni olarak dışa aktarın ve kodda okuyun:

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.xtts.cc/v1",
    api_key=os.environ["XTTS_API_KEY"],
)

resp = client.chat.completions.create(
    model="uncensored",
    messages=[
        {"role": "system", "content": "You write short narration scripts. Plain sentences only."},
        {"role": "user", "content": "Write a 60-word intro for a podcast about night trains."},
    ],
    temperature=0.8,
)

script = resp.choices[0].message.content
print(script)
print(resp.usage.prompt_tokens, resp.usage.completion_tokens)

Bu bütün entegrasyondur. SDK, Authorization: Bearer <key>'i sizin için gönderir. Her yanıt ayrıca bir X-Balance-USD başlığı taşır, böylece isterseniz kalan kredinizi ham yanıtı okuyarak görebilirsiniz. docs sayfası diğer başlıkları ve parametreleri listeler.

temperature, top_p, stop, seed ve cezalar gibi parametreler iletilir. Anlatım için 0,6 ile 0,9 arasında bir sıcaklık makul bir başlangıç aralığıdır ve bir kaydı yeniden üretmek istediğinizde sabit bir seed yardımcı olur.

Metni akış olarak alın ve cümlelere bölün

Konuşma motorları genellikle cümle cümle çalışır. 900 kelimelik bir metnin bitmesini beklerseniz, dinleyici de bekler. stream: true ile API, sunucu gönderilen olaylar üzerinden token gönderir ve geri kalanı yazılırken her tamamlanan cümleyi ses aşamasına verebilirsiniz.

import os
import re
from openai import OpenAI

client = OpenAI(base_url="https://api.xtts.cc/v1", api_key=os.environ["XTTS_API_KEY"])
SENTENCE_END = re.compile(r"(?<=[.?])\s+")

def stream_sentences(topic):
    stream = client.chat.completions.create(
        model="uncensored",
        messages=[
            {"role": "system", "content": "Write spoken narration. One idea per sentence."},
            {"role": "user", "content": topic},
        ],
        stream=True,
    )
    buffer = ""
    for chunk in stream:
        if not chunk.choices:
            continue  # the final chunk can carry usage only
        buffer += chunk.choices[0].delta.content or ""
        parts = SENTENCE_END.split(buffer)
        for sentence in parts[:-1]:
            yield sentence.strip()
        buffer = parts[-1]
    if buffer.strip():
        yield buffer.strip()

for line in stream_sentences("Explain how a tide table is read."):
    print(line)  # replace with: your_voice_engine.say(line)

İki ayrıntı kolayca kaçabilir. İlk olarak, kullanım sayıları akışın sonunda, choices listesi boş olan bir parçada gelir; bu nedenle döngü, seçenekleri olmayan parçaları atlar. İkinci olarak, akışlı bir istek, akış bitene kadar eşzamanlılık slotunu tutar. Ses motorunuz yavaşsa ve akışı tembelce okursanız, slot meşgul kalır. Metni hızlıca çıkarın, cümleleri bir kuyruğa koyun ve ses tarafının kuyruğu kendi hızında tüketmesine izin verin.

Yukarıdaki düzenli ifade, bir nokta veya soru işaretinin ardından gelen boşlukta bölme yapar. "Dr." veya "No." gibi kısaltmaların ardından yanlışlıkla bölecektir; bu nedenle metni önce normalleştirmek gerekir, bunu sonraki bölüm göstermektedir.

Metni kulağa uygun hale getirin

Yazılı metin ile konuşma metni farklılık gösterir. "Dr. Lee, 2. baskı için 3/4 tarihinde 3 kopya satın aldı" cümlesi okumak kolaydır ancak söylemek kulağa takılabilir. Birçok konuşma motoru bu tür durumların bir kısmını işler, ancak motorlar arasında sonuçlar değişir. Bu tür sürprizleri önlemek için metni ses aşamasına girmeden önce temizleyin. Modeli bunu açık bir talimatla yapmaya zorlayın:

import os
from openai import OpenAI

client = OpenAI(base_url="https://api.xtts.cc/v1", api_key=os.environ["XTTS_API_KEY"])

NORMALIZE = (
    "Rewrite the user's text so it can be read aloud. "
    "Spell out numbers, currency, dates and abbreviations as words. "
    "Remove markdown, URLs and emoji. Keep the meaning and the order. "
    "Return only the rewritten text."
)

def normalize(text):
    r = client.chat.completions.create(
        model="uncensored",
        messages=[
            {"role": "system", "content": NORMALIZE},
            {"role": "user", "content": text},
        ],
        temperature=0.2,
    )
    return r.choices[0].message.content.strip()

print(normalize("Dr. Lee bought 3 copies on 3/4 for the 2nd edition."))

Bu adım için düşük bir sıcaklık kullanın. Aynı girdinin aynı çıktıyı vermesini istersiniz ve yaratıcılık yalnızca engel olur. Tüm bir kitabı çalıştırmadan önce sonuçların bir örneğini gözden geçirin ve belirsiz öğelerin nasıl ele alınmasını istediğinize karar verin. "3/4" tarihi standart bir örnektir: Mart'ın dördü mü yoksa Nisan'ın üçü mü olarak okunmalı? Tercihinizi sistem istemine yazın, çünkü model yerel ayınızı tahmin edemez.

Bu adımın maliyeti

Normalizasyon ucuzdur. 600 token girdi ve yaklaşık 650 token çıktı için maliyet: 600 x $0,15 / 1.000.000 = $0,00009 (girdi) ve 650 x $0,50 / 1.000.000 = $0,000325 (çıktı). Toplam $0,000415 eder. Bu, bin paragraf için yaklaşık $0,42 anlamına gelir. fiyatlandırma sayfası tam tabloyu ve bakiye yükleme seçeneklerini içerir.

JSON modu ile yapılandırılmış parçalar döndürün

Bazı konuşma motorları segment başına ayarları kabul eder: bir duraklama uzunluğu, bir konuşma hızı, farklı bir karakter için farklı bir ses. Modelden bu talimatları JSON olarak üretmesini isteyebilir ve Python'da okuyabilirsiniz. response_format'i {"type": "json_object"} olarak ayarlayın ve ayrıca şekli istemde açıkça belirtin; JSON modu geçerli JSON'u garanti eder, şemanızı değil.

import json
import os
from openai import OpenAI

client = OpenAI(base_url="https://api.xtts.cc/v1", api_key=os.environ["XTTS_API_KEY"])

prompt = (
    "Split this scene into segments. Return JSON like "
    '{"segments": [{"speaker": "narrator", "text": "...", "pause_ms": 300}]}. '
    "Speakers are narrator, mara, or tom."
)

r = client.chat.completions.create(
    model="uncensored",
    response_format={"type": "json_object"},
    messages=[
        {"role": "system", "content": prompt},
        {"role": "user", "content": "Mara opens the door. Tom says he is late again. She sighs and lets him in."},
    ],
    temperature=0.3,
)

data = json.loads(r.choices[0].message.content)
for seg in data["segments"]:
    print(seg["speaker"], seg["pause_ms"], seg["text"])

Geleni doğrulayın. segments'in var olduğundan, her öğenin bilinen bir konuşmacıya sahip olduğundan ve pause_ms'in kabul edilebilir bir aralıktaki bir sayı olduğundan emin olun. Doğrulama başarısız olursa, bırakmadan önce daha düşük bir sıcaklıkla bir kez yeniden deneyin. Model çıktısını, herhangi bir kullanıcı metni gibi güvensiz bir girdi olarak değerlendirin.

Zaman kaybettiren hatalar

Bir dil modelini bir konuşma motorunun önüne bağlarken bazı hatalar tekrar tekrar ortaya çıkar.

  • Modelin yorum eklemesine izin vermek. Modeller "Tabii, işte senin için hazırladığım metin" gibi ifadeler kullanmayı sever. Bu cümle sesli olarak okunur. Sistem isteminin sonuna "Yalnızca senaryo metnini döndür" ifadesini ekleyin ve iki nokta ile biten öndeki satırı temizleyin.
  • Cümle uzunluğuna güvenmek. Bazı motorlar çok uzun cümlelerle zorlanır. İsteğe "cümle 25 kelimeden uzun olmasın" kuralını ekleyin ve bir cümle hâlâ çok uzunsa virgülde bölerek Python'da da uygulayın.
  • Bağlam penceresini unutmak. İstem ve tamamlama 100.000 token paylaşır. Uzun bir kitap bölümü için her seferinde tam metni göndermek yerine, önceki bölümün kısa bir özetiyle bölümler halinde gönderin. Bu, girdi faturasını da aşağıda tutar.
  • Bir sınır olmadan bir global istemciyi iş parçacıkları arasında yeniden kullanmak. İstemci paylaşmak güvenlidir ancak hizmet sonsuz değildir. Havuzunuzu anahtarınızın eşzamanlılığına göre sınırlandırın.
  • Anahtarı sabit kodlamak. Bir ortam değişkeni kullanın ve anahtar bir depoda yer alırsa anahtarı yenileyin.

Bir şey yanlış görünürse, X-Request-Id başlığını, buna neden olan istemle birlikte günlüğe kaydedin. Yardım istemeniz gerekirse, bu kimlik belirli bir çağrıya işaret etmenin en hızlı yoludur ve docs nerede bulacağınızı açıklar.

Hız limitlerini ve yeniden denemeleri yönetin

Tam anahtar 8 eşzamanlı isteğe ve dakikada 300 isteğe izin verir. Deneme anahtarı 2 eşzamanlı isteğe ve dakikada 60 isteğe izin verir. Bu limitlerin üzerine çıkarsanız HTTP 429 alırsınız; dakika başına istekler için rate_limited ve aynı anda çok fazla istek için concurrency hata koduyla. Geçici aşırı yüklenmede API ayrıca 429 yanıtı verir ve Retry-After: 5 gönderir.

SDK kendi kendine yeniden dener, ancak açık bir sarmalayıcı size kontrol sağlar ve davranışı günlüklerde görünür hale getirir. Bunu anahtarınıza boyutlandırılmış bir iş parçacığı havuzu ile birleştirin ve neredeyse hiç 429 görmezsiniz:

import os
import time
from concurrent.futures import ThreadPoolExecutor
from openai import OpenAI, RateLimitError

client = OpenAI(
    base_url="https://api.xtts.cc/v1",
    api_key=os.environ["XTTS_API_KEY"],
    max_retries=0,
)

def ask(prompt, tries=5):
    for attempt in range(tries):
        try:
            r = client.chat.completions.create(
                model="uncensored",
                messages=[{"role": "user", "content": prompt}],
            )
            return r.choices[0].message.content
        except RateLimitError as err:
            wait = int(err.response.headers.get("Retry-After", 5))
            time.sleep(wait * (attempt + 1))
    raise RuntimeError("still rate limited after retries")

prompts = ["Narrate a sunrise in two sentences."] * 20
with ThreadPoolExecutor(max_workers=8) as pool:  # use 2 on a trial key
    results = list(pool.map(ask, prompts))
print(len(results))

Başarısız veya reddedilen istekler ücretlendirilmez, bu nedenle bir hatadan sonra yeniden denemek başarısız deneme için size maliyet yaratmaz. Tamamlanan bir istek normal şekilde faturalandırılır, bu nedenle yavaş ama başarılı çağrılarda kör yeniden denemelerden kaçının.

Metni konuşma motorunuza verin

Son adım bu API'nin dışında yer alır. Python'da metinden ses üretmenin birkaç yolu vardır: kendi başınıza çalıştırabileceğiniz açık kaynaklı konuşma modelleri, işletim sistemine yerleşik masaüstü konuşma hizmetleri ve diğer şirketlerden barındırılan konuşma API'leri. Her birinin kendi lisansı, kalitesi ve fiyatı vardır; bu nedenle seçim yapmadan önce mevcut belgelerine ve şartlarına bakın. Bu site bu kısmı sağlamaz.

Temiz bir sınır, kodunuzun kolayca değiştirilmesini sağlar. speak(text: str) -> None imzasıyla bir işlev yazın ve her motor ayrıntısını bunun içinde tutun. Yukarıdaki metin hattı, bu işlevi her cümle veya segment için çağırır. Motorları değiştirdiğinizde başka hiçbir şey değişmez.

Hâlâ deneme ile ücretli kurulum arasında karar veriyorsanız, sayılar basittir: ön ödemeli krediden milyon giriş tokeni başına $0,15 ve milyon çıktı tokeni başına $0,50 ödersiniz; kredi asla sona ermez, abonelik yoktur. Bakiye yükleme $20 ile $500 arasındadır ve kripto (TRC20 üzerinde USDT, Base üzerinde USDC) ile yapılabilir.

Sorular ve cevaplar

Bu API ses dosyaları döndürür mü?

Hayır. Yalnızca metin döndürür. Metinleri yazmak, temizlemek ve yapılandırmak için kullanın, ardından metni ayrı bir konuşma motoruna iletin.

Hangi Python paketini kullanmalıyım?

Resmi openai paketi. base_url'yi https://api.xtts.cc/v1 olarak ayarlayın, anahtarınızı iletin ve uncensored model kimliğini kullanın.

Python ile yanıtları akış olarak alabilir miyim?

Evet. stream=True parametresini iletin ve parçalar üzerinde yineleme yapın. Kullanım, akışın sonunda rapor edilir ve istek, akış bitene kadar eşzamanlılık slotunu tutar.

Hız limitine (rate limit) ulaştığımda ne olur?

rate_limited veya concurrency koduyla HTTP 429 alırsınız. Varsa Retry-After değerini bekleyin ve yeniden deneyin, tam anahtarda çalışan sayısını 8 dahil veya daha az, deneme anahtarında ise 2 dahil veya daha az tutun.

Anahtarınız tek bir formun uzağında

Bir hesap oluşturun, anahtarı kopyalayın ve base URL'yi değiştirin. Kurulum bu kadar basit.