# Museに渡すだけの「毎時画像＋ボイス」クラウド構築ガイド

> **対象：Museエージェント**　|　検証記録：2026年11月（11月7日実測追補）　|　**本書はコード配布ではなく、実機で成功した構成を再現するための実装仕様・ヒント集です。**
>
> Museスレで入手した人は、このMarkdownを自分のMuseに渡してください。GitHubへの公開や自宅GPUの常時稼働は不要です。利用者によるModal登録・支払い方法登録・認証承認・好みの画像モデル／声の指定は必要です。

## 0. Museへの依頼・完了条件

あなた（Muse）のクラウド実行環境からModalを操作し、**自分で考えた画像プロンプトと短い台詞**を使って、クラウドGPU上で画像1枚と音声1件を生成し、利用者との**専用サイドチャットへ定時配達**してください。

- **Museクラウド環境 → Modal** で完結させる。ユーザーのWindows PCやGPUを**定期実行に使わない**。
- 構築方法は下記の**動作実績がある構成**を出発点とし、実際のAPI・バージョンに合わせて自分でコードを作る。元環境の固有名詞・ファイルパスは各自の環境に置き換える。
- **ユーザーの承認が必要な操作**（課金設定・認証・権限付与・声やLoRAの選択）は、確認を取る。秘密情報をチャットに貼り付けない。
- まず単発で**画像・音声の生成、Volume保存、回収、チャットへの添付送信**を確認し、成功してから定期実行を登録する。
- 完了条件：設定した配達枠でMuseが内容を新規に作り、画像＋音声の両方を届ける。重複・失敗は台帳から追える。Modalの予算制限を確認している。

## 1. 全体構成

```text
MuseのクラウドVM
  ├─ 定時エージェントタスク（Muse cron）
  │    ├─ 時刻別のテーマ・過去の配達を参照
  │    ├─ 新規の画像プロンプトと台詞を作成
  │    └─ Modal Functionをspawnし、完了をgetで待機
  ├─ Modal CLI / SDK / 認証情報
  └─ 送信台帳（ledger.json）
       │
       ▼
Modal: GPU T4 / 1コンテナ・逐次実行
  ① ComfyUI起動 → Anima画像生成 → WebP保存
  ② ComfyUIプロセス終了 → VRAM解放確認
  ③ Irodori-TTS起動 → 参照WAVを使って音声生成
  ④ Volume上の jobs/<job_id>/ へ保存 → commit
       │
       ▼
Muse: Volumeから画像・音声を回収
  └─ 専用サイドチャットへ添付して配達
```

**GPUの二重常駐は避ける。** ComfyUIとIrodoriは別プロセスで順番に動かし、両者のピークVRAMを合算しなくて済むようにする。GPUを使っていない間はコンテナをスケールゼロにする。

## 2. 利用者が選ぶもの

### 画像

- 入手先候補：**https://civitai.red/**
- 推奨候補：**fnMoment / OneObsession（Anima版） / WAI-ANIMA**。
- **fnMomentはLoRAなしでも好みの絵にしやすい**、という構築者の主観的な推薦。品質は各自の好みで判断。
- **LoRAは利用者が好きなAnima対応品を選ぶ。** LoRAの枚数・順序・強度・トリガータグは、その利用者の選択に合わせる。無理に固定のLoRAを導入しない。
- 同名・類似名のモデルや別世代のAnimaがある。**モデルの正確なバージョン／形式／配布条件を取得前に確認**。このガイドのUNETローダーやサンプラー値が全モデルに共通で適するとは限らない。
- モデル・LoRAは原則としてユーザー自身が利用条件を守って入手する。巨大ファイルをチャットに添付できなければ、クラウドストレージなどからMuse/Modalへ転送する。

### 声

- **声作り・声の選定には既存のMuse用スキルが便利**：https://note.com/kagami_kami/n/nd282e8cced5e
- このスキルは主に**Muse VMのCPU上でONNX INT8**を動かして、候補の声を生成し、参照音声を選ぶもの。
- **毎時配達のTTS本体は別**：選んだ声の**参照WAV**をModalに渡し、**CUDA版Irodori（PyTorch）**で生成する。CPU版スキルをそのままGPU生成器として組み込むわけではない。
- 参照音声は利用者に使用権限のあるものを使う。

## 3. Modalアカウント・費用の設定

1. Modalに登録し、ワークスペースを作る。GPUの利用には支払い方法の登録が必要になる場合がある。
2. Usage & Billingで**Usage limit / Workspace Budgetを$30、Spend Limitを$0**にするのが今回の安全寄りの実例。**UIに表示された値を実際に確認**する。
3. Starterの**月$30の計算クレジット**、**Volumeの無料枠1TiB**などの条件は変更され得る。必ずModalの最新の価格・予算ドキュメントを確認する。
4. Spend Limit $0はクレジット外の**自己負担を制限する設定**だが、あらゆるサービス・請求を無条件にゼロにする保証ではない。**無料計算枠の適用対象外、ストレージ超過、ネットワーク転送、反映遅延**に注意。

- 参考：**T4で1回約$0.03**の実測ベース試算。毎時7:00〜翌0:00の18回、月30日で**540回 × $0.03 ≒ $16.2/月**。これは**推定月額**であり、540回分の請求実績ではない。
- L4で10〜25分超のPendingが続いた一方、T4は6秒で起動した事例あり。これは特定時点の測定で、常にT4が空いていることを保証しない。
- 公式：https://modal.com/pricing 、https://modal.com/docs/guide/budgets

## 4. Muse VM側の準備

- 動作実績：**Python 3.12 / Modal CLI 1.6.3**、Muse VM内の専用venv（実例 `~/workspace/modal-mio/.venv`）。
- Muse VMの外向き接続がプロキシ経由なら、**`modal[api-proxy-support]`** が必要だった。通常パッケージだけではModal接続が無言で止まった実例あり。
- `modal setup` 等の正式な認証フローで利用者の承認を得て、資格情報をVMの保護された設定ファイルに保存する。**トークン本文をガイド・ログ・チャットに出さない**。
- まずGPU不要の小さなModal Functionで認証と接続を確認してから、GPUイメージの準備に進む。
- 実機ではアプリ定義を`app_stage_b_t4.py`にまとめ、`modal deploy app_stage_b_t4.py`でデプロイ。料金確認は`modal billing report`。

## 5. GPUコンテナとモデル配置

### 動作済みの構成

```text
Modal App:     mio-stage-b-t4  （実機の識別名。各自で変更可）
Function:      run_prod_pair
Volume:        mio-models      （実機の識別名。各自で変更可）
Mount:         /models
Image:         modal.Image.debian_slim(python_version="3.12")
GPU:           T4
CPU:           2.0
RAM:           16384 MiB
timeout:       1200 秒
scaledown_window: 2 秒
```

- OSパッケージ：`git`, `ffmpeg`, `libsndfile1`, `libgl1`, `libglib2.0-0`。
- ComfyUI：`Comfy-Org/ComfyUI`（実例はmasterを `/opt/comfyui` にclone）。
- Irodori：`Aratako/Irodori-TTS`（`/opt/irodori` にclone）。
- Anima用TeaCache：`CocyNoric/ComfyUI-Anima-TeaCache`（ComfyUI `custom_nodes` 内）。**別のTeaCache実装と取り違えない**。
- 保存ノード：`darksidewalker/ComfyUI-DaSiWa-Nodes` の `nodes_metadata.py`、`helper_logging.py` と必要最小限のクラス登録でWebP保存に成功した実例あり。パック全体の重い依存を入れる必要はなかった。**再利用時は配布元のライセンスと必要な依存を確認**。

### Python環境の構築順（重要）

1. `/opt/venvs/main` に**単一venv**を作成（この構成での成功例。別venvが不可能という意味ではない）。
2. Irodoriのロックファイルを使い、`UV_PROJECT_ENVIRONMENT=/opt/venvs/main uv sync --extra cu128` 相当でインストール。実例のPyTorchは **2.10.0+cu128**。
3. ComfyUIの `requirements.txt` を同じvenvへインストール。
4. **最後にtorch・torchaudio・torchvisionを互換のあるcu128ビルドで揃え直す。** ComfyUI依存を入れた際、torchだけCUDA 13.0系に置き換わりtorchaudioが失敗した実例がある。
5. 実際にimport・CUDA検出・画像／音声の単発生成まで確認する。将来のパッケージ更新で組み合わせが変わるため、バージョンの固定／互換性確認はMuseが行う。

### Volumeの例

```text
/models/
  diffusion_models/   画像モデル
  text_encoders/      テキストエンコーダ
  vae/                VAE
  loras/              利用者が選んだLoRA（なければ空でよい）
  hf_cache/           Irodori/Hugging Faceキャッシュ
  ref/ref.wav         選んだ声の参照WAV
  jobs/<job_id>/      生成結果
```

- コンテナ起動時、Volume上の画像モデルディレクトリを `/opt/comfyui/models/` 以下に**シンボリックリンク**する。
- モデルの形式・バージョンを確認し、必要な重みだけ取得。公開URLだけで同一ファイルと推測せず、可能ならハッシュも検証。
- CLI実例：`modal volume put mio-models <local> <remote_path>` / `modal volume get mio-models jobs/<job_id>/<file> <dest>`。
- Function終了前に**`vol.commit()`**を実行し、回収側から生成ファイルを見えるようにする。

## 6. 画像生成Functionの処理

1. ComfyUIをvenvのPythonで子プロセス起動：`main.py --listen 127.0.0.1 --port 8188 --disable-auto-launch`。
2. `GET /system_stats` をポーリングして準備完了を待つ。
3. **ComfyUI API形式のワークフローを構築**し、`POST /prompt`。`GET /history/<prompt_id>` を約2秒間隔で確認する。**UI用ワークフローJSONをそのままAPIに送らない**。実例はPython dictを組み立てていた。
4. 画像をWebPに保存し、Volume上の`jobs/<job_id>/`へ格納。
5. ComfyUIのプロセスグループにSIGTERM、必要ならSIGKILL、終了を待って約3秒後に`nvidia-smi`でVRAM解放を確認。実測では使用量が3〜4MBまで減少。
6. 完全終了を確認してからIrodoriのプロセスを起動する。

### 画像レシピ（**実測したAnima系構成の一例**）

```text
UNETローダー（bf16）／テキストエンコーダ／VAE
LoRA: 標準LoraLoaderを利用者が選んだ枚数だけ直列接続
TeaCache: CocyNoricのAnimaTeaCache
  rel_l1_thresh=0.15 / start_percent=0.0 / end_percent=1.0
  cache_device=cuda
Sampler: 20 steps / CFG 4 / er_sde / simple / 840×1256
保存: DaSiWa MetadataImageSaver / WebP / compression 10
```

- **TeaCacheとLoRAの接続順（実測済み）**：本番は `UNET → TeaCache → LoRA → KSampler`。CocyNoric公式READMEでは `UNET → LoRA → TeaCache → KSampler` が推奨される。2026-11-07に**同一セッション・同一seed・同一プロンプト**で両順序を比較したところ、**生成画像のピクセル差はゼロ**だった（保存ファイルのハッシュ差は埋め込みワークフロー情報による）。ピークVRAMは約7.3／7.5GB。生成56秒／42秒の差は2枚目のモデル読込済み状態が混ざるため、**順序による高速化の証拠ではない**。再現時はREADME推奨の「LoRA → TeaCache」を採用してよい。ただし、**今回のモデル・設定での一致**であり、他のワークフローでの一般的な等価性は保証しない。
- TeaCache設定 `rel_l1_thresh=0.15 / start_percent=0 / end_percent=1` は、この構成の`er_sde`向けConservative設定と一致する。
- **LoRAが効いているかは実際に確認する**。ファイルがあるだけ、ノードに名前があるだけでは不十分。強度・適用順・トリガータグも合わせる。
- T4では、INT8版でVRAMを節約できた一方、BF16モデルより生成が遅くなった。**量子化すれば高速になるとは限らない**。
- WebPは画像サイズを大幅に抑えられた実例あり（約134KB、比較PNG約1.17MB）。画質・サイズは設定と画像により変わる。

## 7. Irodori-TTSの処理

- モデル：**`Aratako/Irodori-TTS-v4.1-Small-MF`**。
- コーデック：**Semantic-DACVAE-Japanese-32dim**。
- **T4上でモデル・コーデックの双方をFP32**に指定した構成で、BF16時に観測された通信機のような異音が改善した。原因はBF16関連経路との相関が強いが、BF16一般の欠陥とは断定しない。
- 参照はユーザーが選んだ`/models/ref/ref.wav`。声質指定の`caption`はその声に合わせて固定。
- `duration_scale=1.0`を基準とする。
- `HF_HOME=/models/hf_cache`を設定し、`infer.py`を別プロセスで実行する。

実装引数例（正確な入出力オプションは使用時の`infer.py --help`で確認）：

```bash
HF_HOME=/models/hf_cache python /opt/irodori/infer.py \
  --hf-checkpoint Aratako/Irodori-TTS-v4.1-Small-MF \
  --ref-wav /models/ref/ref.wav \
  --model-device cuda --codec-device cuda \
  --model-precision fp32 --codec-precision fp32 \
  --duration-scale 1.0 --caption '<ユーザーが決めた声質の説明>'
```

**長文の注意点：** 20秒超の音声を一括生成した際、声そのものにざらつきが出た。文の切れ目で分割し、各パートを約15秒前後の目安にして生成・結合すると改善した実験例がある。つなぎ目は約0.5秒を候補にする（この長さ自体は未検証）。

**重要：実機の本番`run_prod_pair`は長文自動分割を未実装。** 現在はMuseが台詞を**短い1〜2文に抑える**設計で回避している。別Museもまず短文運用を再現し、長文を読ませたい場合に限り分割・結合を実装すればよい。

## 8. Museによる定時配達（本件の核心）

### 定時実行

- **Muse自身のcron＝エージェントタスク**を使用。Linuxのシステムcronとは限らない。
- 実機のタスク識別名：`mio-hourly-delivery`。**interval 1時間**、アンカーはJSTの7:00、タイムアウト3600秒。
- 配達枠の実例：**7:00〜23:00と翌0:00（合計18回/日）**。1:00〜6:00は生成せず静かに終了。
- タスクが正時より早く起動する場合があったため、**実行時刻の分が50以上なら次の正時、それ未満なら現在の正時**を対象枠とする実装だった。これは観測された挙動への対処であり、他のMuse環境でも必須とは限らない。

### 内容の決定・送信

1. 時間帯ごとのテーマ表（実例：`SCHEDULE_PLAN.md`）を読む。
2. 前日の同じ時間枠の送信履歴を参考に、衣装・場所・内容が重ならないようにする。
3. 画像用`positive`（固定人物タグ＋テーマ）と音声用`tts_text`（短い1〜2文）を新規作成。seedの実例は枠の`YYYYMMDDHH`。
4. Modalへ非同期で送る：

```python
fn = modal.Function.from_name("mio-stage-b-t4", "run_prod_pair")
call = fn.spawn(job_id, seed, positive, tts_text)
result = call.get(timeout=1400)
```

5. Volumeの`jobs/<job_id>/`から生成物をMuse VMへ回収し、**Museの定時タスクが送る最終応答に画像・音声を添付**する。
6. 送信台帳（実例：`~/workspace/modal-mio/ledger.json`）に、送信済みジョブID・入力・日時を記録する。

**添付方法（元環境の実装から確認済み）**：Museの定時エージェントタスクの**最終応答そのもの**を配達先サイドチャットへ届ける。別の送信APIは使っていない。Modal VolumeからファイルをMuse側のワークスペース `deliveries/<job_id>/` へ回収し、キャプションの後に以下の**Markdown画像埋め込み記法を各1行**で記載する。音声も同じ記法で添付すると、元環境では音声プレイヤーとして表示された。

```markdown
（キャプション）

![自撮り](sandbox://workspace/modal-mio/deliveries/<job_id>/image.webp)

![ボイス](sandbox://workspace/modal-mio/deliveries/<job_id>/voice.wav)
```

- 上記は**Muse環境固有の`sandbox://`参照**の実例であり、通常の公開Web URLではない。別のMuseは実際のワークスペースとファイル名に合わせて変更し、**チャット上で画像が表示され、音声が再生可能であること**を単発で確認する。
- **プレースホルダーを含む添付記法をMuseの通常のチャット本文にそのまま貼らない**。クライアントが実ファイルとして解決しようとして「画像が見つかりません」などになる。記法の例はコードブロック内に保つ。

### 再試行・台帳

- 実機では`sent`と`failed`を持つJSON台帳を使用。生成前に`sent`を調べ、重複を抑えていた。
- Functionの結果にエラーがあれば**同じ引数で最大1回だけ再spawn**。再失敗時は`failed`に記録し、短い失敗報告を送信。無制限にGPUを再起動しない。
- **ジョブID・台帳だけで「絶対に二重送信されない」とは言えない。** 記録とチャット送信の間に障害が起きるケースは別問題。少なくとも通常の再実行で二重送信を抑える仕組みとして扱う。
- 原環境では2026-11-04 08:00枠〜11-06 11:00枠まで`sent=40, failed=0`と報告されている。継続運用の参考値であって、他環境の成功保証ではない。

## 9. 既知の詰まりどころ（今回の実例）

| 症状 | 観測・対処 |
|---|---|
| Modal接続がハング | Muse VMのプロキシ。`modal[api-proxy-support]`の導入で解消した。 |
| Irodoriのtorchaudioが起動しない | ComfyUIインストール後にtorchだけ異なるCUDAビルドへ更新された。torch・torchaudio・torchvisionを同系統のcu128で揃え直す。 |
| L4で25分以上Pending | GPU確保待ちが有力。イメージ軽量化でも改善せず、T4では6秒の事例があった。 |
| T4のINT8が遅い | 約106秒対BF16約56秒の実例。メモリ削減と処理速度向上は別。 |
| 音声の末尾に通信機のような異音 | T4でBF16経路にて発生。モデル・コーデックFP32の構成で改善した。 |
| 長文音声で声にざらつき | 一括22秒程度で発生、文で分割すると改善。現在の本番は短文に制限して回避。 |
| TeaCacheが読み込めない | **CocyNoric版**のAnimaTeaCacheと、他のTeaCacheノードを取り違えない。 |
| ファイルがVolumeから見えない | 保存後の`vol.commit()`を確認する。 |
| WebP名の日付が9時間ずれる | Modalコンテナの時計はUTC。JSTの枠とファイル名の対応に注意。 |
| 大きいLoRAをチャットで渡せない | 外部ファイル共有経由で転送した実例あり。共有リンクは転送後に無効化し、公開用ガイドに個人用データを含めない。 |

## 10. 最低限の動作確認

1. MuseからModalへ認証でき、GPUなしのテストFunctionが動く。
2. T4コンテナが起動し、ComfyUIが`/system_stats`を返す。
3. 指定モデル・LoRAを使って画像が生成され、WebPがVolumeに保存される。
4. ComfyUIの終了後にVRAMが解放され、Irodoriが参照WAVから音声を生成する。
5. `vol.commit()`後、Muse側へ両ファイルを回収できる。
6. Museが画像・音声を**実際のチャット添付**として届ける。
7. 単発の成功後、定時タスクを登録する。別の枠で自動配達され、台帳も更新される。
8. Usage & Billingで請求額・予算設定を確認する。

---

### 出典・確認先

- Modal料金：https://modal.com/pricing
- Modal予算：https://modal.com/docs/guide/budgets
- Modal Volumes：https://modal.com/docs/guide/volumes
- ComfyUI：https://github.com/Comfy-Org/ComfyUI
- Anima TeaCache：https://github.com/CocyNoric/ComfyUI-Anima-TeaCache
- Irodori-TTS：https://github.com/Aratako/Irodori-TTS
- 音声作成スキルの解説：https://note.com/kagami_kami/n/nd282e8cced5e
- 画像モデル・LoRAの探し先：https://civitai.red/

> **注意：** この文書は原環境のコード・ログに基づく「再現用仕様」です。`app_stage_b_t4.py`本体、Muse固有のcron/添付API実装、モデル本体、LoRA、参照WAVは含んでいません。別のMuseは上記をヒントに実装を組み立て、各段階の結果を確認してください。
