2
0

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で論文を要約しブログに投稿する

Posted at

これは時代が変わるぞという実感がやってきました。

ChatGPTが新着論文を要約し毎朝メールしてくれる仕組みの作り方 | Antaa Slide @antaa__jp #Antaa https://slide.antaa.jp/article/view/d0de1bd8ea414420

Pubmedというアメリカの論文サイトで検索して、その結果をChatGPTに送って、要約・翻訳した結果をまとめてメールするという仕組みです。

-スライドにあったGASをコピー
-ChatGPTのAPIを取得
-API、メアド、検索キーワード、タイトルを変更
-毎朝実行する
(3時間)

新着論文が和訳されてメールがきて、おおーっ、やばいくらい感動しました!
ものすごく苦労してきた事が簡単に・・・

せっかくなので、メールだけではなく、スプレッドシートに内容をストック(3時間)
宛先を個人ではなく、ブログ宛に変更。(3時間)

それにしてもプログラミングって時間どろぼうですね。

test.js

// OpenAI の API keys (https://platform.openai.com/account/api-keys)
const OPENAI_API_KEY = "xxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// ChatGPT に渡す命令
const PROMPT_PREFIX = "あなたはADHDに詳しい心理学者です。以下の論文を、タイトルと要約の2点をそれぞれ改行で分けて日本語で説明してください。要点は箇条書きで。";

// 結果メールの送信先
const EMAIL_RECIPIENT = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// 結果メールのタイトル
const EMAIL_SUBJECT = "PubMedの新着論文の要約";
// 結果メールの送信者の名前
const EMAIL_SENDER = "PubMed要約bot";

// PubMed の検索クエリ
const PUBMED_QUERY = "ADHD";
// PubMed の対象の記事タイプ(以下のいずれかのタイプとマッチする論文のみをヒットさせる ※ 期待したように記事タイプが判定されない場合も多い)
const PUBMED_PUBTYPES = ["Journal Article", "Books and Documents", "Clinical Trial", "Meta-Analysis", "Randomized Controlled Trial", "Review", "Systematic Review"];
// PubMed の検索対象日数
const PUBMED_TERM = 1;
// PubMed の検索時のヒット論文で要約する論文の本数の上限(多ければ多いだけ、ChatGPT API の token を多く消費する)
const MAX_PAPER_COUNT = 100;

//記録用のスプレッドシート
const sheet = SpreadsheetApp.getActiveSheet();

function main() {
    if (!OPENAI_API_KEY) {
        console.log("ERROR: OPEN_API_KEY を指定してください");
        return;
    }
    const today = new Date();
    const yesterday = new Date(today.getFullYear(), today.getMonth(), today.getDate() - PUBMED_TERM);
    const ids = getPaperIDsOn(yesterday);

    let output = "[:contents]\n\n";
    let paperCount = 0;

    for (let i = 0; i < ids.length; i++) {
        Utilities.sleep(1000);
        const id = ids[i];
        const pubmedUrl = `https://pubmed.ncbi.nlm.nih.gov/${id}`;
        const summary = getPaperSummaryByID(id);
        const title = summary.title;

        console.log(`id: ${id}, pubtype: ${summary.pubtype.join(",")}`);
        if (!checkPubtype(summary.pubtype)) {
            console.log("pubtype: NG");
            continue;
        }
        console.log("pubtype: OK");

        if (++paperCount > MAX_PAPER_COUNT) break;
        const abstract = getPaperAbstractByID(id);
        const input = "\n" + "title: " + title + "\n" + "abstract: " + abstract;
        const res = callChatGPT(input);
        console.log(res);
        const paragraphs = res.choices.map((c) => c.message.content.trim());

        //はてぶ記法で先頭に"*"を追記 
        output += "*" + `${paragraphs.join("\n")}\n\n${pubmedUrl}\n\n\n`;
        //スプレッドシートに追記
        sendSheet(paragraphs,pubmedUrl);
    }
    if (paperCount === 0) {
        output += "検索条件に合致した新着論文はありませんでした。";
    }
    output = output.trim();
    sendEmail(output);
 
}

function toYYYYMMDD(date) {
    return [date.getFullYear(), date.getMonth() + 1, date.getDate()].join("/");
}

function getPaperIDsOn(date) {
    const query = encodeURIComponent(PUBMED_QUERY);
    const url = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&retmode=json&sort=pub_date&term=${query}&mindate=${toYYYYMMDD(date)}&maxdate=${toYYYYMMDD(date)}`;
    console.log(url);
    const res = JSON.parse(UrlFetchApp.fetch(url).getContentText());
    return res.esearchresult.idlist;
}

function getPaperSummaryByID(id) {
    const url = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esummary.fcgi?db=pubmed&retmode=json&id=${id}`;
    console.log(url);
    const res = JSON.parse(UrlFetchApp.fetch(url).getContentText());
    return res.result[id];
}

function getPaperAbstractByID(id) {
    const url = `https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&retmode=xml&id=${id}`;
    const xml = UrlFetchApp.fetch(url).getContentText();
    const match = xml.match(/<Abstract>(.*?)<\/Abstract>/);
    return match ? match[1] : "";
}

function checkPubtype(pubtypes) {
    const common = pubtypes.filter(x => PUBMED_PUBTYPES.indexOf(x) !== -1);
    return common.length > 0;
}

function callChatGPT(input) {
    const messages = [
        {
            role: "user",
            content: PROMPT_PREFIX + "\n" + input,
        },
    ];

    const url = "https://api.openai.com/v1/chat/completions";

    const options = {
        "method": "post",
        "headers": {
            "Authorization": `Bearer ${OPENAI_API_KEY}`,
            "Content-Type": "application/json",
        },
        "payload": JSON.stringify({
            model: "gpt-3.5-turbo",
            messages,
        }),
    };

    return JSON.parse(UrlFetchApp.fetch(url, options).getContentText());
}

function sendEmail(body) {
    const options = { name: EMAIL_SENDER };
    
    //件名に日付をいれたい
    const date1 = new Date().toLocaleDateString("ja-JP", {year: "numeric",month: "2-digit",
   day: "2-digit"});
    GmailApp.sendEmail(EMAIL_RECIPIENT, date1 +" "+ EMAIL_SUBJECT, body, options);
}

function sendSheet(body,url) {
  let date = new Date();
  value = [date,url,body];
  value = value.flat();
  //スプレッドシートの最終行に挿入
  sheet.appendRow(value);
}
2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?