Skip to content

feat: initial implementation of on-device Japanese proofreader Chrome extension (Phase 0-4) - #1

Merged
kokoichi206 merged 3 commits into
mainfrom
feat/initial-implementation
May 30, 2026
Merged

kokoichi206 merged 3 commits into
mainfrom
feat/initial-implementation

Conversation

@kokoichi206

@kokoichi206 kokoichi206 commented May 30, 2026 •

Copy link
Copy Markdown
Member

概要

完全ローカルの Gemini Nano で、Web 上の <textarea> / <input type=text> に打った日本語の
誤字脱字・文法・不自然さを検出し、波線 + ツールチップで「直す/直さない」をユーザーに委ねる
Chrome 拡張の初期実装です。クラウドに一切送らず、自動訂正もしません(Grammarly 方式)。

段階的実装(Phase 0-4)

  • Phase 0 phase0/: Nano の日本語校正精度を実機検証する go/no-go ハーネス。
    → 実機結果: 正しい文への誤検出 0/6、各文 0.25〜2.8s、誤字/文法は捕捉(不自然系は弱い)。GO。
  • Phase 1/2: WXT 足場(background/content/popup)+ 入力検出 + IME 確定/デバウンス監視。
  • Phase 3 src/overlay/: オーバーレイ mirror 描画。textarea の computed style を複製した
    不可視 div に getClientRects() で範囲矩形を測り、position:fixed のコンテナ +
    translate(-scroll) のハイライト層で波線をスクロール同期。ツールチップ、controlled-input
    安全な範囲置換。実機で位置精度・折り返し・適用を確認済み。
  • Phase 4 src/ai/: Prompt API(LanguageModel)接続。reason は遅延取得(構造化出力の JSON
    破損対策)、AbortSignal タイムアウト、availability 状態機械。GitHub のコメント欄で実 Nano
    動作を確認済み
    (content script の isolated world から LanguageModel 利用可)。

技術スタック

  • WXT + TypeScript(strict)+ pnpm。AI クライアントは ProofreadEngine 共通インターフェースで、
    将来の Proofreader API への差し替えを想定。
  • lint/format/tsconfig/CI は既存サンプル(chrome-extension-google-search-navigator)の流儀に準拠。

検証

  • pnpm compile(tsc) / pnpm lint / pnpm format:check / pnpm build すべて green。
  • ユニットテスト 17 件(vitest + jsdom)green: normalize(オフセット検証/補正/破棄)・
    detect(対象/機密判定)・apply(original ガード)・mock。CI に pnpm test を追加。
  • Phase 0(精度)・Phase 3(波線位置)・Phase 4(GitHub での実 Nano)を実機で確認。

コードレビュー(codex)と対応

codex CLI で 4 観点(セキュリティ/パフォーマンス/ベストプラクティス/設計整合性)を並列レビューし、
正確性・安全性に関わる指摘を本 PR 内で修正済み(2 つ目のコミット):

  • AI 出力の実行時バリデーション(型/範囲/enum)+ original が一意な時のみ位置補正
  • 置換前ガード(slice===original)でツールチップ表示後の入力変化による誤置換を防止
  • JSON 破損と推論失敗(timeout)の区別、parse 失敗のみリトライ
  • ライフサイクル破棄(MutationObserver で要素切断時に dispose)、ensureReady 競合ガード
  • 機密入力欄(otp/cc/password/token 等)を対象外に
  • 推論の直列化 + 同一テキスト skip + seq ガード、理由のキャッシュ

follow-up(別 PR 予定)

  • 全サイト常時 → サイト単位の opt-in 化 + popup 設定 UI
  • unnatural 型を既定オフ(過剰訂正の抑制、高確信バイアス)
  • mirror 測定の単一パス化(perf)、explain を局所文脈のみに(最小データ)
  • capability ベースのエンジン抽象化(Proofreader API への差し替え整備)
  • テストの拡充(overlay の座標計算・entrypoints の結線)

既知の制約

  • 日本語 Proofreader API は Chrome 149+ 必須。本実装は Chrome 148 +
    chrome://flags/#prompt-api-for-gemini-nano = "Enabled multilingual" + モデル DL 済みで動作。
  • v1 は textarea / 単純な input[type=text] のみ。contenteditable(Gmail/X/Notion)・Google Docs は対象外。

🤖 Generated with Claude Code

kokoichi206 and others added 2 commits May 31, 2026 02:14
完全ローカルの Gemini Nano で textarea/input の日本語を校正し、波線+ツールチップで
提案する Chrome 拡張。クラウド送信なし、自動訂正なし(Grammarly 方式)。

- Phase 0: Nano 日本語精度の検証ハーネス (phase0/, コンソール用 + 手順)
- Phase 1/2: WXT 足場 (background/content/popup) + 入力検出 + IME/デバウンス監視
- Phase 3: オーバーレイ mirror 描画 (波線・座標マッピング・スクロール/リサイズ同期・
  ツールチップ・controlled-input 安全な範囲置換)
- Phase 4: Prompt API(LanguageModel) 接続。reason は遅延取得、AbortSignal タイムアウト、
  JSON parse リトライ、stale ガード、availability 状態機械

技術: WXT + TypeScript(strict) + pnpm。AI クライアントは共通インターフェースで
Proofreader API への差し替えを想定。lint/format/CI はサンプルの流儀に準拠。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
codex による多観点レビューで挙がった正確性・安全性の問題を修正:

- AI 出力を未信頼データとして検証(src/ai/normalize.ts): 型/範囲/enum を実行時チェック、
  original が一意に出現する場合のみ位置補正(複数出現での誤補正を防止)
- 置換前ガード(src/apply/replace.ts): current.slice(start,end)===original を確認してから
  置換し、ツールチップ表示後の入力変化による誤置換を防ぐ
- JSON 破損と推論失敗(timeout/abort)を区別(src/ai/promptClient.ts): runStructured の例外は
  伝播させ、JSON parse 失敗のみ1回リトライ(根本原因を握りつぶさない)
- ensureReady の競合ガード(生成中 Promise の共有で多重 create を防止)
- 機密入力欄(otp/cc/password/token 等)を校正対象から除外(src/input/detect.ts)
- ライフサイクル: Map + MutationObserver で要素切断時に watcher/renderer を dispose
- 推論の直列化 + 同一テキスト skip + seq ガードで stale 表示と無駄な推論を防止
- ensureEngine は非 READY 時に状態をリセット(popup で DL 後、再フォーカスで再判定)
- 理由(reason)を指摘単位でキャッシュし hover ごとの再生成を防止、失敗は console.warn
- availability/create の言語リストを共有(INPUT_LANGUAGES/OUTPUT_LANGUAGES)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kokoichi206 kokoichi206 self-assigned this May 30, 2026
@kokoichi206 kokoichi206 changed the title feat: オンデバイス日本語校正 Chrome 拡張の初期実装 (Phase 0-4) feat: initial implementation of on-device Japanese proofreader Chrome extension (Phase 0-4) May 30, 2026
レビュー修正で入れた境界バリデーション等を回帰から守るため、純粋ロジックと DOM ロジックの
テストを追加。CI(pnpm test)にも組み込み。

- src/ai/normalize.test.ts: オフセット一致採用 / no-op破棄 / 一意出現時の補正 /
  複数出現の破棄 / 構造不正の破棄 / 範囲外破棄
- src/proofread/mock.test.ts: 検出なし / 単一検出のオフセット / 複数検出の順序
- src/input/detect.test.ts: 対象種別 / 非text除外 / disabled,readonly / 機密欄除外
- src/apply/replace.test.ts: 一致時の範囲置換 / original 不一致時は非置換 / input 発火
- vitest + jsdom 導入、test/test:watch スクリプト、CI に test 工程を追加

17 tests passing。compile/lint/format/build も green。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@kokoichi206
kokoichi206 merged commit f82a392 into main May 30, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant