Update and #26
Browse files
app.py
CHANGED
|
@@ -29,9 +29,11 @@ import sys
|
|
| 29 |
import torch
|
| 30 |
import fairseq
|
| 31 |
from picklescan.scanner import scan_file_path
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
ALLOWED_DOMAINS = {"huggingface.co", "hf.co"}
|
|
|
|
| 35 |
|
| 36 |
parser = argparse.ArgumentParser(description="Run the app with optional sharing")
|
| 37 |
parser.add_argument(
|
|
@@ -109,6 +111,14 @@ def check_model_safety(file_path: str):
|
|
| 109 |
print(f"Integrity check skipped for {file_path}: {e}")
|
| 110 |
|
| 111 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
async def get_voices_list(proxy=None):
|
| 113 |
"""Print all available voices."""
|
| 114 |
from edge_tts import list_voices
|
|
@@ -156,6 +166,26 @@ def find_my_model(a_, b_):
|
|
| 156 |
check_model_safety(a_)
|
| 157 |
return a_, b_
|
| 158 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 159 |
txt_files = []
|
| 160 |
for base_file in [a_, b_]:
|
| 161 |
if base_file is not None and base_file.endswith(".txt"):
|
|
@@ -200,6 +230,9 @@ def find_my_model(a_, b_):
|
|
| 200 |
if not index:
|
| 201 |
gr.Warning("Index not found")
|
| 202 |
|
|
|
|
|
|
|
|
|
|
| 203 |
return model, index
|
| 204 |
|
| 205 |
|
|
@@ -471,7 +504,6 @@ def run(
|
|
| 471 |
audio_effects,
|
| 472 |
type_output,
|
| 473 |
steps,
|
| 474 |
-
play_audio=False,
|
| 475 |
):
|
| 476 |
if not audio_files:
|
| 477 |
raise ValueError("The audio pls")
|
|
@@ -487,7 +519,7 @@ def run(
|
|
| 487 |
|
| 488 |
if file_m is not None and (file_m.endswith(".txt") or file_m.endswith(".zip")):
|
| 489 |
file_m, file_index = find_my_model(file_m, file_index)
|
| 490 |
-
print(file_m, file_index)
|
| 491 |
|
| 492 |
random_tag = "USER_"+str(random.randint(10000000, 99999999))
|
| 493 |
|
|
@@ -513,9 +545,37 @@ def run(
|
|
| 513 |
if audio_effects:
|
| 514 |
result = add_audio_effects(result, type_output)
|
| 515 |
|
| 516 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 517 |
|
| 518 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 519 |
|
| 520 |
|
| 521 |
def audio_conf():
|
|
@@ -623,15 +683,6 @@ def output_conf():
|
|
| 623 |
)
|
| 624 |
|
| 625 |
|
| 626 |
-
def active_tts_conf():
|
| 627 |
-
return gr.Checkbox(
|
| 628 |
-
False,
|
| 629 |
-
label="TTS",
|
| 630 |
-
# info="",
|
| 631 |
-
container=False,
|
| 632 |
-
)
|
| 633 |
-
|
| 634 |
-
|
| 635 |
def tts_voice_conf():
|
| 636 |
return gr.Dropdown(
|
| 637 |
label="tts voice",
|
|
@@ -730,16 +781,21 @@ def infer_tts_audio(tts_voice, tts_text, play_audio):
|
|
| 730 |
return [out_path], player_audio
|
| 731 |
|
| 732 |
|
| 733 |
-
def
|
| 734 |
-
return
|
| 735 |
-
visible=
|
| 736 |
-
|
| 737 |
-
visible=
|
| 738 |
-
|
| 739 |
-
visible=value_active
|
| 740 |
)
|
| 741 |
|
| 742 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 743 |
def down_active_conf():
|
| 744 |
return gr.Checkbox(
|
| 745 |
False,
|
|
@@ -787,7 +843,7 @@ def get_gui(theme):
|
|
| 787 |
gr.Markdown(title)
|
| 788 |
gr.Markdown(description)
|
| 789 |
|
| 790 |
-
|
| 791 |
with gr.Row():
|
| 792 |
with gr.Column(scale=1):
|
| 793 |
tts_text = tts_text_conf()
|
|
@@ -799,15 +855,22 @@ def get_gui(theme):
|
|
| 799 |
|
| 800 |
tts_button = tts_button_conf()
|
| 801 |
|
| 802 |
-
|
| 803 |
-
fn=show_components_tts,
|
| 804 |
-
inputs=[active_tts],
|
| 805 |
-
outputs=[tts_voice, tts_text, tts_button],
|
| 806 |
-
)
|
| 807 |
-
|
| 808 |
aud = audio_conf()
|
| 809 |
# gr.HTML("<hr>")
|
| 810 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 811 |
down_active_gui = down_active_conf()
|
| 812 |
down_info = gr.Markdown(
|
| 813 |
f"Provide a link to a zip file, like this one: `https://huggingface.co/MrDawg/ToothBrushing/resolve/main/ToothBrushing.zip?download=true`, or separate links with a comma for the .pth and .index files, like this: `{test_model}`",
|
|
@@ -885,9 +948,17 @@ def get_gui(theme):
|
|
| 885 |
effects_gui,
|
| 886 |
format_out,
|
| 887 |
steps_gui,
|
| 888 |
-
player_gui,
|
| 889 |
],
|
| 890 |
-
outputs=[output_base
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 891 |
)
|
| 892 |
|
| 893 |
gr.Examples(
|
|
@@ -939,7 +1010,7 @@ def get_gui(theme):
|
|
| 939 |
envel_r,
|
| 940 |
const,
|
| 941 |
],
|
| 942 |
-
outputs=[output_base
|
| 943 |
cache_examples=False,
|
| 944 |
)
|
| 945 |
gr.Markdown(RESOURCES)
|
|
@@ -948,12 +1019,16 @@ def get_gui(theme):
|
|
| 948 |
|
| 949 |
|
| 950 |
if __name__ == "__main__":
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
app = get_gui(theme)
|
| 958 |
|
| 959 |
app.queue(default_concurrency_limit=40)
|
|
|
|
| 29 |
import torch
|
| 30 |
import fairseq
|
| 31 |
from picklescan.scanner import scan_file_path
|
| 32 |
+
import hashlib
|
| 33 |
|
| 34 |
|
| 35 |
ALLOWED_DOMAINS = {"huggingface.co", "hf.co"}
|
| 36 |
+
MODEL_CACHE = {}
|
| 37 |
|
| 38 |
parser = argparse.ArgumentParser(description="Run the app with optional sharing")
|
| 39 |
parser.add_argument(
|
|
|
|
| 111 |
print(f"Integrity check skipped for {file_path}: {e}")
|
| 112 |
|
| 113 |
|
| 114 |
+
def get_file_hash(file_path: str) -> str:
|
| 115 |
+
hasher = hashlib.sha256()
|
| 116 |
+
with open(file_path, "rb") as f:
|
| 117 |
+
while chunk := f.read(65536):
|
| 118 |
+
hasher.update(chunk)
|
| 119 |
+
return hasher.hexdigest()
|
| 120 |
+
|
| 121 |
+
|
| 122 |
async def get_voices_list(proxy=None):
|
| 123 |
"""Print all available voices."""
|
| 124 |
from edge_tts import list_voices
|
|
|
|
| 166 |
check_model_safety(a_)
|
| 167 |
return a_, b_
|
| 168 |
|
| 169 |
+
input_hash = None
|
| 170 |
+
if a_ and os.path.exists(a_):
|
| 171 |
+
input_hash = get_file_hash(a_)
|
| 172 |
+
if b_ and os.path.exists(b_):
|
| 173 |
+
input_hash += "_" + get_file_hash(b_)
|
| 174 |
+
|
| 175 |
+
if input_hash and input_hash in MODEL_CACHE:
|
| 176 |
+
cached_model, cached_index = MODEL_CACHE[input_hash]
|
| 177 |
+
model_exists = cached_model and os.path.exists(cached_model)
|
| 178 |
+
index_exists = (cached_index is None) or os.path.exists(cached_index)
|
| 179 |
+
|
| 180 |
+
if model_exists and index_exists:
|
| 181 |
+
check_model_safety(cached_model)
|
| 182 |
+
gr.Info(f"Model found: {cached_model}")
|
| 183 |
+
if cached_index:
|
| 184 |
+
gr.Info(f"Index found: {cached_index}")
|
| 185 |
+
return cached_model, cached_index
|
| 186 |
+
else:
|
| 187 |
+
del MODEL_CACHE[input_hash]
|
| 188 |
+
|
| 189 |
txt_files = []
|
| 190 |
for base_file in [a_, b_]:
|
| 191 |
if base_file is not None and base_file.endswith(".txt"):
|
|
|
|
| 230 |
if not index:
|
| 231 |
gr.Warning("Index not found")
|
| 232 |
|
| 233 |
+
if model and input_hash:
|
| 234 |
+
MODEL_CACHE[input_hash] = (model, index)
|
| 235 |
+
|
| 236 |
return model, index
|
| 237 |
|
| 238 |
|
|
|
|
| 504 |
audio_effects,
|
| 505 |
type_output,
|
| 506 |
steps,
|
|
|
|
| 507 |
):
|
| 508 |
if not audio_files:
|
| 509 |
raise ValueError("The audio pls")
|
|
|
|
| 519 |
|
| 520 |
if file_m is not None and (file_m.endswith(".txt") or file_m.endswith(".zip")):
|
| 521 |
file_m, file_index = find_my_model(file_m, file_index)
|
| 522 |
+
# print(file_m, file_index)
|
| 523 |
|
| 524 |
random_tag = "USER_"+str(random.randint(10000000, 99999999))
|
| 525 |
|
|
|
|
| 545 |
if audio_effects:
|
| 546 |
result = add_audio_effects(result, type_output)
|
| 547 |
|
| 548 |
+
return result
|
| 549 |
+
|
| 550 |
+
|
| 551 |
+
def clear_player():
|
| 552 |
+
return None
|
| 553 |
+
|
| 554 |
+
|
| 555 |
+
def load_first_audio(output_files, play_audio):
|
| 556 |
+
if not play_audio or not output_files:
|
| 557 |
+
return None
|
| 558 |
+
first_file = output_files[0]
|
| 559 |
+
if isinstance(first_file, dict):
|
| 560 |
+
first_file = first_file.get("name")
|
| 561 |
+
return first_file
|
| 562 |
+
|
| 563 |
+
|
| 564 |
+
def audio_source_conf():
|
| 565 |
+
return gr.Radio(
|
| 566 |
+
choices=["📁 Upload", "🗣️ TTS", "🎙️ Record"],
|
| 567 |
+
value="📁 Upload",
|
| 568 |
+
label="Audio Source",
|
| 569 |
+
)
|
| 570 |
|
| 571 |
+
|
| 572 |
+
def mic_conf():
|
| 573 |
+
return gr.Audio(
|
| 574 |
+
sources=["microphone"],
|
| 575 |
+
type="filepath",
|
| 576 |
+
label="Record Audio",
|
| 577 |
+
visible=False,
|
| 578 |
+
)
|
| 579 |
|
| 580 |
|
| 581 |
def audio_conf():
|
|
|
|
| 683 |
)
|
| 684 |
|
| 685 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 686 |
def tts_voice_conf():
|
| 687 |
return gr.Dropdown(
|
| 688 |
label="tts voice",
|
|
|
|
| 781 |
return [out_path], player_audio
|
| 782 |
|
| 783 |
|
| 784 |
+
def show_components_source(mode):
|
| 785 |
+
return (
|
| 786 |
+
gr.update(visible=(mode == "🗣️ TTS")),
|
| 787 |
+
gr.update(visible=(mode == "🗣️ TTS")),
|
| 788 |
+
gr.update(visible=(mode == "🗣️ TTS")),
|
| 789 |
+
gr.update(visible=(mode == "🎙️ Record")),
|
|
|
|
| 790 |
)
|
| 791 |
|
| 792 |
|
| 793 |
+
def sync_mic_audio(mic_path):
|
| 794 |
+
if not mic_path:
|
| 795 |
+
return None
|
| 796 |
+
return [mic_path]
|
| 797 |
+
|
| 798 |
+
|
| 799 |
def down_active_conf():
|
| 800 |
return gr.Checkbox(
|
| 801 |
False,
|
|
|
|
| 843 |
gr.Markdown(title)
|
| 844 |
gr.Markdown(description)
|
| 845 |
|
| 846 |
+
audio_source = audio_source_conf()
|
| 847 |
with gr.Row():
|
| 848 |
with gr.Column(scale=1):
|
| 849 |
tts_text = tts_text_conf()
|
|
|
|
| 855 |
|
| 856 |
tts_button = tts_button_conf()
|
| 857 |
|
| 858 |
+
mic_aud = mic_conf()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 859 |
aud = audio_conf()
|
| 860 |
# gr.HTML("<hr>")
|
| 861 |
|
| 862 |
+
audio_source.change(
|
| 863 |
+
fn=show_components_source,
|
| 864 |
+
inputs=[audio_source],
|
| 865 |
+
outputs=[tts_voice, tts_text, tts_button, mic_aud],
|
| 866 |
+
)
|
| 867 |
+
|
| 868 |
+
mic_aud.change(
|
| 869 |
+
fn=sync_mic_audio,
|
| 870 |
+
inputs=[mic_aud],
|
| 871 |
+
outputs=[aud],
|
| 872 |
+
)
|
| 873 |
+
|
| 874 |
down_active_gui = down_active_conf()
|
| 875 |
down_info = gr.Markdown(
|
| 876 |
f"Provide a link to a zip file, like this one: `https://huggingface.co/MrDawg/ToothBrushing/resolve/main/ToothBrushing.zip?download=true`, or separate links with a comma for the .pth and .index files, like this: `{test_model}`",
|
|
|
|
| 948 |
effects_gui,
|
| 949 |
format_out,
|
| 950 |
steps_gui,
|
|
|
|
| 951 |
],
|
| 952 |
+
outputs=[output_base],
|
| 953 |
+
).success(
|
| 954 |
+
clear_player,
|
| 955 |
+
inputs=None,
|
| 956 |
+
outputs=[player_audio],
|
| 957 |
+
queue=False,
|
| 958 |
+
).success(
|
| 959 |
+
load_first_audio,
|
| 960 |
+
inputs=[output_base, player_gui],
|
| 961 |
+
outputs=[player_audio],
|
| 962 |
)
|
| 963 |
|
| 964 |
gr.Examples(
|
|
|
|
| 1010 |
envel_r,
|
| 1011 |
const,
|
| 1012 |
],
|
| 1013 |
+
outputs=[output_base],
|
| 1014 |
cache_examples=False,
|
| 1015 |
)
|
| 1016 |
gr.Markdown(RESOURCES)
|
|
|
|
| 1019 |
|
| 1020 |
|
| 1021 |
if __name__ == "__main__":
|
| 1022 |
+
try:
|
| 1023 |
+
tts_voice_list = asyncio.new_event_loop().run_until_complete(get_voices_list(proxy=None))
|
| 1024 |
+
voices = sorted([
|
| 1025 |
+
(" - ".join(reversed(v["FriendlyName"].split("-"))).replace("Microsoft ", "").replace("Online (Natural)", f"({v['Gender']})").strip(), f"{v['ShortName']}-{v['Gender']}")
|
| 1026 |
+
for v in tts_voice_list
|
| 1027 |
+
])
|
| 1028 |
+
except Exception as e:
|
| 1029 |
+
print(f"Warning: Could not retrieve online voices ({e}). Using default preset.")
|
| 1030 |
+
voices = [("English (United States) - EmmaMultilingual (Female)", "en-US-EmmaMultilingualNeural-Female")]
|
| 1031 |
+
|
| 1032 |
app = get_gui(theme)
|
| 1033 |
|
| 1034 |
app.queue(default_concurrency_limit=40)
|