cairo-tts 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cairo_tts-0.1.0/.gitignore +21 -0
- cairo_tts-0.1.0/LICENSE +21 -0
- cairo_tts-0.1.0/NOTICE.md +7 -0
- cairo_tts-0.1.0/PKG-INFO +345 -0
- cairo_tts-0.1.0/README.md +304 -0
- cairo_tts-0.1.0/model_card/README.md +172 -0
- cairo_tts-0.1.0/pyproject.toml +60 -0
- cairo_tts-0.1.0/space/README.md +23 -0
- cairo_tts-0.1.0/src/cairo_tts/__init__.py +7 -0
- cairo_tts-0.1.0/src/cairo_tts/__main__.py +3 -0
- cairo_tts-0.1.0/src/cairo_tts/cli.py +88 -0
- cairo_tts-0.1.0/src/cairo_tts/model.py +280 -0
- cairo_tts-0.1.0/src/cairo_tts/server/__init__.py +12 -0
- cairo_tts-0.1.0/src/cairo_tts/server/app.py +222 -0
- cairo_tts-0.1.0/src/cairo_tts/server/static/app.css +386 -0
- cairo_tts-0.1.0/src/cairo_tts/server/static/app.js +679 -0
- cairo_tts-0.1.0/src/cairo_tts/server/static/favicon.png +0 -0
- cairo_tts-0.1.0/src/cairo_tts/server/static/index.html +264 -0
- cairo_tts-0.1.0/src/cairo_tts/server/static/logo.webp +0 -0
- cairo_tts-0.1.0/src/cairo_tts/text/__init__.py +55 -0
- cairo_tts-0.1.0/src/cairo_tts/text/chars.py +113 -0
- cairo_tts-0.1.0/src/cairo_tts/text/egyptian.py +230 -0
- cairo_tts-0.1.0/src/cairo_tts/text/frontend.py +209 -0
- cairo_tts-0.1.0/src/cairo_tts/text/numbers.py +187 -0
- cairo_tts-0.1.0/tests/test_inference.py +52 -0
- cairo_tts-0.1.0/tests/test_text.py +54 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
__pycache__/
|
|
2
|
+
*.py[cod]
|
|
3
|
+
*.egg-info/
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
.venv/
|
|
7
|
+
.pytest_cache/
|
|
8
|
+
.ruff_cache/
|
|
9
|
+
.ipynb_checkpoints/
|
|
10
|
+
|
|
11
|
+
# local model copy, downloads, generated audio
|
|
12
|
+
_model/
|
|
13
|
+
_samples/
|
|
14
|
+
*.zip
|
|
15
|
+
*.wav
|
|
16
|
+
*.safetensors
|
|
17
|
+
outputs/
|
|
18
|
+
|
|
19
|
+
# preset voices are real speakers: they ship only with the Hugging Face model repo
|
|
20
|
+
voices/
|
|
21
|
+
_voice_candidates/
|
cairo_tts-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mohammed Aly
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# Notices
|
|
2
|
+
|
|
3
|
+
* **Code** in this repository: MIT (see `LICENSE`).
|
|
4
|
+
* **Engine**: [pocket-tts](https://github.com/kyutai-labs/pocket-tts) by Kyutai, MIT. Cairo-TTS installs it from PyPI and only adds the Egyptian text pipeline, voices, server and UI.
|
|
5
|
+
* **Model weights** (`mohammedaly22/Cairo-TTS` on Hugging Face) are fine-tuned from Kyutai's Pocket TTS weights and inherit their terms of use. Read the model card before using them.
|
|
6
|
+
* **Diacritics**: the training text was diacritized with [CATT](https://github.com/abjadai/catt).
|
|
7
|
+
* **Preset voices** are short clips of speakers from public Egyptian podcasts (collected with the [EgySpeech](https://github.com/MohammedAly22/EgySpeech) pipeline) and recordings contributed by the author. They are provided for research and demos only. Do not use them, or any cloned voice, to impersonate a real person or to deceive.
|
cairo_tts-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: cairo-tts
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Cairo-TTS: fast Egyptian Arabic text-to-speech with English code-switching, streaming and zero-shot voice cloning (CPU or GPU).
|
|
5
|
+
Project-URL: Homepage, https://github.com/MohammedAly22/Cairo-TTS
|
|
6
|
+
Project-URL: Model, https://huggingface.co/mohammedaly22/Cairo-TTS
|
|
7
|
+
Project-URL: Demo, https://huggingface.co/spaces/mohammedaly22/Cairo-TTS
|
|
8
|
+
Project-URL: Issues, https://github.com/MohammedAly22/Cairo-TTS/issues
|
|
9
|
+
Author: Mohammed Aly
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
License-File: NOTICE.md
|
|
13
|
+
Keywords: arabic,egyptian,pocket-tts,speech-synthesis,text-to-speech,tts,voice-cloning
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Intended Audience :: Science/Research
|
|
17
|
+
Classifier: Natural Language :: Arabic
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Speech
|
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
22
|
+
Requires-Python: <3.15,>=3.10
|
|
23
|
+
Requires-Dist: huggingface-hub>=0.24
|
|
24
|
+
Requires-Dist: numpy
|
|
25
|
+
Requires-Dist: pocket-tts==3.3.0
|
|
26
|
+
Requires-Dist: pyyaml
|
|
27
|
+
Requires-Dist: scipy
|
|
28
|
+
Requires-Dist: soundfile
|
|
29
|
+
Requires-Dist: torch>=2.4
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: fastapi>=0.110; extra == 'dev'
|
|
32
|
+
Requires-Dist: httpx; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
34
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'dev'
|
|
35
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'dev'
|
|
36
|
+
Provides-Extra: ui
|
|
37
|
+
Requires-Dist: fastapi>=0.110; extra == 'ui'
|
|
38
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'ui'
|
|
39
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == 'ui'
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
|
|
42
|
+
<p align="center">
|
|
43
|
+
<img src="https://raw.githubusercontent.com/MohammedAly22/Cairo-TTS/main/assets/banner.png" alt="Cairo-TTS" width="100%">
|
|
44
|
+
</p>
|
|
45
|
+
|
|
46
|
+
<h1 align="center">Cairo-TTS · كايرو</h1>
|
|
47
|
+
|
|
48
|
+
<p align="center">
|
|
49
|
+
<b>Fast Egyptian Arabic text-to-speech with English code-switching, live streaming and zero-shot voice cloning.</b><br>
|
|
50
|
+
<sub>It runs on CPU or GPU, starts speaking in under 100 ms on a GPU, and includes 20 preset voices and a web studio.</sub>
|
|
51
|
+
</p>
|
|
52
|
+
|
|
53
|
+
<p align="center">
|
|
54
|
+
<a href="https://huggingface.co/mohammedaly22/Cairo-TTS"><img src="https://img.shields.io/badge/🤗%20Model-Cairo--TTS-FDB813" alt="Model"></a>
|
|
55
|
+
<a href="https://huggingface.co/spaces/mohammedaly22/Cairo-TTS"><img src="https://img.shields.io/badge/🤗%20Space-Live%20demo-F59E0B" alt="Space"></a>
|
|
56
|
+
<a href="https://colab.research.google.com/github/MohammedAly22/Cairo-TTS/blob/main/notebooks/01_quickstart.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a>
|
|
57
|
+
<a href="https://pypi.org/project/cairo-tts/"><img src="https://img.shields.io/pypi/v/cairo-tts?color=F97316&label=pypi" alt="PyPI"></a>
|
|
58
|
+
<img src="https://img.shields.io/badge/python-3.10–3.14-1E3A5F" alt="Python">
|
|
59
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/code-MIT-23466E" alt="MIT"></a>
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
<p align="center">
|
|
63
|
+
<a href="#-install">Install</a> ·
|
|
64
|
+
<a href="#-python">Python</a> ·
|
|
65
|
+
<a href="#-web-studio">Web studio</a> ·
|
|
66
|
+
<a href="#-colab-notebooks">Colab</a> ·
|
|
67
|
+
<a href="#-hugging-face-space">Space</a> ·
|
|
68
|
+
<a href="#️-pronunciation-control">Pronunciation</a> ·
|
|
69
|
+
<a href="#-text-preprocessing">Preprocessing</a> ·
|
|
70
|
+
<a href="#️-parameters">Parameters</a>
|
|
71
|
+
</p>
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
from cairo_tts import CairoTTS
|
|
77
|
+
|
|
78
|
+
tts = CairoTTS.from_pretrained() # downloads mohammedaly22/Cairo-TTS, runs on CPU
|
|
79
|
+
tts.save("ال meeting بكره الصبح بدري, ف يا ريت متتأخرش.", "out.wav", voice="malak")
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## ✨ Features
|
|
83
|
+
|
|
84
|
+
| | |
|
|
85
|
+
|---|---|
|
|
86
|
+
| 🗣️ **Egyptian Arabic** | Trained on ~747 h of Egyptian podcasts collected with the [EgySpeech](https://github.com/MohammedAly22/EgySpeech) pipeline. It reads everyday عامية naturally. |
|
|
87
|
+
| 🔀 **Code-switching** | English words inside Arabic sentences: «ال deadline بتاع ال project». |
|
|
88
|
+
| 🎙️ **Zero-shot cloning** | Clone any voice from a ~10 s recording, or use one of the **20 preset voices** (10 male, 10 female). |
|
|
89
|
+
| ⚡ **Streaming** | Audio comes out in 80 ms frames while it is generated: ~80 ms to first audio on a GPU. |
|
|
90
|
+
| 💻 **CPU or GPU** | ~100M parameters, faster than real time on a laptop CPU, with optional int8. |
|
|
91
|
+
| 🔢 **Egyptian text frontend** | Numbers, dates, times, money, %, phone numbers, emails, URLs, hashtags and acronyms are read the Egyptian way. |
|
|
92
|
+
| ✍️ **Pronunciation control** | Diacritics override the model's reading; `ةْ` gives a pronounced ta marbuta, and `~` the Egyptian reading of a letter. |
|
|
93
|
+
| 🎛️ **Web studio** | An RTL Arabic UI with generate and stream modes, voices, cloning, parameters, live waveform and metrics, and light/dark themes. |
|
|
94
|
+
|
|
95
|
+
## 📦 Install
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install cairo-tts # Python API + CLI
|
|
99
|
+
pip install "cairo-tts[ui]" # + web studio (FastAPI)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
From source:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
git clone https://github.com/MohammedAly22/Cairo-TTS && cd Cairo-TTS
|
|
106
|
+
pip install -e ".[ui]"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
* **GPU**: install the CUDA build of PyTorch first ([pytorch.org](https://pytorch.org/get-started/locally/)). Cairo-TTS runs on the CPU by default; pass `device="cuda"` (or `--device cuda`) to use the GPU, or `device="auto"` to pick it when available.
|
|
110
|
+
* **CPU only**: `pip install torch --index-url https://download.pytorch.org/whl/cpu` keeps the install small.
|
|
111
|
+
|
|
112
|
+
## 🐍 Python
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from cairo_tts import CairoTTS
|
|
116
|
+
|
|
117
|
+
tts = CairoTTS.from_pretrained(
|
|
118
|
+
"mohammedaly22/Cairo-TTS", # or a local folder
|
|
119
|
+
device="cpu", # "cpu" (default) | "cuda" | "cuda:1" | "auto"
|
|
120
|
+
max_prompt_sec=10, # seconds of reference audio used for cloning
|
|
121
|
+
quantize=False, # int8 weights on CPU
|
|
122
|
+
num_threads=None, # CPU threads
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
# 1) generate: a float32 numpy array at 24 kHz
|
|
126
|
+
audio = tts.generate("النهارده الجو حلو اوي, ايه رأيك ننزل نتمشى شوية؟")
|
|
127
|
+
|
|
128
|
+
# 2) save straight to a file, with a preset voice
|
|
129
|
+
tts.save("عارف ايه اكتر حاجة بتخوفني.", "ahmed.wav", voice="ahmed")
|
|
130
|
+
|
|
131
|
+
# 3) clone any voice (zero-shot) from a short, clean recording
|
|
132
|
+
tts.save("ده صوتي انا, بس الموديل هو اللي بيتكلم.", "me.wav", voice="my_voice.wav")
|
|
133
|
+
tts.export_voice("my_voice.wav", "my_voice.safetensors") # instant to reload: voice="my_voice.safetensors"
|
|
134
|
+
|
|
135
|
+
# 4) stream: chunks arrive while audio is generated
|
|
136
|
+
for chunk in tts.stream("حاسس اني واقف مكاني. كل يوم نفس التاسكات, نفس ال meetings.", voice="sara"):
|
|
137
|
+
play(chunk) # your audio sink
|
|
138
|
+
|
|
139
|
+
# 5) metrics of the last call
|
|
140
|
+
m = tts.last_metrics
|
|
141
|
+
print(f"TTFA {m.ttfa*1000:.0f} ms · {m.audio:.1f}s audio in {m.total:.2f}s · {m.x_realtime:.1f}x real time · {m.device}")
|
|
142
|
+
|
|
143
|
+
# 6) see exactly what the model reads
|
|
144
|
+
print(tts.normalize("كلمني على 01012345678 الساعة 3:30 م"))
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
<details>
|
|
148
|
+
<summary><b>List the preset voices</b></summary>
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
for v in tts.voices():
|
|
152
|
+
print(v["id"], v["name_ar"], v["gender"], v["description_ar"])
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
| Male | | Female | |
|
|
156
|
+
|---|---|---|---|
|
|
157
|
+
| `mohamed` | محمد | `sara` | سارة |
|
|
158
|
+
| `ahmed` | أحمد | `mariam` | مريم |
|
|
159
|
+
| `ali` | علي | `nour` | نور |
|
|
160
|
+
| `omar` | عمر | `fatma` | فاطمة |
|
|
161
|
+
| `youssef` | يوسف | `heba` | هبة |
|
|
162
|
+
| `mostafa` | مصطفى | `yasmin` | ياسمين |
|
|
163
|
+
| `karim` | كريم | `mona` | منى |
|
|
164
|
+
| `hassan` | حسن | `rana` | رنا |
|
|
165
|
+
| `tarek` | طارق | `dina` | دينا |
|
|
166
|
+
| `yehia` | يحيى | `malak` | ملك |
|
|
167
|
+
|
|
168
|
+
Each voice has an Arabic and an English description (pitch, style, tone) in `voices/voices.json`. **`tarek` is the default voice** (used when `voice` is not given). The names are made up.
|
|
169
|
+
</details>
|
|
170
|
+
|
|
171
|
+
A complete script is in [`examples/infer.py`](examples/infer.py).
|
|
172
|
+
|
|
173
|
+
### Command line
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
cairo-tts say "ال meeting اتأجل لبكره." -o out.wav --voice ahmed
|
|
177
|
+
cairo-tts say "صوتي انا." -o me.wav --voice my_voice.wav --device cpu
|
|
178
|
+
echo "النص من ملف" | cairo-tts say - -o out.wav
|
|
179
|
+
cairo-tts voices # preset voices
|
|
180
|
+
cairo-tts normalize "الساعة 3:30 م" # → الساعة تلاتة ونص العصر
|
|
181
|
+
cairo-tts serve --port 8000 # web studio
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
## 🎛️ Web studio
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
pip install "cairo-tts[ui]"
|
|
188
|
+
cairo-tts serve # http://127.0.0.1:8000 (--device cpu|cuda, --host 0.0.0.0)
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
* **Two modes**: **توليد كامل** (generate the whole clip) and **بث مباشر** (live streaming, played while it is generated).
|
|
192
|
+
* **Voices**: a searchable dropdown of the 20 presets (descriptions, play/pause previews), or **استنسخ صوت** (clone a voice): upload a file or record from the microphone.
|
|
193
|
+
* **Parameters**: temperature, LSD steps, EOS threshold, frames after EOS, noise clamp, chunk size.
|
|
194
|
+
* **Metrics** after every run: server TTFA, browser TTFA, total time, audio length, × real time, RTF, chunks / characters, device.
|
|
195
|
+
* **Pronunciation toolbar** (فتحة، ضمة، كسرة، سكون، شدة، `ةْ`، `~`), a random Egyptian sentence button, and a preview of the normalized text.
|
|
196
|
+
* A minimal Arabic, RTL, responsive layout with dark and light themes (`?theme=light|dark`), a waveform that fills in while streaming, and a generation history.
|
|
197
|
+
* Streaming plays through an AudioWorklet at the model's 24 kHz rate with a short pre-buffer, so chunks join without gaps or resampling clicks.
|
|
198
|
+
* A JSON API at `/api/docs`: `POST /api/generate`, `POST /api/stream` (NDJSON PCM chunks), `GET /api/voices`, `POST /api/voices/upload`, `POST /api/normalize`.
|
|
199
|
+
|
|
200
|
+
Use it from Python (e.g. in your own app):
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
from cairo_tts import CairoTTS
|
|
204
|
+
from cairo_tts.server import create_app, serve
|
|
205
|
+
|
|
206
|
+
serve(CairoTTS.from_pretrained(device="cuda"), host="0.0.0.0", port=8000)
|
|
207
|
+
# or: app = create_app(tts) → mount / run with any ASGI server
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
## 📓 Colab notebooks
|
|
211
|
+
|
|
212
|
+
| Notebook | | |
|
|
213
|
+
|---|---|---|
|
|
214
|
+
| **Quick start**: load, preset voices, cloning, streaming, preprocessing, diacritics, parameters | [`01_quickstart.ipynb`](notebooks/01_quickstart.ipynb) | <a href="https://colab.research.google.com/github/MohammedAly22/Cairo-TTS/blob/main/notebooks/01_quickstart.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a> |
|
|
215
|
+
| **Web UI**: the full studio inside Colab, no local install | [`02_web_ui.ipynb`](notebooks/02_web_ui.ipynb) | <a href="https://colab.research.google.com/github/MohammedAly22/Cairo-TTS/blob/main/notebooks/02_web_ui.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open in Colab"></a> |
|
|
216
|
+
|
|
217
|
+
Both download the public model from Hugging Face; no token is needed.
|
|
218
|
+
|
|
219
|
+
## 🤗 Hugging Face Space
|
|
220
|
+
|
|
221
|
+
The [Space](https://huggingface.co/spaces/mohammedaly22/Cairo-TTS) runs the same studio (Docker SDK, port 7860). To deploy your own:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
python scripts/deploy_space.py --space <user>/Cairo-TTS --token-secret # uploads space/ + the package source
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
`--token-secret` stores your token as the Space's `HF_TOKEN` secret (only needed if you point it at a private model). Optional Space variables: `CAIRO_TTS_MODEL`, `CAIRO_TTS_DEVICE`, `CAIRO_TTS_QUANTIZE=1`.
|
|
228
|
+
|
|
229
|
+
## ✍️ Pronunciation control
|
|
230
|
+
|
|
231
|
+
The model adds diacritics on its own. Write them yourself only where it reads a word wrong:
|
|
232
|
+
|
|
233
|
+
| Write | Meaning | Example |
|
|
234
|
+
|---|---|---|
|
|
235
|
+
| **`ةْ`** (ta marbuta + sukun) | ة is pronounced **t**, as in the construct state (إضافة); normalized to `تْ` | `عربيةْ ابويا` → *ʿarabiyyit abūya*; plain `عربية` → *ʿarabiyya* |
|
|
236
|
+
| **`~`** after a letter | the **Egyptian reading** of that letter, mainly **ق → glottal stop (ء)** | `ق~لبي` → *ʾalbi*, `ق~ولتلك` → *ʾultilak* |
|
|
237
|
+
| a vowel (`َ ُ ِ`) | chooses between readings | `نِفسَها` (she wants) vs `نَفسَها` (herself) |
|
|
238
|
+
| shadda `ّ` | doubles the consonant | `بَتمَشَّى` |
|
|
239
|
+
| sukun `ْ` | no vowel | `اتْحَرَجْت` |
|
|
240
|
+
| Latin letters | English words | `ال meeting`, `ال deal` |
|
|
241
|
+
| `CEO`, `AI` | upper-case runs are spelled as English letters | → `c e o`, `a i` (write `ceo` to read it as a word) |
|
|
242
|
+
| `.` `,` `،` | sentence end (long pause) / short pause; `?` `!` become `.` | |
|
|
243
|
+
|
|
244
|
+
> **Order of marks**: letter → `~` → shadda → vowel (e.g. `ق~َ`). The frontend also reorders them for you. `~` is the marker the model learned from [CATT](https://github.com/abjadai/catt)'s Egyptian «؞» sign.
|
|
245
|
+
|
|
246
|
+
<details>
|
|
247
|
+
<summary><b>ملاحظات بالمصري</b></summary>
|
|
248
|
+
|
|
249
|
+
* اكتب زي ما بتتكلم: «مش عارف»، «عشان كدة»، «إزيك». الفصحى بتشتغل بس العامية أحلى.
|
|
250
|
+
* الكلام الإنجليزي اكتبه بالحروف اللاتيني: «ال meeting»، «ال deadline».
|
|
251
|
+
* لو كلمة اتقرت غلط شكّلها بس هي: «نِفسَها» بدل «نفسها».
|
|
252
|
+
* **ةْ**: التاء المربوطة اللي عليها سكون بتتنطق «ت»: «عربيةْ ابويا» ← عربيِّت أبويا.
|
|
253
|
+
* **~**: بعد الحرف معناها انطقه بالمصري، وأشهرها «ق~» تتقري همزة: «ق~لبي» ← ألبي.
|
|
254
|
+
* الصوت المرجعي: ٨–١٠ ثواني نضيفة، صوت واحد، من غير مزيكا.
|
|
255
|
+
* لو آخر الجملة بيتقطع نزّل «حد النهاية» (`eos_threshold`)، ولو الصوت مش ثابت قلل الحرارة.
|
|
256
|
+
</details>
|
|
257
|
+
|
|
258
|
+
## 🔢 Text preprocessing
|
|
259
|
+
|
|
260
|
+
`preprocess_egyptian()` runs before the model frontend. You can use it on its own:
|
|
261
|
+
|
|
262
|
+
```python
|
|
263
|
+
from cairo_tts import preprocess_egyptian, prepare_text
|
|
264
|
+
|
|
265
|
+
preprocess_egyptian("كلمني على 01012345678 او ابعت على ahmed.ali@gmail.com")
|
|
266
|
+
# كلمني على زيرو واحد زيرو, واحد اتنين تلاتة اربعة, خمسة ستة سبعة تمانية, او ابعت على احمد دوت علي ات gmail دوت كوم
|
|
267
|
+
|
|
268
|
+
prepare_text("الاجتماع الساعة 3:30 م و السعر 250 جنيه بخصم 15%")[0]
|
|
269
|
+
# الاجتماع الساعة تلاتة ونص العصر و السعر ميتين وخمسين جنية بخصم خمستاشر في المية
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
| Input | Spoken |
|
|
273
|
+
|---|---|
|
|
274
|
+
| `01012345678`, `+20 10 …` | phone digits grouped 3-4-4: «زيرو واحد زيرو, …», «زائد اتنين زيرو …» |
|
|
275
|
+
| `ahmed.ali@gmail.com` | «احمد دوت علي ات gmail دوت كوم» (Arabic names typed in Latin letters are written in Arabic) |
|
|
276
|
+
| `www.youtube.com`, `https://…` | «w w w دوت youtube دوت كوم» |
|
|
277
|
+
| `3:30 م`, `9:15`, `10:45 pm` | «تلاتة ونص العصر», «تسعة وربع», «حداشر الا ربع بالليل» |
|
|
278
|
+
| `15/3/1998` | «خمستاشر مارس سنة الف وتسعمية وتمانية وتسعين» |
|
|
279
|
+
| `250 جنيه`, `$99`, `50 EGP`, `1.5 €` | Egyptian amounts with currency names |
|
|
280
|
+
| `15%`, `3.5` | «خمستاشر في المية», «تلاتة فاصلة خمسة» |
|
|
281
|
+
| `5K`, `2M`, `3Bn` | «خمسة الف», «اتنين مليون», «تلاتة مليار» |
|
|
282
|
+
| `120 km/h`, `5 kg`, `64 GB` | units in Arabic |
|
|
283
|
+
| `د/ احمد`, `م/`, `ش.`, `ج.م.ع` | «دكتور», «مهندس», «شارع», «جمهورية مصر العربية» |
|
|
284
|
+
| `CEO`, `#مصر`, `@user`, `&` | «c e o», «هاشتاج مصر», «user», «و» |
|
|
285
|
+
|
|
286
|
+
Numbers are verbalized in Egyptian (`1994` → «الف وتسعمية واربعة وتسعين»). Runs of more than 9 digits are read digit by digit.
|
|
287
|
+
|
|
288
|
+
## ⚙️ Parameters
|
|
289
|
+
|
|
290
|
+
| Parameter | Default | |
|
|
291
|
+
|---|---|---|
|
|
292
|
+
| `voice` | default voice | preset id, an audio file (cloning), or an exported `.safetensors` |
|
|
293
|
+
| `temperature` | `0.3` | lower is steadier; higher is more expressive and less stable |
|
|
294
|
+
| `lsd_steps` | `1` | flow decoding steps per 80 ms frame |
|
|
295
|
+
| `eos_threshold` | `-4.0` | end-of-speech threshold: higher stops earlier, lower if the last word gets cut |
|
|
296
|
+
| `noise_clamp` | `None` | clamps the sampling noise (e.g. `2.0`) |
|
|
297
|
+
| `frames_after_eos` | auto | 80 ms frames kept after the end of speech |
|
|
298
|
+
| `max_letters` | `160` | long text is split at `.` then `,` into chunks of this many letters |
|
|
299
|
+
| `stop` | `None` | a `threading.Event` that stops streaming early |
|
|
300
|
+
|
|
301
|
+
## 📊 Speed
|
|
302
|
+
|
|
303
|
+
Measured with this package after warm-up, on 7–11 s sentences:
|
|
304
|
+
|
|
305
|
+
| Device | Time to first audio | Throughput |
|
|
306
|
+
|---|---|---|
|
|
307
|
+
| NVIDIA GTX 1660 Ti (6 GB) | ~80 ms | ~2.2× real time |
|
|
308
|
+
| Intel i7-10750H laptop CPU | ~330 ms | ~2.6× real time |
|
|
309
|
+
|
|
310
|
+
## 🧠 Model
|
|
311
|
+
|
|
312
|
+
The model is a [Pocket TTS](https://github.com/kyutai-labs/pocket-tts) (Kyutai) architecture: a causal transformer over Mimi latents with a 1-step flow head and a streaming Mimi decoder (24 kHz).
|
|
313
|
+
|
|
314
|
+
* A 24-layer teacher was fine-tuned on ~747 h of Egyptian podcasts collected with the [EgySpeech](https://github.com/MohammedAly22/EgySpeech) pipeline, then distilled into this 6-layer student.
|
|
315
|
+
* Details are on the [model card](https://huggingface.co/mohammedaly22/Cairo-TTS).
|
|
316
|
+
|
|
317
|
+
## 🗂️ Repository
|
|
318
|
+
|
|
319
|
+
```
|
|
320
|
+
src/cairo_tts/
|
|
321
|
+
├── model.py CairoTTS: loading, devices, voices, generate / stream / save, metrics
|
|
322
|
+
├── text/ Egyptian preprocessing + the training frontend (numbers, diacritics, ta marbuta)
|
|
323
|
+
├── server/ FastAPI app + static web studio (HTML / CSS / JS)
|
|
324
|
+
└── cli.py cairo-tts say | serve | voices | normalize
|
|
325
|
+
notebooks/ Colab quick start + web UI
|
|
326
|
+
examples/infer.py minimal script
|
|
327
|
+
space/ Hugging Face Space (Docker)
|
|
328
|
+
scripts/ prepare_voices.py · upload_to_hub.py · deploy_space.py
|
|
329
|
+
tests/ text + inference + API tests (pytest)
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
## ⚖️ Responsible use
|
|
333
|
+
|
|
334
|
+
Cairo-TTS can imitate voices.
|
|
335
|
+
|
|
336
|
+
* Do not use it to impersonate anyone without their consent, to deceive, or to commit fraud.
|
|
337
|
+
* The preset voices are short clips of podcast speakers and are provided for research and demos only.
|
|
338
|
+
* Label synthetic audio when you publish it.
|
|
339
|
+
|
|
340
|
+
## 📜 License
|
|
341
|
+
|
|
342
|
+
* The code is [MIT](LICENSE).
|
|
343
|
+
* The model weights are fine-tuned from Kyutai's Pocket TTS and follow its terms. See [NOTICE.md](NOTICE.md) and the model card.
|
|
344
|
+
|
|
345
|
+
<p align="center"><img src="https://raw.githubusercontent.com/MohammedAly22/Cairo-TTS/main/assets/logo.png" width="160" alt=""></p>
|