# 回想部屋 ― 設計図（ブループリント）

生成画像と、その前後の会話を「チップ」として保存し、あとから眺めて追体験できるアーティファクトを作るための設計図です。
このファイルを読んだエージェントは、まず「セットアップ質問」をユーザーに順番に尋ね、回答に合わせて構築してください。質問で決めるのは使い方の好みだけ。データ構造や更新方式などの実装の勘所は、この設計図側で固定してあります（「実装メモ」を参照）。

---

## 1. セットアップ質問（構築前に必ず聞く）

### 必須の質問（4つ）

**Q1. 回想の回収基準はどうしますか？**
- A. リアクション方式：ユーザーがリアクションした画像だけを回収する（おすすめ。思い出として残したいものだけが集まる）
- B. 全部方式：画像が投稿されたら、リアクションの有無にかかわらず回収する
- C. 成果物方式：完成した作品・成果物（作品ブック等）から、採用カット＋対応する本文だけを回収する（制作系チャット向け。リテイク等の制作交渉は含めない）
- チャットごとに方式を変えてもよい（例：日常チャットはA、制作チャットはC）
- Aを選んだ場合の付随ルール：候補が複数枚あり全部にリアクションが付いたら、1チップにまとめて内包し、サムネイルは先頭の画像にする

**Q2. 自動更新しますか？**
- する（1日1回、指定した時刻に新規分だけを回収する）／しない（手動更新ボタンのみ）
- デフォルトは「しない」。時刻を選んで保存したときだけ自動更新が有効になる

**Q3. 構築後のテスト回収は、どのチャットから行いますか？**
- テストは必ず「プレビュー（回収候補の件数と一覧を見せる）→ ユーザー確認 → 投入」の順で行う。いきなり本投入しない

**Q4. 最初に、過去分の全回収を行いますか？**
- 行う／行わない（行わない場合は、構築時点から先の新規分だけが対象）
- 行う場合は対象チャットの範囲も確認する（全チャット／指定したチャットのみ）

### 追加で聞くと喜ばれる質問（任意）

**Q5. チャットごとのデフォルト安全タグ**
- チャット単位で「健全／NSFW」の初期値を決めておくと、回収時の分類が一気に楽になる（例：日常チャット=健全、裏アカウント=NSFW）

**Q6. 相手タグ（partner_tag）の付け方**
- チャットごとに固定か、登場する相手ごとに変えるか。タグの候補もこの時点で聞いておく

**Q7. 会話の取り込み範囲**
- 画像の前後、何件分の会話までチップに入れるか（全部／前後◯件／画像直後の投稿だけ、など）

**Q8. 音声も内包しますか？**
- 音声ファイル（ボイスメモ等）もチップに持たせて詳細画面で再生できるようにするか

**Q9. 生成画像を目視チェックしてよいですか？**
- 回収作業の際、エージェントが画像の中身を見て確認してよいか。「見ない（ファイルの存在確認のみ）」が希望の人もいるので、必ず確認すること

---

## 2. データモデル

### チップ（chip）
| フィールド | 内容 |
|---|---|
| id | 自動採番 |
| title | チップの題名 |
| partner_tag | 相手タグ（例：ハル、りりあ）。自由文字列 |
| safety_tag | 「健全」または「NSFW」（必須） |
| source_chat_name / source_chat_id | 出典チャットの表示名とID |
| generated_at | 画像の生成日時（ISO 8601、タイムゾーン付き） |
| images | 画像の配列。**要素は必ず `{image_file, image_key}` のオブジェクト**（文字列の配列は不可。取り込みで弾かれる）。先頭がサムネイル |
| image_file / image_key | images[0] と同じ値を持つ代表フィールド |
| audios | 音声の配列（images と同じオブジェクト形式）。無ければ空配列 |
| conversation | 会話の配列。要素は `{role, speaker, text, at}`。role は user / assistant / system-note のいずれか |
| preview | 一覧表示用の抜粋。conversation の先頭から自動生成してよい |
| memo | 備考（回収経緯など） |

### 設定（settings）
| フィールド | 内容 |
|---|---|
| auto_refresh_hour | 自動更新の時刻（0〜23）。null = 自動更新なし（デフォルト） |
| last_refresh_at | 最後に回収・更新を実行した日時。差分更新の境界に使う |

---

## 3. 画面仕様

### 一覧
- カードは約250×300px。サムネイル＋会話の先頭抜粋＋タイトル＋生成日時＋タグバッジ
- **サムネイルはNSFWでもぼかさない**（バッジで区別するだけ）
- 複数画像のチップには、サムネイルに「重なった写真」風のアイコンと「◯枚」バッジを表示。1枚のチップには付けない
- 音声を含むチップには音符バッジを表示
- ソート：生成日時の新しい順／古い順、安全タグ、相手タグ
- フィルタ：安全タグ、相手タグ、出典チャット、キーワード検索
- 画面上部に「チップを作成」ボタンと、手動更新ボタン「↻ チャットから更新」を並べる
- 自動更新の設定は時刻プルダウン（0〜23時＋「更新なし」）で変更でき、デフォルトは「更新なし」

### 詳細
- 大きい画像（複数枚なら全部）＋会話の全文＋音声があれば再生UI
- 健全／NSFWの切替ボタン。押したら即時保存し、一覧のバッジにも反映する
- 同じ出典チャット内の前後チップへ移動するボタン（並び順は生成日時の昇順）。先頭／末尾では無効化し、「◯ / ◯」のような現在位置を表示する
- 「一覧に戻る」は前後ボタンと同じ見た目の、ちゃんとしたボタンにする

---

## 4. 回収・更新の仕様（固定。質問で変えない）

- **差分更新が原則**：手動更新も自動更新も、毎回すべての履歴を読み直さない。走査の境界は次の優先順で決める
  1. last_refresh_at があれば、それより後
  2. 無ければ、出典チャットごとに「登録済みチップの最新の generated_at」より後
  3. それも無い場合だけ、最小限の直近範囲（目安：直近1ページ／最大5ターン）
- 更新が完了したら last_refresh_at を記録する
- **重複スキップ**：取り込み時、「タイトル＋先頭画像」が既存チップと一致するものは取り込まない
- **ファイルが無い画像**：リアクション等で対象になっても、実ファイルが存在しないものは回収できない。その旨をチップのメモや報告に明記する
- 回収は Q1 で選んだ方式に従う。成果物方式（C）の場合は、完成物から「画像＋対応本文」を抽出し、制作交渉（リテイク等）のやり取りは含めない

---

## 5. アクション一覧（エージェントが使うAPI）

| アクション | 用途・注意 |
|---|---|
| listChips | 一覧取得。**filter は `{filter:{safety_tag, partner_tag, source_chat_id, search}}` の形でネストして渡す**。sort は generated_at_desc / generated_at_asc / safety_tag / partner_tag |
| getChip | 1件取得 |
| createChip | 1件作成 |
| importChips | 複数件の一括取り込み。重複はスキップされ、inserted / skipped / ids が返る |
| updateChip | 更新（タグ切替など） |
| deleteChip | 削除 |
| seedChips | 初期データ投入用 |
| getSettings / setAutoRefreshHour | 設定の取得／自動更新時刻の保存 |
| requestRefresh / maybeAutoRefresh / refreshFromChats | 手動更新・自動更新の実行系。いずれも差分更新の境界ルールに従う |

---

## 6. 画像の埋め込み

- 回収対象の画像ファイルは、アーティファクト内の埋め込みアセットとして取り込み、ファイル名をそのままキー（image_key）として参照できるようにする
- 埋め込み作業では画像の中身を開かない（Q9 の回答が「見ない」の場合は特に厳守。存在確認とメタデータのみ）

---

## 7. 構築手順チェックリスト

1. セットアップ質問（Q1〜Q4、必要に応じてQ5〜Q9）を聞き、回答を控える
2. データモデルと画面仕様に沿ってアーティファクトを構築する
3. Q3 のチャットでテスト回収：候補をプレビューし、ユーザーの確認を得てから投入する
4. Q4 が「行う」なら、対象範囲について全回収を実施する（方式はQ1、分類はQ5・Q6に従う）
5. Q2 が「する」なら自動更新の時刻を保存する
6. 件数と内訳を検証し、ユーザーに報告する（対象だったが回収できなかったものがあれば、その理由も添える）

---

## 8. 実装メモ（先行実装で詰まった点）

- importChips の images は `{image_file, image_key}` オブジェクトの配列が必須。文字列配列を渡すと失敗する
- listChips の filter はネスト形式 `{filter:{...}}`。フラットに渡すと絞り込まれない
- 自動更新のデフォルトは必ず「なし」。時刻プルダウンには「更新なし」の選択肢を用意する
- 全履歴の再走査はトークンを大量に消費する。差分境界（4章）を最初から実装しておくこと
- 詳細画面の前後移動は「同じ出典チャット内・生成日時昇順」が分かりやすい
- 対象画像のファイル名は、メッセージ本文やファイルの更新日時から機械的に特定できることが多い。会話を全部読み直す前に、軽い照合手段がないか検討すること

---

*この設計図は「回想部屋」（生成画像＋会話の回想ボード）の実運用から抽出したものです。*
