venSpeakerPy 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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 VenalusDev
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,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: venSpeakerPy
3
+ Version: 0.1.0
4
+ Summary: Python TTS package using Silero models for Russian language
5
+ Home-page: https://github.com/VenalusDev/ven-speaker-py
6
+ Author: VenalusDev
7
+ Author-email: Venalusdev@mail.ru
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: numpy>=1.24
15
+ Requires-Dist: scipy<2.0,>=1.10
16
+ Requires-Dist: sounddevice>=0.4.7
17
+ Requires-Dist: soundfile>=0.12.1
18
+ Requires-Dist: torch<3.0,>=2.1
19
+ Requires-Dist: nltk<4.0,>=3.9
20
+ Requires-Dist: num2words<0.6,>=0.5
21
+ Requires-Dist: transliterate>=1.10.2
22
+ Requires-Dist: silero>=0.4
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: license-file
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
+
34
+ # ven-speaker-py
35
+
36
+ **Форк библиотеки `speakerpy` с модификациями и улучшениями для потоковой работы с аудио и TTS.**
37
+
38
+ ![logo](https://raw.githubusercontent.com/denisxab/speakerpy/main/docs/source/_static/logo315x318.png)
39
+
40
+
41
+ ## 🔹 Описание
42
+
43
+ ven-speaker-py — это Python-библиотека для синтеза речи с модификациями:
44
+
45
+ - Потоковая передача аудио в байтовом виде.
46
+ - Исправленная функция ~to_mp3~->`to_wav`.
47
+ - Поддержка гибкой настройки скорости, громкости и sample rate.
48
+ - Постепенно добавляются новые функции и улучшения под конкретные задачи.
49
+
50
+ Библиотека подходит для создания голосовых приложений, озвучивания текста в реальном времени и интеграции с другими проектами.
51
+
52
+
53
+ ## Особенности и преимущества SpeakerPy
54
+
55
+ - **Транскрипция чисел и английских слов**: SpeakerPy способен озвучивать числа и английские слова через транскрипцию.
56
+ - **Синтез больших объемов текста**: SpeakerPy может синтезировать большие объемы текста без проблем.
57
+ - **Корректное деление текста на куски**: благодаря использованию библиотеки nltk, SpeakerPy корректно делит большие тексты на предложения.
58
+ - **Кеширование синтезированного текста**: SpeakerPy синтезирует и хранит текст по кускам, что позволяет кешировать уже ранее синтезированный текст и избежать повторного синтезирования. После первой генерации все последующие обычно занимают менее четверти секунды (имеется в виду не полная генерация, а момент, когда начинает зачитываться речь) на обычном процессоре!
59
+ - **Работа в автономном режиме**: SpeakerPy синтезирует звук локально, без подключения к интернету, что позволяет использовать его в автономном режиме.
60
+ - **Сохранение синтезированного текста в MP3**: SpeakerPy предоставляет возможность сохранять синтезированный текст в формате MP3.
61
+
62
+ ## ⚙️ Установка через pip
63
+
64
+ `ven-speaker-py` можно установить с помощью pip:
65
+
66
+ ```bash
67
+ pip install venspeakerpy
68
+ ```
69
+
70
+ ## 🛠️ Основные возможности
71
+
72
+ - **Преобразование текста в речь.**
73
+ - **Потоковая генерация аудио чанков.**
74
+ - **Поддержка сохранения в различные форматы, включая mp3.**
75
+ - **Настройка скорости, громкости и sample rate.**
76
+ - **Интеграция в голосовые боты и приложения реального времени.**
77
+
78
+ ### 🚀 Системные требования
79
+
80
+ - 2 ГБ ОЗУ
81
+ - Наличие процессора :D
82
+
83
+ ## 💡 Основные компоненты
84
+
85
+ Проект состоит из двух основных компонентов: Lib Speak и Lib SL Text.
86
+
87
+ ### Lib Speak
88
+
89
+ Lib Speak включает классы `Speaker` и `SpeakerBase` для синтеза речи с использованием моделей Silero. Основные методы класса `Speaker`:
90
+
91
+ 1. `speak`: ~~произнесение текста.~~ Теперь это потоковая передача звука в байтах, что позволяет использовать звук где-то еще (например, для трансляции в Discord)
92
+ 2. `to_wav`: конвертация текста в аудиофайл wav.
93
+
94
+ #### 📄 Пример использования функции speak
95
+
96
+ ```python
97
+ from lib_speak import Speaker
98
+ from lib_sl_text import SeleroText
99
+ import sounddevice as sd
100
+ import queue
101
+ import threading
102
+ import numpy as np
103
+
104
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="baya", device="cpu")
105
+
106
+ def text_to_speech(txt: str):
107
+ audio_queue = queue.Queue()
108
+
109
+ def audio_player():
110
+ with sd.OutputStream(samplerate=48000, channels=1, dtype='float32') as stream:
111
+ while True:
112
+ speech_chunk = audio_queue.get()
113
+ if speech_chunk is None:
114
+ break
115
+ audio_array = np.frombuffer(speech_chunk, dtype=np.float32)
116
+ stream.write(audio_array)
117
+
118
+ player_thread = threading.Thread(target=audio_player, daemon=True)
119
+ player_thread.start()
120
+
121
+ for chunk, text in speaker.speak(text=text.text, sample_rate=48000, speed=1.1, volume=0.7):
122
+ audio_queue.put(chunk)
123
+
124
+ audio_queue.put(None)
125
+ player_thread.join()
126
+
127
+ text = SeleroText("Пример текста для синтеза речи")
128
+ text_to_speech(text)
129
+
130
+ #p.s. я не проверял этот код, просто куски из своего проекта сюда напихал в надежде, что у вас заработает, так что удачи.
131
+
132
+ ```
133
+
134
+ #### Пример использования функции to_wav
135
+
136
+ ```python
137
+ from lib_speak import Speaker
138
+
139
+ text = SeleroText("Пример текста для синтеза речи")
140
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="aidar", device="cpu")
141
+ speaker.to_wav(text=text.text, sample_rate=48000, speed=1.0, volume=1.0, name_text='output', audio_dir='output')
142
+ ```
143
+
144
+ ### Lib SL Text
145
+
146
+ Lib SL Text содержит класс `SeleroText` для обработки текста перед синтезом речи. Основной метод класса `SeleroText`:
147
+
148
+ 1. `chunk`: разделение текста на блоки.
149
+
150
+ #### Использование класса SeleroText
151
+
152
+ ```python
153
+ text = SeleroText("Привет, мир!", to_language="ru")
154
+ ```
155
+
156
+ Разделение текста на куски с помощью метода `chunk()`:
157
+
158
+ ```python
159
+ for chunk in text.chunk():
160
+ print(chunk)
161
+ ```
162
+
163
+ ## Ресурсы и ссылки
164
+
165
+ - <a href="https://github.com/snakers4/silero-models/blob/master/models.yml" target="_new">Silero Models на GitHub</a>
166
+ - <a href="https://www.sphinx-doc.org/" target="_new">Sphinx</a>
167
+ - <a href="https://github.com/readthedocs/sphinx_rtd_theme" target="_new">Sphinx RTD Theme</a>
168
+ - <a href="https://readthedocs.org/" target="_new">Read the Docs</a>
@@ -0,0 +1,135 @@
1
+ # ven-speaker-py
2
+
3
+ **Форк библиотеки `speakerpy` с модификациями и улучшениями для потоковой работы с аудио и TTS.**
4
+
5
+ ![logo](https://raw.githubusercontent.com/denisxab/speakerpy/main/docs/source/_static/logo315x318.png)
6
+
7
+
8
+ ## 🔹 Описание
9
+
10
+ ven-speaker-py — это Python-библиотека для синтеза речи с модификациями:
11
+
12
+ - Потоковая передача аудио в байтовом виде.
13
+ - Исправленная функция ~to_mp3~->`to_wav`.
14
+ - Поддержка гибкой настройки скорости, громкости и sample rate.
15
+ - Постепенно добавляются новые функции и улучшения под конкретные задачи.
16
+
17
+ Библиотека подходит для создания голосовых приложений, озвучивания текста в реальном времени и интеграции с другими проектами.
18
+
19
+
20
+ ## Особенности и преимущества SpeakerPy
21
+
22
+ - **Транскрипция чисел и английских слов**: SpeakerPy способен озвучивать числа и английские слова через транскрипцию.
23
+ - **Синтез больших объемов текста**: SpeakerPy может синтезировать большие объемы текста без проблем.
24
+ - **Корректное деление текста на куски**: благодаря использованию библиотеки nltk, SpeakerPy корректно делит большие тексты на предложения.
25
+ - **Кеширование синтезированного текста**: SpeakerPy синтезирует и хранит текст по кускам, что позволяет кешировать уже ранее синтезированный текст и избежать повторного синтезирования. После первой генерации все последующие обычно занимают менее четверти секунды (имеется в виду не полная генерация, а момент, когда начинает зачитываться речь) на обычном процессоре!
26
+ - **Работа в автономном режиме**: SpeakerPy синтезирует звук локально, без подключения к интернету, что позволяет использовать его в автономном режиме.
27
+ - **Сохранение синтезированного текста в MP3**: SpeakerPy предоставляет возможность сохранять синтезированный текст в формате MP3.
28
+
29
+ ## ⚙️ Установка через pip
30
+
31
+ `ven-speaker-py` можно установить с помощью pip:
32
+
33
+ ```bash
34
+ pip install venspeakerpy
35
+ ```
36
+
37
+ ## 🛠️ Основные возможности
38
+
39
+ - **Преобразование текста в речь.**
40
+ - **Потоковая генерация аудио чанков.**
41
+ - **Поддержка сохранения в различные форматы, включая mp3.**
42
+ - **Настройка скорости, громкости и sample rate.**
43
+ - **Интеграция в голосовые боты и приложения реального времени.**
44
+
45
+ ### 🚀 Системные требования
46
+
47
+ - 2 ГБ ОЗУ
48
+ - Наличие процессора :D
49
+
50
+ ## 💡 Основные компоненты
51
+
52
+ Проект состоит из двух основных компонентов: Lib Speak и Lib SL Text.
53
+
54
+ ### Lib Speak
55
+
56
+ Lib Speak включает классы `Speaker` и `SpeakerBase` для синтеза речи с использованием моделей Silero. Основные методы класса `Speaker`:
57
+
58
+ 1. `speak`: ~~произнесение текста.~~ Теперь это потоковая передача звука в байтах, что позволяет использовать звук где-то еще (например, для трансляции в Discord)
59
+ 2. `to_wav`: конвертация текста в аудиофайл wav.
60
+
61
+ #### 📄 Пример использования функции speak
62
+
63
+ ```python
64
+ from lib_speak import Speaker
65
+ from lib_sl_text import SeleroText
66
+ import sounddevice as sd
67
+ import queue
68
+ import threading
69
+ import numpy as np
70
+
71
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="baya", device="cpu")
72
+
73
+ def text_to_speech(txt: str):
74
+ audio_queue = queue.Queue()
75
+
76
+ def audio_player():
77
+ with sd.OutputStream(samplerate=48000, channels=1, dtype='float32') as stream:
78
+ while True:
79
+ speech_chunk = audio_queue.get()
80
+ if speech_chunk is None:
81
+ break
82
+ audio_array = np.frombuffer(speech_chunk, dtype=np.float32)
83
+ stream.write(audio_array)
84
+
85
+ player_thread = threading.Thread(target=audio_player, daemon=True)
86
+ player_thread.start()
87
+
88
+ for chunk, text in speaker.speak(text=text.text, sample_rate=48000, speed=1.1, volume=0.7):
89
+ audio_queue.put(chunk)
90
+
91
+ audio_queue.put(None)
92
+ player_thread.join()
93
+
94
+ text = SeleroText("Пример текста для синтеза речи")
95
+ text_to_speech(text)
96
+
97
+ #p.s. я не проверял этот код, просто куски из своего проекта сюда напихал в надежде, что у вас заработает, так что удачи.
98
+
99
+ ```
100
+
101
+ #### Пример использования функции to_wav
102
+
103
+ ```python
104
+ from lib_speak import Speaker
105
+
106
+ text = SeleroText("Пример текста для синтеза речи")
107
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="aidar", device="cpu")
108
+ speaker.to_wav(text=text.text, sample_rate=48000, speed=1.0, volume=1.0, name_text='output', audio_dir='output')
109
+ ```
110
+
111
+ ### Lib SL Text
112
+
113
+ Lib SL Text содержит класс `SeleroText` для обработки текста перед синтезом речи. Основной метод класса `SeleroText`:
114
+
115
+ 1. `chunk`: разделение текста на блоки.
116
+
117
+ #### Использование класса SeleroText
118
+
119
+ ```python
120
+ text = SeleroText("Привет, мир!", to_language="ru")
121
+ ```
122
+
123
+ Разделение текста на куски с помощью метода `chunk()`:
124
+
125
+ ```python
126
+ for chunk in text.chunk():
127
+ print(chunk)
128
+ ```
129
+
130
+ ## Ресурсы и ссылки
131
+
132
+ - <a href="https://github.com/snakers4/silero-models/blob/master/models.yml" target="_new">Silero Models на GitHub</a>
133
+ - <a href="https://www.sphinx-doc.org/" target="_new">Sphinx</a>
134
+ - <a href="https://github.com/readthedocs/sphinx_rtd_theme" target="_new">Sphinx RTD Theme</a>
135
+ - <a href="https://readthedocs.org/" target="_new">Read the Docs</a>
@@ -0,0 +1,35 @@
1
+ [tool.poetry]
2
+ name = "venSpeakerPy"
3
+ version = "0.1.0"
4
+ description = "Форк библиотеки speakerpy с потоковой TTS, генерацией чанков аудио и улучшениями"
5
+ authors = ["Venalus <Venalusdev@mail.ru>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ homepage = "https://github.com/VenalusDev/ven-speaker-py"
9
+ repository = "https://github.com/VenalusDev/ven-speaker-py"
10
+ keywords = ["TTS", "speech", "speaker", "python", "audio", "streaming"]
11
+
12
+ packages = [
13
+ { include = "venSpeakerPy" }
14
+ ]
15
+
16
+
17
+ [tool.poetry.dependencies]
18
+ python = "^3.11"
19
+ numpy = "^1.24"
20
+ torch = "^2.2"
21
+ scipy = "^1.11"
22
+ sounddevice = "^0.4"
23
+ soundfile = "^0.12"
24
+ silero = "^0.4"
25
+ nltk = "^3.9"
26
+ num2words = "^0.5"
27
+ transliterate = "^1.10"
28
+
29
+
30
+ [tool.poetry.dev-dependencies]
31
+ pytest = "^7.4"
32
+
33
+ [build-system]
34
+ requires = ["setuptools>=65.5.1", "wheel", "numpy>=2.0"]
35
+ build-backend = "setuptools.build_meta"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,30 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="venSpeakerPy",
5
+ version="0.1.0",
6
+ author="VenalusDev",
7
+ author_email="Venalusdev@mail.ru",
8
+ description="Python TTS package using Silero models for Russian language",
9
+ long_description=open("README.md", encoding="utf-8").read(),
10
+ long_description_content_type="text/markdown",
11
+ url="https://github.com/VenalusDev/ven-speaker-py",
12
+ packages=find_packages(),
13
+ python_requires=">=3.11",
14
+ install_requires=[
15
+ "numpy>=1.24",
16
+ "scipy>=1.10,<2.0",
17
+ "sounddevice>=0.4.7",
18
+ "soundfile>=0.12.1",
19
+ "torch>=2.1,<3.0",
20
+ "nltk>=3.9,<4.0",
21
+ "num2words>=0.5,<0.6",
22
+ "transliterate>=1.10.2",
23
+ "silero>=0.4",
24
+ ],
25
+ classifiers=[
26
+ "Programming Language :: Python :: 3",
27
+ "License :: OSI Approved :: MIT License",
28
+ "Operating System :: OS Independent",
29
+ ],
30
+ )
@@ -0,0 +1,3 @@
1
+ import lib_speak
2
+ import lib_helper
3
+ import lib_sl_text
@@ -0,0 +1,99 @@
1
+ import argparse
2
+ import pathlib
3
+
4
+ from .lib_helper import settings_selero
5
+
6
+
7
+ def main(args):
8
+ from .lib_speak import Speaker
9
+
10
+ sample_rate = (
11
+ args.sample_rate
12
+ if args.sample_rate
13
+ else settings_selero[args.language]["sample_rate"]
14
+ )
15
+
16
+ sp = Speaker(**settings_selero[args.language]["sp"])
17
+
18
+ file = pathlib.Path(args.file)
19
+ text = file.read_text()
20
+
21
+ if args.type_out == "speak":
22
+ sp.speak(text, sample_rate=sample_rate, speed=args.speed)
23
+ elif args.type_out == "mp3":
24
+ sp.to_mp3(
25
+ text=text,
26
+ name_text=args.name_text if args.name_text else file.name,
27
+ sample_rate=sample_rate,
28
+ audio_dir=args.audio_dir / "mp3",
29
+ speed=args.speed,
30
+ )
31
+ else:
32
+ raise KeyError("Не указано - Каким образом вывести сентезированный текст")
33
+
34
+
35
+ if __name__ == "__main__":
36
+ parser = argparse.ArgumentParser(
37
+ description="🎙️ SpeakerPy: CLI для синтеза речи с использованием SpeakerPy 🎙️",
38
+ formatter_class=argparse.RawDescriptionHelpFormatter,
39
+ epilog="Примеры использования:\n"
40
+ " python -m speakerpy -l ru -t speak -f ./books/example.txt;\n"
41
+ " python -m speakerpy -l ru -t mp3 -f ./books/example.txt;\n"
42
+ " python -m speakerpy -l en -t speak -f ./books/example.txt;\n"
43
+ " python -m speakerpy -l en -t mp3 -f ./books/example.txt;\n",
44
+ )
45
+ y = "\033[33m"
46
+ r = "\033[0m"
47
+ parser.add_argument(
48
+ "-l",
49
+ "--language",
50
+ choices=list(settings_selero.keys()),
51
+ required=True,
52
+ help=f"{y}Язык синтеза (ru | en){r}",
53
+ )
54
+ parser.add_argument(
55
+ "-f",
56
+ "--file",
57
+ type=str,
58
+ required=True,
59
+ help=f"{y}Путь к файлу с текстом для озвучивания{r}",
60
+ )
61
+ parser.add_argument(
62
+ "-t",
63
+ "--type_out",
64
+ choices=["mp3", "speak"],
65
+ required=True,
66
+ help=f"{y}Каким образом вывести синтезированный текст (mp3 | speak){r}",
67
+ )
68
+ parser.add_argument(
69
+ "-sr",
70
+ "--sample_rate",
71
+ type=int,
72
+ default=48000,
73
+ help=f"{y}Частота дискретизации (по умолчанию: 48000){r}",
74
+ )
75
+ parser.add_argument(
76
+ "-s",
77
+ "--speed",
78
+ type=float,
79
+ default=1.0,
80
+ help=f"{y}Скорость чтения (по умолчанию: 1.0){r}",
81
+ )
82
+ parser.add_argument(
83
+ "-n",
84
+ "--name_text",
85
+ type=str,
86
+ default="",
87
+ help=f"{y}Имя для текста, с таким именем сохранится итоговый mp3 файл (по умолчанию: имя файла с текстом){r}",
88
+ )
89
+ parser.add_argument(
90
+ "-a",
91
+ "--audio_dir",
92
+ type=str,
93
+ default=pathlib.Path(__file__).parent.parent,
94
+ help=f"{y}Папка для сохранения готовых аудио файлов (по умолчанию: текущая папка){r}",
95
+ )
96
+
97
+ args = parser.parse_args()
98
+
99
+ main(args)
@@ -0,0 +1,16 @@
1
+ from time import process_time
2
+
3
+
4
+ def timeit(func):
5
+ """Декоратор замера времени выполнения функции"""
6
+
7
+ def wrapper(*args, **kwargs):
8
+ start_time = process_time()
9
+ result = func(*args, **kwargs)
10
+ end_time = process_time()
11
+ print(
12
+ f"Время выполнения функции '{func.__name__}': {end_time - start_time} секунд"
13
+ )
14
+ return result
15
+
16
+ return wrapper
@@ -0,0 +1,138 @@
1
+ import os
2
+ import pathlib
3
+ import re
4
+ from string import punctuation, whitespace
5
+ from typing import Generator, Literal
6
+
7
+ import nltk
8
+ from num2words import num2words
9
+ from transliterate import translit
10
+
11
+ nltk.download("punkt")
12
+ nltk.download("punkt_tab")
13
+
14
+
15
+ def nltk_remove_other_model_but_russian(directory: str | pathlib.Path):
16
+ """Удалить все языки кроме русского
17
+
18
+ directory: Путь к директории в которой искать файлы
19
+ """
20
+
21
+ extension = ".pickle" # замените на нужное расширение
22
+
23
+ # обходим все файлы в указанной директории
24
+ for root, dirs, files in os.walk(directory):
25
+ for file in files:
26
+ # если файл имеет нужное расширение, выводим его путь
27
+ if file.endswith(extension) and not file.startswith("russian"):
28
+ abs_path = os.path.join(root, file)
29
+ os.remove(abs_path)
30
+
31
+
32
+ class SeleroText:
33
+ """
34
+ Класс для хранения, и удобного использования текста,
35
+ который вы хотите синтезировать в голос
36
+ """
37
+
38
+ #: Флаг, который используется для чтения модели nltk единожды
39
+ IF_INIT = False
40
+ #: Путь для хранения моделей nltk
41
+ download_dir = pathlib.Path(__file__).parent.parent / "models/nltk_store"
42
+ ###
43
+ #
44
+ #: Максимальное количество сиголов в куске текста. Если больше, то это уже новый кусок
45
+ _max_chunk_symbols = 1000
46
+ #: Символы которые нужно исключать
47
+ exclude_characters = whitespace + punctuation
48
+
49
+ def __init__(self, text: str, to_language: Literal["ru"]) -> None:
50
+ """Преобразовать текст в подходящий формат."""
51
+ self.text = text
52
+ self.to_language = to_language
53
+ ###
54
+ #
55
+ # Инициализация моделей nltk
56
+ #
57
+ if not self.IF_INIT:
58
+ os.makedirs(self.download_dir, exist_ok=True)
59
+ # nltk.download(
60
+ # "punkt",
61
+ # download_dir=self.download_dir,
62
+ # )
63
+ if self.to_language in ("ru"):
64
+ # Удалить все модели языки кроме русского языка
65
+ nltk_remove_other_model_but_russian(self.download_dir)
66
+ self.IF_INIT = True
67
+ #
68
+ self._normal()
69
+
70
+ def chunk(self) -> Generator[str, None, None]:
71
+ """Поделить текст на куски"""
72
+
73
+ # 3. Разделения по предложениям
74
+ for t in self._punkt(self.text):
75
+ if t:
76
+ # 4. Разделения длинных предложений
77
+ for t2 in self._split_long_string(t, self._max_chunk_symbols):
78
+ # В тексте должны быть буквы
79
+ if re.search(r"\w", t2):
80
+ yield t2
81
+
82
+ ##########################
83
+ #
84
+ #
85
+ def _normal(self) -> str:
86
+ """Преобразовать текст в подходящий формат для синтеза
87
+
88
+ to_language: В какой язык сделать тралит
89
+ """
90
+ # 1. Транскрипция иностранного языка
91
+ if self.to_language in ("ru"):
92
+ self.text = translit(self.text, self.to_language)
93
+ # 2. Текстовое описание цифр
94
+ self.text = self._nums_to_text()
95
+
96
+ def _transcription(self) -> str:
97
+ """Транскрипция иностранного языка (Типа hello->хелоо)"""
98
+ self.text = translit(self.text, self.to_language)
99
+
100
+ def _nums_to_text(self) -> str:
101
+ """Преобразует числа в буквы: 1 -> один, 23 -> двадцать три"""
102
+ return re.sub(
103
+ r"(\d+)",
104
+ lambda x: num2words(int(x.group(0)), lang=self.to_language),
105
+ self.text,
106
+ )
107
+
108
+ @staticmethod
109
+ def _punkt(text: str) -> Generator[str, None, None]:
110
+ """Разделения по предложениям"""
111
+ for t in nltk.sent_tokenize(text, language="russian"):
112
+ # Оставляем в строке только буквы, цифры и знаки пунктуации.
113
+ yield re.sub(r"[^a-zA-Zа-яА-Я0-9.,!?;:\-\–\'\"\s]", "", t)
114
+
115
+ @staticmethod
116
+ def _split_long_string(text: str, slice_length: int) -> Generator[str, None, None]:
117
+ """Поделить текст на части.
118
+
119
+ :param text: Текст
120
+ :param slice_length: Через сколько символов делить строку
121
+ """
122
+ words = text.split()
123
+ current_slice = []
124
+ current_length = 0
125
+ for word in words:
126
+ # Добавляем текущее слово к текущей "кусочной" строке,
127
+ # если она еще не началась или длина слова и пробела не превышает slice_length.
128
+ if not current_slice or current_length + len(word) + 1 <= slice_length:
129
+ current_slice.append(word)
130
+ current_length += len(word) + 1
131
+ else:
132
+ # Иначе, если текущая "кусочная" строка уже достаточно длинная,
133
+ # то добавляем ее в результат и начинаем новую "кусочную" строку с текущего слова.
134
+ yield " ".join(current_slice)
135
+ current_slice = [word]
136
+ current_length = len(word)
137
+ # Добавляем последнюю "кусочную" строку в результат.
138
+ yield " ".join(current_slice)
@@ -0,0 +1,251 @@
1
+ import pathlib
2
+ import threading
3
+ import time
4
+ from typing import Generator, Literal
5
+ from scipy.signal import resample_poly
6
+
7
+ import sounddevice
8
+ import soundfile
9
+ import torch
10
+ from silero import silero_tts
11
+ import numpy as np
12
+
13
+ from lib_helper import timeit
14
+ from lib_sl_text import SeleroText
15
+
16
+
17
+ class SpeakerBase:
18
+ #: Для синхронизации потоков озвучки текста
19
+ _th_lock_speak = threading.Lock()
20
+
21
+ def __init__(
22
+ self,
23
+ model_id,
24
+ language: Literal["ru", "en"],
25
+ speaker: Literal["aidar", "baya", "kseniya", "xenia", "random"],
26
+ device="cpu",
27
+ ) -> None:
28
+ self.language = language
29
+ self.model_id = model_id
30
+ # Модель
31
+ self.model = self._init_models(
32
+ model_id=model_id,
33
+ language=language,
34
+ device=device,
35
+ )
36
+ # Голос
37
+ self.speaker = speaker
38
+
39
+ @staticmethod
40
+ def _init_models(
41
+ model_id: str,
42
+ language: Literal["ru"] = "ru",
43
+ device: Literal[
44
+ "cpu",
45
+ "cuda",
46
+ "ipu",
47
+ "xpu",
48
+ "mkldnn",
49
+ "opengl",
50
+ "opencl",
51
+ "ideep",
52
+ "hip",
53
+ "ve",
54
+ "fpga",
55
+ "ort",
56
+ "xla",
57
+ "lazy",
58
+ "vulkan",
59
+ "mps",
60
+ ] = "cpu",
61
+ ):
62
+ """
63
+ Инициализация ИИ модели
64
+
65
+ model_id: Доступные модели https://github.com/snakers4/silero-models/blob/master/models.yml (четверку тут использовать не получится)
66
+ """
67
+ _device = torch.device(device)
68
+ _model, *_any = silero_tts(language=language, speaker=model_id, device=_device)
69
+ return _model
70
+
71
+ def _synthesize_text(
72
+ self, text: str, sample_rate: int, put_accent: bool = True, put_yo: bool = True
73
+ ) -> torch.Tensor:
74
+ """Синтезировать текст"""
75
+ audio: torch.Tensor = self.model.apply_tts(
76
+ text=text,
77
+ speaker=self.speaker,
78
+ sample_rate=sample_rate,
79
+ put_accent=put_accent,
80
+ put_yo=put_yo,
81
+ )
82
+ return audio
83
+
84
+ def _speak(
85
+ self,
86
+ th_name: int,
87
+ text: str,
88
+ audio: torch.Tensor,
89
+ sample_rate: int,
90
+ speed: float = 1.0,
91
+ ):
92
+ """Озвучить текст
93
+
94
+ :param audio: Аудио
95
+ :param sample_rate: Частота
96
+ :param speed: Скорость воспроизведения [от 1.0 до 2.0]
97
+ """
98
+ _speed = sample_rate * speed
99
+ # Блокировка потока. Может говорить только один поток
100
+ with self._th_lock_speak:
101
+ # print(f"Th: {th_name}\t| {text}")
102
+ sounddevice.play(audio, samplerate=_speed)
103
+ time.sleep((len(audio) / _speed + 0.02))
104
+ sounddevice.stop()
105
+
106
+
107
+ class Speaker(SpeakerBase):
108
+ def speak(
109
+ self,
110
+ text: str,
111
+ sample_rate: int,
112
+ speed: float = 1.0,
113
+ *,
114
+ volume: float = 1.0,
115
+ put_accent: bool = True,
116
+ put_yo: bool = False,
117
+ normalize: bool = False,
118
+ limiting: bool = False,
119
+ ) -> Generator[tuple[bytes, str], None, None]:
120
+ """
121
+ Генерация и озвучка текста с поддержкой тегов <long:x:duration>
122
+
123
+ :param text: Текст для озвучки (поддерживает <long:буква:время>)
124
+ :param sample_rate: Частота дискретизации
125
+ :param speed: Скорость воспроизведения
126
+ :param volume: Громкость (0.0 - 2.0)
127
+ :param put_accent: Автоматическая постановка ударения
128
+ :param put_yo: Автоматическая постановка буквы ё
129
+ :param normalize: Нормализация звука (вряд ли вообще понадобится, но пусть будет)
130
+ :param limiting: Ограничение звука (вряд ли вообще понадобится, но пусть будет)
131
+ :return: Чанки аудио в формате bytes
132
+ """
133
+ if not (0.0 <= volume <= 2.0):
134
+ raise ValueError("Параметр volume должен быть в диапазоне от 0.0 до 2.0")
135
+ sl_text = SeleroText(text, to_language=self.language)
136
+
137
+ # Генерация чанков с выводом байтов по мере готовности
138
+ chunks = list(sl_text.chunk())
139
+ for i, _chunk_text in enumerate(chunks):
140
+ audio: torch.Tensor = self._synthesize_text(
141
+ _chunk_text,
142
+ sample_rate=sample_rate,
143
+ put_accent=put_accent,
144
+ put_yo=put_yo,
145
+ )
146
+ scaled_audio = (audio.numpy() / 5 * volume).astype(np.float32)
147
+
148
+ adjusted_audio = resample_poly(scaled_audio, up=100, down=int(100 * speed)) if speed != 1 else scaled_audio
149
+
150
+ normal = self.normalize(adjusted_audio) if normalize else adjusted_audio
151
+ limited = self.limiter(normal) if limiting else normal
152
+
153
+ if len(limited) > 0:
154
+ yield adjusted_audio.tobytes(), _chunk_text
155
+
156
+ # Если это последний чанк — добавим тишину
157
+ if i == len(chunks) - 1:
158
+ silence = np.zeros(int(sample_rate * 0.15), dtype=np.float32) # 150 мс тишины
159
+ yield silence.tobytes(), ""
160
+
161
+ @timeit
162
+ def to_wav(
163
+ self,
164
+ text: str,
165
+ name_text: str,
166
+ sample_rate: int,
167
+ audio_dir: pathlib.Path | str,
168
+ speed: float = 1.0,
169
+ volume: float = 1.0,
170
+ put_accent=True
171
+ ) -> pathlib.Path:
172
+ """
173
+ Синтезировать и сохранить звук в WAV файл
174
+
175
+ :param text: Текст
176
+ :param name_text: Имя текста (используется в имени файла)
177
+ :param sample_rate: Частота дискретизации
178
+ :param audio_dir: Куда сохранить файл
179
+ :param speed: Скорость речи
180
+ :param volume: Громкость
181
+ :return: Путь к сохраненному WAV-файлу
182
+ """
183
+ name_text = name_text.replace(" ", "_")
184
+ audio_dir = pathlib.Path(audio_dir)
185
+ audio_dir.mkdir(parents=True, exist_ok=True)
186
+
187
+ output_file = audio_dir / (
188
+ name_text
189
+ + ".wav"
190
+ )
191
+
192
+ if output_file.exists():
193
+ print("Cache___Wav: 0 \t| ", output_file)
194
+ return output_file
195
+
196
+ full_audio = b''.join(self.speak(text=text, sample_rate=sample_rate, speed=speed, volume=volume, put_accent=put_accent, put_yo=True))
197
+
198
+ # Сохраняем как WAV
199
+ with soundfile.SoundFile(output_file, 'w', samplerate=sample_rate, channels=1, subtype='PCM_16') as f:
200
+ audio_array = np.frombuffer(full_audio, dtype=np.float32)
201
+ f.write(audio_array)
202
+
203
+ print("Build___Wav: 0 \t| ", output_file)
204
+ return output_file
205
+
206
+ def normalize(self, audio, target=0.95):
207
+ peak = np.max(np.abs(audio))
208
+ if peak > 0:
209
+ audio = audio / peak * target
210
+ return audio
211
+
212
+ def limiter(self, audio, threshold=0.9):
213
+ audio = np.clip(audio, -threshold, threshold)
214
+ return audio / threshold
215
+
216
+
217
+ if __name__ == '__main__':
218
+ import sounddevice as sd
219
+ import queue
220
+
221
+ audio_queue = queue.Queue()
222
+
223
+
224
+ def audio_player():
225
+ try:
226
+ with sd.OutputStream(samplerate=48000, channels=1, dtype='float32') as stream:
227
+ while True:
228
+ speech_chunk = audio_queue.get()
229
+ if speech_chunk is None:
230
+ break
231
+ audio_array = np.frombuffer(speech_chunk, dtype=np.float32)
232
+ stream.write(audio_array)
233
+ except KeyboardInterrupt:
234
+ print("Stop speaker")
235
+ finally:
236
+ sd.stop()
237
+
238
+
239
+ player_thread = threading.Thread(target=audio_player, daemon=True)
240
+ player_thread.start()
241
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="baya", device="cpu")
242
+ while True:
243
+ text = input('Text: ')
244
+ text = text.replace('ё', 'е')
245
+
246
+ if text.startswith('!w '):
247
+ text = text.replace('!w ', '')
248
+ speaker.to_wav(text=text.text, sample_rate=48000, speed=1.1, volume=0.7, name_text='output', audio_dir='output')
249
+ else:
250
+ for chunk, text in speaker.speak(text=text.text, sample_rate=48000, speed=1.1, volume=0.7):
251
+ audio_queue.put(chunk)
@@ -0,0 +1,168 @@
1
+ Metadata-Version: 2.4
2
+ Name: venSpeakerPy
3
+ Version: 0.1.0
4
+ Summary: Python TTS package using Silero models for Russian language
5
+ Home-page: https://github.com/VenalusDev/ven-speaker-py
6
+ Author: VenalusDev
7
+ Author-email: Venalusdev@mail.ru
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Requires-Python: >=3.11
12
+ Description-Content-Type: text/markdown
13
+ License-File: LICENSE
14
+ Requires-Dist: numpy>=1.24
15
+ Requires-Dist: scipy<2.0,>=1.10
16
+ Requires-Dist: sounddevice>=0.4.7
17
+ Requires-Dist: soundfile>=0.12.1
18
+ Requires-Dist: torch<3.0,>=2.1
19
+ Requires-Dist: nltk<4.0,>=3.9
20
+ Requires-Dist: num2words<0.6,>=0.5
21
+ Requires-Dist: transliterate>=1.10.2
22
+ Requires-Dist: silero>=0.4
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: license-file
30
+ Dynamic: requires-dist
31
+ Dynamic: requires-python
32
+ Dynamic: summary
33
+
34
+ # ven-speaker-py
35
+
36
+ **Форк библиотеки `speakerpy` с модификациями и улучшениями для потоковой работы с аудио и TTS.**
37
+
38
+ ![logo](https://raw.githubusercontent.com/denisxab/speakerpy/main/docs/source/_static/logo315x318.png)
39
+
40
+
41
+ ## 🔹 Описание
42
+
43
+ ven-speaker-py — это Python-библиотека для синтеза речи с модификациями:
44
+
45
+ - Потоковая передача аудио в байтовом виде.
46
+ - Исправленная функция ~to_mp3~->`to_wav`.
47
+ - Поддержка гибкой настройки скорости, громкости и sample rate.
48
+ - Постепенно добавляются новые функции и улучшения под конкретные задачи.
49
+
50
+ Библиотека подходит для создания голосовых приложений, озвучивания текста в реальном времени и интеграции с другими проектами.
51
+
52
+
53
+ ## Особенности и преимущества SpeakerPy
54
+
55
+ - **Транскрипция чисел и английских слов**: SpeakerPy способен озвучивать числа и английские слова через транскрипцию.
56
+ - **Синтез больших объемов текста**: SpeakerPy может синтезировать большие объемы текста без проблем.
57
+ - **Корректное деление текста на куски**: благодаря использованию библиотеки nltk, SpeakerPy корректно делит большие тексты на предложения.
58
+ - **Кеширование синтезированного текста**: SpeakerPy синтезирует и хранит текст по кускам, что позволяет кешировать уже ранее синтезированный текст и избежать повторного синтезирования. После первой генерации все последующие обычно занимают менее четверти секунды (имеется в виду не полная генерация, а момент, когда начинает зачитываться речь) на обычном процессоре!
59
+ - **Работа в автономном режиме**: SpeakerPy синтезирует звук локально, без подключения к интернету, что позволяет использовать его в автономном режиме.
60
+ - **Сохранение синтезированного текста в MP3**: SpeakerPy предоставляет возможность сохранять синтезированный текст в формате MP3.
61
+
62
+ ## ⚙️ Установка через pip
63
+
64
+ `ven-speaker-py` можно установить с помощью pip:
65
+
66
+ ```bash
67
+ pip install venspeakerpy
68
+ ```
69
+
70
+ ## 🛠️ Основные возможности
71
+
72
+ - **Преобразование текста в речь.**
73
+ - **Потоковая генерация аудио чанков.**
74
+ - **Поддержка сохранения в различные форматы, включая mp3.**
75
+ - **Настройка скорости, громкости и sample rate.**
76
+ - **Интеграция в голосовые боты и приложения реального времени.**
77
+
78
+ ### 🚀 Системные требования
79
+
80
+ - 2 ГБ ОЗУ
81
+ - Наличие процессора :D
82
+
83
+ ## 💡 Основные компоненты
84
+
85
+ Проект состоит из двух основных компонентов: Lib Speak и Lib SL Text.
86
+
87
+ ### Lib Speak
88
+
89
+ Lib Speak включает классы `Speaker` и `SpeakerBase` для синтеза речи с использованием моделей Silero. Основные методы класса `Speaker`:
90
+
91
+ 1. `speak`: ~~произнесение текста.~~ Теперь это потоковая передача звука в байтах, что позволяет использовать звук где-то еще (например, для трансляции в Discord)
92
+ 2. `to_wav`: конвертация текста в аудиофайл wav.
93
+
94
+ #### 📄 Пример использования функции speak
95
+
96
+ ```python
97
+ from lib_speak import Speaker
98
+ from lib_sl_text import SeleroText
99
+ import sounddevice as sd
100
+ import queue
101
+ import threading
102
+ import numpy as np
103
+
104
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="baya", device="cpu")
105
+
106
+ def text_to_speech(txt: str):
107
+ audio_queue = queue.Queue()
108
+
109
+ def audio_player():
110
+ with sd.OutputStream(samplerate=48000, channels=1, dtype='float32') as stream:
111
+ while True:
112
+ speech_chunk = audio_queue.get()
113
+ if speech_chunk is None:
114
+ break
115
+ audio_array = np.frombuffer(speech_chunk, dtype=np.float32)
116
+ stream.write(audio_array)
117
+
118
+ player_thread = threading.Thread(target=audio_player, daemon=True)
119
+ player_thread.start()
120
+
121
+ for chunk, text in speaker.speak(text=text.text, sample_rate=48000, speed=1.1, volume=0.7):
122
+ audio_queue.put(chunk)
123
+
124
+ audio_queue.put(None)
125
+ player_thread.join()
126
+
127
+ text = SeleroText("Пример текста для синтеза речи")
128
+ text_to_speech(text)
129
+
130
+ #p.s. я не проверял этот код, просто куски из своего проекта сюда напихал в надежде, что у вас заработает, так что удачи.
131
+
132
+ ```
133
+
134
+ #### Пример использования функции to_wav
135
+
136
+ ```python
137
+ from lib_speak import Speaker
138
+
139
+ text = SeleroText("Пример текста для синтеза речи")
140
+ speaker = Speaker(model_id="ru_v3", language="ru", speaker="aidar", device="cpu")
141
+ speaker.to_wav(text=text.text, sample_rate=48000, speed=1.0, volume=1.0, name_text='output', audio_dir='output')
142
+ ```
143
+
144
+ ### Lib SL Text
145
+
146
+ Lib SL Text содержит класс `SeleroText` для обработки текста перед синтезом речи. Основной метод класса `SeleroText`:
147
+
148
+ 1. `chunk`: разделение текста на блоки.
149
+
150
+ #### Использование класса SeleroText
151
+
152
+ ```python
153
+ text = SeleroText("Привет, мир!", to_language="ru")
154
+ ```
155
+
156
+ Разделение текста на куски с помощью метода `chunk()`:
157
+
158
+ ```python
159
+ for chunk in text.chunk():
160
+ print(chunk)
161
+ ```
162
+
163
+ ## Ресурсы и ссылки
164
+
165
+ - <a href="https://github.com/snakers4/silero-models/blob/master/models.yml" target="_new">Silero Models на GitHub</a>
166
+ - <a href="https://www.sphinx-doc.org/" target="_new">Sphinx</a>
167
+ - <a href="https://github.com/readthedocs/sphinx_rtd_theme" target="_new">Sphinx RTD Theme</a>
168
+ - <a href="https://readthedocs.org/" target="_new">Read the Docs</a>
@@ -0,0 +1,14 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ setup.py
5
+ venSpeakerPy/__init__.py
6
+ venSpeakerPy/__main__.py
7
+ venSpeakerPy/lib_helper.py
8
+ venSpeakerPy/lib_sl_text.py
9
+ venSpeakerPy/lib_speak.py
10
+ venSpeakerPy.egg-info/PKG-INFO
11
+ venSpeakerPy.egg-info/SOURCES.txt
12
+ venSpeakerPy.egg-info/dependency_links.txt
13
+ venSpeakerPy.egg-info/requires.txt
14
+ venSpeakerPy.egg-info/top_level.txt
@@ -0,0 +1,9 @@
1
+ numpy>=1.24
2
+ scipy<2.0,>=1.10
3
+ sounddevice>=0.4.7
4
+ soundfile>=0.12.1
5
+ torch<3.0,>=2.1
6
+ nltk<4.0,>=3.9
7
+ num2words<0.6,>=0.5
8
+ transliterate>=1.10.2
9
+ silero>=0.4
@@ -0,0 +1 @@
1
+ venSpeakerPy