見出し画像

「この案件はどうですか?」メールの情報を読んで、ぴったりな案件を提案してくれるAIシステムを作ったったでぇ!

脳みその休息

どーも。こんにちわ。4月も後半で、忙しさも少し落ち着いてきましたでしょうか。それともまだ忙しくされているでしょうか。
タスクは落ち着いてきても、なんだかか脳内CPUは常に回り続けている感覚があったりします。

現代人は1日で、平安時代の人の情報のやりとり一生分を行うと言われています。なんで平安時代なのかは置いておいて。

でも確かに「電車の移動中」「トイレ」「お風呂」という暇な時間にさえ、携帯を使って、何かしらの情報を頭に入れていますよね。
現在人が情報の全くない環境を作るのは至難の業です。

先日いつものようにカフェに行ったのですが、開店より少し早く着いてしまい、じゃあ近くの公園で時間つぶそうということでベンチに座ると
Oh!携帯が充電切れという事がありました。

図らずも完全なるデジタルデトックスとなり、ベンチで日向ぼっこ。
時間を持て余したなーとか思ってましたが
案外、鳥の声や風で草のすれる音など、五感をフルに感じながらも、頭はすっきりとして、とてもリラックスできました。
たった5分でも10分でも全く何も情報を入れない状況と言うのを、脳みそが望んでいるのかもしれません。皆さんも一度やってみてはいかがでしょうか。
浮世のしがらみから抜け出し、宇宙と一体になりましょう(怖っ!)

さて一方で、私のメールボックスは平安人100万年分の情報であふれ返っております。助けてくれー。

毎日100件以上の案件と技術者の情報がメールが飛んでくるのですが
それはもうすべてに目を通していたら、バルス目ムスカです。

目がーメガー

誰か代わりに確認してほしいなんて、大量のメールが来る仕事の方は共感いただけますでしょうか?

たとえば「こんなメール来てる?」と質問すれば、「こんな案件ありましたよ」答えてくれる。そんなシステムが出来たら…

素敵やん。

AIシステム作ってみた


という事で、『質問したら受信メールの内容を答えてくれるシステム』をAIを使って作ってみようと言うことになりました。
ちくしょーなんでこんなことに…(知らんがな)

プログラミング戦闘力ったたの5なので、コードはChatGPTへ全振りして、やっていこうと思います。

おめーの出番だGPT!

①ChatGPTに要望を出す

まず要望をまとめてみました。
とにかくやりたい事をごちゃごちゃ書きましたが、最近はそんなにプロンプトを整理しなくても理解してくれるんですよね。
本当にセルを圧倒してる悟飯ぐらいの信頼性があります。

プロンプトはこんな感じです。

ChatGPTまた他のAIツールでも良いが
メールの内容をAIが把握し、質問すると適切な回答をさせるシステムを作りたい。
どのように実現すれば良いか?

以下要件
・エンジニアの提案と案件の提案がメールに来るので、そのマッチングを効率化させたい。
・メーラーはThunderbird(ほかのメーラーが良ければ提案してほしい)
・例えばAIに「C♯の技術者を探している」と言えば、「〇月〇日にこんなメールが来てます」と回答させたい。
・ローカルで完結したい。

個人情報も入った機密性の高い情報です。
外に漏れることは絶対ダメですからね。ローカルで完結させたいと思いました。
この要望を投げると、こんな提案をしてくれました。

なるほど。わかりました~

建物探訪
(わかる人にわかればいいです)


メールをPythonで抽出 ⇒ データをJSONに変換 ⇒ AIで読み込む

まぁだいたいこんな流れのようですね。

さて、やることはわかったけど、ここから何をしていいかさっぱりわからん!
「最初に何したらいいの?」って感じでどんどん聞いていきましょう。

順を追って説明してくれる神

こんな感じで、一つずつ教えてくれるので、順を追ってやっていきましょう。

② メールを抽出する

自社でメーラーはThunderbirdを使っています。
これは会社で決められているので仕方ありません。勝手にGmailとかにしちゃだめなんです。たぶん。

メール(MBOX形式)をPythonで読み取りたいので
まずはThunderbirdのメールが保管されているアドレスを知りたいわけです。

抽出したいメールフォルダ上で、右クリック
[プロパティ]を選択します。

するとこんな感じで出てきます。
この矢印部分がアドレスですね!

他のメーラーでも同し事が出来るはずよ

次にPythonインストールしていきましょう。
まさかこの私がPythonを使う日が来るとは…
Windows版かMac版か選んでここからDLします。

次にVScodeを使えるようにしておいてください。
メモ帳でもいいですが、使いやすさが全然違います。何よりこれを使ってるとなんかエンジニアっぽいです(そうなの?)

次に拡張機能でPythonを使えるようにしておきます。
検索欄でPythonを検索してインストールしておきましょう。

新規ファイルをとりあえず[read_mail.py]として作っておきましょう。

はい、準備完了。
あとはChatGPTが作ったコードをぶちこんじゃるだけじゃ。

import mailbox
import email
from email.header import decode_header, make_header
from email.utils import parsedate_to_datetime

mbox_path = r'(ここにメールが保存されているアドレスを入れる)'

def decode_mime_words(s):
    try:
        return str(make_header(decode_header(s)))
    except:
        return s or '(不明)'

def get_mail_date(raw_date):
    try:
        if not raw_date:
            return '(日付なし)'
        decoded_date = str(make_header(decode_header(raw_date)))
        dt = parsedate_to_datetime(decoded_date)
        return dt.strftime('%Y-%m-%d %H:%M')
    except:
        return raw_date or '(日付不明)'

def get_body(msg):
    if msg.is_multipart():
        for part in msg.walk():
            if part.get_content_type() == 'text/plain':
                try:
                    return part.get_payload(decode=True).decode(part.get_content_charset() or 'utf-8', errors='replace')
                except:
                    return '(本文デコード失敗)'
    else:
        try:
            return msg.get_payload(decode=True).decode(msg.get_content_charset() or 'utf-8', errors='replace')
        except:
            return '(本文デコード失敗)'
    return '(本文なし)'

mbox = mailbox.mbox(mbox_path)

for i, message in enumerate(mbox):
    if i >= 10:
        break

    subject = decode_mime_words(message.get('subject', '(件名なし)'))
    sender = decode_mime_words(message.get('from', '(送信者不明)'))

    # 日付取得&表示(中間チェック)
    raw_date = message.get('date')
    print(f"[{i+1}] raw_date: {repr(raw_date)}")  # ← デバッグ出力で中身を確認
    date = get_mail_date(raw_date)

    body = get_body(message)

    print(f"\n--- メール {i+1} ---")
    print("件名:", subject)
    print("送信者:", sender)
    print("日付:", date)  # ← 必ず表示されるようになっている
    print("本文の一部:", body[:1000])

よく意味は分かりませんが
以下の点を含めメールの内容を抽出するコードを作ってほしいと依頼して出てきました。

  • 10件分のメール(とりあえずテストなので)

  • 送信者

  • 件名

  • 日付

  • 本文の一部(1000文字分)※全部出すと多すぎだった。

一度これを動かしてみて、情報が取れているか確認します。

ちょっとわかりにくいですが、抽出には成功しているっぽいですね。
コードの意味はほぼわかりませんが、非エンジニアでもPythonを実行できました。すげーぜ俺。

褒めて伸びる(チョーシにのる)タイプ

③情報をJSON形式にする

AIが検索しやすいように整理して保存しておく必要があるらしいので、先ほどの情報をJSON形式にします。
[extract_mails_to_json.py]として新規ファイルを作成します。

コードはこちら。

import mailbox
import json
from email.header import decode_header, make_header
from email.utils import parsedate_to_datetime

mbox_path = r'(メールが保存されているアドレスを入れるよ)'
output_path = 'mail_data.json'

def decode_mime_words(s):
    try:
        return str(make_header(decode_header(s)))
    except:
        return s or '(不明)'

def get_mail_date(raw_date):
    try:
        if not raw_date:
            return '(日付なし)'
        decoded_date = str(make_header(decode_header(raw_date)))
        dt = parsedate_to_datetime(decoded_date)
        return dt.strftime('%Y-%m-%d %H:%M')
    except:
        return raw_date or '(日付不明)'

def get_body(msg):
    if msg.is_multipart():
        for part in msg.walk():
            if part.get_content_type() == 'text/plain':
                try:
                    return part.get_payload(decode=True).decode(part.get_content_charset() or 'utf-8', errors='replace')
                except:
                    return '(本文デコード失敗)'
    else:
        try:
            return msg.get_payload(decode=True).decode(msg.get_content_charset() or 'utf-8', errors='replace')
        except:
            return '(本文デコード失敗)'
    return '(本文なし)'

# メール抽出
mbox = mailbox.mbox(mbox_path)
mail_data = []

for i, message in enumerate(mbox):
    if i >= 100:
        break

    subject = decode_mime_words(message.get('subject', '(件名なし)'))
    sender = decode_mime_words(message.get('from', '(送信者不明)'))
    raw_date = message.get('date')
    date = get_mail_date(raw_date)
    body = get_body(message)

    mail_data.append({
        "件名": subject,
        "送信者": sender,
        "日付": date,
        "本文": body[:3000]
    })

with open(output_path, 'w', encoding='utf-8') as f:
    json.dump(mail_data, f, ensure_ascii=False, indent=2)

print(f"✅ {len(mail_data)}件のメールを mail_data.json に保存しました。")

先ほどのテストで情報が少なすぎることが分かったので
抽出件数を10件⇒100件
・抜き出す本をを1000文字⇒3000文字

上記に変更してみました。
実行すると[mail_data.json]に保存されるようにしてます。

実行すると、「100件のメールをmail_data.jsonに保存しました」とメッセージが出ました。おそらく保存されたのでしょう。

成功してる?はず。

④AIが情報を取りに行く

JSONファイルををAIに読ませて
「これはエンジニアの紹介だな」「スキルはC#だな」「勤務地は東京、単価は70万円だな」みたいに理解させます。

Ollama + llama3を提案されたのでそれを使ってみましょう。
ちなみにOllamaは大規模言語モデル(LLM)をローカル環境で実行できる無料のAIツールです。
そんなものがあったんですね。
これがあれば自分だけの業務なら、気軽にAIシステムを作れそうな予感がプンプンです。

こちらからインストールします。

インストール出来たら、AIに質問するコードを作ります。

import json
import ollama

# JSONファイルから読み込み
with open('mail_data.json', 'r', encoding='utf-8') as f:
    mail_data = json.load(f)

# ユーザーから質問を入力
query = input("💬 AIに聞きたいことを入力してください:")

# メール本文を圧縮(長文対策)&件数制限
context = "\n\n".join(
    f"件名: {m['件名']}\n送信者: {m['送信者']}\n日付: {m['日付']}\n本文: {m['本文'][:500]}"
    for m in mail_data[:50]
)

# 明確な日本語プロンプトで構造化フォーマットを強制
messages = [
    {
        "role": "system",
        "content": (
            "あなたは日本語でメールデータを解析するアシスタントです。\n"
            "以下のメール群の中から、ユーザーの質問に合致するものを探し、\n"
            "各該当メールについて次の形式で日本語で出力してください:\n\n"
            "【件名】...\n【送信者】...\n【日付】...\n【要約】...\n\n"
            "該当するメールがない場合は「該当メールは見つかりませんでした」とだけ日本語で出力してください。"
        )
    },
    {
        "role": "user",
        "content": f"質問:{query}\n\n---\n{context}"
    }
]

# Ollama 実行&結果表示
try:
    print("\n🤖 AIの回答中...\n")
    response = ollama.chat(model='llama3', messages=messages)
    print("✅ 応答取得成功!\n")
    print("🤖 AIの回答(日本語):\n")
    print(response['message']['content'])

except Exception as e:
    print("❌ エラーが発生しました:", str(e))

そしてこれを実行すると、このような表示が出ました。

あ、ここに直接質問なげる感じ?

それ用のUIも無いので、ここに直接入力して質問できるようですね。

いよいよ佳境です!
果たして質問にちゃんと答えてくれるのでしょうか!?

わかりません!!

⑤AIに質問する

「Springの案件ある?」と聞くと、保存した情報からマッチするメールを探して、AIが要約して教えてくれるというのがゴールです。

コマンドライン上で「Springの案件ある?」とぽちぽち入力。
すると「AI回答中…」という表示がでました。

そして、出ました。じゃん!!

うわー英語かい!!!

一応、回答はしてくれてはいます。
翻訳すると、情報はのってます。
間違ってはいないのですが、英語だし、日付とか情報が少ないっ!あちゃー。
これは次回の課題ですね。なんかいっつもこんな感じだけど。

課題

まず思ったような情報が出なかったのが残念でしたねー。
コード上では、[日本語]で出すようにとしていましたし、
もっと言えば[日付][件名]が出るように指示しているのですが、何故か出来ない。
ちなみに日本語にするためには、質問に直接「日本語で。」と入れれば出ました。
いや、めんどい!。

もう一つは、めっちゃ検索に時間がかかる。
回答出すのに10分以上かかります。これメーラーで検索したほうが早くね?
もちろん自然言語で回答出してくれるので便利な部分はあるんですけどね。

ChatGPTに慣れすぎると気が遠くなるほど回答が遅いんですよね。
PCのスペックも関係していますので、個人差はあると思います。

「頼むよOllama…」と全部この子のせいにしてしまうのは良くないのでしょうが、とりあえずこの保存したJSONをChatGPTに読み込ませたらどうなるか試してみました。あんまり良くは無いのだけど。

やっぱりOllamaのせいじゃーん

おお!ChatGPTはほぼ完ぺきに答えてくれました。
日付は出てないので、「日付もお願い」とすると
それも出してくれましたよ。
さすがはGPT先生です!Ollama!!コラ!

ただセキュリティ的にはNG気味だし、ほぼ手動ですから、システムと呼ぶには程遠いですわね。

別の有料版ローカルAIを使えば、もっと精度が良くなるかもしれませんね。あきらめずに再挑戦してみます(ほんとか?)

まとめ

さて今回ChatGPTと壁打ちしながら作りました。
あっさりとコードは作ってくれたように見えるかもしれませんが
実行してみると、「想定したデータが何故か取れない」とか、「単純な要件忘れ」とかで思ったような結果にならないのが普通です。

実行してみて、納得いく結果になるまで
何度も「ここ出来てないから全部書き直して」とトライ&エラーを繰り返しました。ポイントは全部書いてもらう事!
一部だけコードを書いて「このコードをさっきのに入れてみて」GPTがしてくることもありますが、あまりお勧めしません。
まずどこに入れたらいいかわからん…。
コードレビューができる方ならそれでも良いと思いますが、いろいろこねくり回したあげく、動かなくなった場合、非エンジニアは簡単にハマってしまいます。コードは全部書いてもらうのがベターだと感じました。

それでも驚くほど短い時間でAIシステムを作れたのはさすがですね俺… じゃなくてChatGPT。
私はこまめにやってたので3日ぐらいかかりましたが。丸1日時間もらえたら、ここまでは誰でもできると思います。

近いうち、自分が使う業務ツール程度であれば、自分で作ってしまえ!となるかもしれませんね。それくらいChatGPTの説明はわかりやすかったですね。
1日時間が空いたら、自分だけのAIシステム作ってみてください。


いいなと思ったら応援しよう!

この記事が参加している募集