Spaces:
Running
Running
cockolo terada
commited on
Update gradio_tabs/single.py
Browse files- gradio_tabs/single.py +38 -44
gradio_tabs/single.py
CHANGED
|
@@ -492,8 +492,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 492 |
gr.update(visible=True), # Row
|
| 493 |
gr.update(value=f"**{i+1}**"), # Item Number Display
|
| 494 |
gr.update(value=item['audio_path']), # Audio
|
| 495 |
-
# ▼▼▼ 変更:
|
| 496 |
-
gr.update(value=item['audio_path'], visible=True), # Download
|
| 497 |
# ▲▲▲ 変更 ▲▲▲
|
| 498 |
gr.update(value=info_text) # Info Markdown
|
| 499 |
])
|
|
@@ -502,8 +502,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 502 |
gr.update(visible=False), # Row
|
| 503 |
gr.update(value=""), # Item Number Display
|
| 504 |
gr.update(value=None), # Audio
|
| 505 |
-
# ▼▼▼ 変更:
|
| 506 |
-
gr.update(value=None, visible=False), # Download
|
| 507 |
# ▲▲▲ 変更 ▲▲▲
|
| 508 |
gr.update(value="") # Info
|
| 509 |
])
|
|
@@ -525,8 +525,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 525 |
with gr.Row(elem_classes="audio-output-row"):
|
| 526 |
audio_item_columns = []
|
| 527 |
audio_outputs = []
|
| 528 |
-
# ▼▼▼ 変更:
|
| 529 |
-
|
| 530 |
# ▲▲▲ 変更 ▲▲▲
|
| 531 |
to_workbench_buttons = []
|
| 532 |
synthesized_text_states = []
|
|
@@ -539,8 +539,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 539 |
label=f"結果 {i+1}", elem_classes="compact-audio",
|
| 540 |
type="filepath", interactive=False
|
| 541 |
))
|
| 542 |
-
# ▼▼▼ 変更:
|
| 543 |
-
|
| 544 |
# ▲▲▲ 変更 ▲▲▲
|
| 545 |
with gr.Row():
|
| 546 |
to_workbench_buttons.append(gr.Button("🛠️ キープ", scale=2))
|
|
@@ -606,8 +606,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 606 |
add_merged_to_workbench_button = gr.Button("2.キープに追加", variant="primary")
|
| 607 |
delete_originals_checkbox = gr.Checkbox(label="結合時に自動で元ファイルを削除", value=False, interactive=True)
|
| 608 |
preview_audio_player = gr.Audio(label="結合結果プレビュー", interactive=False, type="filepath")
|
| 609 |
-
# ▼▼▼ 変更:
|
| 610 |
-
|
| 611 |
# ▲▲▲ 変更 ▲▲▲
|
| 612 |
|
| 613 |
ITEMS_PER_COLUMN = 4
|
|
@@ -616,11 +616,11 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 616 |
with parent_column:
|
| 617 |
with gr.Row(visible=False, elem_classes="workbench-item-row") as item_row:
|
| 618 |
item_num_display = gr.Markdown(f"**{i+1}**", elem_classes=["text-center"])
|
| 619 |
-
# ▼▼▼ 変更: AudioとDownloadを同じColumnに入れる ▼▼▼
|
| 620 |
with gr.Column(scale=4):
|
| 621 |
audio = gr.Audio(label=f"音声 {i+1}", interactive=False, type="filepath")
|
| 622 |
-
|
| 623 |
-
|
|
|
|
| 624 |
with gr.Column(scale=4): info = gr.Markdown()
|
| 625 |
delete_btn = gr.Button("削除", scale=1, variant="primary")
|
| 626 |
# ▼▼▼ 変更: downloadコンポーネントを辞書に追加 ▼▼▼
|
|
@@ -653,7 +653,6 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 653 |
"""モデルリストを再読み込みし、UIとバックエンドの状態を同期させる。"""
|
| 654 |
MERGER_CACHE_PATH = Path("/tmp/sbv2_merger_cache")
|
| 655 |
|
| 656 |
-
# FNモードと融☆合モードは排他的なため、FNモードがオンなら融☆合モードはオフとして扱う
|
| 657 |
if use_fn_model_mode:
|
| 658 |
use_symlink_mode = False
|
| 659 |
|
|
@@ -687,21 +686,18 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 687 |
value = None
|
| 688 |
|
| 689 |
if use_fn_model_mode:
|
| 690 |
-
# FNモデルモード: FN1-10のみ表示し、カスタム順でソート
|
| 691 |
ui_model_list = [name for name in current_available_models if fn_model_pattern.match(name)]
|
| 692 |
sorted_list = sort_models_by_custom_order(ui_model_list, FN_MODE_MODEL_ORDER)
|
| 693 |
value = sorted_list[0] if sorted_list else None
|
| 694 |
model_dropdown_update = gr.update(choices=sorted_list, value=value)
|
| 695 |
|
| 696 |
elif use_symlink_mode:
|
| 697 |
-
# 融☆合モデルモード: シンボリックリンクのみ表示
|
| 698 |
ui_model_list_names = [p.name for p in assets_root_path.iterdir() if p.is_symlink()]
|
| 699 |
formatted_choices = format_and_sort_model_names(ui_model_list_names)
|
| 700 |
value = formatted_choices[0][1] if formatted_choices else None
|
| 701 |
model_dropdown_update = gr.update(choices=formatted_choices, value=value)
|
| 702 |
|
| 703 |
else:
|
| 704 |
-
# 通常モード: FNモデル, whisper, シンボリックリンクを除外し、カスタム順でソート
|
| 705 |
ui_model_list = [
|
| 706 |
name for name in current_available_models
|
| 707 |
if name != 'whisper'
|
|
@@ -746,8 +742,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 746 |
error_outputs.extend([
|
| 747 |
gr.update(visible=False), # audio_item_columns
|
| 748 |
gr.update(value=None), # audio_outputs
|
| 749 |
-
# ▼▼▼ 変更:
|
| 750 |
-
gr.update(value=None),
|
| 751 |
# ▲▲▲ 変更 ▲▲▲
|
| 752 |
])
|
| 753 |
for _ in range(ITEMS_PER_ROW - 1):
|
|
@@ -755,6 +751,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 755 |
for _ in range(MAX_AUDIO_OUTPUTS):
|
| 756 |
error_outputs.append("") # synthesized_text_states
|
| 757 |
|
|
|
|
| 758 |
if re.search(INVALID_FILENAME_CHARS_PATTERN, text):
|
| 759 |
found_chars = "".join(sorted(list(set(re.findall(INVALID_FILENAME_CHARS_PATTERN, text)))))
|
| 760 |
error_outputs[0] = f"❌ [エラー] テキストに使用できない文字が含まれています: {found_chars}"
|
|
@@ -768,7 +765,6 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 768 |
if not style_display_name:
|
| 769 |
error_outputs[0] = "❌ [エラー] スタイルが選択されていません。"
|
| 770 |
return tuple(error_outputs)
|
| 771 |
-
|
| 772 |
internal_style_key = None
|
| 773 |
for key, data in styles_data.items():
|
| 774 |
if data.get("display_name") == style_display_name: internal_style_key = key; break
|
|
@@ -793,6 +789,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 793 |
final_audio_paths = []
|
| 794 |
generated_texts = []
|
| 795 |
|
|
|
|
| 796 |
if generation_mode == "発音ガチャ2":
|
| 797 |
try:
|
| 798 |
ratio_list = [float(x.strip()) for x in random_text_ratio_str.split(',') if x.strip()]
|
|
@@ -887,8 +884,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 887 |
audio_val = final_audio_paths[i] if is_visible else None
|
| 888 |
final_outputs.append(gr.update(visible=is_visible))
|
| 889 |
final_outputs.append(gr.update(value=audio_val))
|
| 890 |
-
# ▼▼▼ 変更:
|
| 891 |
-
final_outputs.append(gr.update(value=audio_val))
|
| 892 |
# ▲▲▲ 変更 ▲▲▲
|
| 893 |
|
| 894 |
num_dummies_needed = (ITEMS_PER_ROW - (num_generated % ITEMS_PER_ROW)) % ITEMS_PER_ROW if num_generated > 0 else 0
|
|
@@ -953,27 +950,25 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 953 |
|
| 954 |
def action_merge_preview(current_status: str, first_audio_num: int, second_audio_num: int, pause_ms: int, workbench_list: List[Dict], progress=gr.Progress(track_tqdm=True)):
|
| 955 |
log_messages = []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 956 |
if not workbench_list:
|
| 957 |
log_messages.append("⚠️ [結合プレビュー警告] キープに音声がありません。")
|
| 958 |
-
|
| 959 |
-
# ▼▼▼ 変更: 戻り値にダウンロードボタンの更新を追加 ▼▼▼
|
| 960 |
-
return final_status, None, None, {}
|
| 961 |
-
# ▲▲▲ 変更 ▲▲▲
|
| 962 |
idx1, idx2 = int(first_audio_num) - 1, int(second_audio_num) - 1
|
| 963 |
if not (0 <= idx1 < len(workbench_list) and 0 <= idx2 < len(workbench_list)):
|
| 964 |
log_messages.append(f"⚠️ [結合プレビュー警告] 指定された番号(#{first_audio_num}, #{second_audio_num})の音声が見つかりません。")
|
| 965 |
-
|
| 966 |
-
# ▼▼▼ 変更: 戻り値にダウンロードボタンの更新を追加 ▼▼▼
|
| 967 |
-
return final_status, None, None, {}
|
| 968 |
-
# ▲▲▲ 変更 ▲▲▲
|
| 969 |
item1, item2 = workbench_list[idx1], workbench_list[idx2]
|
| 970 |
audio_path1, audio_path2 = item1.get("audio_path"), item2.get("audio_path")
|
| 971 |
if not audio_path1 or not Path(audio_path1).exists() or not audio_path2 or not Path(audio_path2).exists():
|
| 972 |
log_messages.append("❌ [結合プレビューエラー] 音声ファイルが見つかりません。ファイルが削除された可能性があります。")
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
return final_status, None, None, {}
|
| 976 |
-
# ▲▲▲ 変更 ▲▲▲
|
| 977 |
progress(0, desc="結合準備中...")
|
| 978 |
try:
|
| 979 |
segment1, segment2 = AudioSegment.from_file(audio_path1), AudioSegment.from_file(audio_path2)
|
|
@@ -993,10 +988,8 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 993 |
progress(1, desc="結合完了")
|
| 994 |
except Exception as e:
|
| 995 |
log_messages.append(f"❌ [結合プレビューエラー] 音声の結合中にエラーが発生しました: {e}")
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
return final_status, None, None, {}
|
| 999 |
-
# ▲▲▲ 変更 ▲▲▲
|
| 1000 |
output_filename = f"merged_preview_{uuid.uuid4().hex[:8]}.wav"
|
| 1001 |
temp_path = Path(tempfile.gettempdir()) / output_filename
|
| 1002 |
combined_audio.export(temp_path, format="wav")
|
|
@@ -1007,8 +1000,9 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1007 |
metadata = {"text": f"{item1.get('text', '')} | {item2.get('text', '')}", "display_models": sorted(list(all_display_models)), "original_models": sorted(list(all_original_models)), "audio_path": str(temp_path), "timestamp": datetime.datetime.now(JST).isoformat()}
|
| 1008 |
log_messages.append("✅ 結合プレビューが生成されました。")
|
| 1009 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1010 |
-
|
| 1011 |
-
|
|
|
|
| 1012 |
# ▲▲▲ 変更 ▲▲▲
|
| 1013 |
|
| 1014 |
def action_add_merged_to_workbench(current_status: str, preview_data: Dict, current_workbench_list: List[Dict], delete_originals: bool, first_audio_num: int, second_audio_num: int) -> Tuple:
|
|
@@ -1073,10 +1067,10 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1073 |
current_styles_dropdown.change(on_style_dropdown_select, inputs=[current_styles_dropdown, all_styles_data_state], outputs=[style_weight_for_synth_slider])
|
| 1074 |
use_assist_text_checkbox.change(lambda x: (gr.update(visible=x), gr.update(visible=x)), inputs=[use_assist_text_checkbox], outputs=[assist_text_textbox, assist_text_weight_slider])
|
| 1075 |
|
| 1076 |
-
# ▼▼▼ 変更: generate_buttonのoutputsに
|
| 1077 |
generate_outputs = [status_textbox, audio_output_area]
|
| 1078 |
for i in range(MAX_AUDIO_OUTPUTS):
|
| 1079 |
-
generate_outputs.extend([audio_item_columns[i], audio_outputs[i],
|
| 1080 |
generate_outputs.extend(dummy_audio_item_columns)
|
| 1081 |
generate_outputs.extend(synthesized_text_states)
|
| 1082 |
# ▲▲▲ 変更 ▲▲▲
|
|
@@ -1115,7 +1109,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1115 |
outputs=[status_textbox, workbench_state] + all_workbench_ui_components,
|
| 1116 |
)
|
| 1117 |
|
| 1118 |
-
# ▼▼▼ 変更: merge_preview_buttonのoutputsに
|
| 1119 |
merge_preview_button.click(
|
| 1120 |
fn=action_merge_preview,
|
| 1121 |
inputs=[
|
|
@@ -1125,7 +1119,7 @@ def create_synthesis_app(model_holder: TTSModelHolder) -> gr.Blocks:
|
|
| 1125 |
merge_pause_input,
|
| 1126 |
workbench_state
|
| 1127 |
],
|
| 1128 |
-
outputs=[status_textbox, preview_audio_player,
|
| 1129 |
)
|
| 1130 |
# ▲▲▲ 変更 ▲▲▲
|
| 1131 |
|
|
|
|
| 492 |
gr.update(visible=True), # Row
|
| 493 |
gr.update(value=f"**{i+1}**"), # Item Number Display
|
| 494 |
gr.update(value=item['audio_path']), # Audio
|
| 495 |
+
# ▼▼▼ 変更: DownloadButtonの更新 ▼▼▼
|
| 496 |
+
gr.update(value=item['audio_path'], visible=True), # Download Button
|
| 497 |
# ▲▲▲ 変更 ▲▲▲
|
| 498 |
gr.update(value=info_text) # Info Markdown
|
| 499 |
])
|
|
|
|
| 502 |
gr.update(visible=False), # Row
|
| 503 |
gr.update(value=""), # Item Number Display
|
| 504 |
gr.update(value=None), # Audio
|
| 505 |
+
# ▼▼▼ 変更: DownloadButtonの更新 ▼▼▼
|
| 506 |
+
gr.update(value=None, visible=False), # Download Button
|
| 507 |
# ▲▲▲ 変更 ▲▲▲
|
| 508 |
gr.update(value="") # Info
|
| 509 |
])
|
|
|
|
| 525 |
with gr.Row(elem_classes="audio-output-row"):
|
| 526 |
audio_item_columns = []
|
| 527 |
audio_outputs = []
|
| 528 |
+
# ▼▼▼ 変更: ダウンロードボタンのリスト ▼▼▼
|
| 529 |
+
download_buttons = []
|
| 530 |
# ▲▲▲ 変更 ▲▲▲
|
| 531 |
to_workbench_buttons = []
|
| 532 |
synthesized_text_states = []
|
|
|
|
| 539 |
label=f"結果 {i+1}", elem_classes="compact-audio",
|
| 540 |
type="filepath", interactive=False
|
| 541 |
))
|
| 542 |
+
# ▼▼▼ 変更: gr.Fileからgr.DownloadButtonに変更 ▼▼▼
|
| 543 |
+
download_buttons.append(gr.DownloadButton("ダウンロード", size="sm", visible=False))
|
| 544 |
# ▲▲▲ 変更 ▲▲▲
|
| 545 |
with gr.Row():
|
| 546 |
to_workbench_buttons.append(gr.Button("🛠️ キープ", scale=2))
|
|
|
|
| 606 |
add_merged_to_workbench_button = gr.Button("2.キープに追加", variant="primary")
|
| 607 |
delete_originals_checkbox = gr.Checkbox(label="結合時に自動で元ファイルを削除", value=False, interactive=True)
|
| 608 |
preview_audio_player = gr.Audio(label="結合結果プレビュー", interactive=False, type="filepath")
|
| 609 |
+
# ▼▼▼ 変更: プレビュー用ダウンロードボタン ▼▼▼
|
| 610 |
+
preview_download_button = gr.DownloadButton("プレビューをダウンロード", visible=False)
|
| 611 |
# ▲▲▲ 変更 ▲▲▲
|
| 612 |
|
| 613 |
ITEMS_PER_COLUMN = 4
|
|
|
|
| 616 |
with parent_column:
|
| 617 |
with gr.Row(visible=False, elem_classes="workbench-item-row") as item_row:
|
| 618 |
item_num_display = gr.Markdown(f"**{i+1}**", elem_classes=["text-center"])
|
|
|
|
| 619 |
with gr.Column(scale=4):
|
| 620 |
audio = gr.Audio(label=f"音声 {i+1}", interactive=False, type="filepath")
|
| 621 |
+
# ▼▼▼ 変更: gr.Fileからgr.DownloadButtonに変更 ▼▼▼
|
| 622 |
+
download = gr.DownloadButton("ダウンロード", size="sm", visible=False)
|
| 623 |
+
# ▲▲▲ 変更 ▲▲▲
|
| 624 |
with gr.Column(scale=4): info = gr.Markdown()
|
| 625 |
delete_btn = gr.Button("削除", scale=1, variant="primary")
|
| 626 |
# ▼▼▼ 変更: downloadコンポーネントを辞書に追加 ▼▼▼
|
|
|
|
| 653 |
"""モデルリストを再読み込みし、UIとバックエンドの状態を同期させる。"""
|
| 654 |
MERGER_CACHE_PATH = Path("/tmp/sbv2_merger_cache")
|
| 655 |
|
|
|
|
| 656 |
if use_fn_model_mode:
|
| 657 |
use_symlink_mode = False
|
| 658 |
|
|
|
|
| 686 |
value = None
|
| 687 |
|
| 688 |
if use_fn_model_mode:
|
|
|
|
| 689 |
ui_model_list = [name for name in current_available_models if fn_model_pattern.match(name)]
|
| 690 |
sorted_list = sort_models_by_custom_order(ui_model_list, FN_MODE_MODEL_ORDER)
|
| 691 |
value = sorted_list[0] if sorted_list else None
|
| 692 |
model_dropdown_update = gr.update(choices=sorted_list, value=value)
|
| 693 |
|
| 694 |
elif use_symlink_mode:
|
|
|
|
| 695 |
ui_model_list_names = [p.name for p in assets_root_path.iterdir() if p.is_symlink()]
|
| 696 |
formatted_choices = format_and_sort_model_names(ui_model_list_names)
|
| 697 |
value = formatted_choices[0][1] if formatted_choices else None
|
| 698 |
model_dropdown_update = gr.update(choices=formatted_choices, value=value)
|
| 699 |
|
| 700 |
else:
|
|
|
|
| 701 |
ui_model_list = [
|
| 702 |
name for name in current_available_models
|
| 703 |
if name != 'whisper'
|
|
|
|
| 742 |
error_outputs.extend([
|
| 743 |
gr.update(visible=False), # audio_item_columns
|
| 744 |
gr.update(value=None), # audio_outputs
|
| 745 |
+
# ▼▼▼ 変更: ダウンロードボタンのエラー時更新 ▼▼▼
|
| 746 |
+
gr.update(value=None, visible=False), # download_buttons
|
| 747 |
# ▲▲▲ 変更 ▲▲▲
|
| 748 |
])
|
| 749 |
for _ in range(ITEMS_PER_ROW - 1):
|
|
|
|
| 751 |
for _ in range(MAX_AUDIO_OUTPUTS):
|
| 752 |
error_outputs.append("") # synthesized_text_states
|
| 753 |
|
| 754 |
+
# (バリデーションロジックは変更なし)
|
| 755 |
if re.search(INVALID_FILENAME_CHARS_PATTERN, text):
|
| 756 |
found_chars = "".join(sorted(list(set(re.findall(INVALID_FILENAME_CHARS_PATTERN, text)))))
|
| 757 |
error_outputs[0] = f"❌ [エラー] テキストに使用できない文字が含まれています: {found_chars}"
|
|
|
|
| 765 |
if not style_display_name:
|
| 766 |
error_outputs[0] = "❌ [エラー] スタイルが選択されていません。"
|
| 767 |
return tuple(error_outputs)
|
|
|
|
| 768 |
internal_style_key = None
|
| 769 |
for key, data in styles_data.items():
|
| 770 |
if data.get("display_name") == style_display_name: internal_style_key = key; break
|
|
|
|
| 789 |
final_audio_paths = []
|
| 790 |
generated_texts = []
|
| 791 |
|
| 792 |
+
# (音声合成ロジックは変更なし)
|
| 793 |
if generation_mode == "発音ガチャ2":
|
| 794 |
try:
|
| 795 |
ratio_list = [float(x.strip()) for x in random_text_ratio_str.split(',') if x.strip()]
|
|
|
|
| 884 |
audio_val = final_audio_paths[i] if is_visible else None
|
| 885 |
final_outputs.append(gr.update(visible=is_visible))
|
| 886 |
final_outputs.append(gr.update(value=audio_val))
|
| 887 |
+
# ▼▼▼ 変更: ダウンロードボタンの更新 ▼▼▼
|
| 888 |
+
final_outputs.append(gr.update(value=audio_val, visible=is_visible))
|
| 889 |
# ▲▲▲ 変更 ▲▲▲
|
| 890 |
|
| 891 |
num_dummies_needed = (ITEMS_PER_ROW - (num_generated % ITEMS_PER_ROW)) % ITEMS_PER_ROW if num_generated > 0 else 0
|
|
|
|
| 950 |
|
| 951 |
def action_merge_preview(current_status: str, first_audio_num: int, second_audio_num: int, pause_ms: int, workbench_list: List[Dict], progress=gr.Progress(track_tqdm=True)):
|
| 952 |
log_messages = []
|
| 953 |
+
error_return = (
|
| 954 |
+
(current_status + "\n" + "\n".join(log_messages)).strip(),
|
| 955 |
+
None,
|
| 956 |
+
gr.update(value=None, visible=False),
|
| 957 |
+
{}
|
| 958 |
+
)
|
| 959 |
if not workbench_list:
|
| 960 |
log_messages.append("⚠️ [結合プレビュー警告] キープに音声がありません。")
|
| 961 |
+
return error_return
|
|
|
|
|
|
|
|
|
|
| 962 |
idx1, idx2 = int(first_audio_num) - 1, int(second_audio_num) - 1
|
| 963 |
if not (0 <= idx1 < len(workbench_list) and 0 <= idx2 < len(workbench_list)):
|
| 964 |
log_messages.append(f"⚠️ [結合プレビュー警告] 指定された番号(#{first_audio_num}, #{second_audio_num})の音声が見つかりません。")
|
| 965 |
+
return error_return
|
|
|
|
|
|
|
|
|
|
| 966 |
item1, item2 = workbench_list[idx1], workbench_list[idx2]
|
| 967 |
audio_path1, audio_path2 = item1.get("audio_path"), item2.get("audio_path")
|
| 968 |
if not audio_path1 or not Path(audio_path1).exists() or not audio_path2 or not Path(audio_path2).exists():
|
| 969 |
log_messages.append("❌ [結合プレビューエラー] 音声ファイルが見つかりません。ファイルが削除された可能性があります。")
|
| 970 |
+
return error_return
|
| 971 |
+
|
|
|
|
|
|
|
| 972 |
progress(0, desc="結合準備中...")
|
| 973 |
try:
|
| 974 |
segment1, segment2 = AudioSegment.from_file(audio_path1), AudioSegment.from_file(audio_path2)
|
|
|
|
| 988 |
progress(1, desc="結合完了")
|
| 989 |
except Exception as e:
|
| 990 |
log_messages.append(f"❌ [結合プレビューエラー] 音声の結合中にエラーが発生しました: {e}")
|
| 991 |
+
return error_return
|
| 992 |
+
|
|
|
|
|
|
|
| 993 |
output_filename = f"merged_preview_{uuid.uuid4().hex[:8]}.wav"
|
| 994 |
temp_path = Path(tempfile.gettempdir()) / output_filename
|
| 995 |
combined_audio.export(temp_path, format="wav")
|
|
|
|
| 1000 |
metadata = {"text": f"{item1.get('text', '')} | {item2.get('text', '')}", "display_models": sorted(list(all_display_models)), "original_models": sorted(list(all_original_models)), "audio_path": str(temp_path), "timestamp": datetime.datetime.now(JST).isoformat()}
|
| 1001 |
log_messages.append("✅ 結合プレビューが生成されました。")
|
| 1002 |
final_status = (current_status + "\n" + "\n".join(log_messages)).strip()
|
| 1003 |
+
|
| 1004 |
+
# ▼▼▼ 変更: DownloadButtonの更新を追加 ▼▼▼
|
| 1005 |
+
return final_status, str(temp_path), gr.update(value=str(temp_path), visible=True), metadata
|
| 1006 |
# ▲▲▲ 変更 ▲▲▲
|
| 1007 |
|
| 1008 |
def action_add_merged_to_workbench(current_status: str, preview_data: Dict, current_workbench_list: List[Dict], delete_originals: bool, first_audio_num: int, second_audio_num: int) -> Tuple:
|
|
|
|
| 1067 |
current_styles_dropdown.change(on_style_dropdown_select, inputs=[current_styles_dropdown, all_styles_data_state], outputs=[style_weight_for_synth_slider])
|
| 1068 |
use_assist_text_checkbox.change(lambda x: (gr.update(visible=x), gr.update(visible=x)), inputs=[use_assist_text_checkbox], outputs=[assist_text_textbox, assist_text_weight_slider])
|
| 1069 |
|
| 1070 |
+
# ▼▼▼ 変更: generate_buttonのoutputsにdownload_buttonsを追加 ▼▼▼
|
| 1071 |
generate_outputs = [status_textbox, audio_output_area]
|
| 1072 |
for i in range(MAX_AUDIO_OUTPUTS):
|
| 1073 |
+
generate_outputs.extend([audio_item_columns[i], audio_outputs[i], download_buttons[i]])
|
| 1074 |
generate_outputs.extend(dummy_audio_item_columns)
|
| 1075 |
generate_outputs.extend(synthesized_text_states)
|
| 1076 |
# ▲▲▲ 変更 ▲▲▲
|
|
|
|
| 1109 |
outputs=[status_textbox, workbench_state] + all_workbench_ui_components,
|
| 1110 |
)
|
| 1111 |
|
| 1112 |
+
# ▼▼▼ 変更: merge_preview_buttonのoutputsにpreview_download_buttonを追加 ▼▼▼
|
| 1113 |
merge_preview_button.click(
|
| 1114 |
fn=action_merge_preview,
|
| 1115 |
inputs=[
|
|
|
|
| 1119 |
merge_pause_input,
|
| 1120 |
workbench_state
|
| 1121 |
],
|
| 1122 |
+
outputs=[status_textbox, preview_audio_player, preview_download_button, merged_preview_state]
|
| 1123 |
)
|
| 1124 |
# ▲▲▲ 変更 ▲▲▲
|
| 1125 |
|