
音声ベースの探偵尋問ゲーム。 Mistral Large 3 + Voxtral STT + ElevenLabs TTS。 Mistral Worldwide Hackathon 2026 のために構築されました。

音声ベースの探偵尋問ゲーム。あなたは探偵。Mistralは嘘をついている容疑者です。あなたの仕事は、尋問だけで嘘を見抜くことです。
すべてのケースは手続き的に生成されます——ユニークなホワイトカラー犯罪、容疑者、隠れ話、そして一つだけ隠された嘘。容疑者はMistral Largeによって演じられ、完全なバックストーリーが与えられ、敵対的なプレッシャーの下でそれを守るよう指示されています。二つと同じケースはありません。
Mistral Worldwide Hackathon 2026(オンライントラック)のために構築されました。
"Mistralは推論できる。私はそれを嘘つきにした。あなたの仕事はそれを見破ることだ。"
AIは決して自白しないよう指示されています。最大ストレス時でも。容疑者が折れるのではなく、具体的で正確な告訴を行うことで勝利します。
npm install
cp .env.example .env # APIキーを入力してください
npm run dev # http://localhost:3000
MISTRAL_API_KEY= # 必須 — ケース生成、尋問、評価、STT
ELEVENLABS_API_KEY= # 必須 — 容疑者の声のTTS
ELEVENLABS_VOICE_ID= # オプション — 特定のElevenLabs音声ID
NEXT_PUBLIC_SUPABASE_URL= # 必須 — SupabaseプロジェクトURL
NEXT_PUBLIC_SUPABASE_ANON_KEY= # 必須 — Supabase匿名キー(RLS保護)
SUPABASE_SERVICE_ROLE_KEY= # オプション — 管理者エクスポートエンドポイント
EXPORT_SECRET= # オプション — 管理者エクスポート認証
APIキーは実行時に設定ページでも構成可能です。アプリはキーなしで出荷され、プレイヤーが自分のキーを持ち込みます。
npm run dev # 開発サーバー
npm run build # プロダクションビルド
npm run start # プロダクションサーバー
npm run lint # ESLint
無制限タイマーモードも利用可能。Hard/Expertでは、高ストレスのやり取りが4回連続で続くと容疑者は弁護士を呼びます。
手がかりは1〜9に分散されたストレッショルドで解放されます。条件:
告訴ボタンは必要な手がかりをすべて収集した後にのみロック解除されます。
score = timeScore x difficultyMultiplier x efficiencyBonus x hintPenalty x accusationPenalty
timeScore = 1000 x sqrt(max(0, 1 - elapsed / (parTime x 2)))
multiplier = easy 1.0x, medium 1.5x, hard 2.0x, expert 2.5x
efficiencyBonus = 1.0-1.5x (パーよりも質問が少ない = ボーナス)
hintPenalty = 0.85^hintsUsed
accusePenalty = max(0, 1 - wrongAccusations x 0.1)
スコアは勝利時にフリーズした統計からサーバー側で計算されます。クライアントの値は無視されます。
app/
├── page.tsx # タイトル画面
├── cases/ # ケース選択 — 場所 + 難易度
├── game/
│ ├── page.tsx # メインゲームオーケストレーター
│ ├── hooks/ # useVoiceRecorder, useTTS, useGameTimer, useSfx, useSettings
│ ├── components/ # Dock, TopBar, CaseFile, SuspectZone, BriefingScreen, ダイアログ
│ ├── win/ # 勝利画面 + イニシャル入力
│ └── lose/ # 敗北画面
├── leaderboard/ # トップ20、新エントリーアニメーション
├── settings/ # APIキー設定、エクスポート、設定
├── help/ # 遊び方、スコアリング、概要
├── about/ # 制作者情報
└── api/
├── generate-case/ # GET — Mistralケース生成
├── interrogate/ # POST — プレイヤーの質問 → 容疑者の応答
├── accuse/ # POST — 告訴評価(別の審判)
├── evaluate/ # POST — 勝敗分析
├── hint/ # POST — 難読化されたストレストリガーヒント
├── tts/ # POST — ElevenLabs TTS
├── transcribe/ # POST — Voxtral STT
├── leaderboard/ # GET/POST — Supabaseリーダーボード
├── patterns/ # GET/POST — セッション間学習パターン
└── export/ # GET — 管理者JSONLエクスポート
src/lib/
├── mistral/ # Mistralクライアント、尋問、評価、ケース生成、埋め込み
├── game-session.ts # サーバー側セッションストア、勝利トークン、エクスポート
├── game-state.ts # 型定義
├── scoring.ts # スコア計算 + 探偵評価
├── sanitize.ts # 入力検証、インジェクション検出
├── db.ts # Supabaseクライアント
└── rate-limit.ts # IPごとのレート制限
このゲームは敵対的AIをプレイヤー入力に対して実行します。セキュリティは後付けではなく中核機能です。
入力サニタイズ: 30以上の正規表現インジェクションパターン、Unicode正規化(NFKD)、ゼロ幅文字除去、base64ペイロード検出、支離滅裂/非英語ブロック。
出力スキャン: AI応答をケース秘密情報とファジーマッチングでチェック(40%閾値、ストップワード除外)。漏洩した応答は回避応答に置き換え。
審判の分離: 告訴評価は専用システムプロンプト、ランダム化された境界トークン、インジェクションマーカー除去を含む別のMistral呼び出しを使用。審判呼び出しはプレイヤー提供のAPIキーを使用しません。
ストレス強制: サーバー側単調クランプ——ストレスは上昇のみ、1ターン最大+1。手がかり閾値はサーバー側で強制。AIはゲームゲートを操作するためにストレスを急上昇または低下させることはできません。
勝利トークン: 128ビットランダム、タイミングセーフ比較、1回限り、30分TTL。スコアはサーバー側統計スナップショットから計算——クライアント報告値は無視。
セッションセキュリティ: 192ビットランダムID、ミューテックスロック、1時間TTL、最大5000セッション、LRU退避。タイマーモードは作成時に固定。
TTS検証: アクティブなセッションが必要。テキストは最近のアシスタントメッセージと一致する必要があります。無料TTSプロキシ乱用を防止。
RAGポイズニング対策: セッション間で学習された戦術は、プロンプトに含める前にインジェクション検出とサニタイズを通じてフィルタリング。
完了したゲームはSupabaseに保存され、分析とモデル改善に使用されます:
GET /api/export?limit=100&offset=0&outcome=win&difficulty=hard、ヘッダーに Authorization: Bearer <EXPORT_SECRET>EXPORT_SECRET=xxx npx tsx scripts/export-data.ts --output=data/export.jsonlノワール探偵の美学。ダーク、ミニマル、タイポグラフィック。JetBrains Mono。ピクセルアートの背景と容疑者の肖像画。チャットバブルはなし——ダイアログはシーン内のスタイル付きテキストとして表示。
leaderboard テーブルを作成:
CREATE TABLE leaderboard (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
player_name text NOT NULL,
case_number text,
case_setting text,
suspect_name text,
time_remaining int,
stress_level int,
clues_found int,
hints_used int,
accusations_used int,
detective_rating text,
score int NOT NULL,
created_at timestamptz DEFAULT now()
);
ALTER TABLE leaderboard ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Public read" ON leaderboard FOR SELECT USING (true);
CREATE POLICY "Public insert" ON leaderboard FOR INSERT WITH CHECK (true);
トレーニングデータ用のオプションの game_exports テーブル:
CREATE TABLE game_exports (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
session_id text UNIQUE NOT NULL,
case_data jsonb NOT NULL,
conversation jsonb NOT NULL,
outcome text NOT NULL,
difficulty text NOT NULL,
setting text,
stats jsonb NOT NULL,
accusation_text text,
accusation_correct boolean,
created_at timestamptz DEFAULT now()
);
ALTER TABLE game_exports ENABLE ROW LEVEL SECURITY;
CREATE POLICY "anon_insert" ON game_exports FOR INSERT TO anon WITH CHECK (true);
CREATE POLICY "no_public_read" ON game_exports FOR SELECT TO anon USING (false);
セッション間学習用のオプションの interrogation_patterns テーブル:
CREATE TABLE interrogation_patterns (
id uuid DEFAULT gen_random_uuid() PRIMARY KEY,
session_id text UNIQUE NOT NULL,
setting text,
difficulty text NOT NULL,
outcome text NOT NULL,
questions jsonb,
effective_questions jsonb,
max_stress int,
clues_found int,
time_elapsed int,
embedding vector(1024),
created_at timestamptz DEFAULT now()
);
ALTER TABLE interrogation_patterns ENABLE ROW LEVEL SECURITY;
CREATE POLICY "anon_insert" ON interrogation_patterns FOR INSERT TO anon WITH CHECK (true);
CREATE POLICY "anon_read" ON interrogation_patterns FOR SELECT TO anon USING (true);
Mistral Worldwide Hackathon 2026 — オンライントラック、「Anything Goes」カテゴリ。
審査基準: 創造性/独自性(最も重要)、将来性、技術的実装、ピッチの質。
特別賞: Best Mistral Vibe(AirPods)、Best Voice AI(ElevenLabs 6ヶ月サブスクリプション)。
スポンサー: Mistral、ElevenLabs、NVIDIA、AWS、Hugging Face、Jump Trading、Weights & Biases、Giant、Raise、Tilde Research、White Circle。
ほとんどのハッカソンAIプロジェクトはアシスタントやチャットボットです。これはその逆です——AIはあなたを助けるのではなく、あなたに嘘をついています。プレイヤーはモデルにとって協力者ではなく敵対者です。これにより根本的に異なる相互作用が生まれます:助けを求めるのではなく、矛盾を探り、圧力をかけ、行動の手がかりを読み取るのです。
また、このゲームはトレーニングデータを生成します。完了した各セッション——尋ねられた質問、ストレスの進行、どの戦術が効果的だったか、どれが効果的でなかったか——はJSONLとしてエクスポート可能です。これによりフィードバックループが生まれます:ゲームをプレイし、データをエクスポートし、モデルを微調整し、捕まえにくくするのです。
Jason Poindexter — バルセロナからのオンライントラック、単独エントリー。
| レベル | 手がかり | 制限時間 | 容疑者の行動 |
|---|
| Easy | 2 | 5分 | 明らかな嘘、緊張 |
| Medium | 3 | 7分 | 見破れる嘘、落ち着いている |
| Hard | 4 | 9分 | 微妙な嘘、巧みな回避者 |
| Expert | 5 | 10分 | 深く埋められた嘘、操作的な態度 |