まずフォルダ監視のコードを再度示します.このコードは以前の状態から変更ありません.
watch.py
from pathlib import Path
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
import shutil # ファイルのコピー,移動などを行う標準ライブラリ
import time
import datetime
BASE_DIR = Path(__file__).parent
WATCH_DIR = BASE_DIR / "watch"
QUEUE_DIR = BASE_DIR / "queue"
# ディレクトリを作っておく
WATCH_DIR.mkdir(parents=True, exist_ok=True)
QUEUE_DIR.mkdir(parents=True, exist_ok=True)
def wait_until_complete(path):
"""
watch ディレクトリへのコピー,ファイルサイズの変化がない -> コピー(ダウンロード)が終わったと判断
待っている間にファイル名が変更されたら強制終了
"""
while True:
try:
size1 = path.stat().st_size
time.sleep(5)
size2 = path.stat().st_size
time.sleep(5)
size3 = path.stat().st_size
if size1 == size2 == size3:
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ファイルの受取りが完了しました")
return True
except FileNotFoundError:
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ファイルが見つかりません: {path}") # 途中でファイル名を変更したり,削除した場合
return False
class MyHandler(FileSystemEventHandler):
"""
watchdog が用意している FileSystemEventHandler クラスの継承
「ファイル監視イベントが発生したときに何をするか」を定義する
"""
def on_created(self, event):
if event.is_directory: # ディレクトリは無視
return
src = Path(event.src_path)
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 新しいファイルを検出: {src}")
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 新しいファイルの名前: {src.name}")
if not wait_until_complete(src):
return
dst = QUEUE_DIR / src.name # 移動先の指定
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ファイルの移動開始: {dst}")
shutil.move(src, dst) # ファイルの移動
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ファイルの移動完了: {dst}")
observer = Observer() # 「監視員を作成する」処理
# 監視条件設定
observer.schedule(
MyHandler(),
path=WATCH_DIR,
recursive=False # とりあえず直下だけを監視
)
observer.start() # 監視を始める → 別スレッド(observerスレッド)が生成される
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 停止します")
observer.stop()
observer.join() # observerスレッドが終わるまで待つ
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)
def ask_ollama(prompt):
result = subprocess.run(
["ollama", "run", "qwen3:8b"],
input=prompt,
capture_output=True,
text=True,
encoding="utf-8"
)
return result.stdout
try:
while True:
for src in QUEUE_DIR.glob("*.m*"): # 監視するファイルの拡張子
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] ----------------")
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の処理に失敗しました")
dt = datetime.datetime.now()
err_dir_name = f"{dt.strftime('%Y%m%d-%H%M%S')}_{src.stem}"
err_dst = ERROR_DIR / err_dir_name / src.name
err_transcription_dir = ERROR_DIR / err_dir_name / src.stem
err_transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
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)
# 議事録生成 -----------------------------------
transcription_file_name = src.stem + ".txt"
transcription_file_path = transcription_dir / transcription_file_name
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 議事録生成中...")
time.sleep(3)
with open(transcription_file_path, encoding="utf-8") as f:
transcript = f.read()
prompt = f"""
次の文字起こし結果から議事録を作成してください。
{transcript}
"""
minutes = ask_ollama(prompt)
print(minutes)
print("-----------------")
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 議事録生成完了")
# 作業完了 → ファイルの移動 -----------------------------------
dt = datetime.datetime.now()
done_dir_name = f"{dt.strftime('%Y%m%d-%H%M%S')}_{src.stem}"
done_file = DONE_DIR / done_dir_name / src.name
done_transcription_dir = DONE_DIR / done_dir_name
done_transcription_dir.mkdir(parents=True, exist_ok=True) # ディレクトリを作っておく
shutil.move(working_file, done_file)
shutil.move(transcription_dir, done_transcription_dir)
print(f"[{datetime.datetime.now().strftime('%H:%M:%S.%f')}] 完了: {done_file}")
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つのプログラムが起動できたら,音声ファイル2個を監視フォルダに設置します.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python watch.py
[18:21:25.211513] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample02.m4a
[18:21:25.211803] 新しいファイルの名前: voice-sample02.m4a
[18:21:35.213224] ファイルの受取りが完了しました
[18:21:35.213402] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:21:35.213853] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample02.m4a
[18:21:35.213973] 新しいファイルを検出: C:\Users\rinsaka\Documents\python\watchdog\watch\voice-sample01.m4a
[18:21:35.214046] 新しいファイルの名前: voice-sample01.m4a
[18:21:45.215019] ファイルの受取りが完了しました
[18:21:45.215192] ファイルの移動開始: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
[18:21:45.215968] ファイルの移動完了: C:\Users\rinsaka\Documents\python\watchdog\queue\voice-sample01.m4a
Ctrl + C
[18:23:25.801067] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
ワーカープログラムの出力を確認します.「文字起こし」→「議事録作成」という処理が順番に行われていることが分かりました.
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog> python worker.py
[18:21:35.499413] ----------------
[18:21:35.499510] 処理開始: voice-sample02.m4a
[18:21:35.500080] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02.m4a
[18:21:35.500176] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample02
[18:21:35.500231] 文字起こし処理中...
[18:22:01.998453] 議事録生成中...
Thinking...
Okay, I need to create a meeting minutes based on the provided transcript. Let me start by reading through the transcript carefully to understand the key points.
The first speaker mentions a large-scale drone attack by Ukrainian forces in St. Petersburg, Russia, on the day of the international conference where Putin is attending. Zelenskyy announced that drones targeted oil terminals and other infrastructure. There's mention of smoke rising and casualties. The conference is the St. Petersburg International Economic Forum, which started on the 3rd. The Ukrainian side is believed to be trying to shake Putin's regime by attacking during this event.
Now, I need to structure this into a formal minutes. The title should be something like "Meeting Minutes: St. Petersburg International Economic Forum". The date is the 3rd, but the exact year isn't specified, so I'll leave it as [Date]. The location is St. Petersburg, Russia.
The attendees would include the Russian President, Putin, and other officials, but since the transcript doesn't mention specific names, I'll note that high-ranking officials are present. The main agenda item is the international economic forum, but the attack is an incident that occurred during the event.
The minutes should have sections like:
- Opening Remarks
- Incident Report (the drone attack)
- Casualties and Damage
- Ukrainian Claims
- Possible Motives
- Conclusion
I need to make sure the information flows logically, starting with the event, then the attack, details of the attack, casualties, Ukrainian statements, possible intentions, and a closing note. I should avoid any personal opinions and stick to the facts presented in the transcript. Also, check for any missing details or inconsistencies. Since the transcript mentions the forum started on the 3rd, that's the date. The exact time of the attack isn't specified, so I'll use "on the 3rd" as the time.
Wait, the transcript says the attack happened on the 3rd, which is when the forum started. So the attack occurred during the forum. Need to clarify that in the minutes. Also, the casualties are mentioned, but the exact number isn't given, so I'll note that casualties are reported. The Ukrainian side's motive is to destabilize Putin's regime by attacking during the forum.
I should structure each section with clear headings and bullet points or paragraphs. Avoid markdown, just plain text with clear sections. Make sure the minutes are concise but cover all the key points from the transcript. Check for any typos or errors in the information. Alright, time to put it all together.
...done thinking.
**会議録**
**タイトル**: サンクトペテルブルク国際経済フォーラム開幕日における事件報告
**日時**: 2023年3月3日(開幕日)
**場所**: ロシア・サンクトペテルブルク
---
### **1. 会議の概要**
- **主催**: ロシア政府
- **参加者**: ロシアのプーチン大統領、国際的な経済関係者、高官等
- **目的**: 国際経済フォーラムの開幕式および国際協力の検討
---
### **2. イベントに関する情報**
- **大規模攻撃の発生**:
- 3月3日に、ウクライナ軍がサンクトペテルブルクの重要施設(石油ターミナル等)に対して無人機による長距離攻撃を実施したと発表。
- 攻撃により、各地で黒煙が上がり、複数の地区が無人機の攻撃を受けた。
- 地元当局によると、負傷者が出ているとされる。
- **フォーラムとの関連性**:
- 攻撃は、プーチン大統領が出席する国際経済フォーラムの開幕日に発生した。
- ユーカイナ側は、このタイミングを狙ってプーチン政権を揺さぶる意図があるとされている。
---
### **3. ウクライナ側の主張**
- **攻撃の成果**:
- ウクライナのゼレンスキー大統領は、重要施設への攻撃で「良好な成果」を上げたと主張。
- **目的**:
- フォーラム開催中における攻撃を通じて、プーチン政権の安定性を揺るがす狙いがあると分析されている。
---
### **4. 現在の状況**
- **被害の詳細**:
- 攻撃の具体的な被害規模や死者数は未確認。
- 地元当局が調査を進めている。
- **国際社会の反応**:
- 攻撃の背景や目的に関する国際的な関心が高まっている。
---
### **5. 結論**
- サンクトペテルブルク国際経済フォーラムの開幕日に発生した大規模攻撃は、国際的な注目を集める事態となった。
- 攻撃の動機と結果についての詳細な調査が求められている。
---
**備考**: 会議の進行に影響を与える情報については、今後の公式発表を待って改めて検討する。
-----------------
[18:22:31.870404] 議事録生成完了
[18:22:31.888623] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\20261102-182231_voice-sample02\voice-sample02.m4a
[18:22:32.889540] ----------------
[18:22:32.889619] 処理開始: voice-sample01.m4a
[18:22:32.890606] 作業開始: C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01.m4a
[18:22:32.890741] 出力先 : C:\Users\rinsaka\Documents\python\watchdog\working\voice-sample01
[18:22:32.890797] 文字起こし処理中...
[18:22:51.873308] 議事録生成中...
Thinking...
Okay, I need to create a meeting minutes from the given transcript. Let me start by reading through the provided text carefully. The speaker is talking about the Bank of Japan's Governor, Ueda, giving a lecture in Tokyo today. He mentioned that even if the Middle East situation remains uncertain, there's a possibility of raising interest rates. The Bank of Japan is holding a monetary policy decision meeting from the 15th to the 16th. The speaker also repeated the idea about potential rate hikes despite the uncertain Middle East situation.
First, I should structure the minutes with the appropriate headings. Typically, meeting minutes include the date, time, location, attendees, agenda items, discussions, and decisions. However, in this case, there's no specific meeting mentioned except for the Bank of Japan's policy meeting. The speaker is giving a lecture, so maybe the main event is the lecture, and the policy meeting is upcoming.
Wait, the user provided two speaker entries. The first one mentions the Governor's lecture in Tokyo today, and the second one repeats the same point about the possibility of rate hikes. I need to make sure to include both points. Also, the policy meeting is scheduled from the 15th to the 16th, so that's the next event.
I should start by setting the date and location of the lecture. Then mention the speaker, which is the Governor. The main points are the uncertainty in the Middle East and the possibility of rate hikes. Also, note the upcoming policy meeting dates. Since it's a minutes format, I should use bullet points or sections for clarity.
Wait, the user might be referring to creating a minutes for the policy meeting, but the speaker is talking about the Governor's lecture before the meeting. So maybe the minutes should cover both the lecture and the upcoming meeting. Alternatively, the minutes could be about the lecture itself, but the user might want the minutes related to the policy meeting. I need to clarify that.
Looking back at the original query, the user says "議事録を作成してください" which is "create a minutes record." The content provided is about a lecture by the Governor before the policy meeting. So perhaps the minutes are for the lecture, but usually, minutes are for meetings. Alternatively, maybe the minutes are for the upcoming policy meeting, with the lecture as a discussion point.
Hmm, the user might not be clear, but given the context, the main event is the Governor's lecture, and the policy meeting is the next step. So the minutes could be about the lecture, highlighting the Governor's statements regarding possible rate hikes despite Middle East tensions, and the upcoming policy meeting dates.
I should structure the minutes with the date, location, speaker, key points discussed, and next steps. Let me check the original text again. The first speaker mentions the Governor's lecture in Tokyo today, the second speaker repeats the same point about rate hikes. The policy meeting is from the 15th to the 16th. So the minutes should include the lecture's key points and the upcoming meeting.
I need to make sure to mention that the Governor stated the possibility of rate hikes even with Middle East uncertainty, and that the policy meeting is scheduled for the 15th-16th. The minutes should be concise, in Japanese, with appropriate headings. Let me draft that.
...done thinking.
**議事録**
**日時**: 令和X年X月X日(火曜日)
**場所**: 東京(日銀総裁講演会)
**出席者**: 日銀上田総裁、関係者
---
### **1. 講演の概要**
- **上田総裁の発言**:
- 中東情勢の不透明な状況が続くとしても、利上げを行う可能性を示唆。
- 経済の動向や物価上昇圧力に注視しつつ、金融政策の見通しを調整する必要性を強調。
---
### **2. 次回金融政策決定会合の情報**
- **日程**: 令和X年X月15日(水曜日)から2日間(16日)の期間で開催。
- **目的**: 経済状況の評価と金融政策の方向性を決定。
---
### **3. 議論の重点**
- 中東情勢の影響を踏まえた金融政策の柔軟性の確保。
- 炎上する物価上昇圧力と、景気の動向をバランスよく捉える必要性。
---
### **4. 次回の対応**
- 講演後の記者会見で、上田総裁が詳細な政策展望を語る予定。
- 次回金融政策決定会合の結果は、今後の市場動向に大きな影響を与えると予想される。
---
**備考**: 講演内容は、政策決定会合前の情報提供として位置付けられ、市場の注目が集まる。
-----------------
[18:23:18.956067] 議事録生成完了
[18:23:18.957385] 完了: C:\Users\rinsaka\Documents\python\watchdog\done\20261102-182318_voice-sample01\voice-sample01.m4a
Ctrl + C
[18:23:26.712324] 停止します
(py313watchdog) PS C:\Users\rinsaka\Documents\python\watchdog>
現時点では議事録が画面に出力されています.次のページでは議事録をマークダウン形式のファイルで保存するように修正します.