"""Werea-TSS Hugging Face Space arayuzu.
SPDX-License-Identifier: MIT
"""
from __future__ import annotations
import os
os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "False")
import gradio as gr
from werea_tss import MAX_CHARACTERS, QUALITY_MODES, engine_version, synthesize
CSS = """
:root { color-scheme: dark; }
.gradio-container {
--werea-pink: #ff488b;
--werea-ink: #09090b;
--werea-panel: #111115;
--werea-line: rgba(255,255,255,.11);
max-width: 1180px !important;
margin: 0 auto !important;
color: #f6f6f7 !important;
background:
radial-gradient(circle at 92% 2%, rgba(255,72,139,.16), transparent 31rem),
radial-gradient(circle at 0% 65%, rgba(255,72,139,.07), transparent 28rem),
var(--werea-ink) !important;
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif !important;
}
.main { background: transparent !important; }
#werea-hero { padding: 32px 4px 14px; }
.werea-nav { display:flex; align-items:center; justify-content:space-between; gap:20px; margin-bottom:64px; }
.werea-wordmark { color:#fff; font-weight:700; font-size:27px; letter-spacing:-1.6px; }
.werea-badge { border:1px solid rgba(255,72,139,.45); color:#ff8fb8; border-radius:999px; padding:7px 11px; font-size:12px; letter-spacing:.08em; text-transform:uppercase; }
.werea-kicker { color:var(--werea-pink); text-transform:uppercase; letter-spacing:.13em; font-size:12px; font-weight:700; }
.werea-title { max-width:850px; margin:14px 0 16px; font-weight:550 !important; line-height:.95 !important; letter-spacing:-.065em !important; font-size:clamp(48px,9vw,106px) !important; }
.werea-title span { color:var(--werea-pink); }
.werea-lead { color:#aaaab2 !important; font-size:clamp(17px,2vw,22px) !important; line-height:1.45 !important; max-width:700px; margin:0 0 28px; }
.werea-pills { display:flex; flex-wrap:wrap; gap:8px; }
.werea-pill { border:1px solid var(--werea-line); border-radius:999px; padding:8px 12px; color:#c7c7cd; font-size:13px; background:rgba(255,255,255,.025); }
#studio { border:1px solid var(--werea-line) !important; border-radius:22px !important; padding:18px !important; background:rgba(17,17,21,.88) !important; box-shadow:0 28px 90px rgba(0,0,0,.32); }
#studio textarea { min-height:218px !important; font-size:18px !important; line-height:1.6 !important; background:#0d0d10 !important; color:#f6f6f7 !important; }
#studio .form { border-color:var(--werea-line) !important; background:#0d0d10 !important; }
#generate { min-height:50px; font-weight:700; background:var(--werea-pink) !important; border-color:var(--werea-pink) !important; color:#18030b !important; box-shadow:none !important; }
#generate:hover { filter:brightness(1.08); }
#clear { min-height:50px; }
#status { min-height:30px; color:#bdbdc5; background:transparent !important; border:0 !important; padding:10px 0 0 !important; }
#status p { color:#c7c7cd !important; }
.werea-section-title { margin:48px 0 8px; font-size:24px; letter-spacing:-.03em; }
.werea-note { color:#92929c; font-size:14px; line-height:1.65; }
.werea-footer { border-top:1px solid var(--werea-line); margin-top:48px; padding:24px 0 10px; color:#777781; font-size:12px; display:flex; justify-content:space-between; flex-wrap:wrap; gap:10px; }
footer { display:none !important; }
@media (max-width: 700px) {
#werea-hero { padding-top:18px; }
.werea-nav { margin-bottom:42px; }
#studio { padding:12px !important; border-radius:16px !important; }
}
"""
HEAD = """
"""
HERO = """
Türkçe Ses Sentezi
Metni sese.
Açıkça.
Türkçe metninizi Werea'nın 183 milyon parametreli açık modeliyle doğal bir 48 kHz WAV dosyasına dönüştürün. Ses klonlama yok, hesap yok, kalıcı metin kaydı yok.
%100 Türkçe arayüz
183M gerçek model
48 kHz çıktı
Apache-2.0 ağırlık
Ses klonlamaz
"""
INFO = """
### Şeffaflık notu
Bu sürüm, **Werea-co/Werea-TSS** adlı 183,2M parametreli neural modeli kullanır. Model Apache-2.0 FreyaTTS-small tabanından, Werea'nın özgün Türkçe metinleri ve sabit tohumla üretilmiş sentetik öğretmen sesleriyle fine-tune edilmiştir. İzinsiz gerçek kişi kaydı kullanılmamıştır. Çıktı sentetiktir ve gerçek insan kaydı gibi sunulmamalıdır.
### Sorumlu kullanım
Dolandırıcılık, kimliğe bürünme, taciz, izinsiz otomatik arama, yanıltıcı haber veya sentetik sesi gerçek kayıt gibi gösterme amacıyla kullanmayın. Hassas ya da kamuya açık içerikleri yayımlamadan önce bir insan tarafından dinleyip doğrulayın.
### Gizlilik özeti
Metin yalnızca ses üretmek için bellekte işlenir. Uygulama metni veritabanına yazmaz ve içerik analitiği çalıştırmaz. Oluşturulan geçici ses dosyaları düzenli olarak temizlenir. Barındırma sağlayıcısı Hugging Face kendi güvenlik ve işletim kayıtlarını işleyebilir; ayrıntılar depo içindeki `GIZLILIK.md` belgesindedir.
"""
def generate(text: str, quality: str):
try:
return synthesize(text, quality)
except ValueError as error:
raise gr.Error(str(error), duration=5) from error
except RuntimeError as error:
raise gr.Error(str(error), duration=5) from error
theme = gr.themes.Base(
primary_hue="pink",
neutral_hue="zinc",
radius_size="lg",
font=["Inter", "ui-sans-serif", "system-ui", "sans-serif"],
).set(
body_background_fill="#09090b",
body_background_fill_dark="#09090b",
block_background_fill="#111115",
block_background_fill_dark="#111115",
block_border_color="rgba(255,255,255,.11)",
block_border_color_dark="rgba(255,255,255,.11)",
button_primary_background_fill="#ff488b",
button_primary_background_fill_dark="#ff488b",
)
with gr.Blocks(
title="Werea-TSS · Türkçe Ses Sentezi",
delete_cache=(900, 3600),
fill_width=True,
) as demo:
gr.HTML(HERO)
with gr.Group(elem_id="studio"):
with gr.Row(equal_height=False):
with gr.Column(scale=7, min_width=320):
text = gr.Textbox(
label="Seslendirilecek metin",
placeholder="Bugün yeni bir fikri seslendirelim…",
lines=8,
max_lines=16,
max_length=MAX_CHARACTERS,
autofocus=True,
info=f"En fazla {MAX_CHARACTERS:,} karakter".replace(",", "."),
)
with gr.Row():
generate_button = gr.Button("Sesi üret", variant="primary", elem_id="generate")
clear_button = gr.Button("Temizle", variant="secondary", elem_id="clear")
with gr.Column(scale=4, min_width=280):
quality = gr.Dropdown(
choices=list(QUALITY_MODES),
value="Dengeli",
label="Üretim kalitesi",
info="Yüksek kalite daha uzun sürebilir.",
)
audio = gr.Audio(
label="Üretilen ses",
type="filepath",
format="wav",
buttons=["download"],
editable=False,
)
status = gr.Markdown("Metninizi yazın ve **Sesi üret** düğmesine basın.", elem_id="status")
gr.HTML('
Başlamak için örnekler
')
gr.Examples(
examples=[
["Merhaba! Burası Werea Türkçe Ses Sentezi. Yazdığınız metni kendi açık modelimizle sese dönüştürüyoruz."],
["İstanbul'da bugün hava serin. Yanınıza ince bir ceket almayı unutmayın."],
["Bir fikrin değeri, onu ne kadar açık anlattığınızla büyür."],
],
inputs=[text],
cache_examples=False,
label="Örnekler",
)
with gr.Accordion("Kaynak, lisans ve gizlilik", open=False):
gr.Markdown(INFO)
gr.HTML(
f''
)
generate_event = generate_button.click(
fn=generate,
inputs=[text, quality],
outputs=[audio, status],
concurrency_limit=1,
concurrency_id="synthesis",
api_name="turkce_ses_uret",
)
text.submit(
fn=generate,
inputs=[text, quality],
outputs=[audio, status],
concurrency_limit=1,
concurrency_id="synthesis",
api_name=False,
)
clear_button.click(
fn=lambda: ("", None, "Metninizi yazın ve **Sesi üret** düğmesine basın."),
outputs=[text, audio, status],
queue=False,
api_name=False,
)
demo.queue(max_size=12, default_concurrency_limit=1)
if __name__ == "__main__":
demo.launch(show_error=False, theme=theme, css=CSS, head=HEAD)