Skip to content

Instantly share code, notes, and snippets.

@resnant
Last active May 5, 2023 04:14
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save resnant/d42ae67315f0c073e3c244a913f6d408 to your computer and use it in GitHub Desktop.
Save resnant/d42ae67315f0c073e3c244a913f6d408 to your computer and use it in GitHub Desktop.
arXiv新着論文のChatGPTによる日本語要約をメール送信するGoogle App Script
// 使い方:
// 1. OpenAIのAPI keyを取得する→(https://platform.openai.com/account/api-keys
// 2. https://script.google.com/home/ にアクセスし、新しいプロジェクトを作成する。
// 3. 作成したプロジェクトを開き、このコード全文をエディタにコピペする。API Keyとメールアドレスを埋める。
// 4. この時点でコードエディタ画面上部の実行ボタン(再生マーク)を押して正しく実行できるか確認しておくと良い
// 5. 左カラムからトリガー設定画面(目覚ましアイコン)を開き、よしなに自動実行を設定する。
// 参考にさせていただいたスクリプト:
// https://script.google.com/home/projects/1M6yhI6PTaFpvcZeRVycmJZoh2LhUL_Zk64pxwDYCLjD1K14Qirf7Nov-
// https://twitter.com/niniziv/status/1638155751515631617
// OpenAI の API keyを入力↓
const OPENAI_API_KEY = "sk-";
// ChatGPT に渡すプロンプト(適宜変えること)
const PROMPT_PREFIX = "あなたは機械学習と材料科学に精通した研究者で、論文を簡潔に要約することに優れています。以下の論文を、タイトルと要約の2点をそれぞれ改行で分けて日本語で説明してください。要点は箇条書きで4-8行程度にまとめること。";
// 結果メールの送信先を入力↓
const EMAIL_RECIPIENT = "";
// 結果メールのタイトル
const EMAIL_SUBJECT = "arXivの新着論文のお知らせ";
// 結果メールの送信者の名前
const EMAIL_SENDER = "arXiv要約Bot";
// 検索クエリを定義(適宜修正する)
// 例:cond-mat.mtrl-sciカテゴリの論文のうち、タイトルか要旨にmachine learningもしくはdeep learningを含む論文を検索する場合↓
const ARXIV_QUERY = "cat:cond-mat.mtrl-sci AND (ti:machine learning OR ti:deep learning OR abs:machine learning OR abs:deep learning)";
const MAX_PAPER_COUNT = 10; // 最大結果数
const ARXIV_API_URL = `http://export.arxiv.org/api/query`;
const ARXIV_TERM = 7; // 過去何日分の記事を検索するか
function main() {
if (!OPENAI_API_KEY) {
console.log("ERROR: OPEN_API_KEY を指定してください");
return;
}
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - ARXIV_TERM);
const { entries, namespace } = getEntriesOn(yesterday);
let output = "arXivの新着論文のお知らせ\n\n";
let paperCount = 0;
entries.forEach(entry => {
const arxivUrl = entry.getChild('id', namespace).getText();
const title = entry.getChild("title", namespace).getText();
if (++paperCount > MAX_PAPER_COUNT) return;
const authors = entry.getChildren("author", namespace);
const authorNames = authors.map(author => author.getChild("name", namespace).getText()).join(", ");
const summary = entry.getChild("summary", namespace).getText();
const input = "\n" + "title: " + title + "\n" + "summary: " + summary;
const res = callChatGPT([
{
role: "user",
content: PROMPT_PREFIX + "\n" + input,
},
]);
const paragraphs = res.choices.map((c) => c.message.content.trim());
output += `Title: ${title}\nAuthors: ${authorNames}\n\n ${paragraphs.join("\n")}\n\n${arxivUrl}\n------------------------\n\n\n`;
});
output = output.trim();
console.log(output);
sendEmail(output);
}
function toYYYYMMDD(date) {
return [date.getFullYear(), date.getMonth() + 1, date.getDate()].join("-");
}
function getEntriesOn(date) {
const url = `${ARXIV_API_URL}?search_query=${ARXIV_QUERY}&sortBy=lastUpdatedDate&sortOrder=descending&max_results=${MAX_PAPER_COUNT}&start=0&start=0&submitted_date[from]=${toYYYYMMDD(date)}&submitted_date[to]=${toYYYYMMDD(date)}`;
// console.log(url);
const feed = UrlFetchApp.fetch(url).getContentText();
// console.log(feed);
const xml = UrlFetchApp.fetch(url).getContentText();
// const xml = XmlService.parse(feed);
// console.log(xml);
const xmlDocs = XmlService.parse(xml);
const namespace = XmlService.getNamespace('', 'http://www.w3.org/2005/Atom');
const entries = xmlDocs.getRootElement().getChildren('entry', namespace);
// console.log(entries);
return { entries, namespace };
}
function callChatGPT(messages) {
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 recipient = EMAIL_RECIPIENT;
const subject = EMAIL_SUBJECT;
const options = { name: EMAIL_SENDER };
GmailApp.sendEmail(recipient, subject, body, options);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment