0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ChatGPTで営業メールを要約 → DBに保存 → クエリで探せる仕組みを作ってみた

Last updated at Posted at 2025-06-08

営業メールって、正直つらくないですか?

毎日のように届く営業メール、
・数が多い
・検索がしづらい
・欲しい情報が載っていないことも多い

そんな不便さを何とかしたくて、IT業界のエンジニア向け営業メールをAIで字句解析して、DBに保存して検索できるアプリを作ってみました。

表示イメージ

このように集計できるようになります。
image.png

設計

ミッション

営業メールを構造化し、検索可能な形で保存する。

分析対象

対象は「案件メール」と「人材メール」の2種類。
※すべてのメールを解析するとAPIコストがかかるため、Gmailのフィルター機能でラベルが付与されたメールのみを対象とします。

設計上のポイント

  • 表現の揺らぎはAIによって吸収
  • メール本文と構造化データは分離して保存
  • 言語・フレームワークなどの技術キーワードは、マスタ管理により柔軟な検索を実現

サービス選定

メール:Gmail

社内で利用しているため、連携もスムーズ。

AI:ChatGPT

ローカルLLMも試しましたが精度がイマイチだったため、API型を選定。
その中で、精度と価格のバランスから GPT-4.1 miniを採用しました。

解析フォーマット

営業メールは主に「案件紹介」と「人材紹介」の2種類に分けられます。
それぞれ定型的な情報が含まれていますが、表現に揺らぎがあるため抽出はAIに任せます。

フォーマット例
[
    {
        "メール区分": "案件 or 人材",
        "案件名": "Go/AWS なんとか業界の開発案件",
        "業務": [
            "バックエンド実装",
            "インフラ構築"
        ],
        "入場時期・開始時期": [
            "2025/06/01",
            "2025/07/01"
        ],
        "終了時期": "~長期",
        "勤務場所": "東京都",
        "単価FROM": 800000,
        "単価TO": 900000,
        "言語": [
            "TypeScript",
            "JavaScript",
            "PHP"
        ],
        "フレームワーク": [
            "React",
            "Laravel"
        ],
        "ポジション": [
            "PL",
            "PM",
            "SE",
            "PG"
        ],
        "求めるスキル MUST": [],
        "求めるスキル WANT": [],
        "リモートワーク区分": "フルリモート or リモート可 or 不可",
        "リモートワークの頻度": "週一回"
    }
]

処理の流れ

  1. CLI からコマンドを実行して処理を開始
  2. Gmail API で特定ラベルがついているメールを取得
    ※ラベルへのメール振り分け設定が完了している想定です
  3. ChatGPT API に投げて要約・構造化
  4. JSONで受け取り、案件 or 人材に分類
  5. パースしてDBに保存(メール本文は別途保存)
    ※(将来的に)フロントで検索インターフェース提供予定

DB設計

検索性を高めるため、emails テーブルに基本情報を格納し、案件/人材情報を子テーブルとして管理する。
言語やフレームワークなどは表現に揺れがあるため、単語を正規化するマスタ設計が必要。
例えば「PHP(Laravel)」のような単語は、言語とフレームワークの両カテゴリに対応できる構造とする。
以上を踏まえるとこのような設計になりました。
※人材情報は今後対応予定です。

フォーマット例
tables:
  emails:
    role: "全メール共通の基本情報(件名・送信元・本文など)"
    relation: []

  email_projects:
    role: "案件メール専用の詳細情報(単価・勤務地・技術要素など)"
    relation:
      - emails (1:1)
      - entry_timings (1:N)
    note: "一覧画面用に技術・業務・ポジションなどをカンマ区切り文字列でも保持(二重管理)"

  entry_timings:
    role: "案件の入場時期(複数)を正規化管理"
    relation: ["email_projects (N:1)"]

  keyword_groups:
    role: "正規化された技術キーワードのマスタ(PHP、Reactなど)"
    relation: ["key_words (1:N)", "email_projects (N:N keyword_group_word_links)"]
  
  keyword_group_word_links:
    role: "email_projects  keyword_groups を多対多で結びつける中間テーブル"
    relation: ["email_projects (N:1)", "keyword_groups (N:1)"]

  key_words:
    role: "キーワードの表記ゆれを keyword_groups に紐付ける"
    relation: ["keyword_group_word_links (N:1)"]

  key_words:
    role: "キーワードの表記ゆれを keyword_groups に紐付ける"
    relation: ["keyword_groups (N:1)"]

  email_keyword_groups:
    role: "emails  keyword_groups の多対多中間テーブル(type区分あり)"
    relation: ["emails (N:1)", "keyword_groups (N:1)"]

  position_groups:
    role: "正規化されたポジション名のマスタ(例: PM, PL)"
    relation: ["position_words (1:N)", "email_position_groups (1:N)"]

  position_words:
    role: "ポジションの表記ゆれを position_groups に紐付ける"
    relation: ["position_groups (N:1)"]

  email_position_groups:
    role: "emails  position_groups の多対多中間テーブル"
    relation: ["emails (N:1)", "position_groups (N:1)"]

  work_type_groups:
    role: "正規化された業務種別マスタ(例: バックエンド開発)"
    relation: ["work_type_words (1:N)", "email_work_type_groups (1:N)"]

  work_type_words:
    role: "業務表記ゆれを work_type_groups に紐付ける"
    relation: ["work_type_groups (N:1)"]

  email_work_type_groups:
    role: "emails  work_type_groups の多対多中間テーブル"
    relation: ["emails (N:1)", "work_type_groups (N:1)"]

言語選定

ぱぱっと開発したかったのと、ローカル環境の構築が自分の既存リポジトリから流用できたこと、そして学習目的もあって、Go言語を採用しました。
あとから振り返ると、Laravelでフロントも一緒に作ったほうがよかったかも…と少し後悔してます(笑)

今後の対応について

  1. 人材情報メールへの対応
  2. フロントの作成
    ・単語マスターの管理画面
    ・検索インターフェース
    ※気になる、既読、非表示などでより選別を簡単にすることも可能
    ・案件・人材情報に単語を追加で紐づける

ソースコード

※フロントは時間に余裕ができたら作る予定です。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?