Paper AI - arXivから興味のある論文を検索し、論文のabstractを要約しSlackへ投稿するAIボット

Paper AIは、arXivから興味のある論文を検索し、見つかった論文のabstractを要約しSlackへ投稿するAIボットです。FirebaseのCloud Functionsで動作します。
Singularity Societyで開催している半年間にわたるオンラインのハッカソン、BootCampのサブプロジェクトとして作成されました。

ソースはこちら

動作の仕組み

FirebaseのCloud Funstions上で動作します

export const search_arxiv = async (db: admin.firestore.Firestore) => {
  try {
    const papers = await search_arxiv_papers();

    for await (const data of papers) {
      const id = data.id.replace("http://", "").replace(/\//g, "-");
      data.authors = data.authors.map((author) => author.join(","));

      const path = `/papers/${id}`;
      const currentDoc = (await db.doc(path).get()).data();
      if (!currentDoc) {
        await db.doc(path).set(data);
      }
    }
  } catch (error) {
    console.log(error);
  }
};
export const createPaperEvent = async (
  db: firebase.firestore.Firestore,
  snap: firebase.firestore.QueryDocumentSnapshot,
  context: EventContext,
) => {
  const data = snap.data();
  const { paperId } = context.params;
  if (!data) {
    console.log("no data");
    return;
  }
  const summary_data = await call_llm(data);
  if (!summary_data) {
    console.log("no summary");
    return;
  }
  await db.doc(`summaries/${paperId}`).set({
    summary: summary_data,
    id: data.id,
    title: data.title,
  });
  const message = formatPushMessage(summary_data, data);
  await pushSlask(message);

  return;
};

export const call_llm = async (data: firebase.firestore.DocumentData) => {
  const text = `title: ${data.title}\nbody: ${data.summary}"`;

  const res = await call_slashgpt(text);
  if (res.result) {
    return res.function_result;
  }
  return null;
};

設定

Firebaseのプロジェクト設定

functions:secrets にOpenAIのsecret keyとSlack bot用のtoken/channnelをセットする

Slack apiのページのCreate New APPでアプリを作成します。

作成したアプリのOAuth tokenをコピーし、SLACKTOKENとして登録します。

SLACKCHANNELはbotが要約を出力するチャンネル。このチャンネルにbotを招待します。

OPENAI_API_KEYはopenaiのapikeyを指定します。

Secret Manager APIの設定を要求された場合は、それに従って有効にする。

firebase functions:secrets:set SLACKTOKEN --project=default
firebase functions:secrets:set SLACKCHANNEL --project=default
firebase functions:secrets:set OPENAI_API_KEY --project=default
firebase deploy --only functions --project=default

正しく設定できていると、以下のようにSlackのチャンネルにpaper aiのbotが要約を投稿するようになります。

初回実行時はOpenAIのAPIへのアクセスが大量になり、上限に引っかかってエラーになることがあります。2回目以降は差分となるので、エラーはほぼ出なくなります。

カスタマイズ

検索とSlack投稿formatのカスタマイズ

初期の状態では、arXivにはLLMのキーワードで検索をしています。search_arxiv_papers関数を変更することで、検索内容を変更することができます。

Slackの投稿時に、formatPushMessageで整形をしています。

この2つの関数はlib/utils.tsにあります。

export const search_arxiv_papers = async () => {
  const papers = await search({
    searchQueryParams: [
      {
        include: [{ name: "LLM" }],
      },
    ],
    sortBy: "lastUpdatedDate",
    sortOrder: "descending",
    start: 0,
    maxResults: 100,
  });
  return papers;
};

export const formatPushMessage = (
  summary_data: LLMSummary,
  data: firebase.firestore.DocumentData,
) => {
  const { title, keywords, issues, methods, results } = summary_data;
  const base_title = data.title.replaceAll("\n", "");
  return [
    "------------------",
    `${base_title} (${data.id})`,
    "------------------",
    "",
    [
      `📚内容: ${title}`,
      `🔑キーワード: ${keywords}`,
      `❓問題点: ${issues}`,
      `⚒️手法:️ ${methods}`,
      `⭐結果: ${results}`,
    ].join("\n\n"),
  ].join("\n");
};

プロンプトのカスタマイズ

Paper AIでは、LLMの処理にSlashGPTTypescript版を利用しています。プロンプトはマニフェストに書かれています。また、要約の結果を整形した状態で受け取るために、Function callingを使っています。Function callingの定義はこちら
これらをカスタマイズすることにより、要約の精度の向上や他の項目の取得が可能になります。

動作テスト

Paper AIを実際に動かすのは、FirebaseのFirestore, Functionsが必要となり、Trigger処理をしているので開発時に環境設定が複雑になります。

そのためlocalでテストするために、各それぞれの機能を関数にして、Firebaseに依存しない形でテスト可能にしています。

以下のスクリプトで、単体の動作が可能となる。

論文を検索するスクリプト

 npx ts-node tests/arxiv.ts

GPTに要約させるスクリプト

 OPENAI_API_KEY=xxxx npx ts-node tests/gpt.ts

Slackに投稿するデータを変換するスクリプト

 npx ts-node tests/format_data.ts

おわりに。

以下TODOです。パッチ大歓迎です。