AIエージェント 最新研究論文をo3-miniで要約してTeamsに毎朝投稿するbot

技術者や研究者が開発や研究をするためには文献調査(サーベイ)が不可欠です。しかし、他の業務に追われてなかなか手がつかないケースも多いですよね。

今回紹介するエージェントは、
1)研究論文の情報をarxivから任意のキーワードで検索して、
2)内容をAIで要約し
3)毎朝Microsoft Teamsのチャネルに自動投稿してくれる
というものです。毎朝始業時に最新論文の要約が自動配信されたらとても嬉しいですよね。

高品質な要約を得るために2025年2月現在、最高性能の生成AI(LLM)のOpenAI 「o3-mini」を採用しました。

動作の概要

検索する研究論文のデータベースはコーネル大学の運営する「arxiv」を使います。arxivは物理学、数学、計算機科学、数量生物学(英語版)、数量ファイナンス、統計学、電子工学・システム科学、経済学の、プレプリントを含む様々な論文が保存・公開されているウェブサイトです。ここから設定しておいた任意のキーワードでデータベースを検索して、論文をピックアップします。

キーワードは事前にプログラムに指定しておき、自動で実行させます。

選んだ論文はPDFを自動でダウンロードした後、文字情報をpythonで抜き出します。

抜き出したテキスト情報は生成AI(o3-mini)で要約させます。このとき、論文要約に使うプロンプトは下記のものを使いました。

system_message = """添付したテキストは学術論文です。この論文全体を読み込み、内容を解釈した上で
1.どんなもの?(翻訳したタイトルとアブストラクト)
2.先行研究を比べてどこがすごい?
3.技術や手法の肝はどこ?
4.どうやって有効だと検証した?
5.理科学機器メーカーの技術者にとって、新製品を開発するために何が参考になる?
6.理科学機器メーカーの営業担当にとって、マーケティング目線で何が参考になる?
7.この分野は今後、どのように進んでいく?
の7つの項目それぞれについて150文字以上300文字以内で階層からなる箇条書きにしてまとめてください。
一般用語以外は元の言語のまま表記してください。"""

筑波大の落合陽一さんが、考案された「落合式」論文読みプロンプトをアレンジしたものとなっています。ここはみなさんの好みや目的に応じてアレンジが可能です。

出力結果は下記のようになります。

=== 論文の要約 ===

Title: Visible metalenses with high focusing efficiency fabricated using nanoimprint lithography
Authors: Andrew McClung, Mahsa Torfeh, Vincent J. Einck, James J. Watkins, Amir Arbabi
Published: 2023-12-21 13:48:09+00:00
PDF URL: http://arxiv.org/pdf/2312.13851v1

Summary:

  1. どんなもの?
    • 本論文は、visible metalens(可視光領域のメタレンズ)をnanoimprint lithography(ナノインプリントリソグラフィー)を用いて高効率に製作する方法を提案しています。
      • メタレンズは、subwavelength scatterers(サブウェーブレングス散乱体)を表面に配置して光の波面を制御する薄型光学素子です。
      • 従来のelectron-beam lithography(電子ビームリソグラフィー)は低スループットで大量生産に不向きでした。
    • 本研究では、mask-templating nanoimprint lithographyプロセスを開発し、シリコンナイトライド製のnano-posts(ナノポスト)からなる直径6 mm、NA 0.2のメタレンズを製作しました。
      • このメタレンズは波長550 nmで動作し、高い集光効率(81±1%)を達成しています。
  2. 先行研究を比べてどこがすごい?
    • 従来のメタサーフェス製作ではelectron-beam lithographyが主流であり、コストとスループットの面で課題がありました。
      • 本研究は、nanoimprint lithographyを用いることで、高速かつ低コストでの大量生産を可能にしました。
    • mask-templatingプロセスにより、varying fill factors(変化する填充率)とnegligible wavefront aberrations(無視できる波面収差)を有するメタサーフェスの製作が実現。
      • composite stamps(複合スタンプ)を使用し、高精度なパターン転写を達成。
    • 作製したメタレンズは、高い集光効率と低い波面収差を示し、従来の方法と同等の性能を持ちながら生産性を大幅に向上。
  3. 技術や手法の肝はどこ?
    • tri-layer composite stamps(三層構造の複合スタンプ)を用いたmask-templating nanoimprint lithographyの開発。
      • スタンプの変形を抑え、高精度なパターン転写を可能に。
    • varying fill factorsを持つパターンの再現性。
      • polarization-insensitive metasurfaces(偏光非依存のメタサーフェス)の製作が可能。
    • シリコンナイトライドを材料とし、visible wavelength metasurfacesに適用。
      • 高い集光効率と優れた光学特性を実現。
    • 大口径(6 mm)でNA 0.2のメタレンズを製作し、実用的なサイズでの性能を実証。
  4. どうやって有効だと検証した?
    • 作製したメタレンズの集光効率を測定し、ピーク効率(81±1%)を確認。
      • 対照としてelectron beam lithographyで製作したメタレンズ(効率89±1%)と比較。
    • spatially resolved deflection efficiency(空間分解偏向効率)とwavefront data(波面データ)を取得。
      • 波面収差が小さいことを確認し、設計とプロセスの精度を評価。
    • シミュレーション結果と実験結果を比較し、一致を確認。
      • プロセスの再現性と信頼性を示唆。
  5. 理科学機器メーカーの技術者にとって、新製品を開発するために何が参考になる?
    • nanoimprint lithographyを用いた高精度なメタサーフェスの大量生産技術。
      • 製造コスト削減とスループット向上により、新製品の競争力を高める。
    • mask-templatingプロセスによる複雑なパターンの再現。
      • デザインの自由度が増し、差別化要因となる製品開発が可能。
    • シリコンナイトライドを用いることで、可視光領域での高性能デバイスの実現。
      • 光学性能の向上や新機能の付加に寄与。
    • 大口径メタレンズの製作技術。
      • 高解像度イメージングやコンパクト光学系への応用展開が期待。
  6. 理科学機器メーカーの営業担当にとって、マーケティング目線で何が参考になる?
    • 高性能かつコスト効率の良いメタサーフェス製品の市場投入が可能。
      • 大量生産に対応し、価格競争力を持つ製品としてアピール。
    • nanoimprint lithographyによる生産性向上を強調。
      • 短納期対応やカスタム製品の提案が容易に。
    • 可視光領域での高効率メタレンズへの需要拡大。
      • スマートフォンやVRデバイスなどのコンパクト光学系市場をターゲット。
    • 競合技術との差別化ポイントを明確化。
      • electron-beam lithographyに比べ、生産性とコストで優位性を持つことを訴求。
  7. この分野は今後、どのように進んでいく?
    • nanoimprint lithographyを活用したメタサーフェスのさらなる普及と応用拡大。
      • 消費者向け電子機器や医療用デバイスへの適用が期待。
    • 製造プロセスの最適化とスケールアップ。
      • 大面積化や生産速度の向上により、市場ニーズに対応。
    • 新材料や新構造の探求による性能向上。
      • 高NAメタレンズや多機能性メタサーフェスの開発。
    • 他分野との融合による新たなイノベーション。
      • フォトニクスやプラズモニクスとの組み合わせによる新技術創出。

この結果をmicrosoft teamsの指定のチャネルに投稿させます。

自動実行させるために、GCP(Google Cloud Platform)のCloud Runサービスを使いサーバーレス運用しています。

技術者が効率的に最新の研究情報を知ることができるほか、Teams上で投稿された論文をもとにチームでの会話が活性化する効果も得られます。

フローチャート

ソースコード

import requests
import json
import os
import arxiv
import openai
import random
import re
import tempfile
import PyPDF2
# OpenAIのapiキー
openai.api_key = os.environ.get("OPENAI_API_KEY")
def download_pdf(pdf_url, paper_id):
    """
    PDFをダウンロードし一時ファイルとして保存する
    """
    # URLをPDF形式に変換
    pdf_url = pdf_url.replace('/abs/', '/pdf/')
    if not pdf_url.endswith('.pdf'):
        pdf_url += '.pdf'
    response = requests.get(pdf_url)
    if response.status_code == 200:
        temp_dir = tempfile.gettempdir()
        pdf_path = os.path.join(temp_dir, f"{paper_id.split('/')[-1]}.pdf")
        print("[INFO] pdf_path")
        print(pdf_path)
        with open(pdf_path, 'wb') as f:
            f.write(response.content)
        
        return pdf_path
    else:
        raise Exception(f"PDFのダウンロードに失敗しました (status code: {response.status_code}). URL: {pdf_url}")
def extract_text_from_pdf(pdf_path):
    """
    PDFファイルからテキストを抽出する
    """
    text = ""
    with open(pdf_path, 'rb') as file:
        reader = PyPDF2.PdfReader(file)
        for page in reader.pages:
            text += page.extract_text()
    return text
def get_summary(result):
    """
    Arxivの結果からPDFをダウンロードし、その内容を要約する
    """
    try:
        # PDF URLを取得してダウンロード
        print(f"Downloading PDF for paper: {result.title}")
        pdf_path = download_pdf(result.pdf_url, result.entry_id)
        
        # PDFからテキストを抽出
        print("Extracting text from PDF...")
        pdf_text = extract_text_from_pdf(pdf_path)
        
        # 抽出したテキストをGPTで要約
        system_message = """添付したテキストは学術論文です。この論文全体を読み込み、内容を解釈した上で
1.どんなもの?(翻訳したタイトルとアブストラクト)
2.先行研究を比べてどこがすごい?
3.技術や手法の肝はどこ?
4.どうやって有効だと検証した?
5.理科学機器メーカーの技術者にとって、新製品を開発するために何が参考になる?
6.理科学機器メーカーの営業担当にとって、マーケティング目線で何が参考になる?
7.この分野は今後、どのように進んでいく?
の7つの項目それぞれについて150文字以上300文字以内で階層からなる箇条書きにしてまとめてください。
一般用語以外は元の言語のまま表記してください。"""
        user_message = f"title: {result.title}\nbody: {pdf_text[:100000]}"  # GPT-4に送信するテキストを100000文字以内に制限
        response = openai.ChatCompletion.create(
            model="gpt-4o-mini",
            messages=[
                {'role': 'system', 'content': system_message},
                {'role': 'user', 'content': user_message}
            ],
            temperature=0.25,
        )
        summary = response['choices'][0]['message']['content']
        # 要約結果を整形
        title_en = result.title
        title, *body = summary.split('\n')
        body = '\n'.join(body)
        date_str = result.published.strftime("%Y-%m-%d %H:%M:%S")
        message = f"発行日: {date_str}\n{result.entry_id}\n{title_en}\n{title}\n{body}\n"
        
        # 一時ファイルを削除
        os.remove(pdf_path)
        return message
    except Exception as e:
        return f"Error in processing paper '{result.title}': {str(e)}"
def send_to_teams(webhook_url, message):
    """
    要約結果をMicrosoft Teamsに送信する
    """
    headers = {
        "Content-Type": "application/json"
    }
        # ログに送信内容を記録
    print("[INFO] Sending message to Teams:")
    print(message)
    
    def create_text_block_with_link(line):
        url_pattern = re.compile(r'http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\\(\\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+')
        urls = url_pattern.findall(line)
        if urls:
            text_fragments = url_pattern.split(line)
            text_without_url = "".join(text_fragments)
            line_with_link = f"{text_without_url} [({urls[0]})]({urls[0]})"
            return {"type": "TextBlock", "text": line_with_link, "wrap": True}
        else:
            return {"type": "TextBlock", "text": line, "wrap": True}
    
    message_lines = message.split("\n")
    text_blocks = [create_text_block_with_link(line) for line in message_lines]
    
    payload = {
        "type": "message",
        "attachments": [
            {
                "contentType": "application/vnd.microsoft.card.adaptive",
                "content": {
                    "type": "AdaptiveCard",
                    "version": "1.2",
                    "body": text_blocks
                }
            }
        ]
    }
    response = requests.post(webhook_url, headers=headers, data=json.dumps(payload))
    if response.status_code != 200:
        raise ValueError(f"Request to Teams returned an error: {response.status_code}, {response.text}")
query_list = ['ti:%22 Electron beam lithography%22', 'ti:%22 nanoindentation %22']
def main(event, context):
    for query in query_list:
        search = arxiv.Search(
            query=query,
            max_results=250,
            sort_by=arxiv.SortCriterion.SubmittedDate,
            sort_order=arxiv.SortOrder.Descending,
        )
        result_list = list(search.results())
        
        if not result_list:
            print(f"No papers found for query: {query}")
            continue
        results = random.sample(result_list, k=1)  # ランダムに1件選択
        output = get_summary(results[0])
        output_add = f"{output}**本要約はgpt-4o-miniによって生成されました。**"
        webhook_url = os.environ.get("TEAMS_WEBHOOK_URL")
        send_to_teams(webhook_url, output_add)

OpenAI APIのバージョンが更新される前に書いたコードなので、古いバージョンOpenAIのライブラリで動いています。

# Function dependencies, for example:
# package>=version
requests>=2.28.2
arxiv>=1.4.4
openai== 0.27.4
PyPDF2>=3.0.0