created_at
updated_at
tags
toc
headings

OpenAI API を用いた文書校正(誤字脱字検出)

Intro

OpenAI の API を用いて、長年の課題だった文書校正を VSCode 上で実現するプラグインを修作したところ、思った以上の成果だった。

文章校正と誤字脱字検出

執筆を補助するツールは多々開発されているが、基本は形態素解析を用いた品詞分析の延長で行うものが多かった。

よくある「助詞の連続」、「漢字の開き閉じ」、「一文の長さ」などは、ある程度の精度で検出可能ではあるが、結局執筆時に一番検出して欲しいのは「誤字脱字」だ。

文体をどんなに揃えたところで、誤字脱字があるとやはりクオリティが低く感じるし、そこさえ抑えられていれば、他のスタイル統一は訓練である程度なんとかなる。

英語のスペルチェックはかなり進んでいるが、日本語においてはそこまで革新的なものが見当たらない。あらゆるツールを試したが、結局満足のいく精度が出る誤字脱字検出は「Word の校正機能」しかなかった。

そこで筆者は、書籍執筆などは Markdown で原稿を書き、ある程度まとまったら HTML でレンダリングしたものを Word に流し込んで校正していたが、これはあまりにも面倒くさい。

Word の校正機能だけ CLI にならないかと何度も夢みたが、それが叶うはずもなく。「紙に印刷して読んだ方が見つけられる」「音声読み上げしたら気づける」などのワークアラウンドでなんとか見つけだし、それを次の修正で誤字脱字だらけに戻しながら、たまに Word を行き来して今に至る。

こんなに執筆エコシステムが発達しているのに、 VSCode での執筆フローの中で効率よく誤字脱字を検出し修正する方法には、巡り会えないままでいた。

ChatGPT での校正

ChatGPT の Proofreading プロンプトは、頻出ユースケースの一つだ。そして、これは日本語でも動作する。

筆者が求めているのは、ヒントから文章を書き上げて欲しいわけでも、丸っと書き直して欲しいわけでもなく、「誤字脱字だけ見つけて直してほしい」だけなので、指令はごくシンプルだ。

むしろ、細かく条件を加えた方が、 ChatGPT が余計なことをしだすので、さまざまなプロンプトを試しながら、結局このシンプルなものに戻ってきた。

次の文章の誤字、脱字、スペルミスを修正してください。

- 執筆を補助するツールは多々開発されいるが、基本は携帯素解析を用いた品詞分析の延長で行うものが多かった。
+ 執筆を補助するツールは多々開発されているが、基本は形態素解析を用いた品詞分析の延長で行うものが多かった。

GPT-4 で文書校正を依頼し、上記の結果を得た様子

もちろん、試行差があるため同じ結果にならない場合があるが、この精度が出るのであれば、執筆しながらの校正補助には十分使えそうだ。

毎回 Chat のプロンプトで依頼するのはもちろん手間なので、これを OpenAI API を用いて自動化する VSCode プラグインを作成すれば良い。

VSCode Plugin

もともと筆者は、執筆などに必要な全く汎用性の無い機能を雑に詰め込んだ自分用プラグインを持っており、ちょっとした機能を都度追加して使っている。今回もそこに追加実装した。

内容は、選択したテキストを OpenAI API に渡し、前述の処理を行った結果を上書きする簡単なものだ。 Git で管理していれば、見比べて気に食わなければ簡単に Revert できるため、精度はあまり気にする必要がない。

筆者はまだ GPT-4 API の利用が許可されてない(Waiting List にだいぶ並んでるがいつ落ちてくるんだろうか...)ので 3.5 ベースだが、とにかく呼び出すべきは Edits API だ。

VSCode の Extension は node v16 ベースなので fetch() は使えないが、もし使えるとしたら大体こんな感じのコードになる(疑似コードである点に注意)。

async function openai_edit(input) {
  const url = "https://api.openai.com/v1/edits"
  const model = "text-davinci-edit-001"
  const instruction = "文章の誤字、脱字、スペルミスを修正してください。"
  const body = {
    model,
    input,
    instruction,
    temperature: 0.2
  }

  const res = await fetch(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${process.env.api_key}`
    },
    body: JSON.stringify(body)
  })

  const result = await res.json()
  console.log(result)
}

あとは、選択範囲を取得したり、 API Key を Config から取ったり、 fetch() を HTTP Module で書き直したりなどをすれば、拡張自体を作るのは難しくない。

長いと落ちるが、行ごとだと API コールが増えるので、セクションごとくらいで呼び出しつつ、意図しない修正は Git で revert していく運用を想定している。

精度

試しに 前回のブログ の原稿を校正した(月一回は書きたいという個人的な目標を達成するために、月末に大急ぎで書いたため、誤字脱字だらけだった)。

検出した Diff が以下だ。

- ブラウザがバースできなければ jQuery 側の Sizzle という独自パーサにフォールバックすることで
+ ブラウザがパースできなければ jQuery 側の Sizzle という独自パーサにフォールバックすることで

- `:has(:contains(div))` のようなセレクタがエラーにならいのは
+ `:has(:contains(div))` のようなセレクタがエラーにならないのは
  
- そして jQuery こそが `:has()` の有用性証明の一旦を担っていたため、それがなければ標準化されることもなかったかもしれない。
+ そして jQuery こそが `:has()` の有用性証明の一端を担っていたため、それがなければ標準化されることもなかったかもしれない。
  
- 「古い実装が足をひっぱてる」
+ 「古い実装が足を引っ張ってる」
  
- 解決をみたことでもう話題にはならないだろうが
+ 解決を見たことでもう話題にはならないだろうが

これこそが、筆者が長年追い求めていた、紛れも無い「誤字脱字修正」の自動化だと言える。

Outro

GPT-4 でなくても十分な精度だと思える。今後精度がさらに向上すると、もう Word での校正からも卒業できるかもしれない。

ご時世的には、ちょっとしたアウトラインを書いて、残りは ChatGPT に書かせるような使い方が示されているが、書籍を表現手段として自分で書きたい筆者にとっては、欲しいのは Generator というよりも Linter だった。

今回「誤字脱字検出」というミッシングピースが埋まったことは、地味かもしれないが、筆者にとっては非常に大きな進歩なので、本当に興奮している。

本当に興奮しているのだ。

Resources