Spaces:
Running
Running
cockolo terada
commited on
Update gradio_tabs/single.py
Browse files- gradio_tabs/single.py +72 -81
gradio_tabs/single.py
CHANGED
|
@@ -72,6 +72,14 @@ class TTSModelHolder:
|
|
| 72 |
}
|
| 73 |
with open(model2_path / "style_settings.json", "w", encoding="utf-8") as f:
|
| 74 |
json.dump(style_settings_data, f, indent=2, ensure_ascii=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
|
| 76 |
def refresh(self) -> List[str]:
|
| 77 |
"""
|
|
@@ -79,6 +87,7 @@ class TTSModelHolder:
|
|
| 79 |
更新後のモデルリストを返す。
|
| 80 |
"""
|
| 81 |
if self.root_dir.is_dir():
|
|
|
|
| 82 |
self.model_names = sorted([d.name for d in self.root_dir.iterdir() if d.is_dir()])
|
| 83 |
print(f"TTSModelHolder model list refreshed. Known models: {self.model_names}")
|
| 84 |
else:
|
|
@@ -92,7 +101,7 @@ class TTSModelHolder:
|
|
| 92 |
error_msg = (
|
| 93 |
f"Model '{model_name}' is not in the known list of TTSModelHolder. "
|
| 94 |
f"Current list: {self.model_names}. "
|
| 95 |
-
"Please refresh the model list by
|
| 96 |
)
|
| 97 |
print(f"[ERROR] {error_msg}")
|
| 98 |
raise ValueError(error_msg)
|
|
@@ -418,7 +427,9 @@ def process_single_synthesis_webui(
|
|
| 418 |
# ▲▲▲ 変更点 ▲▲▲
|
| 419 |
|
| 420 |
def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
| 421 |
-
|
|
|
|
|
|
|
| 422 |
|
| 423 |
custom_css = """
|
| 424 |
.audio-output-row { display: flex !important; flex-wrap: wrap !important; gap: 10px !important; }
|
|
@@ -434,7 +445,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 434 |
with gr.Blocks(css=custom_css) as app:
|
| 435 |
MAX_AUDIO_OUTPUTS = 4
|
| 436 |
ITEMS_PER_ROW = 4
|
| 437 |
-
# ▼▼▼ 変更点:
|
| 438 |
MAX_WORKBENCH_ITEMS = 8
|
| 439 |
# ▲▲▲ 変更点 ▲▲▲
|
| 440 |
|
|
@@ -445,7 +456,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 445 |
# saved_audio_hashes_state = gr.State(set())
|
| 446 |
# ▲▲▲ 変更点 ▲▲▲
|
| 447 |
|
| 448 |
-
# ---
|
| 449 |
def update_workbench_ui(workbench_list: List[Dict]) -> Tuple:
|
| 450 |
updates = []
|
| 451 |
for i in range(MAX_WORKBENCH_ITEMS):
|
|
@@ -510,9 +521,9 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 510 |
type="filepath", interactive=False
|
| 511 |
))
|
| 512 |
with gr.Row():
|
| 513 |
-
# ▼▼▼ 変更点:
|
| 514 |
# save_buttons.append(gr.Button("💾 保存", scale=1))
|
| 515 |
-
to_workbench_buttons.append(gr.Button("🛠️
|
| 516 |
# ▲▲▲ 変更点 ▲▲▲
|
| 517 |
audio_item_columns.append(audio_col)
|
| 518 |
|
|
@@ -533,10 +544,12 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 533 |
status_textbox = gr.Textbox(interactive=False, lines=5, max_lines=5, autoscroll=True, show_label=False, placeholder="ここにログが表示されます...")
|
| 534 |
|
| 535 |
with gr.Column(scale=1):
|
|
|
|
| 536 |
with gr.Row():
|
| 537 |
-
|
| 538 |
refresh_model_list_button = gr.Button("再読込", scale=1)
|
| 539 |
-
|
|
|
|
| 540 |
# ▼▼▼ 変更点: モデルファイル選択ドロップダウンを削除 ▼▼▼
|
| 541 |
# selected_model_file_dropdown = gr.Dropdown(label="モデルファイル (.safetensors)", choices=[], value=None, interactive=True)
|
| 542 |
# ▲▲▲ 変更点 ▲▲▲
|
|
@@ -566,9 +579,9 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 566 |
random_text_mode_slider = gr.Slider(label="分割の単位", minimum=1, maximum=4, value=1, step=1, info="1:形態素, 2:チャンク, 3:文節, 4:節", interactive=True)
|
| 567 |
random_text_ratio_textbox = gr.Textbox(label="カタカナ化の割合", value="0.5, 1", info="カンマ区切りで複数指定可。指定値からランダムに1つ使用。", interactive=True)
|
| 568 |
|
| 569 |
-
# ▼▼▼ 変更点 2:
|
| 570 |
-
with gr.Tab("
|
| 571 |
-
gr.Markdown("##
|
| 572 |
|
| 573 |
workbench_items = []
|
| 574 |
all_workbench_ui_components = []
|
|
@@ -599,16 +612,16 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 599 |
|
| 600 |
with gr.Row():
|
| 601 |
merge_preview_button = gr.Button("1.結合&プレビュー", variant="primary")
|
| 602 |
-
add_merged_to_workbench_button = gr.Button("
|
| 603 |
delete_originals_checkbox = gr.Checkbox(label="結合時に自動で元ファイルを削除", value=False, interactive=True)
|
| 604 |
|
| 605 |
preview_audio_player = gr.Audio(label="結合結果プレビュー", interactive=False, type="filepath")
|
| 606 |
|
| 607 |
-
# ▼▼▼ 変更点:
|
| 608 |
# gr.Markdown("---")
|
| 609 |
#
|
| 610 |
# with gr.Blocks():
|
| 611 |
-
# gr.Markdown("####
|
| 612 |
# with gr.Row():
|
| 613 |
# with gr.Column(scale=1):
|
| 614 |
# audio_to_save_num_input = gr.Number(label="保存する音声の番号", value=1, minimum=1, step=1, precision=0, interactive=True)
|
|
@@ -674,52 +687,23 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 674 |
default_weight = styles_map[first_key].get("weight", DEFAULT_STYLE_WEIGHT)
|
| 675 |
return gr.update(choices=display_names, value=default_display_name), gr.update(value=default_weight), styles_map
|
| 676 |
|
| 677 |
-
|
|
|
|
| 678 |
"""モデルリストを再読み込みし、UIとバックエンドの状態を同期させる。"""
|
| 679 |
-
SHM_PATH = Path("/dev/shm")
|
| 680 |
-
|
| 681 |
-
# 既存のシンボリックリンクをクリアする処理
|
| 682 |
-
if assets_root_path.exists():
|
| 683 |
-
for item in assets_root_path.iterdir():
|
| 684 |
-
if item.is_symlink():
|
| 685 |
-
try:
|
| 686 |
-
item.unlink()
|
| 687 |
-
except OSError as e:
|
| 688 |
-
print(f"Failed to remove symlink {item}: {e}")
|
| 689 |
-
|
| 690 |
-
# シンボリックリンクモードが有効なら、新しいリンクを作成する処理
|
| 691 |
-
if use_symlink_mode:
|
| 692 |
-
if SHM_PATH.exists() and SHM_PATH.is_dir():
|
| 693 |
-
for item in SHM_PATH.iterdir():
|
| 694 |
-
if item.is_dir():
|
| 695 |
-
target_link = assets_root_path / item.name
|
| 696 |
-
if not target_link.exists():
|
| 697 |
-
try:
|
| 698 |
-
os.symlink(item, target_link)
|
| 699 |
-
except OSError as e:
|
| 700 |
-
print(f"Warning: Could not create symlink for {item.name}: {e}")
|
| 701 |
-
else:
|
| 702 |
-
print(f"Warning: Symlink mode is on, but {SHM_PATH} does not exist or is not a directory.")
|
| 703 |
-
|
| 704 |
# バックエンドのリストを更新
|
| 705 |
model_holder.refresh()
|
| 706 |
-
|
| 707 |
-
#
|
| 708 |
-
|
| 709 |
-
|
| 710 |
-
|
| 711 |
-
|
| 712 |
-
|
| 713 |
-
else:
|
| 714 |
-
ui_model_list = [p.name for p in assets_root_path.iterdir() if p.is_dir() and not p.is_symlink()]
|
| 715 |
-
sorted_list = sorted(ui_model_list)
|
| 716 |
-
value = sorted_list[0] if sorted_list else None
|
| 717 |
-
model_dropdown_update = gr.update(choices=sorted_list, value=value)
|
| 718 |
|
| 719 |
style_dropdown_update, style_weight_update, styles_data_state_update = load_styles_for_ui(value)
|
| 720 |
|
| 721 |
return model_dropdown_update, style_dropdown_update, style_weight_update, styles_data_state_update
|
| 722 |
-
|
| 723 |
|
| 724 |
def on_model_select_change(selected_model_name: Optional[str]):
|
| 725 |
# ▼▼▼ 変更点: モデルファイル選択UIがなくなったため、関連処理を削除 ▼▼▼
|
|
@@ -913,7 +897,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 913 |
|
| 914 |
return tuple(final_outputs)
|
| 915 |
|
| 916 |
-
# ---
|
| 917 |
def add_to_workbench(
|
| 918 |
current_status: str,
|
| 919 |
current_workbench_list: List[Dict],
|
|
@@ -923,12 +907,12 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 923 |
safe_workbench_list = current_workbench_list or []
|
| 924 |
|
| 925 |
if not audio_path or not Path(audio_path).exists():
|
| 926 |
-
log_messages.append("⚠️ [
|
| 927 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 928 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 929 |
|
| 930 |
if any(item['audio_path'] == audio_path for item in safe_workbench_list):
|
| 931 |
-
log_messages.append("ℹ️
|
| 932 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 933 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 934 |
|
|
@@ -957,10 +941,10 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 957 |
path_to_delete.unlink()
|
| 958 |
except Exception as e:
|
| 959 |
print(f"Warning: Failed to delete old workbench audio file: {e}")
|
| 960 |
-
log_messages.append(f"ℹ️
|
| 961 |
|
| 962 |
ui_updates = update_workbench_ui(updated_list)
|
| 963 |
-
log_messages.append("✅
|
| 964 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 965 |
return (final_status, updated_list) + ui_updates
|
| 966 |
|
|
@@ -975,13 +959,13 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 975 |
path_to_delete = Path(item_to_remove['audio_path'])
|
| 976 |
if path_to_delete.exists() and str(path_to_delete.parent) == tempfile.gettempdir():
|
| 977 |
path_to_delete.unlink()
|
| 978 |
-
log_messages.append(f"✅
|
| 979 |
elif path_to_delete.exists():
|
| 980 |
-
log_messages.append(f"✅
|
| 981 |
else:
|
| 982 |
-
log_messages.append(f"✅
|
| 983 |
except Exception as e:
|
| 984 |
-
log_messages.append(f"⚠️
|
| 985 |
|
| 986 |
updated_list = [item for i, item in enumerate(safe_workbench_list) if i != index_to_remove]
|
| 987 |
ui_updates = update_workbench_ui(updated_list)
|
|
@@ -996,7 +980,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 996 |
):
|
| 997 |
log_messages = []
|
| 998 |
if not workbench_list:
|
| 999 |
-
log_messages.append("⚠️ [結合プレビュー警告]
|
| 1000 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1001 |
return final_status, None, {}
|
| 1002 |
|
|
@@ -1096,13 +1080,13 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1096 |
log_messages = []
|
| 1097 |
safe_workbench_list = current_workbench_list or []
|
| 1098 |
if not preview_data or "audio_path" not in preview_data:
|
| 1099 |
-
log_messages.append("⚠️ [
|
| 1100 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1101 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 1102 |
|
| 1103 |
src_path = Path(preview_data["audio_path"])
|
| 1104 |
if not src_path.exists():
|
| 1105 |
-
log_messages.append("⚠️ [
|
| 1106 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1107 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 1108 |
|
|
@@ -1134,10 +1118,10 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1134 |
log_messages.append(f"⚠️ 元の音声ファイル削除中にエラー: {e}")
|
| 1135 |
|
| 1136 |
final_workbench_list = [new_merged_item] + remaining_list
|
| 1137 |
-
log_messages.append(f"✅
|
| 1138 |
else:
|
| 1139 |
final_workbench_list = [new_merged_item] + safe_workbench_list
|
| 1140 |
-
log_messages.append("✅
|
| 1141 |
|
| 1142 |
if len(final_workbench_list) > MAX_WORKBENCH_ITEMS:
|
| 1143 |
item_to_remove = final_workbench_list.pop(-1)
|
|
@@ -1147,7 +1131,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1147 |
path_to_delete.unlink()
|
| 1148 |
except Exception as e:
|
| 1149 |
print(f"Warning: Failed to delete old workbench audio file: {e}")
|
| 1150 |
-
log_messages.append(f"ℹ️
|
| 1151 |
|
| 1152 |
ui_updates = update_workbench_ui(final_workbench_list)
|
| 1153 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
|
@@ -1156,11 +1140,11 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1156 |
|
| 1157 |
# --- イベントリスナー接続 ---
|
| 1158 |
# ▼▼▼ 変更点: イベントリスナーの inputs/outputs を修正 ▼▼▼
|
| 1159 |
-
|
| 1160 |
-
|
| 1161 |
-
|
| 1162 |
-
|
| 1163 |
-
|
| 1164 |
|
| 1165 |
selected_model_dropdown.change(on_model_select_change,
|
| 1166 |
inputs=[selected_model_dropdown],
|
|
@@ -1179,7 +1163,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1179 |
fn=action_run_synthesis,
|
| 1180 |
inputs=[
|
| 1181 |
selected_model_dropdown, # selected_model_file_dropdown は削除
|
| 1182 |
-
# use_symlink_mode_checkbox
|
| 1183 |
current_styles_dropdown, style_weight_for_synth_slider,
|
| 1184 |
text_input, generation_mode_radio, batch_count_slider,
|
| 1185 |
language_dropdown, seed_input, speaker_name_textbox,
|
|
@@ -1225,7 +1209,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1225 |
outputs=[status_textbox, preview_audio_player, merged_preview_state]
|
| 1226 |
)
|
| 1227 |
|
| 1228 |
-
# ▼▼▼ 変更点:
|
| 1229 |
# save_creative_button.click(...)
|
| 1230 |
# ▲▲▲ 変更点 ▲▲▲
|
| 1231 |
|
|
@@ -1244,9 +1228,11 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1244 |
|
| 1245 |
player_width_slider.release(lambda w: f"<script>document.documentElement.style.setProperty('--audio-width', '{w}px');</script>", inputs=[player_width_slider], outputs=[js_injector_html])
|
| 1246 |
|
| 1247 |
-
app.load(
|
| 1248 |
-
|
| 1249 |
-
|
|
|
|
|
|
|
| 1250 |
# ▲▲▲ 変更点 ▲▲▲
|
| 1251 |
return app
|
| 1252 |
|
|
@@ -1254,7 +1240,9 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1254 |
if __name__ == "__main__":
|
| 1255 |
if Path("model_assets").exists(): shutil.rmtree("model_assets")
|
| 1256 |
|
| 1257 |
-
shm_path
|
|
|
|
|
|
|
| 1258 |
|
| 1259 |
mock_model_holder = TTSModelHolder()
|
| 1260 |
print(f"Initial models loaded by TTSModelHolder: {mock_model_holder.model_names}")
|
|
@@ -1263,8 +1251,11 @@ if __name__ == "__main__":
|
|
| 1263 |
assets_dir_path = assets_root_path.resolve()
|
| 1264 |
assets_dir_path.mkdir(exist_ok=True)
|
| 1265 |
allowed_paths = [str(assets_dir_path)]
|
| 1266 |
-
|
| 1267 |
-
|
|
|
|
|
|
|
|
|
|
| 1268 |
|
| 1269 |
output_dir_path = Path("output").resolve()
|
| 1270 |
(output_dir_path / "normal").mkdir(exist_ok=True, parents=True)
|
|
|
|
| 72 |
}
|
| 73 |
with open(model2_path / "style_settings.json", "w", encoding="utf-8") as f:
|
| 74 |
json.dump(style_settings_data, f, indent=2, ensure_ascii=False)
|
| 75 |
+
|
| 76 |
+
# Sample Merged Model
|
| 77 |
+
merged_model_path = p / "miku_90p_rinu_10p"
|
| 78 |
+
merged_model_path.mkdir(parents=True, exist_ok=True)
|
| 79 |
+
(merged_model_path / "G_merged.safetensors").touch()
|
| 80 |
+
with open(merged_model_path / "config.json", "w", encoding="utf-8") as f:
|
| 81 |
+
json.dump(config1, f, indent=2)
|
| 82 |
+
|
| 83 |
|
| 84 |
def refresh(self) -> List[str]:
|
| 85 |
"""
|
|
|
|
| 87 |
更新後のモデルリストを返す。
|
| 88 |
"""
|
| 89 |
if self.root_dir.is_dir():
|
| 90 |
+
# is_dir()はシンボリックリンクされたディレクトリもTrueを返す
|
| 91 |
self.model_names = sorted([d.name for d in self.root_dir.iterdir() if d.is_dir()])
|
| 92 |
print(f"TTSModelHolder model list refreshed. Known models: {self.model_names}")
|
| 93 |
else:
|
|
|
|
| 101 |
error_msg = (
|
| 102 |
f"Model '{model_name}' is not in the known list of TTSModelHolder. "
|
| 103 |
f"Current list: {self.model_names}. "
|
| 104 |
+
"Please refresh the model list by clicking the refresh button."
|
| 105 |
)
|
| 106 |
print(f"[ERROR] {error_msg}")
|
| 107 |
raise ValueError(error_msg)
|
|
|
|
| 427 |
# ▲▲▲ 変更点 ▲▲▲
|
| 428 |
|
| 429 |
def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
| 430 |
+
# ▼▼▼ 変更点: is_shm_available 変数を削除 ▼▼▼
|
| 431 |
+
# is_shm_available = sys.platform != "win32" and Path("/dev/shm").exists() and Path("/dev/shm").is_dir()
|
| 432 |
+
# ▲▲▲ 変更点 ▲▲▲
|
| 433 |
|
| 434 |
custom_css = """
|
| 435 |
.audio-output-row { display: flex !important; flex-wrap: wrap !important; gap: 10px !important; }
|
|
|
|
| 445 |
with gr.Blocks(css=custom_css) as app:
|
| 446 |
MAX_AUDIO_OUTPUTS = 4
|
| 447 |
ITEMS_PER_ROW = 4
|
| 448 |
+
# ▼▼▼ 変更点: キープの最大アイテム数を8に変更 ▼▼▼
|
| 449 |
MAX_WORKBENCH_ITEMS = 8
|
| 450 |
# ▲▲▲ 変更点 ▲▲▲
|
| 451 |
|
|
|
|
| 456 |
# saved_audio_hashes_state = gr.State(set())
|
| 457 |
# ▲▲▲ 変更点 ▲▲▲
|
| 458 |
|
| 459 |
+
# --- キープUI更新ヘルパー ---
|
| 460 |
def update_workbench_ui(workbench_list: List[Dict]) -> Tuple:
|
| 461 |
updates = []
|
| 462 |
for i in range(MAX_WORKBENCH_ITEMS):
|
|
|
|
| 521 |
type="filepath", interactive=False
|
| 522 |
))
|
| 523 |
with gr.Row():
|
| 524 |
+
# ▼▼▼ 変更点: 保存ボタンを削除し、キープボタンの幅を広げる ▼▼▼
|
| 525 |
# save_buttons.append(gr.Button("💾 保存", scale=1))
|
| 526 |
+
to_workbench_buttons.append(gr.Button("🛠️ キープに追加", scale=2))
|
| 527 |
# ▲▲▲ 変更点 ▲▲▲
|
| 528 |
audio_item_columns.append(audio_col)
|
| 529 |
|
|
|
|
| 544 |
status_textbox = gr.Textbox(interactive=False, lines=5, max_lines=5, autoscroll=True, show_label=False, placeholder="ここにログが表示されます...")
|
| 545 |
|
| 546 |
with gr.Column(scale=1):
|
| 547 |
+
# ▼▼▼ 変更点: 「融☆合モデルを使う」チェックボックスを削除し、レイアウトを調整 ▼▼▼
|
| 548 |
with gr.Row():
|
| 549 |
+
selected_model_dropdown = gr.Dropdown(label="話者", choices=[], value=None, interactive=True, scale=4)
|
| 550 |
refresh_model_list_button = gr.Button("再読込", scale=1)
|
| 551 |
+
# ▲▲▲ 変更点 ▲▲▲
|
| 552 |
+
|
| 553 |
# ▼▼▼ 変更点: モデルファイル選択ドロップダウンを削除 ▼▼▼
|
| 554 |
# selected_model_file_dropdown = gr.Dropdown(label="モデルファイル (.safetensors)", choices=[], value=None, interactive=True)
|
| 555 |
# ▲▲▲ 変更点 ▲▲▲
|
|
|
|
| 579 |
random_text_mode_slider = gr.Slider(label="分割の単位", minimum=1, maximum=4, value=1, step=1, info="1:形態素, 2:チャンク, 3:文節, 4:節", interactive=True)
|
| 580 |
random_text_ratio_textbox = gr.Textbox(label="カタカナ化の割合", value="0.5, 1", info="カンマ区切りで複数指定可。指定値からランダムに1つ使用。", interactive=True)
|
| 581 |
|
| 582 |
+
# ▼▼▼ 変更点 2: キープのレイアウトを2列に変更 ▼▼▼
|
| 583 |
+
with gr.Tab("キープ"):
|
| 584 |
+
gr.Markdown("## キープ\n読み上げタブで生成した音声をここにストックし、結合や保存ができます。最大8個まで保持できます。")
|
| 585 |
|
| 586 |
workbench_items = []
|
| 587 |
all_workbench_ui_components = []
|
|
|
|
| 612 |
|
| 613 |
with gr.Row():
|
| 614 |
merge_preview_button = gr.Button("1.結合&プレビュー", variant="primary")
|
| 615 |
+
add_merged_to_workbench_button = gr.Button("2.キープに追加", variant="primary")
|
| 616 |
delete_originals_checkbox = gr.Checkbox(label="結合時に自動で元ファイルを削除", value=False, interactive=True)
|
| 617 |
|
| 618 |
preview_audio_player = gr.Audio(label="結合結果プレビュー", interactive=False, type="filepath")
|
| 619 |
|
| 620 |
+
# ▼▼▼ 変更点: キープの保存機能を削除 ▼▼▼
|
| 621 |
# gr.Markdown("---")
|
| 622 |
#
|
| 623 |
# with gr.Blocks():
|
| 624 |
+
# gr.Markdown("#### キープの音声を保存")
|
| 625 |
# with gr.Row():
|
| 626 |
# with gr.Column(scale=1):
|
| 627 |
# audio_to_save_num_input = gr.Number(label="保存する音声の番号", value=1, minimum=1, step=1, precision=0, interactive=True)
|
|
|
|
| 687 |
default_weight = styles_map[first_key].get("weight", DEFAULT_STYLE_WEIGHT)
|
| 688 |
return gr.update(choices=display_names, value=default_display_name), gr.update(value=default_weight), styles_map
|
| 689 |
|
| 690 |
+
# ▼▼▼ 変更点: action_refresh_model_list関数からシンボリックリンク関連のロジックを削除 ▼▼▼
|
| 691 |
+
def action_refresh_model_list():
|
| 692 |
"""モデルリストを再読み込みし、UIとバックエンドの状態を同期させる。"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 693 |
# バックエンドのリストを更新
|
| 694 |
model_holder.refresh()
|
| 695 |
+
|
| 696 |
+
# UIのドロップダウンを更新
|
| 697 |
+
# マージモデルのパースとソートは維持する
|
| 698 |
+
ui_model_list = model_holder.model_names
|
| 699 |
+
formatted_choices = format_and_sort_model_names(ui_model_list)
|
| 700 |
+
value = formatted_choices[0][1] if formatted_choices else None
|
| 701 |
+
model_dropdown_update = gr.update(choices=formatted_choices, value=value)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 702 |
|
| 703 |
style_dropdown_update, style_weight_update, styles_data_state_update = load_styles_for_ui(value)
|
| 704 |
|
| 705 |
return model_dropdown_update, style_dropdown_update, style_weight_update, styles_data_state_update
|
| 706 |
+
# ▲▲▲ 変更点 ▲▲▲
|
| 707 |
|
| 708 |
def on_model_select_change(selected_model_name: Optional[str]):
|
| 709 |
# ▼▼▼ 変更点: モデルファイル選択UIがなくなったため、関連処理を削除 ▼▼▼
|
|
|
|
| 897 |
|
| 898 |
return tuple(final_outputs)
|
| 899 |
|
| 900 |
+
# --- キープイベントハンドラ ---
|
| 901 |
def add_to_workbench(
|
| 902 |
current_status: str,
|
| 903 |
current_workbench_list: List[Dict],
|
|
|
|
| 907 |
safe_workbench_list = current_workbench_list or []
|
| 908 |
|
| 909 |
if not audio_path or not Path(audio_path).exists():
|
| 910 |
+
log_messages.append("⚠️ [キープ追加エラー] 追加する音声ファイルが見つかりません。")
|
| 911 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 912 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 913 |
|
| 914 |
if any(item['audio_path'] == audio_path for item in safe_workbench_list):
|
| 915 |
+
log_messages.append("ℹ️ この音声はすでにキープに存在します。")
|
| 916 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 917 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 918 |
|
|
|
|
| 941 |
path_to_delete.unlink()
|
| 942 |
except Exception as e:
|
| 943 |
print(f"Warning: Failed to delete old workbench audio file: {e}")
|
| 944 |
+
log_messages.append(f"ℹ️ キープのアイテムが最大数({MAX_WORKBENCH_ITEMS})に達したため、一番古いアイテムを削除しました。")
|
| 945 |
|
| 946 |
ui_updates = update_workbench_ui(updated_list)
|
| 947 |
+
log_messages.append("✅ キープに音声を追加しました。")
|
| 948 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 949 |
return (final_status, updated_list) + ui_updates
|
| 950 |
|
|
|
|
| 959 |
path_to_delete = Path(item_to_remove['audio_path'])
|
| 960 |
if path_to_delete.exists() and str(path_to_delete.parent) == tempfile.gettempdir():
|
| 961 |
path_to_delete.unlink()
|
| 962 |
+
log_messages.append(f"✅ キープからアイテム #{index_to_remove + 1} を削除し、一時ファイル��クリーンアップしました。")
|
| 963 |
elif path_to_delete.exists():
|
| 964 |
+
log_messages.append(f"✅ キープからアイテム #{index_to_remove + 1} を削除しました。(ファイルは保持: {path_to_delete.name})")
|
| 965 |
else:
|
| 966 |
+
log_messages.append(f"✅ キープからアイテム #{index_to_remove + 1} を削除しました。(関連ファイルなし)")
|
| 967 |
except Exception as e:
|
| 968 |
+
log_messages.append(f"⚠️ キープのアイテム #{index_to_remove + 1} のファイル削除中にエラー: {e}")
|
| 969 |
|
| 970 |
updated_list = [item for i, item in enumerate(safe_workbench_list) if i != index_to_remove]
|
| 971 |
ui_updates = update_workbench_ui(updated_list)
|
|
|
|
| 980 |
):
|
| 981 |
log_messages = []
|
| 982 |
if not workbench_list:
|
| 983 |
+
log_messages.append("⚠️ [結合プレビュー警告] キープに音声がありません。")
|
| 984 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 985 |
return final_status, None, {}
|
| 986 |
|
|
|
|
| 1080 |
log_messages = []
|
| 1081 |
safe_workbench_list = current_workbench_list or []
|
| 1082 |
if not preview_data or "audio_path" not in preview_data:
|
| 1083 |
+
log_messages.append("⚠️ [キープ追加エラー] 追加する結合済み音声がありません。先にプレビューを生成してください。")
|
| 1084 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1085 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 1086 |
|
| 1087 |
src_path = Path(preview_data["audio_path"])
|
| 1088 |
if not src_path.exists():
|
| 1089 |
+
log_messages.append("⚠️ [キープ追加エラー] 結合済み音声ファイルが見つかりません。")
|
| 1090 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1091 |
return (final_status, safe_workbench_list) + update_workbench_ui(safe_workbench_list)
|
| 1092 |
|
|
|
|
| 1118 |
log_messages.append(f"⚠️ 元の音声ファイル削除中にエラー: {e}")
|
| 1119 |
|
| 1120 |
final_workbench_list = [new_merged_item] + remaining_list
|
| 1121 |
+
log_messages.append(f"✅ 結合音声をキープに追加し、元の音声(#{idx1+1}, #{idx2+1})を削除しました。")
|
| 1122 |
else:
|
| 1123 |
final_workbench_list = [new_merged_item] + safe_workbench_list
|
| 1124 |
+
log_messages.append("✅ 結合済みの音声をキープの一番上に追加しました。")
|
| 1125 |
|
| 1126 |
if len(final_workbench_list) > MAX_WORKBENCH_ITEMS:
|
| 1127 |
item_to_remove = final_workbench_list.pop(-1)
|
|
|
|
| 1131 |
path_to_delete.unlink()
|
| 1132 |
except Exception as e:
|
| 1133 |
print(f"Warning: Failed to delete old workbench audio file: {e}")
|
| 1134 |
+
log_messages.append(f"ℹ️ キープが最大数({MAX_WORKBENCH_ITEMS})に達したため一番古いアイテムを削除しました。")
|
| 1135 |
|
| 1136 |
ui_updates = update_workbench_ui(final_workbench_list)
|
| 1137 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
|
|
|
| 1140 |
|
| 1141 |
# --- イベントリスナー接続 ---
|
| 1142 |
# ▼▼▼ 変更点: イベントリスナーの inputs/outputs を修正 ▼▼▼
|
| 1143 |
+
refresh_model_list_button.click(
|
| 1144 |
+
action_refresh_model_list,
|
| 1145 |
+
inputs=[],
|
| 1146 |
+
outputs=[selected_model_dropdown, current_styles_dropdown, style_weight_for_synth_slider, all_styles_data_state]
|
| 1147 |
+
)
|
| 1148 |
|
| 1149 |
selected_model_dropdown.change(on_model_select_change,
|
| 1150 |
inputs=[selected_model_dropdown],
|
|
|
|
| 1163 |
fn=action_run_synthesis,
|
| 1164 |
inputs=[
|
| 1165 |
selected_model_dropdown, # selected_model_file_dropdown は削除
|
| 1166 |
+
# use_symlink_mode_checkbox は削除
|
| 1167 |
current_styles_dropdown, style_weight_for_synth_slider,
|
| 1168 |
text_input, generation_mode_radio, batch_count_slider,
|
| 1169 |
language_dropdown, seed_input, speaker_name_textbox,
|
|
|
|
| 1209 |
outputs=[status_textbox, preview_audio_player, merged_preview_state]
|
| 1210 |
)
|
| 1211 |
|
| 1212 |
+
# ▼▼▼ 変更点: キープの保存ボタンのクリックイベントを削除 ▼▼▼
|
| 1213 |
# save_creative_button.click(...)
|
| 1214 |
# ▲▲▲ 変更点 ▲▲▲
|
| 1215 |
|
|
|
|
| 1228 |
|
| 1229 |
player_width_slider.release(lambda w: f"<script>document.documentElement.style.setProperty('--audio-width', '{w}px');</script>", inputs=[player_width_slider], outputs=[js_injector_html])
|
| 1230 |
|
| 1231 |
+
app.load(
|
| 1232 |
+
action_refresh_model_list,
|
| 1233 |
+
inputs=[],
|
| 1234 |
+
outputs=[selected_model_dropdown, current_styles_dropdown, style_weight_for_synth_slider, all_styles_data_state]
|
| 1235 |
+
)
|
| 1236 |
# ▲▲▲ 変更点 ▲▲▲
|
| 1237 |
return app
|
| 1238 |
|
|
|
|
| 1240 |
if __name__ == "__main__":
|
| 1241 |
if Path("model_assets").exists(): shutil.rmtree("model_assets")
|
| 1242 |
|
| 1243 |
+
# ▼▼▼ 変更点: shm_path関連のコードを削除 ▼▼▼
|
| 1244 |
+
# shm_path = Path("/dev/shm")
|
| 1245 |
+
# ▲▲▲ 変更点 ▲▲▲
|
| 1246 |
|
| 1247 |
mock_model_holder = TTSModelHolder()
|
| 1248 |
print(f"Initial models loaded by TTSModelHolder: {mock_model_holder.model_names}")
|
|
|
|
| 1251 |
assets_dir_path = assets_root_path.resolve()
|
| 1252 |
assets_dir_path.mkdir(exist_ok=True)
|
| 1253 |
allowed_paths = [str(assets_dir_path)]
|
| 1254 |
+
|
| 1255 |
+
# ▼▼▼ 変更点: shm_pathをallowed_pathsに追加するロジックを削除 ▼▼▼
|
| 1256 |
+
# if sys.platform != "win32" and shm_path.exists():
|
| 1257 |
+
# allowed_paths.append(str(shm_path.resolve()))
|
| 1258 |
+
# ▲▲▲ 変更点 ▲▲▲
|
| 1259 |
|
| 1260 |
output_dir_path = Path("output").resolve()
|
| 1261 |
(output_dir_path / "normal").mkdir(exist_ok=True, parents=True)
|