| # GAHAKU EXAM 仕様書(実装準拠 v1.2) |
|
|
| ## 1. 概要 |
|
|
| プレーヤーにランダムで1つの英単語(お題)を与え、プレーヤーはPyxelベースのドット絵エディタでその単語を表現する。 |
| 描いたドット絵をAIへ入力し、推論結果の上位5件にお題語が含まれていれば成功とする。 |
|
|
| ゲームの目的は「できるだけ少ないドット数でAIに正解させること」。 |
|
|
| ## 2. 対象プラットフォーム |
|
|
| - デプロイ先: Hugging Face Spaces |
| - SDK: Gradio |
| - 描画エンジン: Pyxel(pyxel.js経由でWeb実行) |
| - 推論: Hugging Face Inference API(VLM優先 + フォールバック) |
|
|
| ## 3. 用語定義 |
|
|
| - お題: プレーヤーに提示される英単語 |
| - キャンバス: ドット絵を描く領域(16x16) |
| - ドット数: 背景色以外で塗られたセル数 |
| - 試行: 1回のAI判定リクエスト |
| - ラウンド: 1つのお題に対する挑戦単位 |
|
|
| ## 4. ゲームルール |
|
|
| 1. ゲーム開始時に英単語を1つランダム出題する。 |
| 2. プレーヤーは24色パレットを使い、マウスまたはタッチでドット絵を描く。 |
| 3. Pyxel内の `EXPORT` で描画データを `window.__PYXEL_PAYLOAD` に保存する。 |
| 4. Gradio側の `Sync from Pyxel`(日本語UIでは `Python側へ取り込む`)で受信確認できる。 |
| 5. `Judge with AI`(日本語UIでは `AIで判定する`)でAI判定を行う。 |
| 6. AI上位5候補にお題語が含まれる場合は成功。 |
| 7. 含まれない場合は失敗カウントを1増やす。 |
| 8. 失敗が3回に達した時点でラウンド失敗(ゲームオーバー)。 |
| 9. `Next Round`(日本語UIでは `次のラウンド`)で次ラウンドへ進む。 |
|
|
| ## 5. 機能要件 |
|
|
| ### 5.1 お題出題 |
|
|
| - お題辞書(英単語リスト)からランダムに1語を選択。 |
| - 同一ラウンド中はお題を固定。 |
| - 前ラウンドと同じ単語は可能な限り連続しないよう回避(候補数が2語以上の場合)。 |
|
|
| ### 5.2 ドット絵エディタ |
|
|
| - キャンバスサイズ: 16x16セル(固定) |
| - 画面サイズ: `pyxel.init(310, 220)` |
| - パレット: 論理24色 |
| - 実行環境が16色のみ対応の場合: |
| - 17〜24色相当はディザリングで近似表示 |
| - 入力方式: |
| - マウス: クリック/ドラッグ |
| - タッチ: タップ/スワイプ |
| - 基本ツール: |
| - ペン |
| - 消しゴム |
| - 全消去 |
| - EXPORT |
| - 画面表示: |
| - 使用ドット数(リアルタイム) |
| - 操作ガイド(`TOUCH/DRAG TO DRAW`) |
|
|
| ### 5.3 AI判定 |
|
|
| - 入力: キャンバス画像(PNG, 224x224へ最近傍拡大) |
| - 推論フロー(優先順): |
| 1. VLMチャット補完(候補モデルを順に試行) |
| 2. Zero-shot image classification(provider live のみ) |
| 3. 画像分類モデル(`google/vit-base-patch16-224`) |
| - provider live 判定: |
| - Hugging Face model info の `inferenceProviderMapping` を参照 |
| - モデル×タスク結果をキャッシュ |
| - 出力: |
| - 上位5候補(`label`, `score`) |
| - VLM経路では順位ベース擬似スコアを付与 |
| - 正誤判定: |
| - ラベルとお題語を正規化(小文字化、記号除去、空白正規化) |
| - 上位5件内に一致があれば正解 |
|
|
| ### 5.4 スコアリング |
|
|
| - 成功時にラウンドスコアを確定。 |
| - 計算式: |
|
|
| `score = max(0, BASE_SCORE - DOT_PENALTY * used_dots - MISS_PENALTY * miss_count)` |
|
|
| - 定数: |
| - `BASE_SCORE = 1000` |
| - `DOT_PENALTY = 8` |
| - `MISS_PENALTY = 120` |
|
|
| ### 5.5 失敗条件 |
|
|
| - 不正解が3回でラウンド失敗。 |
| - 失敗時もAI上位5結果は表示される(取得できた場合)。 |
|
|
| ### 5.6 多言語対応(実装済み) |
|
|
| - UI言語: 日本語 / 英語 |
| - 言語切替: Gradioのラジオボタン |
| - 切替対象: |
| - イントロ文 |
| - ボタンラベル |
| - テキスト/JSONのラベル |
| - ラウンド情報表示 |
| - ステータスメッセージ |
| - 既定言語: 英語 |
|
|
| ### 5.7 判定演出(実装済み) |
|
|
| - Pyxel側に演出状態を保持(`idle / judging / success / fail`)。 |
| - `Judge with AI` 押下時に `judging` へ遷移。 |
| - `Next Round` 押下時に `idle` へリセット。 |
| - Pyxel上に簡易アニメーションと文言を表示: |
| - `AI JUDGING...` |
| - `CORRECT!` |
| - `NOT YET` / `TRY AGAIN` |
|
|
| ## 6. 画面仕様(現行) |
|
|
| ### 6.1 メイン画面 |
|
|
| - サイドバー(Spaces時のみ): |
| - Loginボタン |
| - ヘッダ行: |
| - 左: タイトルと手順 |
| - 右: 言語トグル(日本語/English) |
| - エディタ表示: |
| - Pyxelキャンバス埋め込み |
| - ヘルプ文 |
| - ラウンド情報: |
| - Round / お題(Target) / 状態 / ミス / 使用ドット / ラウンドスコア / 合計スコア |
| - 操作行: |
| - `Sync from Pyxel` |
| - `Judge with AI` |
| - `Next Round` |
| - 情報表示: |
| - Statusテキスト |
| - Received JSON(開発表示) |
| - AI Top 5 |
|
|
| ### 6.2 ボタン活性 |
|
|
| - `Next Round` は常時押下可能。 |
| - ラウンドが `success` または `fail` のとき、同一ラウンドへの再判定は拒否してメッセージを返す。 |
|
|
| ## 7. 状態管理 |
|
|
| ### 7.1 ラウンド状態(Gradio State) |
|
|
| - `round_id` |
| - `round_number` |
| - `target_word` |
| - `miss_count` |
| - `round_result`(`ongoing` / `success` / `fail`) |
| - `used_dots` |
| - `round_score` |
| - `total_score` |
| - `last_top5_predictions` |
|
|
| ### 7.2 UI補助状態 |
|
|
| - `lang_state`(`ja` / `en`) |
| - `window.__PYXEL_PAYLOAD`(Pyxel→Gradio受け渡し) |
| - `window.__AI_JUDGE_STATE`(演出状態連携) |
|
|
| ## 8. 外部連携仕様 |
|
|
| ### 8.1 Inference API |
|
|
| - 認証: |
| - Spaces: OAuthトークン優先 |
| - ローカル: `HF_TOKEN` 環境変数 |
| - 主な利用API: |
| - Chat Completions(VLM) |
| - Zero-shot image classification |
| - Image classification |
| - タイムアウト: |
| - provider確認: 10秒 |
| - リトライ: |
| - 同一モデルへの自動リトライはなし |
| - モデル切替フォールバックで継続 |
|
|
| ### 8.2 モデル選定 |
|
|
| - 第一候補VLM: `Qwen/Qwen3-VL-8B-Instruct` |
| - 代替VLM候補あり(provider liveのみ実行) |
| - Zero-shot候補: |
| - `openai/clip-vit-large-patch14` |
| - `openai/clip-vit-base-patch32` |
| - 最終フォールバック: |
| - `google/vit-base-patch16-224` |
|
|
| ## 9. 非機能要件 |
|
|
| - 操作性: |
| - PC/スマートフォン対応 |
| - Pyxel表示領域は `31:22` の比率で表示 |
| - セキュリティ: |
| - トークンはクライアントへ露出しない |
| - ロギング: |
| - 判定フローをコンテナログへ出力 |
| - 例: `judge_start`, `vlm_try`, `vlm_success`, `fallback_to_image_classification` |
|
|
| ## 10. 受け入れ基準(現行実装) |
|
|
| 1. ラウンド開始時に英単語がランダム表示される。 |
| 2. 24色・16x16のドット絵編集がマウス/タッチで可能。 |
| 3. `EXPORT` → `Sync from Pyxel` でJSON受信確認ができる。 |
| 4. `Judge with AI` 実行でAI上位5ラベルが表示される。 |
| 5. 上位5にお題語が含まれると成功判定になる。 |
| 6. 不正解3回で失敗終了になる。 |
| 7. 成功時スコアがドット数とミス数を反映して算出される。 |
| 8. 第一候補VLMが利用可能な場合はVLM経路で判定できる。 |
| 9. 第一候補VLMが利用不能でもフォールバック経路で継続判定できる。 |
| 10. 日本語/英語UI切替が機能する。 |
| 11. `Next Round` 押下で判定演出が `idle` にリセットされる。 |
|
|
| ## 11. 既知の制約 |
|
|
| - `Received JSON` は開発向け表示として常時表示される。 |
| - 演出の成功/失敗遷移は `status_box.change` フックに依存するため、接続経路やUI更新順によって見え方が変わる場合がある。 |
|
|
| ## 12. 今後拡張候補 |
|
|
| - 難易度別お題セット |
| - 制限時間モード |
| - ランキング機能 |
| - お題に対する禁止色/使用色制限 |
| - 複数ラウンド合計スコア制 |
| - 開発用表示(Received JSON)の表示切替 |
|
|