Spaces:
Runtime error
Runtime error
Upload folder using huggingface_hub
Browse files- .vscode/launch.json +1 -1
- README.md +1 -1
- logging.yml +8 -0
- notebooks/sample.txt +7 -34
- poetry.lock +12 -1
- pyproject.toml +2 -0
- requirements.txt +3 -0
- rvc/infer/infer.py +6 -0
- rvc/lib/tools/prerequisites_download.py +20 -4
- tabs/workflow/workflow.py +14 -1
- tts_service/app.py +6 -38
- tts_service/cli.py +9 -31
- tts_service/start.py +30 -0
- tts_service/tts.py +4 -1
- tts_service/voices.py +6 -1
.vscode/launch.json
CHANGED
@@ -17,7 +17,7 @@
|
|
17 |
"name": "App",
|
18 |
"type": "debugpy",
|
19 |
"request": "launch",
|
20 |
-
"program": "tts_service/
|
21 |
"args": ["--open"],
|
22 |
"console": "integratedTerminal",
|
23 |
"envFile": "${workspaceFolder}/.env",
|
|
|
17 |
"name": "App",
|
18 |
"type": "debugpy",
|
19 |
"request": "launch",
|
20 |
+
"program": "tts_service/start.py",
|
21 |
"args": ["--open"],
|
22 |
"console": "integratedTerminal",
|
23 |
"envFile": "${workspaceFolder}/.env",
|
README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1 |
---
|
2 |
title: tts-service
|
3 |
-
app_file: tts_service/
|
4 |
sdk: gradio
|
5 |
sdk_version: 4.43.0
|
6 |
---
|
|
|
1 |
---
|
2 |
title: tts-service
|
3 |
+
app_file: tts_service/start.py
|
4 |
sdk: gradio
|
5 |
sdk_version: 4.43.0
|
6 |
---
|
logging.yml
CHANGED
@@ -9,6 +9,14 @@ handlers:
|
|
9 |
formatter: simple
|
10 |
stream: ext://sys.stdout
|
11 |
loggers:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
tts_service:
|
13 |
level: INFO
|
14 |
handlers: [console]
|
|
|
9 |
formatter: simple
|
10 |
stream: ext://sys.stdout
|
11 |
loggers:
|
12 |
+
rvc:
|
13 |
+
level: INFO
|
14 |
+
handlers: [console]
|
15 |
+
propagate: no
|
16 |
+
tabs:
|
17 |
+
level: INFO
|
18 |
+
handlers: [console]
|
19 |
+
propagate: no
|
20 |
tts_service:
|
21 |
level: INFO
|
22 |
handlers: [console]
|
notebooks/sample.txt
CHANGED
@@ -1,34 +1,7 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
In
|
8 |
-
Elon Musk, Trump's crony and the richest man in the world, with a fortune of $300 billion and counting, will be joined by fellow billionaire Vivek Ramaswamy at the head of Trump's new Department of Government Efficiency, where they plan to cut the federal budget by $2 trillion. This will mean the gutting of Medicare, Medicaid and Social Security and the firing of hundreds of thousands of government workers.
|
9 |
-
This is on top of an already unfolding social disaster for the masses. Almost 40 percent of Americans, in a survey by the Harris Poll for Bloomberg News in December of 2023, said their household recently relied on extra money besides their regular income **** to make ends meet. Of those, 38 percent said the additional amounts barely covered their monthly expenses with nothing left over, and 23 per cent said it wasn't enough to pay their bills.
|
10 |
-
Since last December, mass layoffs in auto, aerospace, retail and other sectors have continued to spread, further devastating working class families. These conditions have already sparked a wave of strikes---at Boeing, on the docks, in the auto sector---in which workers rebelled against the union bureaucrats and voted down sellout contracts.
|
11 |
-
Here are some key indices of the social reality confronting broad layers of the American people on Thanksgiving Day:
|
12 |
-
Hunger
|
13 |
-
According to the most recent Census Bureau Household Pulse Survey (October 2023), one out of every eight American adults is struggling to afford enough food. Nearly 28 million adults nationwide---12.5 percent of the adult population---are living in homes where there is either sometimes or often not enough to eat. This is the highest that figure has reached since the first year of the COVID-19 pandemic.
|
14 |
-
Homelessness
|
15 |
-
The "State of Homelessness" document of the National Alliance to End Homelessness, 2024 edition, reports:
|
16 |
-
In 2023, the year-over-year increase in the number of people experiencing homelessness was 12.1 percent, the biggest increase since data collection began in 2007.
|
17 |
-
From 2022 to 2023, homelessness for entire families increased by 15.5 percent.
|
18 |
-
More people than ever are experiencing homelessness for the first time. From 2019 to 2023, the number of people who entered emergency shelter for the first time increased more than 23 percent. Over the course of 2023, nearly one million people experienced homelessness for the first time.
|
19 |
-
Severe housing cost burdens are on the rise. The number of renter households paying more than 50 percent of their income on rent increased dramatically, rising over 12.6 percent between 2015 and 2022.
|
20 |
-
More than half of people experiencing sheltered homelessness, and slightly less than half of people experiencing unsheltered homelessness are formally employed.
|
21 |
-
Poverty
|
22 |
-
According to the Organization for Economic Cooperation and Development (OECD), the United States has the highest poverty rate among the world's 26 most developed countries. The United Nations Children's Fund (UNICEF) ranks the United States second behind Mexico on a scale of what economists call "relative child poverty" when measured against 35 of the world's richest nations.
|
23 |
-
In 2023, the official US poverty rate, according to the United States Census Bureau, was 11.1 percent. There were 36.8 million people in poverty in 2023.
|
24 |
-
Life expectancy
|
25 |
-
Overall life expectancy in the US was 76.4 years as of early 2023, the lowest in over 20 years.
|
26 |
-
How is this possible in the richest country in the world? The answer is capitalism. This is a system in which the working class, which produces all of the wealth, is systematically robbed of the vast portion of what it produces on the basis of private ownership of the means of production, production for profit, and the historically outmoded nation-state framework of economic life.
|
27 |
-
The levels of oligarchic excess and parasitism in the US are particularly grotesque due to the complete political subordination of the working class to the ruling elite by means of the two-party system. The exclusion of the working class from political life is enforced by the union bureaucracy and its pseudo-left hangers on in such pro-Democratic groups as the Democratic Socialists of America (DSA).
|
28 |
-
This is reflected in such facts as a federal minimum wage that remains at $7.25 an hour, not even sufficient to sustain human life. Meanwhile, the two-party monopoly spends a trillion dollars a year on war and the military and a trillion a year to service a national debt of $34 trillion and rising. The latter payouts, which directly enrich the banks and hedge funds, are on top of a combined $12 trillion doled out to rescue the financial elite in the Wall Street crises of 2008 and 2020.
|
29 |
-
The millions of workers who voted for Trump did so as a protest against the undisguised indifference of Biden and Harris to the devastating impact of inflation and austerity, including the purging of 40 million people from the Medicaid rolls. They did not vote for dictatorship, the rounding up of immigrant workers in concentration camps policed by the military for summary deportation, the expansion of US imperialism's global war to China, an increase in Washington's support for the genocide in Gaza, or the destruction of millions more jobs and basic social services.
|
30 |
-
They will be stunned and enraged by what is coming under Trump, and they will resist, massively and on a revolutionary scale. Leon Trotsky in his monumental History of the Russian Revolution devoted a chapter to "The Tzar and the Tzarina," in which he wrote of the cognitive blindness that seems to possess ruling classes on the eve of revolutionary upheavals. He wrote:
|
31 |
-
To that historic flood which was rolling its billows each one closer to the gates of his palace, the last Romanov opposed only a dumb indifference. It seemed as though between his consciousness and his epoch there stood some transparent but absolutely impenetrable medium.
|
32 |
-
Trotsky continued:
|
33 |
-
The tzar had no need of narcotics: the fatal "dope" was in his blood. Its symptoms merely seemed especially striking on the background of those great events of war and domestic crisis which led up to the revolution.
|
34 |
-
The American ruling class is facing a historical reckoning. The social force that alone can stop and reverse the slide to fascism and world war is the working class, in the US and internationally. It will fight, but it requires a scientific Marxist and internationalist perspective and strategy and the building of a new leadership, which can be accomplished only by the Trotskyist movement, the Socialist Equality Party and the International Committee of the Fourth International. To all those who see the dangers and want to fight, we say join the SEP and take up the fight for the political independence of the working class and socialism!
|
|
|
1 |
+
The International Monetary Fund (IMF) announced on Saturday that it had reached a staff-level agreement under Sri Lanka’s $US3 billion bailout loan program with the new Janatha Vimukthi Peramuna (JVP)/National Peoples Power (NPP) government and thanked it for its “excellent collaboration.”
|
2 |
+
|
3 |
+
The agreement was announced just two days after President Anura Dissanayake stated in his policy address to parliament on Thursday that the government was committed to implement the IMF demands in full, ditching his previous promise to “renegotiate” the terms.
|
4 |
+
|
5 |
+
All of this is being done in the name of establishing “debt sustainability”—that is, creating conditions to resume loan repayments after the previous Gotabhaya Rajapakse government defaulted in April 2022. From 2028, the Sri Lankan government must resume the payment of $5 billion annually to the international loan sharks.
|
6 |
+
|
7 |
+
In his inaugural speech to the parliament, Dissanayake made clear that his government had rapidly caved in to IMF demands on debt restructuring. The discussions, he said, were in the final stages and his government would reach a common understanding regarding bilateral debt without “debating” whether the plan was “good or bad”—effectively junking his criticisms of the previous President Ranil Wickremesinghe government.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
poetry.lock
CHANGED
@@ -5062,6 +5062,17 @@ files = [
|
|
5062 |
dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
|
5063 |
doc = ["Sphinx", "sphinx-rtd-theme"]
|
5064 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5065 |
[[package]]
|
5066 |
name = "shellingham"
|
5067 |
version = "1.5.4"
|
@@ -6194,4 +6205,4 @@ propcache = ">=0.2.0"
|
|
6194 |
[metadata]
|
6195 |
lock-version = "2.0"
|
6196 |
python-versions = "~3.10"
|
6197 |
-
content-hash = "
|
|
|
5062 |
dev = ["Django (>=1.11)", "check-manifest", "colorama (<=0.4.1)", "coverage", "flake8", "nose2", "readme-renderer (<25.0)", "tox", "wheel", "zest.releaser[recommended]"]
|
5063 |
doc = ["Sphinx", "sphinx-rtd-theme"]
|
5064 |
|
5065 |
+
[[package]]
|
5066 |
+
name = "sh"
|
5067 |
+
version = "2.1.0"
|
5068 |
+
description = "Python subprocess replacement"
|
5069 |
+
optional = false
|
5070 |
+
python-versions = "<4.0,>=3.8.1"
|
5071 |
+
files = [
|
5072 |
+
{file = "sh-2.1.0-py3-none-any.whl", hash = "sha256:bf5e44178dd96a542126c2774e9b7ab1d89bfe0e2ef84d92e6d0ed7358d63d01"},
|
5073 |
+
{file = "sh-2.1.0.tar.gz", hash = "sha256:7e27301c574bec8ca5bf6f211851357526455ee97cd27a7c4c6cc5e2375399cb"},
|
5074 |
+
]
|
5075 |
+
|
5076 |
[[package]]
|
5077 |
name = "shellingham"
|
5078 |
version = "1.5.4"
|
|
|
6205 |
[metadata]
|
6206 |
lock-version = "2.0"
|
6207 |
python-versions = "~3.10"
|
6208 |
+
content-hash = "d1a5b230b811073006a1e63ea0853c11dc6e27ada05990ef3adc730ef1ed861c"
|
pyproject.toml
CHANGED
@@ -51,6 +51,7 @@ wget = "^3.2"
|
|
51 |
httpx = "^0.28.0"
|
52 |
pandoc = "^2.4"
|
53 |
pyyaml = "^6.0.2"
|
|
|
54 |
|
55 |
[tool.poetry.group.ci.dependencies]
|
56 |
gradio = "4.43.0"
|
@@ -159,6 +160,7 @@ module = [
|
|
159 |
"pypresence",
|
160 |
"resampy",
|
161 |
"scipy.*",
|
|
|
162 |
"sklearn.*",
|
163 |
"soundfile",
|
164 |
"stftpitchshift",
|
|
|
51 |
httpx = "^0.28.0"
|
52 |
pandoc = "^2.4"
|
53 |
pyyaml = "^6.0.2"
|
54 |
+
sh = "^2.1.0"
|
55 |
|
56 |
[tool.poetry.group.ci.dependencies]
|
57 |
gradio = "4.43.0"
|
|
|
160 |
"pypresence",
|
161 |
"resampy",
|
162 |
"scipy.*",
|
163 |
+
"sh",
|
164 |
"sklearn.*",
|
165 |
"soundfile",
|
166 |
"stftpitchshift",
|
requirements.txt
CHANGED
@@ -2160,6 +2160,9 @@ segments==2.2.1 ; python_version >= "3.10" and python_version < "3.11" \
|
|
2160 |
semantic-version==2.10.0 ; python_version >= "3.10" and python_version < "3.11" \
|
2161 |
--hash=sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c \
|
2162 |
--hash=sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177
|
|
|
|
|
|
|
2163 |
shellingham==1.5.4 ; python_version >= "3.10" and python_version < "3.11" and sys_platform != "emscripten" \
|
2164 |
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
|
2165 |
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
|
|
|
2160 |
semantic-version==2.10.0 ; python_version >= "3.10" and python_version < "3.11" \
|
2161 |
--hash=sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c \
|
2162 |
--hash=sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177
|
2163 |
+
sh==2.1.0 ; python_version >= "3.10" and python_version < "3.11" \
|
2164 |
+
--hash=sha256:7e27301c574bec8ca5bf6f211851357526455ee97cd27a7c4c6cc5e2375399cb \
|
2165 |
+
--hash=sha256:bf5e44178dd96a542126c2774e9b7ab1d89bfe0e2ef84d92e6d0ed7358d63d01
|
2166 |
shellingham==1.5.4 ; python_version >= "3.10" and python_version < "3.11" and sys_platform != "emscripten" \
|
2167 |
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
|
2168 |
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
|
rvc/infer/infer.py
CHANGED
@@ -241,20 +241,26 @@ class VoiceConverter:
|
|
241 |
start_time = time.time()
|
242 |
log.info(f"Converting audio '{audio_input_path}'...")
|
243 |
|
|
|
244 |
if upscale_audio:
|
245 |
from audio_upscaler import upscale
|
246 |
|
247 |
upscale(audio_input_path, audio_input_path)
|
|
|
|
|
248 |
audio = load_audio_infer(
|
249 |
audio_input_path,
|
250 |
16000,
|
251 |
**kwargs,
|
252 |
)
|
|
|
|
|
253 |
audio_max = np.abs(audio).max() / 0.95
|
254 |
|
255 |
if audio_max > 1:
|
256 |
audio /= audio_max
|
257 |
|
|
|
258 |
if not self.hubert_model or embedder_model != self.last_embedder_model:
|
259 |
self.load_hubert(embedder_model, embedder_model_custom)
|
260 |
self.last_embedder_model = embedder_model
|
|
|
241 |
start_time = time.time()
|
242 |
log.info(f"Converting audio '{audio_input_path}'...")
|
243 |
|
244 |
+
# Step 1: Upscale to 48kHz using Predict() model. Currently disabled
|
245 |
if upscale_audio:
|
246 |
from audio_upscaler import upscale
|
247 |
|
248 |
upscale(audio_input_path, audio_input_path)
|
249 |
+
|
250 |
+
# Step 2: Load input audio file and downsample to 16kHz mono
|
251 |
audio = load_audio_infer(
|
252 |
audio_input_path,
|
253 |
16000,
|
254 |
**kwargs,
|
255 |
)
|
256 |
+
|
257 |
+
# Step 3: Normalize audio to 105%
|
258 |
audio_max = np.abs(audio).max() / 0.95
|
259 |
|
260 |
if audio_max > 1:
|
261 |
audio /= audio_max
|
262 |
|
263 |
+
# Step 4: Load hubert model
|
264 |
if not self.hubert_model or embedder_model != self.last_embedder_model:
|
265 |
self.load_hubert(embedder_model, embedder_model_custom)
|
266 |
self.last_embedder_model = embedder_model
|
rvc/lib/tools/prerequisites_download.py
CHANGED
@@ -1,11 +1,16 @@
|
|
|
|
1 |
import os
|
|
|
2 |
from concurrent.futures import ThreadPoolExecutor
|
3 |
|
4 |
import requests
|
5 |
from tqdm import tqdm
|
6 |
|
|
|
7 |
from tts_service.voices import voice_manager
|
8 |
|
|
|
|
|
9 |
url_base = "https://huggingface.co/IAHispano/Applio/resolve/main/Resources"
|
10 |
|
11 |
pretraineds_v1_list = [
|
@@ -69,7 +74,7 @@ def get_file_size_if_missing(file_list: list[tuple[str, list[str]]]) -> int:
|
|
69 |
destination_path = os.path.join(local_folder, file)
|
70 |
if not os.path.exists(destination_path):
|
71 |
url = f"{url_base}/{remote_folder}{file}"
|
72 |
-
response = requests.head(url)
|
73 |
total_size += int(response.headers.get("content-length", 0))
|
74 |
return total_size
|
75 |
|
@@ -85,10 +90,15 @@ def download_file(url: str, destination_path: str, global_bar: tqdm) -> None:
|
|
85 |
os.makedirs(dir_name, exist_ok=True)
|
86 |
response = requests.get(url, stream=True)
|
87 |
block_size = 1024
|
|
|
88 |
with open(destination_path, "wb") as file:
|
89 |
for data in response.iter_content(block_size):
|
90 |
file.write(data)
|
91 |
global_bar.update(len(data))
|
|
|
|
|
|
|
|
|
92 |
|
93 |
|
94 |
def download_mapping_files(file_mapping_list: list[tuple[str, list[str]]], global_bar: tqdm) -> None:
|
@@ -152,7 +162,7 @@ def calculate_total_size(
|
|
152 |
return total_size
|
153 |
|
154 |
|
155 |
-
def
|
156 |
pretraineds_v1_f0: bool,
|
157 |
pretraineds_v1_nof0: bool,
|
158 |
pretraineds_v2_f0: bool,
|
@@ -163,6 +173,10 @@ def prequisites_download_pipeline(
|
|
163 |
"""
|
164 |
Manage the download pipeline for different categories of files.
|
165 |
"""
|
|
|
|
|
|
|
|
|
166 |
total_size = calculate_total_size(
|
167 |
pretraineds_v1_f0_list if pretraineds_v1_f0 else [],
|
168 |
pretraineds_v1_nof0_list if pretraineds_v1_nof0 else [],
|
@@ -173,7 +187,9 @@ def prequisites_download_pipeline(
|
|
173 |
)
|
174 |
|
175 |
if total_size > 0:
|
176 |
-
|
|
|
|
|
177 |
if models:
|
178 |
download_mapping_files(models_list, global_bar)
|
179 |
download_mapping_files(embedders_list, global_bar)
|
@@ -188,4 +204,4 @@ def prequisites_download_pipeline(
|
|
188 |
if voices:
|
189 |
voice_manager.download_voice_files(global_bar)
|
190 |
else:
|
191 |
-
|
|
|
1 |
+
import logging
|
2 |
import os
|
3 |
+
import sys
|
4 |
from concurrent.futures import ThreadPoolExecutor
|
5 |
|
6 |
import requests
|
7 |
from tqdm import tqdm
|
8 |
|
9 |
+
from tts_service.utils import env_bool
|
10 |
from tts_service.voices import voice_manager
|
11 |
|
12 |
+
log = logging.getLogger(__name__)
|
13 |
+
|
14 |
url_base = "https://huggingface.co/IAHispano/Applio/resolve/main/Resources"
|
15 |
|
16 |
pretraineds_v1_list = [
|
|
|
74 |
destination_path = os.path.join(local_folder, file)
|
75 |
if not os.path.exists(destination_path):
|
76 |
url = f"{url_base}/{remote_folder}{file}"
|
77 |
+
response = requests.head(url, allow_redirects=True)
|
78 |
total_size += int(response.headers.get("content-length", 0))
|
79 |
return total_size
|
80 |
|
|
|
90 |
os.makedirs(dir_name, exist_ok=True)
|
91 |
response = requests.get(url, stream=True)
|
92 |
block_size = 1024
|
93 |
+
total = 0
|
94 |
with open(destination_path, "wb") as file:
|
95 |
for data in response.iter_content(block_size):
|
96 |
file.write(data)
|
97 |
global_bar.update(len(data))
|
98 |
+
total += len(data)
|
99 |
+
global_bar.clear()
|
100 |
+
log.info(f"Downloaded {total:,} bytes to {destination_path}")
|
101 |
+
global_bar.display()
|
102 |
|
103 |
|
104 |
def download_mapping_files(file_mapping_list: list[tuple[str, list[str]]], global_bar: tqdm) -> None:
|
|
|
162 |
return total_size
|
163 |
|
164 |
|
165 |
+
def prerequisites_download_pipeline(
|
166 |
pretraineds_v1_f0: bool,
|
167 |
pretraineds_v1_nof0: bool,
|
168 |
pretraineds_v2_f0: bool,
|
|
|
173 |
"""
|
174 |
Manage the download pipeline for different categories of files.
|
175 |
"""
|
176 |
+
if env_bool("OFFLINE", False):
|
177 |
+
log.info("Skipping download due to OFFLINE environment variable")
|
178 |
+
return
|
179 |
+
|
180 |
total_size = calculate_total_size(
|
181 |
pretraineds_v1_f0_list if pretraineds_v1_f0 else [],
|
182 |
pretraineds_v1_nof0_list if pretraineds_v1_nof0 else [],
|
|
|
187 |
)
|
188 |
|
189 |
if total_size > 0:
|
190 |
+
log.info(f"Will download {total_size:,} bytes")
|
191 |
+
miniters = None if sys.stdout.isatty() else total_size
|
192 |
+
with tqdm(total=total_size, unit="iB", unit_scale=True, desc="Downloading...", miniters=miniters) as global_bar:
|
193 |
if models:
|
194 |
download_mapping_files(models_list, global_bar)
|
195 |
download_mapping_files(embedders_list, global_bar)
|
|
|
204 |
if voices:
|
205 |
voice_manager.download_voice_files(global_bar)
|
206 |
else:
|
207 |
+
log.info("No files to download")
|
tabs/workflow/workflow.py
CHANGED
@@ -1,14 +1,20 @@
|
|
|
|
|
|
1 |
import gradio as gr
|
2 |
|
3 |
from assets.i18n.i18n import I18nAuto
|
4 |
from tts_service.docs import document_manager
|
5 |
from tts_service.tts import run_tts_script
|
6 |
from tts_service.utils import html_to_markdown, markdown_to_text
|
|
|
7 |
|
8 |
i18n = I18nAuto()
|
9 |
|
|
|
|
|
10 |
|
11 |
async def fetch_document(source: str) -> tuple[str, gr.Dataset]:
|
|
|
12 |
doc = await document_manager.get_doc(source)
|
13 |
if doc:
|
14 |
overline = doc.get("overline")
|
@@ -29,6 +35,7 @@ async def fetch_document(source: str) -> tuple[str, gr.Dataset]:
|
|
29 |
pieces.append(content)
|
30 |
content = "\n\n".join(pieces)
|
31 |
text = markdown_to_text(content)
|
|
|
32 |
return content, text
|
33 |
return "", ""
|
34 |
|
@@ -48,6 +55,12 @@ def workflow_tab():
|
|
48 |
interactive=True,
|
49 |
)
|
50 |
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
synthesize_button = gr.Button(i18n("Synthesize"))
|
52 |
|
53 |
status = gr.Textbox(visible=False)
|
@@ -67,6 +80,6 @@ def workflow_tab():
|
|
67 |
|
68 |
synthesize_button.click(
|
69 |
fn=run_tts_script,
|
70 |
-
inputs=[text],
|
71 |
outputs=[status, audio],
|
72 |
)
|
|
|
1 |
+
import logging
|
2 |
+
|
3 |
import gradio as gr
|
4 |
|
5 |
from assets.i18n.i18n import I18nAuto
|
6 |
from tts_service.docs import document_manager
|
7 |
from tts_service.tts import run_tts_script
|
8 |
from tts_service.utils import html_to_markdown, markdown_to_text
|
9 |
+
from tts_service.voices import voice_manager
|
10 |
|
11 |
i18n = I18nAuto()
|
12 |
|
13 |
+
log = logging.getLogger(__name__)
|
14 |
+
|
15 |
|
16 |
async def fetch_document(source: str) -> tuple[str, gr.Dataset]:
|
17 |
+
log.info("Fetching document %s", source)
|
18 |
doc = await document_manager.get_doc(source)
|
19 |
if doc:
|
20 |
overline = doc.get("overline")
|
|
|
35 |
pieces.append(content)
|
36 |
content = "\n\n".join(pieces)
|
37 |
text = markdown_to_text(content)
|
38 |
+
log.info("Successfully fetched document %s: %s chars", source, len(text))
|
39 |
return content, text
|
40 |
return "", ""
|
41 |
|
|
|
55 |
interactive=True,
|
56 |
)
|
57 |
|
58 |
+
voice = gr.Dropdown(
|
59 |
+
label=i18n("Voice"),
|
60 |
+
choices=voice_manager.voices.keys(),
|
61 |
+
value=voice_manager.voice_names[0],
|
62 |
+
)
|
63 |
+
|
64 |
synthesize_button = gr.Button(i18n("Synthesize"))
|
65 |
|
66 |
status = gr.Textbox(visible=False)
|
|
|
80 |
|
81 |
synthesize_button.click(
|
82 |
fn=run_tts_script,
|
83 |
+
inputs=[text, voice],
|
84 |
outputs=[status, audio],
|
85 |
)
|
tts_service/app.py
CHANGED
@@ -1,34 +1,23 @@
|
|
1 |
-
import logging
|
2 |
-
import sys
|
3 |
-
from pathlib import Path
|
4 |
-
|
5 |
import gradio as gr
|
6 |
-
import yaml
|
7 |
|
8 |
import assets.installation_checker as installation_checker
|
9 |
import assets.themes.loadThemes as loadThemes
|
10 |
from assets.i18n.i18n import I18nAuto
|
11 |
-
from rvc.lib.tools.prerequisites_download import
|
12 |
from tabs.plugins import plugins_core
|
|
|
13 |
from tabs.workflow.workflow import workflow_tab
|
14 |
-
from tts_service.utils import env_bool
|
15 |
-
|
16 |
-
# Set up logging
|
17 |
-
logging.getLogger("uvicorn").setLevel(logging.WARNING)
|
18 |
-
logging.getLogger("httpx").setLevel(logging.WARNING)
|
19 |
-
|
20 |
-
# Import Tabs
|
21 |
|
22 |
plugins_core.check_new_folders()
|
23 |
|
24 |
# Run prerequisites
|
25 |
-
|
26 |
pretraineds_v1_f0=False,
|
27 |
pretraineds_v1_nof0=False,
|
28 |
pretraineds_v2_f0=True,
|
29 |
pretraineds_v2_nof0=False,
|
30 |
models=True,
|
31 |
-
voices=
|
32 |
)
|
33 |
|
34 |
# Initialize i18n
|
@@ -49,26 +38,5 @@ with gr.Blocks(theme=my_applio, title="TTS Playground", css="footer{display:none
|
|
49 |
gr.Markdown(i18n("Enter a page URL, click fetch and then synthesize"))
|
50 |
with gr.Tab(i18n("Workflow")):
|
51 |
workflow_tab()
|
52 |
-
|
53 |
-
|
54 |
-
def setup_logging():
|
55 |
-
path = Path("logging.yml")
|
56 |
-
if not path.exists():
|
57 |
-
return
|
58 |
-
with path.open() as f:
|
59 |
-
from logging.config import dictConfig
|
60 |
-
|
61 |
-
dictConfig(yaml.safe_load(f))
|
62 |
-
|
63 |
-
|
64 |
-
def launch_gradio():
|
65 |
-
setup_logging()
|
66 |
-
app.queue(status_update_rate=1).launch(
|
67 |
-
favicon_path="assets/ICON.ico",
|
68 |
-
share="--share" in sys.argv,
|
69 |
-
inbrowser="--open" in sys.argv,
|
70 |
-
)
|
71 |
-
|
72 |
-
|
73 |
-
if __name__ == "__main__":
|
74 |
-
launch_gradio()
|
|
|
|
|
|
|
|
|
|
|
1 |
import gradio as gr
|
|
|
2 |
|
3 |
import assets.installation_checker as installation_checker
|
4 |
import assets.themes.loadThemes as loadThemes
|
5 |
from assets.i18n.i18n import I18nAuto
|
6 |
+
from rvc.lib.tools.prerequisites_download import prerequisites_download_pipeline
|
7 |
from tabs.plugins import plugins_core
|
8 |
+
from tabs.tts.tts import tts_tab
|
9 |
from tabs.workflow.workflow import workflow_tab
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
plugins_core.check_new_folders()
|
12 |
|
13 |
# Run prerequisites
|
14 |
+
prerequisites_download_pipeline(
|
15 |
pretraineds_v1_f0=False,
|
16 |
pretraineds_v1_nof0=False,
|
17 |
pretraineds_v2_f0=True,
|
18 |
pretraineds_v2_nof0=False,
|
19 |
models=True,
|
20 |
+
voices=True,
|
21 |
)
|
22 |
|
23 |
# Initialize i18n
|
|
|
38 |
gr.Markdown(i18n("Enter a page URL, click fetch and then synthesize"))
|
39 |
with gr.Tab(i18n("Workflow")):
|
40 |
workflow_tab()
|
41 |
+
with gr.Tab(i18n("TTS")):
|
42 |
+
tts_tab()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
tts_service/cli.py
CHANGED
@@ -1,10 +1,10 @@
|
|
1 |
import os
|
2 |
-
|
3 |
|
4 |
-
import boto3
|
5 |
import click
|
6 |
from click_help_colors import HelpColorsGroup
|
7 |
from dotenv import load_dotenv
|
|
|
8 |
|
9 |
load_dotenv()
|
10 |
|
@@ -37,37 +37,15 @@ def service() -> None:
|
|
37 |
@click.option("--prefix", "-p", default=lambda: os.environ["VOICES_KEY_PREFIX"], help="the prefix to use for the keys")
|
38 |
@click.option("--delete", is_flag=True, help="delete extraneous files from dest")
|
39 |
@click.option("--dry-run", "-n", is_flag=True, help="perform a trial run with no changes made")
|
40 |
-
@click.argument("directory", type=click.Path(exists=True, file_okay=False
|
41 |
-
def upload_voices(bucket: str, prefix: str, delete: bool, dry_run: bool, directory:
|
42 |
"""Upload voices to the service"""
|
43 |
-
|
44 |
-
prefix = prefix.strip("/")
|
45 |
-
names = set()
|
46 |
-
for path in directory.glob("*.pth"):
|
47 |
-
names.add(path.name)
|
48 |
-
with path.open("rb") as file:
|
49 |
-
if dry_run:
|
50 |
-
click.echo(f"Would upload {path.name} to {bucket}/{prefix}")
|
51 |
-
else:
|
52 |
-
s3.put_object(Bucket=bucket, Key=f"{prefix}/{path.name}", Body=file)
|
53 |
-
# s3.upload_fileobj(file, bucket, f"{prefix}/{path.name}")
|
54 |
-
if not names:
|
55 |
-
raise click.ClickException(f"no voices found in directory {directory}")
|
56 |
-
deleted = 0
|
57 |
if delete:
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
if key.split("/")[-1] not in names:
|
63 |
-
if dry_run:
|
64 |
-
click.echo(f"Would delete {key}")
|
65 |
-
else:
|
66 |
-
s3.delete_object(Bucket=bucket, Key=key)
|
67 |
-
deleted += 1
|
68 |
-
deleted_message = f", {deleted} deleted" if delete else ""
|
69 |
-
if not dry_run:
|
70 |
-
click.echo(f"{bucket}/{prefix}: {len(names)} voices uploaded{deleted_message}")
|
71 |
|
72 |
|
73 |
if __name__ == "__main__":
|
|
|
1 |
import os
|
2 |
+
import sys
|
3 |
|
|
|
4 |
import click
|
5 |
from click_help_colors import HelpColorsGroup
|
6 |
from dotenv import load_dotenv
|
7 |
+
from sh import aws
|
8 |
|
9 |
load_dotenv()
|
10 |
|
|
|
37 |
@click.option("--prefix", "-p", default=lambda: os.environ["VOICES_KEY_PREFIX"], help="the prefix to use for the keys")
|
38 |
@click.option("--delete", is_flag=True, help="delete extraneous files from dest")
|
39 |
@click.option("--dry-run", "-n", is_flag=True, help="perform a trial run with no changes made")
|
40 |
+
@click.argument("directory", type=click.Path(exists=True, file_okay=False), nargs=1)
|
41 |
+
def upload_voices(bucket: str, prefix: str, delete: bool, dry_run: bool, directory: str) -> None:
|
42 |
"""Upload voices to the service"""
|
43 |
+
args = [directory, f"s3://{bucket}/{prefix}/"]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
if delete:
|
45 |
+
args.insert(0, "--delete")
|
46 |
+
if dry_run:
|
47 |
+
args.insert(0, "--dryrun")
|
48 |
+
aws.s3.sync(*args, _out=sys.stdout, _err=sys.stderr)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
49 |
|
50 |
|
51 |
if __name__ == "__main__":
|
tts_service/start.py
ADDED
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import sys
|
2 |
+
from pathlib import Path
|
3 |
+
|
4 |
+
import yaml
|
5 |
+
|
6 |
+
|
7 |
+
def setup_logging():
|
8 |
+
path = Path("logging.yml")
|
9 |
+
if not path.exists():
|
10 |
+
return
|
11 |
+
with path.open() as f:
|
12 |
+
from logging.config import dictConfig
|
13 |
+
|
14 |
+
dictConfig(yaml.safe_load(f))
|
15 |
+
|
16 |
+
|
17 |
+
def launch_gradio():
|
18 |
+
setup_logging()
|
19 |
+
|
20 |
+
from tts_service.app import app
|
21 |
+
|
22 |
+
app.queue(status_update_rate=1).launch(
|
23 |
+
favicon_path="assets/ICON.ico",
|
24 |
+
share="--share" in sys.argv,
|
25 |
+
inbrowser="--open" in sys.argv,
|
26 |
+
)
|
27 |
+
|
28 |
+
|
29 |
+
if __name__ == "__main__":
|
30 |
+
launch_gradio()
|
tts_service/tts.py
CHANGED
@@ -23,7 +23,7 @@ def import_voice_converter():
|
|
23 |
# TTS
|
24 |
async def run_tts_script(
|
25 |
text: str,
|
26 |
-
voice_name: str
|
27 |
rate: int = 0,
|
28 |
progress=gr.Progress(), # noqa: B008
|
29 |
) -> tuple[str, str]:
|
@@ -32,6 +32,8 @@ async def run_tts_script(
|
|
32 |
progress(pct, msg)
|
33 |
await asyncio.sleep(0)
|
34 |
|
|
|
|
|
35 |
await update_progress(0, "Starting...")
|
36 |
voice = voice_manager.voices[voice_name]
|
37 |
format = "wav"
|
@@ -104,6 +106,7 @@ async def run_tts_script(
|
|
104 |
callback=lambda pct: update_progress(0.5 + pct / 2, "Converting..."),
|
105 |
)
|
106 |
|
|
|
107 |
return "Text synthesized successfully.", str(output_rvc_path)
|
108 |
|
109 |
|
|
|
23 |
# TTS
|
24 |
async def run_tts_script(
|
25 |
text: str,
|
26 |
+
voice_name: str,
|
27 |
rate: int = 0,
|
28 |
progress=gr.Progress(), # noqa: B008
|
29 |
) -> tuple[str, str]:
|
|
|
32 |
progress(pct, msg)
|
33 |
await asyncio.sleep(0)
|
34 |
|
35 |
+
log.info("Synthesizing text (%s chars)", len(text))
|
36 |
+
|
37 |
await update_progress(0, "Starting...")
|
38 |
voice = voice_manager.voices[voice_name]
|
39 |
format = "wav"
|
|
|
106 |
callback=lambda pct: update_progress(0.5 + pct / 2, "Converting..."),
|
107 |
)
|
108 |
|
109 |
+
log.info("Successfully synthesized text (%s chars)", len(text))
|
110 |
return "Text synthesized successfully.", str(output_rvc_path)
|
111 |
|
112 |
|
tts_service/voices.py
CHANGED
@@ -10,6 +10,8 @@ from tqdm import tqdm
|
|
10 |
|
11 |
from .utils import data_dir, env_str
|
12 |
|
|
|
|
|
13 |
|
14 |
@dataclass
|
15 |
class S3VoiceObj:
|
@@ -89,6 +91,9 @@ class VoiceManager:
|
|
89 |
destination_path = self.voices_dir / obj.name
|
90 |
if not destination_path.exists() or destination_path.stat().st_size != obj.size:
|
91 |
self.s3.download_file(Bucket=self.bucket, Key=obj.key, Filename=destination_path, Callback=callback)
|
|
|
|
|
|
|
92 |
|
93 |
@cached_property
|
94 |
def tts_voices(self) -> dict[str, TTSVoice]:
|
@@ -103,7 +108,7 @@ class VoiceManager:
|
|
103 |
@cached_property
|
104 |
def voices(self) -> dict[str, Voice]:
|
105 |
rv = {}
|
106 |
-
for path in self.voices_dir.glob("*.json"):
|
107 |
voice = Voice.model_validate_json(path.read_bytes())
|
108 |
model_path = self.voices_dir / f"{voice.model}"
|
109 |
if not model_path.exists():
|
|
|
10 |
|
11 |
from .utils import data_dir, env_str
|
12 |
|
13 |
+
log = logging.getLogger(__name__)
|
14 |
+
|
15 |
|
16 |
@dataclass
|
17 |
class S3VoiceObj:
|
|
|
91 |
destination_path = self.voices_dir / obj.name
|
92 |
if not destination_path.exists() or destination_path.stat().st_size != obj.size:
|
93 |
self.s3.download_file(Bucket=self.bucket, Key=obj.key, Filename=destination_path, Callback=callback)
|
94 |
+
progress_bar.clear()
|
95 |
+
log.info(f"Downloaded {obj.size:,} bytes to {destination_path}")
|
96 |
+
progress_bar.display()
|
97 |
|
98 |
@cached_property
|
99 |
def tts_voices(self) -> dict[str, TTSVoice]:
|
|
|
108 |
@cached_property
|
109 |
def voices(self) -> dict[str, Voice]:
|
110 |
rv = {}
|
111 |
+
for path in sorted(self.voices_dir.glob("*.json")):
|
112 |
voice = Voice.model_validate_json(path.read_bytes())
|
113 |
model_path = self.voices_dir / f"{voice.model}"
|
114 |
if not model_path.exists():
|