jlopez00 commited on
Commit
2c01ee6
1 Parent(s): b3385db

Upload folder using huggingface_hub

Browse files
.vscode/launch.json CHANGED
@@ -17,7 +17,7 @@
17
  "name": "App",
18
  "type": "debugpy",
19
  "request": "launch",
20
- "program": "tts_service/app.py",
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/app.py
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
- Thanksgiving in America 2024: Social devastation for the working class, billions more for the oligarchs
2
- By Barry Grey
3
- On Thanksgiving Day 2024, the broad mass of the American population has precious little to be thankful for. Inflated costs for all necessities---housing, food, healthcare, childcare, transport---continue to weigh on working class families. Workers are struggling to scrape together turkey dinners for their families and friends under conditions where the cost of a Thanksgiving meal is up 19 percent from pre-pandemic 2019, according to the American Farm Bureau Federation.
4
- But there is an entirely different reality in the environs of the rich and the super-rich. Champagne glasses are clinking on Wall Street, at Donald Trump's Mar-a-Lago estate, at the White House and on Capitol Hill as the stock market booms and the bonanza reaped by America's oligarchs and their political servants under Joe Biden is set to be massively amplified under the incoming Trump administration.
5
- Outgoing President Biden is spending his holiday at the Nantucket home of David Rubenstein, billionaire co-founder of the Carlyle Group. Defeated presidential candidate Kamala Harris is sunning herself in Hawaii. Most of their voters, and most of Trump's, are struggling simply to get by.
6
- The ranks of America's billionaires grew to 800 under Biden and their collective wealth increased by 62 percent to more than $6.2 trillion (not counting the additional hundreds of billions amassed in the stock market surge since the election of Trump). As of December of last year, the top 1 percent of Americans took 21 percent of all personal incomes, more than double the share of the bottom 50 percent. The top one percent of Americans owned 35 percent of all personal wealth and the top 10 percent owned 71 percent, while the bottom 50 percent owned just 1 percent.
7
- In less than eight weeks, Trump's cabal of billionaires, fascists and quacks is set to take office. It will seek to impose an agenda of mass deportations and state repression, escalation of war and genocide, further tax cuts for the rich, the ripping up of what remains of the social safety net, the dismantling of public health and public education, and the lifting of virtually all regulations on big business. Things could not appear rosier for the financial parasites who control both parties and the entire political system.
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 = "9aec331b8bb3a245ef2f232c85343bc8a1114e5d03679e3309882d59d617e083"
 
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 prequisites_download_pipeline(
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
- with tqdm(total=total_size, unit="iB", unit_scale=True, desc="Downloading all files") as global_bar:
 
 
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
- pass
 
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 prequisites_download_pipeline
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
- prequisites_download_pipeline(
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=not env_bool("OFFLINE", False),
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
- from pathlib import Path
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, path_type=Path), nargs=1)
41
- def upload_voices(bucket: str, prefix: str, delete: bool, dry_run: bool, directory: Path) -> None:
42
  """Upload voices to the service"""
43
- s3 = boto3.client("s3")
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
- paginator = s3.get_paginator("list_objects_v2")
59
- for page in paginator.paginate(Bucket=bucket, Prefix=prefix):
60
- for obj in page["Contents"]:
61
- key = obj["Key"]
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 = "male-1",
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():