自分向けメモ。
Cloud functionにデプロイしてる。
コードは下記。
index.js
const axios = require("axios");
const schedule = require("node-schedule");
const { DOMParser } = require("xmldom");
const { Configuration, OpenAIApi } = require("openai");
const OPENAI_API_KEY = process.env.OPENAI_API_KEY;
const SLACK_WEBHOOK_URL = process.env.SLACK_WEBHOOK_URL;
const configuration = new Configuration({
apiKey: OPENAI_API_KEY
});
const openai = new OpenAIApi(configuration);
const slackWebhookUrl = SLACK_WEBHOOK_URL;
const project = 'hogehogehoge'
async function fetchArxivPapers(query) {
const response = await axios.get("https://export.arxiv.org/api/query", {
params: {
search_query: query,
sortBy: "submittedDate",
sort_order: "descending",
max_results: 5
}
});
const data = new DOMParser().parseFromString(response.data, "application/xml");
const entries = Array.from(data.getElementsByTagName("entry"));
return entries.map(entry => {
return {
id: entry.getElementsByTagName("id")[0].textContent,
title: entry.getElementsByTagName("title")[0].textContent,
summary: entry.getElementsByTagName("summary")[0].textContent,
link: entry.getElementsByTagName("link")[0].getAttribute("href"),
published: entry.getElementsByTagName("published")[0].textContent
};
});
}
async function summarizeAbstract(paper) {
const prompt = `
あなたは、${paper.title}という論文を読んでいます。
この論文の要約を作成してください。
要約: ${paper.summary}
`;
const response = await openai.createChatCompletion({
model: "gpt-3.5-turbo",
messages: [{"role": "user", "content": prompt}],
});
return response.data.choices[0].message.content;
}
async function postToSlack(paper, summary) {
const message = {
text: `*${paper.title}* \n_URL: ${paper.id} \n要約: ${summary}\n`
};
await axios.post(slackWebhookUrl, message);
}
exports.arxivSummaryBot = async (req, res) => {
const globalLogFields = {};
// Add log correlation to nest all log messages beneath request log in Log Viewer.
// (This only works for HTTP-based invocations where `req` is defined.)
if (typeof req !== 'undefined') {
const traceHeader = req.header('X-Cloud-Trace-Context');
if (traceHeader && project) {
const [trace] = traceHeader.split('/');
globalLogFields[
'logging.googleapis.com/trace'
] = `projects/${project}/traces/${trace}`;
}
}
const queryLLM = "LLM";
const queryChatGPT = "ChatGPT";
const papersLLM = await fetchArxivPapers(queryLLM);
const papersChatGPT = await fetchArxivPapers(queryChatGPT);
const papers = [...papersLLM, ...papersChatGPT].filter(
(paper, index, self) =>
index === self.findIndex((p) => p.id === paper.id)
);
const today = new Date();
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 2);
let postedSummaries = false;
for (const paper of papers) {
const submittedDate = new Date(paper.published);
if (submittedDate >= yesterday && submittedDate <= today) {
const summary = await summarizeAbstract(paper);
await postToSlack(paper, summary);
postedSummaries = true;
}
}
if (res) {
if (postedSummaries) {
console.log(JSON.stringify(Object.assign(
{
severity: 'INFO',
message: 'Posted summaries to Slack',
},
globalLogFields
)))
res.status(200).send();
} else {
console.log(JSON.stringify(Object.assign(
{
severity: 'INFO',
message: 'No new papers found.',
},
globalLogFields
)))
res.status(200).send();
}
} else {
if (postedSummaries) {
console.log(JSON.stringify(Object.assign(
{
severity: 'INFO',
message: 'Posted summaries to Slack',
},
globalLogFields
)))
} else {
console.log(JSON.stringify(Object.assign(
{
severity: 'INFO',
message: 'No new papers found.',
},
globalLogFields
)))
}
}
};
schedule.scheduleJob("0 8 * * *", () => {
exports.arxivSummaryBot();
});
// exports.arxivSummaryBot();
で、毎朝8時にこれを叩くために、cloud schedulerに設定する。
これで、毎朝8時に論文要約もどきが投稿される。