はじめに
医療系 SEO コンテンツの編集をしていた頃、ライターさんとの修正往復で最も時間を取られていたのが"曖昧表現の指摘"でした。
「〜でしょう」「場合がある」といった表現が多用されると、読者に内容が伝わりにくいだけでなく、クリニックの信頼性低下にも直結します。
これを毎回人力で修正していては、記事構成やファクトチェックなど本質的な編集業務に手が回りません。
そこで今回、「曖昧表現の検出」「理由の提示」「言い換え候補」「履歴の可視化」までを一括で行う 「曖昧表現チェッカー」 を個人開発しました。
なぜ作ったのか
編集者としてライターさんが納品してくださった記事コンテンツを添削していた際「〜でしょう」「場合がある」といった曖昧表現が多用され、修正指示の往復が多発していました。
曖昧表現が多いと、読者・編集者・ライター目線で、以下のようなデメリットがあります。
読者
- 内容の解像度が低くなり「結局どうなの?」という印象を与えてしまう
- 医療系など正確性が求められる分野では、クリニックの信頼を損ねる要因になる
編集者
- 曖昧箇所を1つ1つ言語化するのに、往復のフィードバック回数が増える
- 本来注力すべきである、構成やファクトチェック・読者体験向上に割く時間が削られる
ライター
- 曖昧さの基準が分かりにくい
- 定量的に成長を評価してもらいにくい
特にライター目線では、自分の曖昧表現の傾向や改善度を定量的に把握できないため、修正内容を次回以降の執筆に活かすモチベーションが湧きにくいという課題がありました。
「修正される -> なんとなく直す -> 次の記事でも同じ指摘を受ける」というサイクルになりがちで、スキルアップの実感が得にくい状態です。
そこで「曖昧さを曖昧なままにしない」仕組みを提示し、ライター自身で「気付く -> 修正する -> 学ぶ」の循環を作れるように、本プロダクトを作成しました。
開発で工夫したポイント
- ワンクリックで検出と彩色表示:Monaco Editor 上で正規表現検出を行い、カテゴリ × 深刻度でハイライトして即時フィードバック
-
OpenAI Responses API の活用:曖昧表現を選択すると
JSON Schema
で制約したリライト案を取得し、敬体・断定的な書き換えを提案 -
データ永続化のフォールバック:Supabase(PostgreSQL)接続が落ちても
USE_IN_MEMORY_STORAGE=true
でFunctions
内のメモリ実装へ自動切替 - 成長の可視化:履歴やダッシュボードで改善推移・カテゴリ傾向・頻出語を表示し、ライターの成長を可視化 -> 編集者目線では評価もしやすい
コンセプト
このプロダクトは、次の価値仮説に基づいています。
- 可視化:曖昧な箇所が視覚的にわかる(気づける)
- 納得:なぜ曖昧なのか、理由がわかる(腑に落ちる)
- 前進:言い換えのヒントが得られる(時短につながる)
- 成長:修正の積み重ねが可視化される(続けられる)
曖昧の理由が分かったり成長度合いが可視化されたりすることで、業務委託ライターのモチベーション向上に繋がるだけでなく、曖昧な理由を知れることで同じ理由のフィードバックを削減し、編集者とライターの関係性悪化を防げます。
これにより、短期の契約解除を防ぐ効果も期待できます。
- 編集者:本当に価値のある指摘(構成・論拠・読者体験)への集中
- 読者:曖昧さに迷わず要点へ辿り着ける体験
- 執筆者:自分の癖に気づき、上達を実感できる環境
この三者が同時に報われる状態を、このプロダクトで目指しています。
プロダクト概要
- 曖昧表現の検出とハイライト: Monaco Editor 上で文章をチェックし、カテゴリ別・深刻度別に装飾。検出結果の一覧や頻出語も表示します
- 言い換え候補の提案: 選択した曖昧表現について、対象箇所の前後 120 文字前後の文脈を参照しつつ OpenAI から 1 案と理由を取得します
- バージョン保存 & 履歴管理: 保存時に Firebase UID と著者ラベルを Supabase に記録。履歴画面では複数バージョンを比較し、Diff を表示できます
- 統計ダッシュボード: 最新版と前回との差分や曖昧度スコアの推移、カテゴリ別件数、頻出の曖昧語を確認できます
想定シナリオ(ライター視点のフロー)
- 原稿を下書きしながら曖昧箇所に気づく
- 理由を読み、適切な言い換えに変換する
- 積み重ねを振り返り、自分の癖と変化を知る
実際の画面
エディタ画面
- 文章入力とリアルタイム検出(カテゴリ×深刻度でハイライト、ホバーで理由表示)
- 検出一覧の操作(対象箇所へジャンプ、頻度ソート、カテゴリソート)
- 言い換え候補の生成と差し替え(OpenAI Responses API、敬体・断定的な1案+理由を取得してワンクリック置換)
- タイトル入力・自動保存(localStorage に本文・タイトル・記事IDを保存/クリア)
- チェック履歴の簡易ログ(件数・文字数・処理時間・頻出語トップ3)
- バージョン保存(Firebase Auth のユーザーで Supabase に保存。保存時に計測値も記録)
履歴画面
- 記事一覧の取得と選択(記事ごとに最新・前回のバージョン要約を表示)
- バージョン一覧の表示(作成日時、スコア、件数、文字数などの要約)
- Monaco DiffEditor で 2 バージョン比較(差分可視化)
- トレンド表示(直近2回の件数・スコアの増減と増減率を表示)
- バージョン/記事の削除
ダッシュボード画面
- サマリー(最新と前回の要約:スコア、件数、文字数、作成日時)
- 差分(件数/スコアの増減と増減率)
- スコア推移(直近最大20件のチェックランの折れ線)
- カテゴリ推移(直近最大10バージョンのカテゴリ別件数の時間変化)
- 頻出語トップ(直近最大200件の検出から、フレーズ×カテゴリの出現回数、平均深刻度、最終検出時刻の上位)
ダッシュボードの計算ロジック
-
文字数 charLength:
- 本文の文字数
-
検出件数 totalCount:
- そのチェックで見つかった曖昧表現の件数
-
曖昧度スコア aimaiScore:
- 正式値 = totalCount * 1000 / charLength(文字数あたりの件数を1000文字基準に正規化)
- 表示時は小数第2位で切り捨て
-
サマリー差分:
- 件数差 countDiff = 最新件数 − 前回件数
- 件数増減率 countPercent = 前回件数が0より大きいとき countDiff / 前回件数 * 100、それ以外は表示なし
- スコア差 scoreDiff = 最新スコア − 前回スコア
- スコア増減率 scorePercent = 前回スコアが0でないとき scoreDiff / 前回スコア * 100、それ以外は表示なし
-
スコア推移:
- ユーザーのチェックラン(最大20件)を新 -> 旧で取得後、昇順で並べ替え
-
カテゴリ別件数推移:
- 各バージョンの最新チェックランからカテゴリ別件数を集計(最大10バージョン)
-
頻出語トップ:
- 直近200件の検出を「カテゴリ + 一致テキスト」でグルーピング
- 指標: totalCount(出現回数)、severityAvg(平均深刻度 = 合計/件数)、lastFoundAt(最後に検出された日時)
- 並び順: 出現回数降順、同数なら最後の検出が新しい順
作ってみて気づいたこと
今回、実際にプロダクトを作ってみて、「曖昧表現の検出 -> 修正 -> グラフ化」という一見シンプルな機能でも、UI/UX・データ構造・運用フローなど、考えるべきことが意外と多いと実感しました。
特に、検出結果を“ただ出す”のではなく、「どう曖昧なのか」や「どう改善できるか」まで踏み込む設計は、技術というよりも言語化や編集の知見が必要で、過去の編集経験が大いに役立ちました。
また、Prisma や Firebase Emulator Suite、OpenAI API 、shadcn/ui と、初めて触る技術が多かったですが、
- 小さく動くものから始める
- 機能追加は MVP を区切って進める
- 不明点は AI に聞きながら進める
という進め方が功を奏し、約1カ月でここまで形にできました。
ChatGPT との違い ・ 差別化ポイント
「曖昧表現の修正」だけで言えば、ChatGPT に文章を投げればある程度は綺麗な文章にしてくれて、なにがどう良くなかったかの学びにはなるかと思います。
ただ、今回作ったプロダクトは"ライター教育用"であるため、一方通行の添削ではなく、「気づきと学び・成長を実感するというプロセス」を重視しています。
-
ChatGPT: 文章を投げる -> 綺麗な文になる
└ しかし自分の癖や曖昧さの理由が見えにくく、成長の可視化もできない -
本プロダクト: 曖昧な箇所を 検出・分類・履歴管理・可視化
└ ライター自身の成長を可視化し、気付きと改善の循環を作る
つまり、「結果」だけでなく「過程」も支援する点が最大の違いです。
特に業務委託のライターや社内のライターチームは、個人の成長に加えて編集者のフィードバックの省力化が会社の売上に直結するため、この差別化は大きいと感じています。
使用技術
レイヤー | 採用技術 |
---|---|
フロントエンド | React 19 / Vite / TypeScript / Tailwind CSS (shadcn/ui) / Monaco Editor / Recharts |
バックエンド | Firebase Functions + Prisma |
データベース | Supabase (PostgreSQL) |
CI / CD | GitHub Actions |
認証 | Firebase Authentication(Email/Password) |
AI | OpenAI Responses API。既定は gpt-4.1-mini OPENAI_REWRITE_MODEL で gpt-4.1 / gpt-4o などに切替可 |
インフラ | Firebase Hosting + Functions、Firebase Emulator Suite |
品質管理 | ESLint / TypeScript / Jest + React Testing Library |
Firebase Emulator Suite
は、ローカル環境で認証や Hosting、Functions の機能を確認する目的で導入したのですが、個人開発レベルなら必要ないかなとも感じました。
ただ、使った方が何度もデプロイする手間を省けるのと、実務に近いかな?くらいの感覚でした。
認証に Supabase Auth
ではなく、Firebase Authentication
を使用した理由は、MVP5 まで進めた段階でログイン機能が必要になることに気が付き、その時点でアプリの api を Firebase Functions
が受け持つ形にしてしまっていたため、Firebase の方が工数少なく済んだからです。
MVP 設計の段階で穴に気付けなかったのが反省点です。
今後の展望
下記の機能を実装予定です。
- 曖昧表現辞書のカスタマイズ(編集)機能
- ダッシュボードの共有・エクスポート(CSV/PDF)
- 医学的根拠チェックやファクト検証
- チーム単位のロール管理と共通ダッシュボード
- トンマナを意識した言い換え
- 曖昧と冗長表現検出の切り替え
これまでを振り返って
3カ月前までは、GAS でちょっとした業務自動化スクリプトを書く程度のスキルでした。
そこから JavaScript、React、TypeScript などを一歩ずつ学び進め、今回、初めて自分のアイデアを Web アプリという形に落とし込むことができました。
そしてこの「曖昧表現チェッカー」は、実は 2年前からずっと温めてきた夢のアイデアでもあります。
前職で編集の仕事をしていた頃、「いつか、ライターの成長が可視化できるツールを自分の手で作りたい」と思い続けてきて、ようやく形にできたのは本当に感慨深いです。
また、このプロダクトの他にも、ずっと構想を練ってきたアイデアがもう一つあるので、この経験を糧に、次のプロダクトにも着手し、さらにスキルと表現の幅を広げていきます。
おわりに
曖昧表現修正の往復で疲弊していた編集者・ライターに、執筆段階で修正・自走できる体験を届けたいという想いから生まれたプロダクトです。
3カ月前は、自分のアイデアをプロダクトに落とし込むことなんて想像もできないような初心者でしたが、毎日コツコツ継続すれば、アイデアを形にするところまで成長できるんだなと実感しました。
また、今回初めて Prisma や OpenAI API 、Tailwind CSS (shadcn/ui)、Recharts を使ってみましたが、使ったことない技術にチャレンジできるのが個人開発のいいところだなと再認識しました。
バックエンド / インフラの部分は最初分からなすぎてAIに頼ってしまいましたが、質問に質問を重ねて、何となくではありますが理解できるようになり、自分のレベルも少しは上がったなとも感じています。
これからも技術的なスキルを身につけつつ、プロダクトを通して課題解決も行なっていきたいです。
JISOUのメンバー募集中!
プログラミングコーチングJISOUでは、新たなメンバーを募集しています。
日本一のアウトプットコミュニティでキャリアアップしませんか?
興味のある方は、ぜひホームページをのぞいてみてください!
▼▼▼