毎日特定のキーワードでPubMed検索して引っかかった論文の要約をChatGPTでおこないメールで通知する
実現したこと
研究者にとって、最新の医学研究論文をフォローすることは非常に重要ですが、同時に時間がかかる作業でもあります。本記事では、毎朝7時に設定したキーワードに基づいて前日にPubMedに掲載された論文を自動的に収集し、AIを使用して日本語で要約した上でメール通知する仕組みを紹介します。
以前、Microsoft teamsバージョンの記事は書きました↓
Slackバージョンの記事も書きました↓
しかし、TeamsもSlackもラボで使っていないという場合もあると思いますのでメールで通知する仕組みも紹介します。
目的
研究室のメンバーが最新の研究動向を効率的に把握できるようにする
興味のある論文を見逃すリスクを減らす
英語論文の内容を日本語で簡単に理解できるようにする
学生の研究リテラシーと英語力の向上を支援する
実装の概要
この仕組みは以下の要素で構成されています:
Raspberry Pi(ラズパイ)上の Python 仮想環境
PubMedを使用した論文検索
OpenAI GPTモデルを使用した論文要約
smtplibを利用してメール送信
実装手順
Raspberry pi (ラズパイ)仮想環境
# Pythonのバージョンチェック
python -V
# Venvで仮想環境構築
sudo python3.xx -m venv hoge
source hoge/bin/activate
sudo chown -R fuga:fuga /home/fuga/仮想環境フォルダ名
ライブラリのインストール
pip install openai requests xmltodict python-dotenv
OpanAI APIキー取得
OpenAIのウェブサイトでアカウントを作成し、APIキーを取得します。詳細な手順はこちらの記事を参照してください。
Pythonスクリプト
以下のPythonスクリプトを作成し、script.pyとして保存します。このスクリプトが論文の検索、要約、Slackへの投稿を行います。
cd hoge
sudo nano script.py
from openai import OpenAI
import os
import requests
import xmltodict
from datetime import datetime, timedelta
from dotenv import load_dotenv
import time
import smtplib
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
load_dotenv()
OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
SMTP_SERVER = os.getenv("SMTP_SERVER")
SMTP_PORT = os.getenv("SMTP_PORT")
SMTP_USERNAME = os.getenv("SMTP_USERNAME")
SMTP_PASSWORD = os.getenv("SMTP_PASSWORD")
SENDER_EMAIL = os.getenv("SENDER_EMAIL")
RECIPIENT_EMAIL = os.getenv("RECIPIENT_EMAIL")
CC_EMAIL = os.getenv("CC_EMAIL", "")
BCC_EMAIL = os.getenv("BCC_EMAIL", "")
PUBMED_QUERIES = os.getenv("PUBMED_QUERIES").split(',')
PUBMED_PUBTYPES = [
"Journal Article",
"Books and Documents",
"Clinical Trial",
"Meta-Analysis",
"Randomized Controlled Trial",
"Review",
"Systematic Review",
]
PUBMED_TERM = 1
PROMPT_PREFIX = (
"あなたは高度に教育と訓練をした研究者です。以下の論文を、タイトルと要約の2点をそれぞれ改行で分けて日本語で説明してください。要点は必ず箇条書き形式で書いてください。"
)
def main():
client = OpenAI(api_key=OPENAI_API_KEY)
today = datetime.now()
yesterday = today - timedelta(days=PUBMED_TERM)
for query in PUBMED_QUERIES:
while True:
try:
ids = get_paper_ids_on(yesterday, query)
print(f"{query} の論文ID数: {len(ids)}")
output = ""
paper_count = 0
for i, id in enumerate(ids):
summary = get_paper_summary_by_id(id)
pubtype_check_result = check_pubtype(summary["pubtype"])
print(f"ID {id} のpubtype: {summary['pubtype']}, チェック結果: {pubtype_check_result}")
if not pubtype_check_result:
continue
paper_count += 1
abstract = get_paper_abstract_by_id(id)
print(f"ID {id} のタイトル: {summary['title']}")
print(f"ID {id} の要約: {abstract}\n")
input_text = f"\ntitle: {summary['title']}\nabstract: {abstract}"
response = client.chat.completions.create(
messages=[
{
"role": "user",
"content": PROMPT_PREFIX + "\n" + input_text,
},
],
model="gpt-4o-mini",
)
content = response.choices[0].message.content.strip()
pubmed_url = f"https://pubmed.ncbi.nlm.nih.gov/{id}"
output += f"PubMed の新着論文のお知らせ ({query})\n\n{content}\n\n{pubmed_url}\n\n\n"
if output:
send_email(query, output, to_yyyymmdd(yesterday))
else:
print(f"No new papers for query: {query}")
break
except openai.RateLimitError as e:
print("Rate limit exceeded. Waiting for 300 seconds before retrying.")
time.sleep(300)
except Exception as e:
print(f"An error occurred: {e}")
time.sleep(60)
def to_yyyymmdd(date):
return date.strftime("%Y/%m/%d")
def get_paper_ids_on(date, query):
url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&retmode=json&sort=pub_date&term={query}&mindate={to_yyyymmdd(date)}&maxdate={to_yyyymmdd(date)}&retmax=1000&retstart=0"
res = requests.get(url).json()
return res["esearchresult"]["idlist"]
def get_paper_summary_by_id(id):
url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id={id}"
res = requests.get(url).json()
return res["result"][id]
def get_paper_abstract_by_id(id):
url = f"https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&retmode=xml&id={id}"
res = requests.get(url).text
xml_dict = xmltodict.parse(res)
abstract = xml_dict["PubmedArticleSet"]["PubmedArticle"]["MedlineCitation"]["Article"].get("Abstract", {}).get("AbstractText", "")
return abstract if abstract else ""
def check_pubtype(pubtypes):
return any(pubtype in PUBMED_PUBTYPES for pubtype in pubtypes)
def send_email(query, content, search_date):
msg = MIMEMultipart('alternative')
msg['Subject'] = f'新着論文のお知らせ ({query}) - 検索対象日: {search_date}'
msg['From'] = SENDER_EMAIL
msg['To'] = RECIPIENT_EMAIL
if CC_EMAIL:
msg['Cc'] = CC_EMAIL
text = content
html = content.replace('\n', '<br>')
html = f'<html><body>{html}</body></html>'
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')
msg.attach(part1)
msg.attach(part2)
try:
with smtplib.SMTP(SMTP_SERVER, SMTP_PORT) as server:
server.starttls()
server.login(SMTP_USERNAME, SMTP_PASSWORD)
recipients = [RECIPIENT_EMAIL]
if CC_EMAIL:
recipients.extend(CC_EMAIL.split(','))
if BCC_EMAIL:
recipients.extend(BCC_EMAIL.split(','))
server.sendmail(SENDER_EMAIL, recipients, msg.as_string())
print(f"Email sent for query: {query}")
except Exception as e:
print(f"Failed to send email for query {query}. Error: {e}")
if __name__ == "__main__":
main()
環境変数の設定
.envファイルを作成し、以下の内容を記入します:
cd hoge
sudo nano .env
# OpenAI API Key
OPENAI_API_KEY=ここにopenAIのAPIキー
# E-mail setting
SMTP_SERVER=ここにSMTPサーバー記述
SMTP_PORT=587 #メールシステムに依存
SMTP_USERNAME=メールID
SMTP_PASSWORD=ここにパスワード
SENDER_EMAIL=ここに送信メールアドレス
RECIPIENT_EMAIL=ここに宛先メールアドレス #複数の時はxxx@xxx.xx, yyy@yyy.yy
CC_EMAIL=ここにCCメールアドレス #空欄でもOK。複数の時はxxx@xxx.xx, yyy@yyy.yy
BCC_EMAIL=ここにBCCメールアドレス #空欄でもOK。複数の時はxxx@xxx.xx, yyy@yyy.yy
# PubMed search queries, separated by commas
PUBMED_QUERIES=hoge fuga, fuga, hoge, hhh xxx yyy
実行スクリプトの作成
script.shというシェルスクリプトを作成し、以下の内容を記入します:
# シェルスクリプト作成
cd hoge
sudo nano script.sh
#!/bin/sh
PROG_DIR=/home/fuge/hoge
source hoge/bin/activate
python3 $PROG_DIR/script.py
deactivate
Crontabの設定
crontab -e
0 7 * * * cd /home/fuga/huge; sudo bash script.sh
もしくは
0 7 * * * /home/user/hoge/venv/bin/python /home/user/fuga/huge/script.py
これにより、毎朝7時にスクリプトが実行されます。
まとめ
この仕組みを使うことで、以下のメリットが得られます:
毎日自動的に最新の研究論文を収集し、日本語で要約された内容を簡単に確認できる
複数のキーワードを設定することで、幅広い研究分野をカバーできる
メールを利用することで、チーム全体で情報を共有しやすい
生成AIによる要約により、素早く論文の概要を把握できる
興味のある論文はPubMedリンクから詳細を確認できる
この仕組みは、研究室の生産性向上に大きく貢献し、学生の研究スキル向上にも役立つでしょう。定期的にキーワードを見直すことで、常に最新かつ関連性の高い情報を得ることができます。
この記事が気に入ったらサポートをしてみませんか?