Skip to main content

anka-tts

English · Türkçe

Zero-shot Turkish text-to-speech and voice cloning. anka-tts/v0.1 is a model trained for Turkish on the F5-TTS architecture.

The weights were fine-tuned for 260k steps on Turkish speech with verified public-domain provenance, and score WER 1.50%, CER 0.31% on a 495-sentence Turkish evaluation set — first of the eight systems measured.

Around the model, the package brings Turkish text normalization (numbers, suffixes, abbreviations, dates/times/money), reference audio validation (it catches problems with the reference recording before synthesis) and measured defaults calibrated on that same evaluation set.


The model

architecture F5-TTS (DiT + flow matching), base: OpenF5-TTS-Base (Apache-2.0)
training 260k steps
corpus broadcast recordings with verified public-domain status — no synthetic data
preprocessing VAD, diarization, language ID; no denoising
output 24 kHz mono
WER / CER 1.50% / 0.31% (495 sentences x 3 runs, faster-whisper large-v3, tr, beam 5)

No synthetic speech went into the corpus, and no recording was put through noise removal: both measurably degrade fine-tune quality. No dataset was taken in whose provenance could not be verified — a license tag on the Hub was not treated as sufficient evidence on its own.

Zero-shot means there is no per-speaker training step: one reference recording of a few seconds is enough, and the quality of that recording matters more than any parameter (see Reference audio guide).


Installation

There are two separate installs; which one you need depends on what you are doing.

pip install anka-tts          # text normalization + reference validation
pip install anka-tts[tts]     # the above + synthesis
anka-tts anka-tts[tts]
dependencies numpy, soundfile + torch, torchaudio, f5-tts, huggingface-hub
download size a few MB ~2 GB
anka.text
anka.audio
AnkaTTS.synthesize()

Someone who only wants to normalize text should not have to download 2 GB of PyTorch: anka.text and anka.audio run on the pure standard library plus soundfile. Torch is loaded only when AnkaTTS.from_pretrained() is called.


In five lines

from anka import AnkaTTS

tts = AnkaTTS.from_pretrained("anka-tts/v0.1", device="cuda")
wav = tts.synthesize("2026'da toplantı 14:30'da mı?")  # built-in voice
tts.save_wav(wav, "cikti.wav")

Two voices ship with the package, male (the default) and female. To speak in your own voice, register a reference recording once — see Voices.

Without synthesis, normalization only:

from anka.text import normalize

normalize("15.03.2026'da saat 14:30'da %20 indirim başlıyor.")
# 'on beş mart iki bin yirmi altıda saat on dört otuzda yüzde yirmi indirim başlıyor.'

Reference audio guide

The single most important thing determining cloning quality is the reference recording — more so than the model or the parameters. The rules:

good bad
duration 7-9 s < 5 s (the model cannot pick up the voice), > 12 s (F5 clips it, the rest is wasted)
content a complete sentence ending on falling intonation a fragment cut off mid-sentence
transcript punctuated, word for word what is said unpunctuated, approximate, incomplete
recording single speaker, quiet room, 24 kHz+ noise, music, reverb, 16 kHz
level normal recording level normalized afterwards (raises the noise floor)
# Good
ref_text = "Akşam yemeğinden sonra kısa bir yürüyüşe çıktık. Sokak lambaları yeni yanmıştı."

# Bad -- a sentence fragment, no punctuation, does not match the audio word for word
ref_text = "akşam yemeğinden sonra kısa bir yürüyüşe"

ref_text must match the audio word for word. F5 estimates the duration of the generated speech from the ratio ref_duration / ref_text_length; if the transcript is too long or too short, that ratio breaks and the model swallows syllables.

Check before synthesizing:

from anka.audio import check_reference

check = check_reference("referans.wav", ref_text, gen_text="Üretilecek metin.")
print(check.duration, check.estimated_chunks)
print(check.ok)       # True only when nothing at all was flagged
print(check.fatal)    # True when the reference cannot be used (missing ref_text)
for w in check.warnings:
    print("!", w)

ok is the strict answer: it goes False on any warning at all, a 16 kHz recording or a 3-second one included. fatal is the narrow one -- the reference cannot be used, which today means only a missing ref_text. So test ok when you want a clean reference and fatal when you only want to know whether synthesis can go ahead.

synthesize() already calls this automatically and surfaces the findings as warnings; it can be turned off with validate_reference=False.

Why 7-9 seconds

F5 computes the generation window like this (utils_infer.py):

max_chars = (ref_bytes / ref_duration) × (22 − ref_duration) × speed
          =       speaking_rate        × (22 − ref_duration) × speed

There is a 22-second budget: the more room the reference takes up, the less is left for generation. Which means a longer reference splits the text into more chunks. A short reference has a different problem — not chunking, but the model not picking up enough of the voice characteristics. 7-9 s is the band between the two.

Note: the formula counts UTF-8 bytes, not characters. Since ğ ü ş ı ö ç take two bytes each, Turkish text splits earlier than English text of the same length.

Long texts

Once the budget fills up, F5 splits the text at any of [;:,.!?] — that is, at a comma, mid-sentence. With a 12-second reference it looks like this:

2. Bavulları akşamdan hazırlarsak,
3. sabah yola çıkarken hiç acele etmeyiz.

A pause landing there sounds wrong to the ear, and since it depends entirely on the reference duration, it is outside the control of whoever wrote the text.

That is why anka does not leave the splitting to F5: it first breaks the text into sentences, synthesizes the sentence groups that fit the budget separately, then joins them with a short pause in between. A seam always lands at the end of a sentence — where the ear expects a pause anyway. Whether the reference is 7 s or 12 s, sentences stay whole.

Paragraphs separated by a blank line are preserved, and a longer pause is placed at the paragraph transition. Sentences are never grouped across a paragraph boundary.

tts.synthesize(uzun_metin, voice="anlatici")   # defaults: 0.15 s / 0.45 s
tts.synthesize(uzun_metin, voice="anlatici", sentence_pause=0.2, paragraph_pause=0.6)
tts.synthesize(uzun_metin, voice="anlatici", chunk_by_sentence=False)  # F5's own splitting

A sentence that exceeds the budget on its own is passed to F5 unsplit; F5 makes its own decision inside that sentence, but the others are unaffected.

You do not need to change any setting to produce both short and long text with the same voice. A one-sentence text goes out in a single call and forms no seam at all; a two-paragraph text is broken into sentences. The reference duration only affects how many pieces there will be, not where the splits happen.


Console output

F5 prints a block of its own for every chunk it generates — the reference transcript, each gen_text, blank lines and a progress bar. Since anka calls it once per sentence group, that block repeats for every segment. anka captures it and shows its own view instead:

anka model  anka-tts/v0.1  ·  mps  ·  24 kHz
anka voice  anlatici  ·  7.8s reference
anka warn   the text will be split into 3 chunks, and every seam between them
            is a potentially audible pause. AnkaTTS aligns those seams with
            sentence ends, where a pause is expected anyway…
  ✓ 1/3  Dr. Ayşe Yılmaz'ın 15.03.2026 tarihli raporuna göre %12 arttı.  2.6s
  ✓ 2/3  Sabah 09:05'te başlayan toplantı 14:30'da sona erdi.            2.6s
  ▸ 3/3  ████████████░░░░░░  00:02  Katılımcılara 250 ml su dağıtıldı.

Segments are named in the wording you wrote, not the normalized text the model is handed: Dr. Ayşe Yılmaz'ın 15.03.2026 rather than doktor Ayşe Yılmazın on beş mart iki bin yirmi altı. The two are aligned sentence by sentence; where they cannot be aligned, the normalized text is shown rather than a wrong guess. A sentence too long for the budget is generated in pieces, and the pieces after the first are marked .

Warnings are routed through the same renderer. Left to Python they are written straight to stderr — landing in the middle of the live line and leaving a mangled row — and printed with the file, line number and source line, none of which help whoever is listening to the result. Only the message is shown, and a warning raised by another library keeps its origin as a caption (torch: …), so it stays clear who is complaining.

progress= decides what is drawn. F5's own output is captured either way.

value behaviour
"auto" (default) the live view above on an interactive terminal, silence anywhere else
False / None silence
"plain" one line per segment, no escape sequences — for logs and CI
"pretty" / True force the live view even when redirected
a callable callback(done, total, segment_text) after each segment
tts.synthesize(metin, voice="anlatici")                    # auto
tts.synthesize(metin, voice="anlatici", progress=False)    # silent
tts.synthesize(metin, voice="anlatici", progress="plain")  # one line per segment

Two kinds of third-party noise are dropped, because they are addressed to the author of the library that raised them rather than to you:

  • torch's An output with one or more elements was resized…, which fires on every stft/istft call vocos and F5 make;
  • the hub backend's You are sending unauthenticated requests to the HF Hub, printed on every load because F5 fetches the vocos vocoder from the hub. Set HF_TOKEN to silence it at the source, or HF_HUB_OFFLINE=1 to skip the lookup once the vocoder is cached.

Download progress bars are never touched: a silent 2 GB fetch would be worse than the noise.

Set ANKA_DEBUG=1 to see everything that was hidden — F5's prints, the muted warnings and the hub notice — on stderr. NO_COLOR is honoured, and the rendering falls back to plain lines on a dumb terminal.


Normalization

normalize() turns text into something that can be handed to the model. Punctuation is preserved? above all, because the model derives question intonation from it.

input output
1994'te bin dokuz yüz doksan dörtte
5'de (typed wrong) beşte
4'ü dördü
6'nın altının
90'lar doksanlar
3. sınıf üçüncü sınıf
Sıralamada 3. (left alone — it may be the end of a sentence)
15.03.2026 on beş mart iki bin yirmi altı
14:30 / 14:00 / 09:05 on dört otuz / on dört / dokuz sıfır beş
1.250 TL bin iki yüz elli lira
3,5 TL üç lira elli kuruş
2,75 $ iki dolar yetmiş beş sent
2,5 milyon TL iki virgül beş milyon lira
%20 / %50'si yüzde yirmi / yüzde ellisi
5 km'de beş kilometrede
36,6 °C otuz altı virgül altı derece
II. Abdülhamid ikinci Abdülhamid
TBMM'de te be me mede
MEB açıkladı (left alone — it is read as a word)
Dr. Ayşe doktor Ayşe
Ali & Veli Ali ve Veli

Suffixes are built from the reading, not from the way they were typed. The user may have written 5'de; the correct form is beşte, because what decides the correct form is how the number is spoken. Vowel harmony, consonant devoicing, the dört → dörd softening and the linking consonants are applied accordingly.

Abbreviations

Whether an abbreviation is read as a word (MEB → "meb") or letter by letter (TCDD → "te ce de de") was not left to a hand-maintained list — such a list never ends. The decision follows from phonotactics: the Turkish syllable has the shape (C)V(C)(C), no consonant cluster may open a word, and only certain two-consonant clusters may close one.

from anka.text import is_pronounceable

is_pronounceable("MEB")     # True  -> "meb"
is_pronounceable("TCDD")    # False -> "te ce de de"  (no vowel)
is_pronounceable("ABD")     # False -> "a be de"      (bd is an invalid final cluster)
is_pronounceable("TÜRKSAT") # True  -> "TÜRKSAT"      (rk|s is valid)

The rule was tested on 58 real institution abbreviations and classified every one of them correctly. The few cases where it is wrong (AB → "a be", RTÜK → "ertük") live in two small exception sets in lexicon.py. You can add your own entries without touching the lexicon:

normalize("XYZKUR bildirdi.", extra_acronyms={"XYZKUR"})
normalize("Xyz. geldi", extra_abbreviations={"Xyz.": "iksiz"})

Circumflex letters and the vocab

The circumflexed â î û are preservedkâr and kar are not the same word, and these letters also drive vowel harmony (kârkârda, mahkûmmahkûmu). If you are working with a checkpoint whose vocab does not carry these letters, fold_circumflex=True folds them to their plain counterparts.

If a vocab is given (and AnkaTTS passes its own automatically), missing characters are handled too:

normalize("MAHKÛM oldu.", vocab=vocab)   # 'mahkûm oldu.'  (no uppercase Û in the vocab)
normalize("Fiyat 100 ₼", vocab=vocab)    # warning: '₼' is not in the vocab at all

A blanket lower() is not applied — the model was trained on normally written text. Only the word carrying an out-of-vocab character is lowered, and only if the lowercase form solves the problem. If it does not, the word is left intact and a warning is raised.


Parameters

There are three layers. Day to day, only the first one is needed.

Everyday: text, voice or ref_audio + ref_text, seed, sentence_pause (0.15 s), paragraph_pause (0.45 s)

Synthesis settings: one measured set of defaults. Any value can be changed on its own; whatever you leave out keeps its default.

parameter default
speed 0.85
nfe_step 32
cfg_strength 2.0
sway_sampling_coef -1.0
tts.synthesize("Metin.", voice="anlatici")                          # the defaults
tts.synthesize("Metin.", voice="anlatici", speed=1.0, nfe_step=16)  # change two of them

The defaults are not guesses: speed and nfe_step were swept over the 495-sentence evaluation set described above, scored through one and the same ASR pass, and fixed at the values that came out best. cfg_strength and sway_sampling_coef are F5's own values — no sweep has been run on those two yet.

Undocumented: cross_fade_duration, target_rms, fix_duration, ode_method are passed through **f5_kwargs but do not appear in the signature. The urge to fiddle with cross_fade_duration in particular is usually an attempt to "fix" the chunking pause; the actual fix is the reference duration, and the library already says so.


Voices

Two voices ship inside the package, so synthesis works without any reference:

tts.synthesize("Metin.")                    # male, the default
tts.synthesize("Metin.", voice="female")
voice reference
male (default) 7.2 s
female 7.0 s

Both are AI-generated: each was designed from a text description, and neither is a recording of a real person. The recordings are licensed CC-BY-NC-4.0, separately from the Apache-2.0 code; their origin is documented in anka/data/voices/README.md.

To speak in your own voice, register a reference once:

tts.add_voice("anlatici", "kayit.wav", "Referansta birebir söylenen cümle.")
tts.list_voices()                      # ['anlatici']
tts.synthesize("Metin.", voice="anlatici")

The audio file is copied under ~/.local/share/anka/voices/ — the voice keeps working even if you move the original file. The directory can be changed with ANKA_HOME. Without voice=, a single registered voice is used; with none registered, the built-in male voice speaks; with several, name one. A registered voice with the same name as a built-in one takes its place. list_voices() lists the voices you registered; the built-in ones are always there.


Output contract

synthesize() always returns:

  • numpy.float32
  • 24 000 Hz
  • mono (a one-dimensional array)
  • values within [-1, 1]

save_wav() writes in the same format. The same text + the same seed + the same reference = the same output (random if seed=None is given).


Out of scope

There is no automatic transcription (ASR): if you pass ref_audio, you must pass ref_text with it. A Whisper dependency would have tripled the install size.


Development

pip install -e ".[dev]"
pytest                    # 794 tests, no model required

The determinism test needs a model; to run it:

export ANKA_TEST_MODEL=/yol/model_dizini
export ANKA_TEST_REF=referans.wav
export ANKA_TEST_REF_TEXT="Referansta söylenen cümle."
pytest tests/test_tts.py -k determinizm

License

Code: Apache-2.0.

anka-tts/v0.1 weights and the built-in voices: CC-BY-NC-4.0 — free for personal, hobby and research use; commercial use is not permitted under this license. A separate commercial license is available for the weights — see [CONTACT] .

Dependencies and weights are subject to their own licenses — f5-tts is MIT, but the license of the model weight you use is separate and may not permit commercial use. Getting permission from the owner of the cloned voice is your responsibility as well.



anka-tts (Türkçe)

English · Türkçe

Zero-shot Türkçe metinden konuşma ve ses klonlama. anka-tts/v0.1, F5-TTS mimarisi üzerine Türkçe için eğitilmiş bir modeldir Ağırlıklar, kamu malı statüsü doğrulanmış Türkçe konuşma külliyatıyla 260 bin adım fine-tune edildi; 495 cümlelik Türkçe değerlendirme setinde WER %1,50, CER %0,31 — ölçülen sekiz sistem içinde birinci.

Paket, modelin çevresinde Türkçe metin normalizasyonu (sayılar, ekler, kısaltmalar, tarih/saat/para), referans ses doğrulama (referans kayıttaki sorunları sentezden önce yakalar) ve aynı değerlendirme setinde ölçülmüş sentez varsayılanları getirir.


Model

mimari F5-TTS (DiT + flow matching), taban: OpenF5-TTS-Base (Apache-2.0)
eğitim 260k adım
korpus kamu malı statüsü doğrulanmış yayın kaydı — sentetik veri yok
ön işleme VAD, diarization, dil tespiti; denoising uygulanmadı
çıktı 24 kHz mono
WER / CER %1,50 / %0,31 (495 cümle x 3 koşu, faster-whisper large-v3, tr, beam 5)

Külliyatta sentetik ses kullanılmadı ve kayıtlar gürültü temizlemeden geçirilmedi: ikisi de fine-tune kalitesini ölçülebilir biçimde düşürüyor. Kaynağı doğrulanamayan hiçbir veri kümesi alınmadı — Hub üzerindeki lisans etiketi tek başına yeterli kanıt sayılmadı.

Zero-shot, konuşmacıya özel bir eğitim adımı olmaması demek: birkaç saniyelik tek bir referans kaydı yeterli, ve o kaydın kalitesi herhangi bir parametreden daha belirleyici (bkz. Referans ses kılavuzu).


Kurulum

İki ayrı kurulum var; hangisine ihtiyacın olduğu ne yapacağına bağlı.

pip install anka-tts          # metin normalizasyonu + referans doğrulama
pip install anka-tts[tts]     # yukarıdakiler + sentez
anka-tts anka-tts[tts]
bağımlılıklar numpy, soundfile + torch, torchaudio, f5-tts, huggingface-hub
indirme boyutu birkaç MB ~2 GB
anka.text
anka.audio
AnkaTTS.synthesize()

Metni normalize etmek isteyen birinin 2 GB PyTorch indirmesi gerekmiyor: anka.text ve anka.audio saf standart kütüphane + soundfile ile çalışır. Torch yalnızca AnkaTTS.from_pretrained() çağrıldığında yüklenir.


Beş satırda

from anka import AnkaTTS

tts = AnkaTTS.from_pretrained("anka-tts/v0.1", device="cuda")
wav = tts.synthesize("2026'da toplantı 14:30'da mı?")  # gömülü ses
tts.save_wav(wav, "cikti.wav")

Pakette iki ses geliyor: male (varsayılan) ve female. Kendi sesinle konuşturmak için bir referans kaydını bir kez tanıtman yeterli — bkz. Sesler.

Sentez olmadan, yalnızca normalizasyon:

from anka.text import normalize

normalize("15.03.2026'da saat 14:30'da %20 indirim başlıyor.")
# 'on beş mart iki bin yirmi altıda saat on dört otuzda yüzde yirmi indirim başlıyor.'

Referans ses kılavuzu

Klonlama kalitesini belirleyen tek en önemli şey referans kaydıdır — modelden ya da parametrelerden daha çok. Kurallar:

iyi kötü
süre 7-9 sn < 5 sn (model sesi tanıyamaz), > 12 sn (F5 kırpar, boşa gider)
içerik tamamlanmış cümle, düşen tonlamayla biten cümle ortasından kesilmiş parça
transkript noktalamalı, birebir söylenen noktalamasız, yaklaşık, eksik
kayıt tek konuşmacı, sessiz ortam, 24 kHz+ gürültü, müzik, yankı, 16 kHz
seviye normal kayıt seviyesi sonradan normalize edilmiş (taban gürültüsü yükselir)
# İyi
ref_text = "Akşam yemeğinden sonra kısa bir yürüyüşe çıktık. Sokak lambaları yeni yanmıştı."

# Kötü -- cümle parçası, noktalama yok, sesle birebir eşleşmiyor
ref_text = "akşam yemeğinden sonra kısa bir yürüyüşe"

ref_text sesle birebir eşleşmeli. F5 üretilecek sesin süresini ref_süre / ref_metin_uzunluğu oranından tahmin ediyor; transkript uzun ya da kısa olursa bu oran bozulur ve model hece yutar.

Sentezden önce kontrol et:

from anka.audio import check_reference

check = check_reference("referans.wav", ref_text, gen_text="Üretilecek metin.")
print(check.duration, check.estimated_chunks)
print(check.ok)       # yalnızca hiç uyarı yoksa True
print(check.fatal)    # referans hiç kullanılamıyorsa True (ref_text yoksa)
for w in check.warnings:
    print("!", w)

ok katı olan cevap: tek bir uyarı bile varsa False olur -- 16 kHz'lik bir kayıt ya da 3 saniyelik bir referans dahil. fatal ise dar olan: referans hiç kullanılamıyor demektir, bugün yalnızca ref_text eksikse. Temiz bir referans istiyorsan ok'a, sentezin yürüyüp yürüyemeyeceğini soruyorsan fatal'a bak.

synthesize() bunu zaten otomatik çağırır ve uyarıları warnings olarak verir; validate_reference=False ile kapatılabilir.

Neden 7-9 saniye

F5 üretim penceresini şöyle hesaplıyor (utils_infer.py):

max_chars = (ref_bayt / ref_süre) × (22 − ref_süre) × speed
          =     konuşma_hızı      × (22 − ref_süre) × speed

22 saniyelik bir bütçe var: referans ne kadar yer kaplarsa üretime o kadar az kalıyor. Yani uzun referans metni daha çok parçaya böler. Kısa referansın sorunu ise farklı — parçalanma değil, modelin ses karakteristiğini yeterince alamaması. 7-9 sn ikisinin ortasındaki bant.

Not: formül karakter değil UTF-8 bayt sayıyor. ğ ü ş ı ö ç iki bayt olduğu için Türkçe metin aynı uzunluktaki İngilizce metinden daha erken bölünür.

Uzun metinler

F5 bütçe dolduğunda metni [;:,.!?] işaretlerinin herhangi birinden böler — yani virgülden, cümlenin ortasından. 12 sn'lik bir referansta şöyle oluyor:

2. Bavulları akşamdan hazırlarsak,
3. sabah yola çıkarken hiç acele etmeyiz.

Orada duraksama olması kulakta yanlış duyulur, ve bu tamamen referansın süresine bağlı olduğu için metni yazan kişinin kontrolünde değil.

anka bu yüzden bölmeyi F5'e bırakmaz: metni önce cümlelere ayırır, bütçeye sığan cümle gruplarını ayrı ayrı sentezler ve aralarına kısa bir duraklama koyup birleştirir. Ek yeri her zaman cümle sonuna denk gelir — kulağın zaten duraklama beklediği yere. Referans 7 sn de olsa 12 sn de olsa cümleler bütün kalır.

Boş satırla ayrılmış paragraflar korunur ve paragraf geçişine daha uzun bir duraklama konur. Cümleler paragraf sınırını aşarak gruplanmaz.

tts.synthesize(uzun_metin, voice="anlatici")   # varsayılan: 0.15 sn / 0.45 sn
tts.synthesize(uzun_metin, voice="anlatici", sentence_pause=0.2, paragraph_pause=0.6)
tts.synthesize(uzun_metin, voice="anlatici", chunk_by_sentence=False)  # F5'in kendi bölmesi

Tek başına bütçeyi aşan bir cümle bölünmeden F5'e bırakılır; o cümlede F5 kendi kararını verir ama diğerleri etkilenmez.

Aynı sesle hem kısa hem uzun metin üretmek için ayar değiştirmen gerekmez. Tek cümlelik bir metin tek çağrıya gider, hiç ek yeri oluşmaz; iki paragraflık bir metin cümlelere ayrılır. Referans süresi yalnızca kaç parça olacağını etkiler, nereden bölüneceğini değil.


Konsol çıktısı

F5 ürettiği her parça için kendi bloğunu basar — referans transkripti, her gen_text, boş satırlar ve bir ilerleme çubuğu. anka F5'i her cümle grubu için bir kez çağırdığından bu blok her segmentte tekrar eder. anka bu çıktıyı yakalar ve yerine kendi görünümünü çizer:

anka model  anka-tts/v0.1  ·  mps  ·  24 kHz
anka voice  anlatici  ·  7.8s reference
anka warn   the text will be split into 3 chunks, and every seam between them
            is a potentially audible pause. AnkaTTS aligns those seams with
            sentence ends, where a pause is expected anyway…
  ✓ 1/3  Dr. Ayşe Yılmaz'ın 15.03.2026 tarihli raporuna göre %12 arttı.  2.6s
  ✓ 2/3  Sabah 09:05'te başlayan toplantı 14:30'da sona erdi.            2.6s
  ▸ 3/3  ████████████░░░░░░  00:02  Katılımcılara 250 ml su dağıtıldı.

Segmentler senin yazdığın hâliyle adlandırılır, modele giden normalize metinle değil: doktor Ayşe Yılmazın on beş mart iki bin yirmi altı değil, Dr. Ayşe Yılmaz'ın 15.03.2026. İkisi cümle cümle hizalanır; hizalama kurulamazsa yanlış tahmin yerine normalize metin gösterilir. Bütçeye sığmayan bir cümle parça parça üretilir ve ilkinden sonraki parçalar ile işaretlenir.

Uyarılar da aynı çiziciden geçer. Python'a bırakılırsa doğrudan stderr'e yazılır — canlı satırın ortasına düşüp satırı bozar — ve dosya adı, satır numarası, kaynak satırıyla birlikte basılır; hiçbiri sesi dinleyen kişinin işine yaramaz. Yalnızca mesaj gösterilir; başka bir kütüphanenin uyarısı kaynağını etiket olarak korur (torch: …), böylece kimin şikâyet ettiği belli kalır.

Ne çizileceğine progress= karar verir. F5'in kendi çıktısı her hâlükârda yakalanır.

değer davranış
"auto" (varsayılan) etkileşimli terminalde yukarıdaki canlı görünüm, başka her yerde sessizlik
False / None sessizlik
"plain" segment başına tek satır, kaçış dizisi yok — log ve CI için
"pretty" / True yönlendirilmiş çıktıda bile canlı görünümü zorla
bir callable her segmentten sonra callback(done, total, segment_text)
tts.synthesize(metin, voice="anlatici")                    # auto
tts.synthesize(metin, voice="anlatici", progress=False)    # sessiz
tts.synthesize(metin, voice="anlatici", progress="plain")  # segment başına tek satır

İki tür üçüncü taraf gürültüsü elenir; çünkü ikisi de sana değil, uyarıyı üreten kütüphanenin yazarına hitap ediyor:

  • torch'un An output with one or more elements was resized… uyarısı — vocos ve F5'in yaptığı her stft/istft çağrısında tetikleniyor;
  • hub arka ucunun You are sending unauthenticated requests to the HF Hub mesajı — F5 vocos vocoder'ını hub'dan çektiği için her yüklemede basılıyor. Kaynağında susturmak için HF_TOKEN, vocoder önbellekteyse sorguyu tamamen atlamak için HF_HUB_OFFLINE=1.

İndirme çubuklarına dokunulmaz: sessiz bir 2 GB indirme gürültüden kötüdür.

Gizlenen her şeyi — F5'in çıktısı, susturulan uyarılar ve hub mesajı — stderr'de görmek için ANKA_DEBUG=1. NO_COLOR dikkate alınır, dumb terminalde düz satırlara düşülür.


Normalizasyon

normalize() metni modele verilebilir hâle getirir. Noktalama korunur — özellikle ?, çünkü model soru tonlamasını ondan çıkarıyor.

girdi çıktı
1994'te bin dokuz yüz doksan dörtte
5'de (yanlış yazım) beşte
4'ü dördü
6'nın altının
90'lar doksanlar
3. sınıf üçüncü sınıf
Sıralamada 3. (dokunulmaz — cümle sonu olabilir)
15.03.2026 on beş mart iki bin yirmi altı
14:30 / 14:00 / 09:05 on dört otuz / on dört / dokuz sıfır beş
1.250 TL bin iki yüz elli lira
3,5 TL üç lira elli kuruş
2,75 $ iki dolar yetmiş beş sent
2,5 milyon TL iki virgül beş milyon lira
%20 / %50'si yüzde yirmi / yüzde ellisi
5 km'de beş kilometrede
36,6 °C otuz altı virgül altı derece
II. Abdülhamid ikinci Abdülhamid
TBMM'de te be me mede
MEB açıkladı (dokunulmaz — sözcük gibi okunur)
Dr. Ayşe doktor Ayşe
Ali & Veli Ali ve Veli

Ekler yazılıştan değil okunuştan üretilir. Kullanıcı 5'de yazmış olabilir; doğrusu beştedir, çünkü doğru biçimi belirleyen sayının söylenişidir. Ünlü uyumu, ünsüz sertleşmesi, dört → dörd yumuşaması ve kaynaştırma harfleri buna göre uygulanır.

Kısaltmalar

Bir kısaltmanın sözcük gibi mi (MEB → "meb") yoksa harf harf mi (TCDD → "te ce de de") okunacağı elle tutulan bir listeye bırakılmadı — o liste hiç bitmez. Karar fonotaktikten çıkıyor: Türkçe hecesi (C)V(C)(C) kalıbındadır, sözcük başında ünsüz kümesi bulunmaz, sonda yalnızca belirli ikili kümeler gelir.

from anka.text import is_pronounceable

is_pronounceable("MEB")     # True  -> "meb"
is_pronounceable("TCDD")    # False -> "te ce de de"  (ünlü yok)
is_pronounceable("ABD")     # False -> "a be de"      (bd geçersiz son küme)
is_pronounceable("TÜRKSAT") # True  -> "TÜRKSAT"      (rk|s geçerli)

Kural 58 gerçek kurum kısaltmasında sınandı ve hepsini doğru sınıflandırdı. Yanıldığı birkaç durum (AB → "a be", RTÜK → "ertük") lexicon.py'deki iki küçük istisna kümesinde. Kendi ekini lexicon'a dokunmadan verebilirsin:

normalize("XYZKUR bildirdi.", extra_acronyms={"XYZKUR"})
normalize("Xyz. geldi", extra_abbreviations={"Xyz.": "iksiz"})

Şapkalı harfler ve vocab

Düzeltme işaretli â î û korunurkâr ile kar aynı sözcük değil, ve ünlü uyumunu da bu harfler belirler (kârkârda, mahkûmmahkûmu). Vocab'ı bu harfleri taşımayan bir kontrol noktasıyla çalışıyorsan fold_circumflex=True düz karşılıklarına indirir.

Vocab verilirse (ki AnkaTTS kendi vocab'ını otomatik verir) eksik karakterler de ele alınır:

normalize("MAHKÛM oldu.", vocab=vocab)   # 'mahkûm oldu.'  (büyük Û vocab'da yok)
normalize("Fiyat 100 ₼", vocab=vocab)    # uyarı: '₼' vocab'da hiç yok

Genel bir lower() yapılmaz — model normal yazılmış metinle eğitildi. Yalnızca vocab dışı karakter taşıyan kelime küçültülür, o da ancak küçük hâli sorunu çözüyorsa. Çözmüyorsa kelime bozulmaz, uyarı verilir.


Parametreler

Üç katman var. Günlük kullanımda yalnızca ilki gerekir.

Günlük: text, voice ya da ref_audio + ref_text, seed, sentence_pause (0.15 sn), paragraph_pause (0.45 sn)

Sentez ayarları: ölçülmüş tek bir varsayılan set. Her değer tek başına değiştirilebilir; vermediğiniz değerler varsayılanında kalır.

parametre varsayılan
speed 0.85
nfe_step 32
cfg_strength 2.0
sway_sampling_coef -1.0
tts.synthesize("Metin.", voice="anlatici")                          # varsayılanlar
tts.synthesize("Metin.", voice="anlatici", speed=1.0, nfe_step=16)  # ikisini değiştir

Varsayılanlar tahmin değil: speed ve nfe_step, yukarıda anlatılan 495 cümlelik değerlendirme setinde tarandı, hepsi aynı ASR geçişinden geçirildi ve en iyi sonucu veren değerlerde sabitlendi. cfg_strength ve sway_sampling_coef F5'in kendi değerleri — bu ikisinde henüz tarama yapılmadı.

Gizli: cross_fade_duration, target_rms, fix_duration, ode_method **f5_kwargs ile geçer ama imzada görünmez. Özellikle cross_fade_duration'ı kurcalama isteği genellikle chunking duraksamasını "düzeltme" çabasıdır; asıl çözüm referans süresidir ve kütüphane bunu zaten söylüyor.


Sesler

Pakette iki ses gömülü geliyor, bu yüzden sentez hiç referans vermeden de çalışır:

tts.synthesize("Metin.")                    # male, varsayılan
tts.synthesize("Metin.", voice="female")
ses referans
male (varsayılan) 7,2 sn
female 7,0 sn

İkisi de yapay zekâyla üretildi: her biri bir metin tarifinden tasarlandı, hiçbiri gerçek bir kişinin kaydı değil. Kayıtlar Apache-2.0 kodundan ayrı olarak CC-BY-NC-4.0 ile lisanslı; kökenleri anka/data/voices/README.md dosyasında yazıyor.

Kendi sesinle konuşturmak için bir referansı bir kez kaydet:

tts.add_voice("anlatici", "kayit.wav", "Referansta birebir söylenen cümle.")
tts.list_voices()                      # ['anlatici']
tts.synthesize("Metin.", voice="anlatici")

Ses dosyası ~/.local/share/anka/voices/ altına kopyalanır — kaynak dosyayı taşısan da ses çalışmaya devam eder. Dizin ANKA_HOME ile değiştirilebilir. voice= verilmezse tek kayıtlı ses kullanılır; hiç kayıtlı ses yoksa gömülü male sesi konuşur; birden çok varsa birini seçmen gerekir. Gömülü bir sesle aynı adı taşıyan kayıtlı ses onun yerine geçer. list_voices() yalnızca senin kaydettiklerini listeler; gömülü sesler her zaman hazır.


Çıktı sözleşmesi

synthesize() her zaman şunu döner:

  • numpy.float32
  • 24 000 Hz
  • mono (tek boyutlu dizi)
  • değerler [-1, 1] aralığında

save_wav() aynı biçimde yazar. Aynı metin + aynı seed + aynı referans = aynı çıktı (seed=None verilirse rastgele).


Kapsam dışı

Otomatik transkripsiyon (ASR) yok: ref_audio verirsen ref_text de vermelisin. Whisper bağımlılığı kurulum boyutunu üçe katlardı.


Geliştirme

pip install -e ".[dev]"
pytest                    # 794 test, model gerektirmez

Determinizm testi model ister; çalıştırmak için:

export ANKA_TEST_MODEL=/yol/model_dizini
export ANKA_TEST_REF=referans.wav
export ANKA_TEST_REF_TEXT="Referansta söylenen cümle."
pytest tests/test_tts.py -k determinizm

Lisans

Kod: Apache-2.0.

anka-tts/v0.1 ağırlıkları ve gömülü sesler: CC-BY-NC-4.0 — kişisel, hobi ve araştırma amaçlı kullanım serbest; bu lisans altında ticari kullanım yasak. Ağırlıklar için ayrı bir ticari lisans veriliyor — iletişim: [CONTACT] .

Bağımlılıklar ve ağırlıklar kendi lisanslarına tabidir — f5-tts MIT'tir, ama kullandığın model ağırlığının lisansı ayrıdır ve ticari kullanıma izin vermeyebilir. Klonlanan sesin sahibinden izin almak da senin sorumluluğundadır.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

anka_tts-0.1.6.tar.gz (700.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

anka_tts-0.1.6-py3-none-any.whl (666.3 kB view details)

Uploaded Python 3

File details

Details for the file anka_tts-0.1.6.tar.gz.

File metadata

  • Download URL: anka_tts-0.1.6.tar.gz
  • Upload date:
  • Size: 700.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for anka_tts-0.1.6.tar.gz
Algorithm Hash digest
SHA256 ddd711d09888ad5ee3af6cc26f6f6cfa743a58339298f10f8ad86710329a6ecb
MD5 a48e8db321c344a01e3a66eae610f6ae
BLAKE2b-256 ed5829037eeaad58d8f71bd622405b3605c104eb9a2d84f8d28a3b94796c794e

See more details on using hashes here.

Provenance

The following attestation bundles were made for anka_tts-0.1.6.tar.gz:

Publisher: publish.yml on KrmKayabasi/Anka-TTS

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file anka_tts-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: anka_tts-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 666.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for anka_tts-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 15fb66f02888e2cd33fcb5d24ef4fffa98230543dd4587b19e5393ea7d10a63b
MD5 fea20c447b08fb7af54b0dc7bd248f8b
BLAKE2b-256 b5da9667ed437808f7d69359ca3c3e428ec4a80e75f5c728bee74caa1510adad

See more details on using hashes here.

Provenance

The following attestation bundles were made for anka_tts-0.1.6-py3-none-any.whl:

Publisher: publish.yml on KrmKayabasi/Anka-TTS

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.1.6 This release

2 files

0.1.5

2 files

0.1.4

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page