株式会社ブレインパッド プロダクトユニットの shichi です。
ブレインパッドでは「データ活用の促進を通じて持続可能な未来をつくる」をミッションに、データ分析支援やSaaSプロダクトの提供を通じて、企業の「データ活用の日常化」を推進しています。
2025年はgpt-ossの発表もあり、ローカルPCで動く小型の言語モデルが注目を集めた年でもありました。同じ潮流がブラウザの世界でも進んでおり、ブラウザ環境でモデルダウンロードと推論を完結させる「ブラウザの組み込み AI」が進歩を遂げています。
今回は、この「ブラウザの組み込み AI」を使って、画面共有を入力としたデスクワークの作業レポートを自動生成するデモアプリを作ってみました。
ブラウザの組み込み AI
Google Chromeをはじめ、ブラウザで小型言語モデルを動かす流れが進んできました。Prompt APIという専用のAPI経由で言語モデルを利用できます。ChromeにはGemini Nanoが搭載され、Microsoft EdgeではPhi系モデルを利用できます。
ブラウザの組み込み AIには以下のメリットがあると考えます。
| メリット | どううれしい? |
|---|---|
| セキュア | データをクラウドに送らずに済むので、機密情報投入のハードルが低い。 |
| ほぼ無料 | 費用はPCの電気代のみ。API課金を気にせず試せる。 |
| 誰でも簡単 | モデルのセットアップ不要。コードを書けばすぐ動かせる。 |
今回作ったWebアプリ
今回のアプリのテーマは「パソコンの作業画面をGemini Nanoに実況してもらい、最後に作業レポートを書いてもらう」ことです。ブラウザはChromeを利用します。
以下のリンクからアクセスできます。
コンセプトは、業務中のパソコン画面のような機密情報が多い入力を、データを外に出さずに生成AIに処理させることです。組み込みAIのメリットを生かして、お手軽かつセキュアにこのコンセプトを実現します。
アプリの動作は至ってシンプルで、
- 画面共有を開始
- 一定間隔でフレームを切り出す
- フレームをPrompt APIに渡し、短い日本語要約を作る
- サマリが溜まったら、まとめてMarkdownの作業レポートにする
という流れです。実行間隔はUIで変えられるようにしています。データはlocalStorageに保存するので、仮にブラウザがクラッシュして続きから再開することになっても大丈夫です。
使い方
- 「録画を開始」を押してブラウザに画面共有を許可する
- 左ペインのスライダーでキャプチャ間隔・自動レポート間隔を調整する
- 右ペインのタイムラインで逐次生成される要約を確認し、必要なら手動で「レポート生成」
- ローカルデータを消したいときは「データをクリア」を実行
Prompt APIは執筆時点では実験段階であり、事前にchrome://flags で 以下のフラグを有効化する必要があります。URIをコピペして設定にアクセスしてください。
-
chrome://flags/#optimization-guide-on-device-model-
Enabled BypassPerfRequirementに設定
-
-
chrome://flags/#prompt-api-for-gemini-nano-
Enabledに設定
-
開発者ツールのコンソールから以下のコマンドを実行して、availableになっていれば問題ありません。
await LanguageModel.availability();
// > 'available'
実装のポイント
Screen Capture API による画面キャプチャ
Screen Capture API で画面共有を開始し、MediaStream を受け取ります。これを canvas 経由で画像にします。Prompt API に渡すために、PNG の Blob に変換します。
// 1) 画面共有を開始
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
audio: false,
});
// 2) MediaStream を video に流し込む
const video = document.createElement("video");
video.muted = true;
video.playsInline = true;
video.srcObject = stream;
// 3) video の現在フレームを canvas に描画して PNG Blob 化
const canvas = document.createElement("canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
const ctx = canvas.getContext("2d");
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
const frameBlob = await new Promise<Blob>((resolve, reject) => {
canvas.toBlob(
(b) => (b ? resolve(b) : reject(new Error("画像のBlob化に失敗しました"))),
"image/png"
);
});
Prompt APIによるキャプチャサマリ生成
切り出した画像を Prompt API に渡し、短い要約を生成します。Prompt API は画像と音声のマルチモーダル入力に対応しています。
Prompt APIでは、モデルの初期化コストを抑えるために、セッションの使い回しが可能です。システムプロンプトと入出力データの型・言語を指定したセッションを作成できます。
const CAPTURE_SUMMARY_SYSTEM = `
## タスク
あなたはユーザーのパソコン作業内容を記録するライターです。
画面スクリーンショットを根拠に、その時点でユーザーがしている作業を日本語で書いてください。
## 出力形式
- 出力はプレーンテキストで書いてください。見出しや強調などの書式は使いません。`;
const EXPECTED_OUTPUTS_JA = [{ type: "text", languages: ["ja"] }];
const EXPECTED_INPUTS_IMAGE = [{ type: "image" }];
let captureSummaryBase = null;
async function getCaptureSummaryBase() {
if (captureSummaryBase) {
// セッション作成済みの場合はキャッシュを返す
return captureSummaryBase;
}
// システムプロンプトと入出力データの型・言語を指定したセッションを作成
const created = await LanguageModel.create({
initialPrompts: [{ role: "system", content: CAPTURE_SUMMARY_SYSTEM }],
expectedInputs: EXPECTED_INPUTS_IMAGE,
expectedOutputs: EXPECTED_OUTPUTS_JA,
});
captureSummaryBase = created;
return created;
}
このセッションを、サマリ生成ごとにクローンします。今回は同じ処理を繰り返したいのでクローンしていますが、モデルとの会話履歴を保持したい場合は、同じインスタンスを利用することもできます。
const base = await getCaptureSummaryBase();
// サマリ生成のたびに clone して prompt
const session = await base.clone();
const summaryText = await session.prompt([
{ role: "user", content: [{ type: "image", value: frameBlob }] },
]);
session.destroy();
Prompt APIによる作業レポート生成
サマリを元にPrompt API で Markdown の作業レポートを生成します。
レポート生成は頻度が低いので、このアプリではセッションを保持しません。必要なときだけセッションを作って、生成が終わったら破棄します。
const REPORT_SYSTEM = `
## タスク
あなたは作業レポートを作る専門のライターです。
与えられた時系列の作業記録を根拠に、ユーザーの作業レポートを日本語Markdownで作成してください。
## 出力形式
- Markdownで書いてください。タイトルは「作業レポート」です。
- 各h2は作業区分として互いに重複しないように分けてください。
- 各見出し内は短い段落または箇条書きで、要点を2-5行にまとめます。
`;
const summaries = [
{
timestamp: Date.now(),
summary: "スプレッドシートでデータを整形し、集計条件を更新した。",
},
{
timestamp: Date.now() + 30_000,
summary: "ダッシュボードを確認し、数値の変化をチェックした。",
},
];
const logText = summaries
.map((s, index, arr) => {
const time = new Date(s.timestamp).toLocaleTimeString();
return `${time}\n${s.summary}`;
})
.join("\n\n");
const session = await LanguageModel.create({
initialPrompts: [{ role: "system", content: REPORT_SYSTEM }],
expectedInputs: [{ type: "text", languages: ["ja"] }],
expectedOutputs: [{ type: "text", languages: ["ja"] }],
});
const markdown = await session.prompt(logText);
session.destroy();
実際に使ってみた結果
今回は「このアプリを開発している最中の画面」をそのまま画面共有し、サマリとレポートがどれくらい実用になるかを見てみました(つまり、アプリがアプリ自身の開発ログを取る、という構図です。)
実行時間
サマリ生成は、1件あたり10~20秒程度でした。30秒間隔くらいで走らせれば、処理待ちが溜まりすぎずに実行し続けられそうでした。レポート生成はサマリより重く、1分程度かかっていました。
精度
画面上の大まかな作業内容はいい感じに推察してくれていました。少なくともコードを書いているのか、ブラウザを開いているのか程度の認識はできています。一方で完璧とは言えず、画面上の文言を完全に文字起こしして拾えるほどではありませんでした。
改善案として、画面キャプチャを分割したり、ワークフローを組んで処理を分担させたりすることで精度向上の余地はありそうだなと感じました。今後のモデル自体の性能向上にも期待したいと思います。
まとめ
Prompt APIを使うと、ブラウザ内蔵の言語モデルで推論を実行できます。
今回は、セキュリティを気にすることなく画面キャプチャから作業レポートを生成するアプリを作ってみました。
精度はまだ発展途上で、細部の読み取りや文脈の保持には限界があります。ただ、オンデバイスでこの体験ができること自体が驚きで、ブラウザ内蔵モデルも実用の領域に入ってきた印象です。
機会があれば音声入力も試してみたいと思います。
実装コード

