Commit
·
a7307d4
1
Parent(s):
d1aa8f4
GPU制限エラーを検知する例外クラスを追加し、処理中にGPU制限に達した場合のエラーハンドリングを強化。音声ファイル処理時にエラーを適切に報告するように修正。
Browse files- local_controller.py +50 -17
- transcribe_cli.py +1 -1
local_controller.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
import os
|
| 2 |
import json
|
| 3 |
import time
|
|
|
|
| 4 |
import requests
|
| 5 |
from pathlib import Path
|
| 6 |
# from pydub import AudioSegment # 現在のコードでは直接使用されていません
|
|
@@ -109,6 +110,10 @@ def split_audio_with_ffmpeg(audio_path: str, output_dir_base: str, chunk_length_
|
|
| 109 |
|
| 110 |
# test_space_connection, process_chunk, write_srt, write_vtt, write_json_output, write_lrc は前回とほぼ同じ
|
| 111 |
# (ログ出力にファイル名を追加するなどの微調整は有効)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 112 |
def process_chunk(chunk_path: str, original_audio_filename: str) -> Optional[Dict]:
|
| 113 |
"""チャンクをSpaceに送信して処理"""
|
| 114 |
chunk_name = Path(chunk_path).name
|
|
@@ -123,12 +128,16 @@ def process_chunk(chunk_path: str, original_audio_filename: str) -> Optional[Dic
|
|
| 123 |
client = Client(SPACE_URL)
|
| 124 |
break
|
| 125 |
except Exception as e:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 126 |
print(f" Connection attempt {attempt + 1} for {chunk_name} (from {original_audio_filename}) failed: {e}")
|
| 127 |
if attempt < 2: time.sleep(5)
|
| 128 |
else: raise
|
| 129 |
if client is None: return None
|
| 130 |
-
|
| 131 |
-
# print(f" Sending chunk to Space: {chunk_name} (from {original_audio_filename})")
|
| 132 |
result = None
|
| 133 |
api_methods_to_try = [{"name": "fn_index=1", "fn_index": 1}, {"name": "fn_index=0", "fn_index": 0}, {"name": "default", "fn_index": None}]
|
| 134 |
for method_info in api_methods_to_try:
|
|
@@ -139,16 +148,21 @@ def process_chunk(chunk_path: str, original_audio_filename: str) -> Optional[Dic
|
|
| 139 |
result = client.predict(gradio_file(chunk_path))
|
| 140 |
# print(f" Successfully used API method '{method_info['name']}' for {chunk_name}")
|
| 141 |
break
|
| 142 |
-
except Exception
|
| 143 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 144 |
result = None
|
| 145 |
|
| 146 |
if result is None:
|
| 147 |
print(f" All API call methods failed for {chunk_name} (from {original_audio_filename})")
|
| 148 |
return None
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
elif isinstance(result, str):
|
| 153 |
try: return json.loads(result)
|
| 154 |
except json.JSONDecodeError:
|
|
@@ -157,7 +171,15 @@ def process_chunk(chunk_path: str, original_audio_filename: str) -> Optional[Dic
|
|
| 157 |
else:
|
| 158 |
print(f" Unexpected response format for {chunk_name}: {type(result)}")
|
| 159 |
return None
|
|
|
|
|
|
|
|
|
|
| 160 |
except Exception as e:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
print(f"Error sending chunk {chunk_name} (from {original_audio_filename}) to Space: {e}")
|
| 162 |
return None
|
| 163 |
|
|
@@ -445,8 +467,7 @@ def process_audio_file(input_path_str: str, output_dir_str: str):
|
|
| 445 |
temp_conversion_dir = base_temp_dir / "conversion"
|
| 446 |
# チャンクは split_audio_with_ffmpeg 内で output_dir_path / "temp_chunks" / audio_stem に保存される
|
| 447 |
|
| 448 |
-
try:
|
| 449 |
-
# WAV以外の入力はWAV (16kHz, mono) に変換
|
| 450 |
if original_input_path_obj.suffix.lower() not in ['.wav']:
|
| 451 |
print(f" Converting {audio_filename} to WAV...")
|
| 452 |
temp_conversion_dir.mkdir(parents=True, exist_ok=True)
|
|
@@ -489,12 +510,18 @@ def process_audio_file(input_path_str: str, output_dir_str: str):
|
|
| 489 |
print(f" Processing {len(chunk_paths)} chunks for {audio_filename} via API...")
|
| 490 |
chunk_results = []
|
| 491 |
for i, chunk_p_str in enumerate(chunk_paths):
|
| 492 |
-
|
| 493 |
-
|
| 494 |
-
|
| 495 |
-
|
| 496 |
-
|
| 497 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 498 |
|
| 499 |
# APIリクエスト間の待機時間を追加
|
| 500 |
if i < len(chunk_paths) - 1: # 最後のチャンクの後は待機不要
|
|
@@ -639,8 +666,14 @@ def main():
|
|
| 639 |
for i, file_to_process_obj in enumerate(actual_files_to_process):
|
| 640 |
print(f"\n--- [{i+1}/{total_to_process_count}] Processing: {file_to_process_obj.name} ---")
|
| 641 |
output_dir_for_this_file = file_to_process_obj.parent.as_posix()
|
| 642 |
-
|
| 643 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 644 |
|
| 645 |
print(f"\nAll {total_to_process_count} new file(s) processed.")
|
| 646 |
|
|
|
|
| 1 |
import os
|
| 2 |
import json
|
| 3 |
import time
|
| 4 |
+
import sys
|
| 5 |
import requests
|
| 6 |
from pathlib import Path
|
| 7 |
# from pydub import AudioSegment # 現在のコードでは直接使用されていません
|
|
|
|
| 110 |
|
| 111 |
# test_space_connection, process_chunk, write_srt, write_vtt, write_json_output, write_lrc は前回とほぼ同じ
|
| 112 |
# (ログ出力にファイル名を追加するなどの微調整は有効)
|
| 113 |
+
class GPUQuotaExceededError(Exception):
|
| 114 |
+
"""GPU制限に達した場合の例外"""
|
| 115 |
+
pass
|
| 116 |
+
|
| 117 |
def process_chunk(chunk_path: str, original_audio_filename: str) -> Optional[Dict]:
|
| 118 |
"""チャンクをSpaceに送信して処理"""
|
| 119 |
chunk_name = Path(chunk_path).name
|
|
|
|
| 128 |
client = Client(SPACE_URL)
|
| 129 |
break
|
| 130 |
except Exception as e:
|
| 131 |
+
error_msg = str(e).lower()
|
| 132 |
+
# GPU制限エラーを検知
|
| 133 |
+
if any(keyword in error_msg for keyword in ['gpu', 'quota', 'limit', 'exceeded', 'unavailable']):
|
| 134 |
+
print(f" GPU quota exceeded detected: {e}")
|
| 135 |
+
raise GPUQuotaExceededError(f"GPU quota exceeded: {e}")
|
| 136 |
print(f" Connection attempt {attempt + 1} for {chunk_name} (from {original_audio_filename}) failed: {e}")
|
| 137 |
if attempt < 2: time.sleep(5)
|
| 138 |
else: raise
|
| 139 |
if client is None: return None
|
| 140 |
+
# print(f" Sending chunk to Space: {chunk_name} (from {original_audio_filename})")
|
|
|
|
| 141 |
result = None
|
| 142 |
api_methods_to_try = [{"name": "fn_index=1", "fn_index": 1}, {"name": "fn_index=0", "fn_index": 0}, {"name": "default", "fn_index": None}]
|
| 143 |
for method_info in api_methods_to_try:
|
|
|
|
| 148 |
result = client.predict(gradio_file(chunk_path))
|
| 149 |
# print(f" Successfully used API method '{method_info['name']}' for {chunk_name}")
|
| 150 |
break
|
| 151 |
+
except Exception as api_e:
|
| 152 |
+
error_msg = str(api_e).lower()
|
| 153 |
+
# GPU制限エラーを検知
|
| 154 |
+
if any(keyword in error_msg for keyword in ['gpu', 'quota', 'limit', 'exceeded', 'unavailable', 'out of memory', 'resource']):
|
| 155 |
+
print(f" GPU quota exceeded during API call: {api_e}")
|
| 156 |
+
raise GPUQuotaExceededError(f"GPU quota exceeded during API call: {api_e}")
|
| 157 |
+
# print(f" API method '{method_info['name']}' for {chunk_name} failed: {api_e}")
|
| 158 |
result = None
|
| 159 |
|
| 160 |
if result is None:
|
| 161 |
print(f" All API call methods failed for {chunk_name} (from {original_audio_filename})")
|
| 162 |
return None
|
| 163 |
+
# print(f" Received response from Space for {chunk_name} (type: {type(result)})")
|
| 164 |
+
if isinstance(result, dict):
|
| 165 |
+
return result
|
| 166 |
elif isinstance(result, str):
|
| 167 |
try: return json.loads(result)
|
| 168 |
except json.JSONDecodeError:
|
|
|
|
| 171 |
else:
|
| 172 |
print(f" Unexpected response format for {chunk_name}: {type(result)}")
|
| 173 |
return None
|
| 174 |
+
except GPUQuotaExceededError:
|
| 175 |
+
# GPU制限エラーは再発生させて上位で処理
|
| 176 |
+
raise
|
| 177 |
except Exception as e:
|
| 178 |
+
error_msg = str(e).lower()
|
| 179 |
+
# 最後の砦としてもう一度GPU制限エラーをチェック
|
| 180 |
+
if any(keyword in error_msg for keyword in ['gpu', 'quota', 'limit', 'exceeded', 'unavailable', 'out of memory', 'resource']):
|
| 181 |
+
print(f"GPU quota exceeded detected in general exception: {e}")
|
| 182 |
+
raise GPUQuotaExceededError(f"GPU quota exceeded: {e}")
|
| 183 |
print(f"Error sending chunk {chunk_name} (from {original_audio_filename}) to Space: {e}")
|
| 184 |
return None
|
| 185 |
|
|
|
|
| 467 |
temp_conversion_dir = base_temp_dir / "conversion"
|
| 468 |
# チャンクは split_audio_with_ffmpeg 内で output_dir_path / "temp_chunks" / audio_stem に保存される
|
| 469 |
|
| 470 |
+
try: # WAV以外の入力はWAV (16kHz, mono) に変換
|
|
|
|
| 471 |
if original_input_path_obj.suffix.lower() not in ['.wav']:
|
| 472 |
print(f" Converting {audio_filename} to WAV...")
|
| 473 |
temp_conversion_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
| 510 |
print(f" Processing {len(chunk_paths)} chunks for {audio_filename} via API...")
|
| 511 |
chunk_results = []
|
| 512 |
for i, chunk_p_str in enumerate(chunk_paths):
|
| 513 |
+
try:
|
| 514 |
+
api_result = process_chunk(chunk_p_str, audio_filename)
|
| 515 |
+
if api_result:
|
| 516 |
+
chunk_results.append(api_result)
|
| 517 |
+
print(f" Successfully processed chunk {i+1}/{len(chunk_paths)}")
|
| 518 |
+
else:
|
| 519 |
+
print(f" Failed to process chunk {i+1}/{len(chunk_paths)}")
|
| 520 |
+
except GPUQuotaExceededError as gpu_error:
|
| 521 |
+
print(f" GPU quota exceeded while processing {audio_filename}")
|
| 522 |
+
print(f" Error: {gpu_error}")
|
| 523 |
+
print(f" GPU制限に達しました。処理を強制終了します。")
|
| 524 |
+
raise # main()関数で捕捉するために再発生
|
| 525 |
|
| 526 |
# APIリクエスト間の待機時間を追加
|
| 527 |
if i < len(chunk_paths) - 1: # 最後のチャンクの後は待機不要
|
|
|
|
| 666 |
for i, file_to_process_obj in enumerate(actual_files_to_process):
|
| 667 |
print(f"\n--- [{i+1}/{total_to_process_count}] Processing: {file_to_process_obj.name} ---")
|
| 668 |
output_dir_for_this_file = file_to_process_obj.parent.as_posix()
|
| 669 |
+
try:
|
| 670 |
+
process_audio_file(file_to_process_obj.as_posix(), output_dir_for_this_file)
|
| 671 |
+
print(f"--- Finished: {file_to_process_obj.name} ---")
|
| 672 |
+
except GPUQuotaExceededError as gpu_error:
|
| 673 |
+
print(f"\n=== GPU QUOTA EXCEEDED ===")
|
| 674 |
+
print(f"処理を中断します。GPU制限に達しました。")
|
| 675 |
+
print(f"Error details: {gpu_error}")
|
| 676 |
+
sys.exit(1) # 即座に強制終了
|
| 677 |
|
| 678 |
print(f"\nAll {total_to_process_count} new file(s) processed.")
|
| 679 |
|
transcribe_cli.py
CHANGED
|
@@ -987,7 +987,7 @@ if __name__ == "__main__":
|
|
| 987 |
# ダイアログを最前面に表示する試み (環境による)
|
| 988 |
root.attributes('-topmost', True)
|
| 989 |
# WSL環境での初期ディレクトリを設定
|
| 990 |
-
initial_dir = "/mnt/
|
| 991 |
selected_path = filedialog.askdirectory(
|
| 992 |
title="処理対象のディレクトリを選択してください",
|
| 993 |
initialdir=initial_dir
|
|
|
|
| 987 |
# ダイアログを最前面に表示する試み (環境による)
|
| 988 |
root.attributes('-topmost', True)
|
| 989 |
# WSL環境での初期ディレクトリを設定
|
| 990 |
+
initial_dir = "/mnt/t/demucs_folder/htdemucs" # Windowsのユーザーディレクトリを初期値として設定
|
| 991 |
selected_path = filedialog.askdirectory(
|
| 992 |
title="処理対象のディレクトリを選択してください",
|
| 993 |
initialdir=initial_dir
|