Appearance
EP-027 daily_article_ai_chat_send(日別記事 AI 相談送信)
← EP-一覧 · EP-028 セッション削除 · EP-031 セッション作成 · EP-032 セッション読込
概要
日別記事の編集画面から、ホールと前半・後半考察を指定して AI に相談する。ハンドラは返信文と欄別下書きを JSON で返す。考察欄の post meta へは自動保存しない(画面上のエディタ末尾への挿入はフロントが行う)。会話履歴は db_daily_article_ai_chat_message にセッション単位で保存する(session_id 必須。LLM 履歴も当該セッションのみ)。
LLM のプロバイダ・モデル・API キーは ADM-028 の設定を再利用する。システムプロンプトは ADM-028 の日別記事 AI 相談用 option(mycustom_daily_article_ai_chat_system_prompt / PaidArticleAiOptions)を参照する。空のときは DailyArticleAiChatServiceCopy::DEFAULT_SYSTEM_PROMPT にフォールバックする(一括生成用システムプロンプト mycustom_paid_article_ai_system_prompt は使わない)。ツールは同イベント関係日一覧・同じ日にちの機種差枚・6の日の機種差枚・同イベントの機種差枚・編集メモ検索・編集メモ保存・機種名解決・機種の期間差枚・ホールの期間合計差枚・機種別差枚(日付リスト)・公開済み過去考察・店舗調査(X 投稿取得 fetch_hall_x_posts/Grok 調査 investigate_hall_with_grok。契約は 店舗調査 AI ツール)(有料記事 AI のツールカタログは使わない。店舗調査ツールのみ同じインスタンスを共有する)。
差枚系ツールの引数と役割分担
| ツール | 主な用途 | 任意の機種指定 |
|---|---|---|
resolve_kishu_name | 略称・通称を正式名称 / kishu_id へ事前解決(差枚は返さない) | 必須 kishu(string 1 件)。共通 ArticleAiKishuNameResolver。未解決・曖昧時は status / candidates |
fetch_kishu_samai_for_dates | 指定した日付リスト×ホールの日単位差枚 | kishu(公式名の文字列配列・最大20)/ kishu_ids(整数配列・最大20)。省略時は合計差枚 TOP N。指定時は該当機種のみ(TOP 外も可)。データ無しの日×ホールは machines: [] |
fetch_same_calendar_day_results / fetch_six_day_results / fetch_same_event_results | 関連日(同じ日にち・6の日・同イベント)ごとの日単位差枚 | 同上。ヘルパー経由で同一契約 |
fetch_period_kishu_samai | 期間全体の合計・平均差枚(相対期間は考察日から Y-m-d に直して呼ぶ) | 機種は必須。編集メモ → 機種マスタ名・ヒートマップ略称・機種表示マッピング(共通 ArticleAiKishuNameResolver)→ 期間内部分一致で通称解決。未解決・曖昧時は差枚を返さず status。日単位・関連日の列挙には使わない |
fetch_kishu_samai_for_dates および関連日系ツールの kishu は有効な機種マスタの公式名完全一致で ID 解決し(一覧を一括取得して照合)、kishu_ids とマージする。1 件でも未解決の機種名があれば JSON error(KISHU_NOT_IN_MASTER)。件数超過は KISHU_TOO_MANY / KISHU_IDS_TOO_MANY。部分成功(一部名だけ捨てて返す)はしない。
fetch_period_kishu_samai の機種解決は上記の公式名完全一致フィルタとは別経路(共通 Resolver + 編集メモ + 期間内部分一致)である。resolve_kishu_name は Resolver 単体の結果を返す(編集メモや期間内部分一致は使わない)。
セッションタイトルが空のとき、初回送信のユーザー文先頭 40 文字で自動設定する。
POST パラメータ
| フィールド | 必須 | 型・制約 | 説明 |
|---|---|---|---|
action | ○ | 文字列 | daily_article_ai_chat_send |
_wpnonce | ○ | 文字列 | daily_article_ai_chat で発行した nonce。nonce でも受け付ける |
post_id | ○ | 正整数 | 対象の daily_article 投稿 ID |
session_id | ○ | 正整数 | 対象セッション(当該 post_id に属すること) |
message | ○ | 非空文字列 | ユーザーの相談文 |
halls | ○ | 文字列配列、または JSON 配列文字列 | island / espasu / bigapple を 1 つ以上 |
fields | ○ | 文字列配列、または JSON 配列文字列 | pre / after を 1 つ以上 |
field_contents | − | JSON オブジェクト文字列(meta キー → HTML) | 画面上の現行考察本文。省略時は空マップ |
成功時 data
| 論理名 | 物理名 | 型 | 説明 |
|---|---|---|---|
| 返信文 | reply | string | チャットに表示する説明文 |
| 下書き | drafts | object | 選択された {hall}_{pre|after} キー → 段落 HTML(空オブジェクト可) |
| 根拠 | sources | array | 今回の返答で呼んだツール根拠(下記)。ツール未使用時は空配列 |
| セッション一覧 | sessions | array | 当該投稿のセッション一覧(タイトル更新後) |
| アクティブセッション | activeSessionId | number | 送信に使ったセッション ID |
| 履歴 | messages | array | 当該セッションの保存後メッセージ(下記) |
sessions[]
| 論理名 | 物理名 | 型 | 説明 |
|---|---|---|---|
| ID | id | number | セッション ID |
| タイトル | title | string | 空なら UI で「新しいチャット」 |
| 作成日時 | created_at | string | MySQL datetime |
| 更新日時 | updated_at | string | MySQL datetime |
sources[] / messages[].sources[]
assistant メッセージのみ。ツール未使用は空配列 []、旧データ・user は null(パネル非表示)。
| 論理名 | 物理名 | 型 | 説明 |
|---|---|---|---|
| ツール名 | tool | string | Tool Use の name(例: fetch_six_day_results) |
| 表示名 | label | string | 日本語ラベル |
| 引数要約 | args | string | 呼び出し引数の短い要約(例: date=…, halls=[…]) |
| 結果要約 | summary | string | ツール結果の短い要約(件数・日付・記事ID・機種例など) |
messages[]
| 論理名 | 物理名 | 型 | 説明 |
|---|---|---|---|
| ID | id | number | 行 ID |
| セッションID | session_id | number | 所属セッション |
| 役割 | role | string | user / assistant |
| 本文 | body | string | ユーザー文または reply |
| ホール | halls | string[] | 送信時点の選択ホール |
| 欄 | fields | string[] | 送信時点の選択欄(pre / after) |
| 下書き | drafts | object|null | assistant のみ。user は null |
| 根拠 | sources | array|null | assistant のみ。ツール未使用は []、旧データは null |
| 作成日時 | created_at | string | MySQL datetime |
失敗・ブロック(success: false)
| 条件 | message の内容 |
|---|---|
| AJAX コンテキスト外・nonce 不正 | Messages::AUTH_FAILED |
post_id が不正、または投稿タイプが daily_article でない | DailyArticleAiChatAjaxCopy::INVALID_POST |
edit_post 権限なし | Messages::PERMISSION_DENIED |
session_id が欠落・0 | DailyArticleAiChatAjaxCopy::SESSION_REQUIRED |
session_id が当該投稿に属さない | DailyArticleAiChatServiceCopy::SESSION_INVALID(Ajax 経由でそのまま返却) |
message が空 | DailyArticleAiChatAjaxCopy::MESSAGE_REQUIRED |
halls が空 | DailyArticleAiChatAjaxCopy::HALLS_REQUIRED |
halls に許可外 slug が含まれる | DailyArticleAiChatAjaxCopy::HALLS_INVALID |
fields が空 | DailyArticleAiChatAjaxCopy::FIELDS_REQUIRED |
fields に許可外値が含まれる | DailyArticleAiChatAjaxCopy::FIELDS_INVALID |
| Claude / Gemini 両方の API キー未設定(Service 例外) | DailyArticleAiChatServiceCopy::API_KEY_MISSING または GEMINI_API_KEY_MISSING(保存済みプロバイダ側の文言。詳細は error_log にも記録) |
| HTTP 429 / quota(Service 例外) | Messages::AI_LLM_CLAUDE_RATE_LIMITED / AI_LLM_GEMINI_RATE_LIMITED(応答から取れた待ち秒が 1〜120 なら「(約 N 秒後)」を付与。生レスポンスは出さない) |
| HTTP 401 / 403(Service 例外) | Messages::AI_LLM_CLAUDE_AUTH_FAILED / AI_LLM_GEMINI_AUTH_FAILED |
| HTTP タイムアウト・経過上限(Service 例外) | Messages::AI_LLM_CLAUDE_TIMEOUT / AI_LLM_GEMINI_TIMEOUT |
| 接続失敗(WP_Error、タイムアウト以外)(Service 例外) | Messages::AI_LLM_CLAUDE_CONNECTION_FAILED / AI_LLM_GEMINI_CONNECTION_FAILED |
| その他の HTTP 非 200(Service 例外) | Messages::AI_LLM_CLAUDE_HTTP_ERROR / AI_LLM_GEMINI_HTTP_ERROR(ステータスコードのみ。例: …(HTTP 500)。) |
| 応答切れ・履歴保存失敗・形式不正・ループ上限・セッション上限など | 対応する DailyArticleAiChatServiceCopy の固定文言(詳細は error_log) |
| 上記以外の Service 例外 | DailyArticleAiChatAjaxCopy::NOTICE_GENERIC_ERROR(詳細は error_log) |
上流 API のレスポンス本文や WP_Error の生メッセージは画面・JSON に載せない(Issue #3866)。ArticleAiLlmClient は ArticleAiLlmHttpErrorMode::ClientSafe で固定文言だけを例外に入れ、DailyArticleAiChatAjaxHandler は ArticleAiLlmClientErrorFilter で許可した文言以外を汎用文言に置き換える。上流の詳細は ExternalApiErrorLogFormatter の要約(HTTP ステータス・短い要約・ハッシュ)で error_log に残す。
権限
- ログイン必須(
wp_ajax_のみ。noprivは付けない) - capability:
edit_post(対象post_id)