◉RORK LABEN
●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…●GPT-6.1 SOL — Rork のモデルメニューに追加(09-29)。Low/Medium/High を選べ、Pro・Max に含まれます●SONNET 5.5 — UI づくりが得意で、Sonnet 5 より出力が速いモデルが選べます(09-28)●SDK 58 — Beta が 09/15 から。stable の案内はまだなく、Expo Go でのプロジェクト実行は 09/03 からログインが必要です●WIDGET — iOS のウィジェットが本番ビルドだけ真っ黒になる原因を追った報告が出ています●OBSERVE — EAS Observe がネイティブクラッシュも記録します(SDK 57.0.21 以降・10/07)●NEW — 起動広告が、背面から戻った回にしか出ていませんでした。「前面に戻った」合図が、…
記事一覧/AIモデル
◉ AIモデル/2026-03-27上級

Rork × マルチモーダルAI:カメラ・音声・テキストを統合したインテリジェントアプリ設計パターン

Rork でカメラ画像認識・音声入力・テキスト解析を統合したマルチモーダルAIアプリを構築する設計パターンを解説。入力統合レイヤーからAIオーケストレーション、UXフローまで実装コード付きで詳しく紹介します。

Rork585マルチモーダルAIカメラ音声認識4テキスト解析Core ML6Whisper4Gemini8アプリ設計パターン上級7

✦ プレミアム記事

取り組みの背景 — 単一入力で詰まる前に整えておく層

カメラを呼び出すボタンを置き、音声入力のマイクボタンを置き、テキスト欄を置く——3つそろえた瞬間に、画面はもう成立しなくなります。個人開発でアプリを運用していると、入力手段を1つ足すたびに同じ壁に突き当たりました。「次の機能を足すとUIが破綻する」という感覚が、機能追加のたびに先に来るようになったのです。

問題は「複数の入力を並べた」ことではなく、入力を統合する「層」を持たずに UI 側で繋ごうとしたことでした。マルチモーダルAIアプリで実際に難しいのは、Gemini や Whisper を呼ぶことではありません。入力の意味的な順序、優先度、コスト境界、フォールバックを、UIから離れた1か所に閉じ込めることです。

この記事は、Rork と Rork Max でカメラ・音声・テキストを束ねる設計パターンを、私自身が壁紙系・癒し系・引き寄せ系アプリで踏んできた失敗のうえで書き直したものです。コードは実運用で動いている形を、判断基準は実測値を、それぞれ可能な範囲で開示します。

この記事の対象読者:

  • Rork でAI機能を実装した経験があり、次のステップを模索している方
  • 複数のAIモデル(Gemini、Claude、Core ML)を組み合わせたアプリを作りたい方
  • マルチモーダル入力の状態管理やUX設計に課題を感じている方

従来の記事では個別のモダリティ(カメラ・ギャラリー機能ガイド、Whisper × Claude による会議メモアプリ、Claude API連携)を取り上げてきましたが、ここではこれらを統合するアーキテクチャに焦点を当てます。


マルチモーダル入力統合レイヤーの設計

なぜ統合レイヤーが必要なのか

カメラ、音声、テキストの各入力をそれぞれ独立に処理すると、以下の問題が発生します。

  1. コンテキストの断絶: ユーザーが画像を撮影した後に音声で質問しても、画像の文脈が音声処理へ渡りません
  2. 状態管理の複雑化: 3種類の入力状態が分散し、UIの整合性が崩れやすくなります
  3. AIモデルへの入力構築が煩雑: 各モダリティのデータを手動で組み立て、プロンプトへ詰め込む手間がかかります

これらを解決するのが Unified Input Layer(統合入力レイヤー) パターンです。

Unified Input Layer の構造

// types/multimodal.ts — マルチモーダル入力の型定義
 
export interface ModalityInput {
  type: 'image' | 'audio' | 'text';
  timestamp: number;
  data: ImageInput | AudioInput | TextInput;
  metadata?: Record<string, unknown>;
}
 
export interface ImageInput {
  uri: string;
  base64?: string;
  width: number;
  height: number;
  mimeType: string;
}
 
export interface AudioInput {
  uri: string;
  transcription?: string;       // Whisper で変換済みのテキスト
  durationMs: number;
  language?: string;
}
 
export interface TextInput {
  content: string;
  intent?: 'question' | 'command' | 'context';
}
 
// 統合コンテキスト — AI に渡す最終的な入力
export interface MultimodalContext {
  sessionId: string;
  inputs: ModalityInput[];
  conversationHistory: ConversationTurn[];
  userPreferences: UserPreferences;
}

このように、すべての入力を ModalityInput として正規化し、MultimodalContext に集約します。AIモデルはこの統合コンテキストだけを受け取れば、入力の種類を意識せずに処理できます。

入力キューとバッチ処理

ユーザーが短時間に複数のモダリティを使う場合(画像を撮影→即座に音声質問)、入力をキューに溜めてバッチ処理する設計が有効です。

// hooks/useMultimodalQueue.ts
 
import { useState, useCallback, useRef } from 'react';
import { ModalityInput, MultimodalContext } from '../types/multimodal';
 
const BATCH_DELAY_MS = 1500; // 1.5秒の猶予期間
 
export function useMultimodalQueue(sessionId: string) {
  const [queue, setQueue] = useState<ModalityInput[]>([]);
  const [isProcessing, setIsProcessing] = useState(false);
  const timerRef = useRef<NodeJS.Timeout | null>(null);
 
  const enqueue = useCallback((input: ModalityInput) => {
    setQueue(prev => [...prev, input]);
 
    // タイマーをリセット — 連続入力を待つ
    if (timerRef.current) clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => {
      flushQueue();
    }, BATCH_DELAY_MS);
  }, []);
 
  const flushQueue = useCallback(async () => {
    setIsProcessing(true);
    const currentQueue = [...queue];
    setQueue([]);
 
    const context: MultimodalContext = {
      sessionId,
      inputs: currentQueue,
      conversationHistory: [],   // 実装時は会話履歴を注入
      userPreferences: {},       // 実装時はユーザー設定を注入
    };
 
    try {
      const response = await processMultimodalInput(context);
      // AI 応答の処理
      return response;
    } finally {
      setIsProcessing(false);
    }
  }, [queue, sessionId]);
 
  return { enqueue, isProcessing, queueSize: queue.length };
}

BATCH_DELAY_MS(1.5秒)は、ユーザーが画像を撮影した直後に音声で補足する典型的な操作パターンに基づいた値です。実際のアプリではA/Bテストで調整してください。


✦

ここまでお読みいただきありがとうございます。

この記事の続きを読む

この先には、実装コードやベンチマーク結果など、実務でお役に立てる内容をご用意しています。このサイトは広告を掲載しておらず、サーバーや開発にかかる費用はメンバーの皆様のご支援で成り立っています。もしお役に立てていましたら、ご支援いただけますと大変ありがたいです。

この記事で得られること
✦カメラ・マイク・写真の権限を Just-in-Time で要求し、拒否されても機能を残す縮退設計の実装パターン
✦Gemini と Claude の使い分け、Core ML フォールバック、コスト管理の実測値ベースの判断基準
✦公式ドキュメントに書かれていない、本番運用で気づいた落とし穴と回避パターン
Stripe による安全な決済 · いつでもキャンセル可能
✦

この記事を購入する

この先の内容をすべてお読みいただけます。一度のご購入で、いつでも何度でもアクセスできます。このサイトは広告を掲載しておらず、皆さまのご支援がサーバー費用などの運営を支えています。

または
メンバーシップなら全記事が読み放題 →
シェア

お読みいただきありがとうございます

Rork Lab は広告なしで運営しており、サーバー費用などの運営コストはメンバーシップのご支援で賄っています。実装コード・ベンチマーク・本番設計パターンなど、実務でお役立ていただける記事を毎日更新しています。もし読んでよかったと感じていただけましたら、ぜひご覧ください。

  • ✦コピー&ペーストで使える実装コード付き
  • ✦毎日新しい上級ガイドを追加
  • ✦¥580/月 または ¥1,480 の永久アクセス
メンバーシップを見る →

関連記事

◉ AI モデル2026-09-17
推奨された移行先が、すでに停止していました — Gemini の廃止表 74 行を突き合わせた記録
Gemini の廃止表を突き合わせたところ、推奨代替として書かれたモデル自体がすでに停止している行が5件ありました。10月2日に消える gemini-2.5-flash-image もその一つです。移行先の確かめ方と、404 の受け皿の置き方をまとめました。
◉ AI モデル2026-07-17
3分の動画だけが失敗する — Rork の動画解析をワーカー経由から端末直送に引き直す
Gemini Files API に動画を渡す経路を、Cloudflare Workers 中継から端末直送へ引き直した記録です。128MB のメモリ上限に当たる仕組み、resumable upload の発行だけを残す実装、Expo SDK 54 での書き換え、20GB の保存枠と請求の見立てまでをまとめます。
◉ AI モデル2026-05-05
Rork Max で AI 面接コーチアプリを作る:音声録音・Claude 評価・進捗管理の実装ガイド
Rork Maxで音声録音、Whisperによる文字起こし、Claude APIでの回答評価を組み合わせたAI面接コーチアプリを構築します。Cloudflare Workersでの評価API実装、セッション管理と進捗トラッキング、フリーミアム課金設計、本番環境の注意点まで一気通貫で扱います。