0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ChatGPTで毎朝arxivのLLM関連論文を要約してSlackに投稿するbot

Posted at

自分向けメモ。
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に設定する。

image.png

これで、毎朝8時に論文要約もどきが投稿される。

0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?