# v2 — Phase 1 Lv2 Jarvis常駐デーモン Whisper常駐レイヤー

## 概要

Phase 1 SPEC の Whisper常駐レイヤー実装。  
ffmpeg による連続録音と whisper-cli によるリアルタイム文字起こしを並列実行し、  
`transcripts/YYYY-MM-DD.jsonl` に蓄積する。  
`jarvis_daemon.py`（呼名検出側）がこの jsonl を読み込む。

---

## 旧版（live_session/transcribe.sh）からの変更点

| 項目 | 旧版 | v2 |
|---|---|---|
| ディレクトリ構成 | 入出力が同一フォルダ | raw / split / processed / transcripts を物理分離 |
| 自己増殖バグ | `${base}_L.wav` を再帰的に入力として拾い26並列爆死 | 正規表現 `^CHUNK_\d{3}\.wav$` で厳格マッチ・処理済み即 processed/ 移動 |
| whisper-cli 上限 | なし | 5並列上限ガード |
| 多重起動 | 防止なし | .recorder.pid / .watcher.pid で拒否 |
| 異常増殖検知 | なし | 1分20ファイル超で自動停止 |
| dry-run | なし | 必須化（起動前に自動実行） |
| 統合起動 | 手動で各スクリプト起動 | live_run.sh 1コマンドで完結 |

---

## ディレクトリ構成

```
v2/
├── recorder.py           # ffmpeg録音（raw/ に30秒チャンクを出力）
├── transcriber.py        # whisper呼び出し（1チャンク→jsonl追記）
├── watcher.py            # raw/ 監視→transcriber 発火
├── live_run.sh           # 統合起動スクリプト
├── README.md             # このファイル
├── recording/
│   ├── raw/              # 録音生wav（watcherが監視）
│   ├── split/            # L/R分離後（処理後即削除）
│   └── processed/        # 処理済みwav（再処理防止・履歴保存）
├── transcripts/
│   └── YYYY-MM-DD.jsonl  # 文字起こし結果（日付別・追記式）
└── logs/
    ├── recorder.log
    └── watcher.log
```

---

## 起動方法

```bash
# 事前テスト（依存確認・設定チェック・実際には録音しない）
bash live_run.sh --dry-run

# 通常起動（dry-runを自動実行してから起動）
bash live_run.sh

# 停止（graceful）
bash live_run.sh --stop
# または起動中ターミナルで Ctrl+C
```

---

## 過去事故の根本原因と対策

### 2026-05-04: PC 2連続クラッシュ事故

**原因:**  
旧 `transcribe.sh` が `recording/` フォルダ内の wav を監視していたが、  
whisper の出力 `${base}_L.wav` が同フォルダに生成され、それを再帰的に入力として検出。  
whisper-cli が26並列で起動し、CPU/メモリを食い潰して PC が2連続クラッシュした。

**v2 での対策:**

1. **ディレクトリ3層分離**  
   `raw/`（録音器出力） → `split/`（L/R分離処理中） → `processed/`（完了済み）  
   各ステージが別フォルダなので出力が入力に混入する経路を物理的に遮断

2. **ファイル名正規表現厳格化**  
   watcher が監視するのは `^CHUNK_\d{3}\.wav$` にマッチするファイルのみ  
   `*_L.wav` `*_R.wav` は検出対象外

3. **処理済み即移動**  
   transcriber が wav を受け取った時点で即座に `processed/` へ移動  
   watcher が再検出しても `processed/` は監視対象外

4. **whisper-cli 上限 5並列**  
   同時実行数が5を超えた場合は新チャンクをキューに保留

5. **異常増殖検知**  
   1分間に `raw/` に積まれるファイルが20件超の場合、全プロセスを停止

---

## トラブルシュート

**whisper-cli が見つからない**
```bash
brew install whisper-cpp
```

**モデルファイルがない**
```bash
whisper-cpp-download-ggml-model medium
```

**プロセスが残骸として残っている**
```bash
bash live_run.sh --stop
# または
pkill -f "recorder.py|watcher.py|transcriber.py"
```

**recording/raw/ が肥大している**
```bash
# 処理済みのはずが残っている場合
find recording/raw/ -name "*.wav" -mtime +1 -delete
# processed/ もまとめて掃除する場合
find recording/ -name "*.wav" -mtime +7 -delete
```

**起動後すぐ落ちる**  
`logs/recorder.log` または `logs/watcher.log` の末尾を確認する。  
dry-run が通っているか先に確認すること: `bash live_run.sh --dry-run`

---

## SPEC.md との関係

本実装は `clone-jarvis/jarvis/live_session/SPEC.md` Phase 1 の  
「Whisper常駐レイヤー」に相当する。  
`jarvis_daemon.py`（呼名検出側）は `transcripts/YYYY-MM-DD.jsonl` を tail -f 相当で読み、  
「Jarvis」呼名を検出してコマンド受付モードに移行する。
