前のページにおいてワーカープログラムの出力には WhisperX のログや文字起こし結果が表示されていました.ここではログをファイルに出力することを考えます.さらに,WhisperXでエラーが発生し文字起こしに失敗した場合は,例外処理を行い当該ファイルとログファイルをエラー用の error フォルダに移動することで,プログラムが終了せず,次のファイルの処理が始まるような機能も理も追加します.
worker.py
from pathlib import Path
import shutil
import time
import datetime
import subprocess
BASE_DIR = Path(__file__).parent
QUEUE_DIR = BASE_DIR / "queue"
WORKING_DIR = BASE_DIR / "working"
DONE_DIR = BASE_DIR / "done"
ERROR_DIR = BASE_DIR / "error"
# ディレクトリを作っておく
QUEUE_DIR.mkdir(parents=True, exist_ok=True)
WORKING_DIR.mkdir(parents=True, exist_ok=True)
DONE_DIR.mkdir(parents=True, exist_ok=True)
ERROR_DIR.mkdir(parents=True, exist_ok=True)
try:
while True:
for src in QUEUE_DIR.glob("*.m*"): # 監視するファイルの拡張子
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 処理開始: {src.name}")
working_file = WORKING_DIR / src.name
transcription_dir = WORKING_DIR / src.stem
transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
log_file = transcription_dir / "whisperx.log"
shutil.move(src, working_file)
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 作業開始: {working_file}")
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 出力先 : {transcription_dir}")
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 処理中...")
try:
with open(log_file, "w", encoding="utf-8") as f:
subprocess.run([
"whisperx",
"--model", "turbo", # tubo / large ...
"--language", "ja",
# "--device", "cuda", # NVIDIA GPU を利用できる場合
"-o", str(transcription_dir),
"--diarize", # 話者分離
str(working_file)
],
stdout=f,
stderr=subprocess.STDOUT,
check=True)
except subprocess.CalledProcessError:
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] WhisperXの処理に失敗しました")
err_dst = ERROR_DIR / src.name
err_transcription_dir = ERROR_DIR / src.stem
shutil.move(working_file, err_dst)
shutil.move(transcription_dir, err_transcription_dir)
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 失敗: {err_dst}")
continue
time.sleep(3)
dst = DONE_DIR / src.name
done_transcription_dir = DONE_DIR / src.stem
shutil.move(working_file, dst)
shutil.move(transcription_dir, done_transcription_dir)
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 完了: {dst}")
time.sleep(1)
except KeyboardInterrupt:
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 停止します")
ターミナルを2個起動し,それぞれで watch.py と worker.py を実行します.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py ⏎
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py ⏎
2つのプログラムを起動後に監視用の watch フォルダに2個のマークダウンファイルと2個の音声ファイルを設置します.監視プログラムはファイルタイプの検証をせずにフォルダ直下に置かれた全てのファイルを待ち行列に送ります.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py
[18:00:01.713344] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample02.m4a
[18:00:01.713580] 新しいファイルの名前: voice-sample02.m4a
[18:00:11.714753] ファイルの受取りが完了しました
[18:00:11.714893] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:00:11.715407] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:00:11.715592] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\sample1.md
[18:00:11.715686] 新しいファイルの名前: sample1.md
[18:00:21.717199] ファイルの受取りが完了しました
[18:00:21.717452] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\sample1.md
[18:00:21.718993] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\sample1.md
[18:00:21.719228] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\sample2.md
[18:00:21.719450] 新しいファイルの名前: sample2.md
[18:00:31.720796] ファイルの受取りが完了しました
[18:00:31.720978] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\sample2.md
[18:00:31.721552] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\sample2.md
[18:00:31.721694] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample01.m4a
[18:00:31.721756] 新しいファイルの名前: voice-sample01.m4a
[18:00:41.722884] ファイルの受取りが完了しました
[18:00:41.723029] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
[18:00:41.723820] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
Ctrl + C
[18:01:40.111840] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
ワーカープログラムは拡張子が .m で始まる全てのファイルについて WhisperX による文字起こし処理を実行します.もちろんマークダウンファイル(つまりテキスト形式のファイル)では文字起こし処理に失敗します.WhisperXのログをファイルに書き出したことでターミナルへの出力がスッキリしました.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py [18:00:12.476224] 処理開始: voice-sample02.m4a [18:00:12.477121] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02.m4a [18:00:12.477184] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02 [18:00:12.477210] 処理中... [18:00:35.708352] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\voice-sample02.m4a [18:00:36.709409] 処理開始: sample1.md [18:00:36.711010] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\sample1.md [18:00:36.711089] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\sample1 [18:00:36.711118] 処理中... [18:00:49.129976] WhisperXの処理に失敗しました [18:00:49.131247] 失敗: C:\Users\rinsaka\Documents\python\watchdog\error\sample1.md [18:00:49.131378] 処理開始: sample2.md [18:00:49.132037] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\sample2.md [18:00:49.132091] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\sample2 [18:00:49.132133] 処理中... [18:00:59.629126] WhisperXの処理に失敗しました [18:00:59.630227] 失敗: C:\Users\rinsaka\Documents\python\watchdog\error\sample2.md [18:01:00.630858] 処理開始: voice-sample01.m4a [18:01:00.632298] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01.m4a [18:01:00.632385] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01 [18:01:00.632453] 処理中... [18:01:19.877177] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\voice-sample01.m4a Ctrl + C [18:01:42.143140] 停止します (py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
全ての処理が終わったので,完了用 done フォルダの内容を確認します.音声ファイルとその結果が格納されていることが分かります.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci done -Recurse ⏎
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2026/11/02 18:01 voice-sample01
d---- 2026/11/02 18:00 voice-sample02
-a--- 2026/10/27 12:36 329637 voice-sample01.m4a
-a--- 2026/10/27 12:39 554089 voice-sample02.m4a
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\voice-sample01
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2026/11/02 18:01 28431 voice-sample01.json
-a--- 2026/11/02 18:01 566 voice-sample01.srt
-a--- 2026/11/02 18:01 505 voice-sample01.tsv
-a--- 2026/11/02 18:01 494 voice-sample01.txt
-a--- 2026/11/02 18:01 558 voice-sample01.vtt
-a--- 2026/11/02 18:01 2994 whisperx.log
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\done\voice-sample02
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2026/11/02 18:00 58602 voice-sample02.json
-a--- 2026/11/02 18:00 1113 voice-sample02.srt
-a--- 2026/11/02 18:00 1014 voice-sample02.tsv
-a--- 2026/11/02 18:00 1005 voice-sample02.txt
-a--- 2026/11/02 18:00 1096 voice-sample02.vtt
-a--- 2026/11/02 18:00 3355 whisperx.log
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
エラー用の error フォルダの内容を確認します.文字起こし処理に失敗したマークダウンファイルとそのログファイルが格納されていることが分かります.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci error -Recurse ⏎
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error
Mode LastWriteTime Length Name
---- ------------- ------ ----
d---- 2026/11/02 18:00 sample1
d---- 2026/11/02 18:00 sample2
-a--- 2026/10/25 18:18 56 sample1.md
-a--- 2026/10/25 18:18 115 sample2.md
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error\sample1
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2026/11/02 18:00 4412 whisperx.log
ディレクトリ:C:\Users\rinsaka\Documents\python\watchdog\error\sample2
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2026/11/02 18:00 4412 whisperx.log
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
監視用 watch フォルダ,待ち行列用 queue フォルダと処理用 working フォルダはいずれも空になっていることが分かります.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci watch ⏎ (py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci queue ⏎ (py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> gci working ⏎ (py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
現時点では,同じファイル名の音声ファイルを繰り返し処理したときに,出力用の done フォルダで結果が上書きされてしまいます.例えば WhisperX のモデルを turbo から large に変更するなど,結果の比較を行いたい場合にはこの設計は不便に感じる可能性があります.次のページでは完了用フォルダやエラーフォルダに日時情報を含んだサブフォルダを作成し,その中に結果を保存するようにしてみます.