見出し画像

GPTとNotionを連携した会話AIを作る!miibo✖️NotionAPIの繋ぎ方

はじめまして!
株式会社miiboでエンジニア & Developer Advocateをしている森琢郎(takumori)です。
エンジニア目線で、ちょっとテクニカルなmiiboの使い方やアイデアを発信していきます!

この記事では、miiboを使ったサービスでの会話中にNotionの記事を検索する方法を紹介します。


※本記事は、株式会社miiboの提供です

この記事のゴール

この記事では、miiboとNotionをAWS Lambdaで繋ぐことで、Notionのページ情報をmiiboのプロンプトに注入することをゴールにしています。

構成のイメージ

処理の流れとしては、以下のように行います。
① Function Callingされたタイミングで、lambdaにリクエストする
②③ AWS Lambdaから、Notionの検索を行う
④⑤ 検索結果があれば、NotionのPageの中身を抽出する
⑥ 結果をmiiboに返して、プロンプトに挿入する

Notionのセットアップ

最初にNotionのセットアップをしましょう。

検索対象の準備

今回は、料理のアイデアという内容でページをいくつか用意しました。

Notion上のページ一覧
ページの内容例

Notion APIの準備

APIのsecretを生成するため、まずはインテグレーションの準備をします。
下記に簡単に手順を示します。

  1. https://www.notion.com/my-integrations にアクセスする

  2. 新しいインテグレーションを作成する

  3. Secretsを取得する

Secretsが取得できたら、まずは疎通確認をしましょう。

# 検索APIを使ったサンプルリクエスト
% curl -X POST 'https://api.notion.com/v1/search' \
  -H 'Authorization: Bearer '"$NOTION_API_KEY"'' \
  -H 'Content-Type: application/json' \
  -H 'Notion-Version: 2022-06-28' \
  --data '{
    "sort":{
      "direction":"ascending",
      "timestamp":"last_edited_time"
    }
  }'

{"object":"list","results":[{"object":"page","id":"7e403f24-92b5-4008-b776-399a5a63547d","created_time":"2023-10-14T10:41:00.000Z","last_edited_time":"2023-10-14T10:41:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"料理の基本:誰でもできる料理のステップバイステップガイド","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"料理の基本:誰でもできる料理のステップバイステップガイド","href":null}]}},"url":"https://www.notion.so/7e403f2492b54008b776399a5a63547d","public_url":null},{"object":"page","id":"28eeddf3-f73f-4d11-ac33-96d8b1b251d6","created_time":"2023-10-14T10:41:00.000Z","last_edited_time":"2023-10-14T10:42:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"健康的な食事の楽しみ方:栄養バランスの取れた献立の作り方","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"健康的な食事の楽しみ方:栄養バランスの取れた献立の作り方","href":null}]}},"url":"https://www.notion.so/28eeddf3f73f4d11ac3396d8b1b251d6","public_url":null},{"object":"page","id":"4be0afe0-b173-47e1-8b11-902bd18bdbaa","created_time":"2023-10-14T10:43:00.000Z","last_edited_time":"2023-10-14T10:44:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"ダイエットと美味しさの両立:ヘルシーなレシピの提案","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"ダイエットと美味しさの両立:ヘルシーなレシピの提案","href":null}]}},"url":"https://www.notion.so/4be0afe0b17347e18b11902bd18bdbaa","public_url":null},{"object":"page","id":"47658e59-2012-4998-9380-71838a7403d9","created_time":"2023-10-14T10:44:00.000Z","last_edited_time":"2023-10-14T10:45:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"世界を味わう:国際料理のレシピ集","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"世界を味わう:国際料理のレシピ集","href":null}]}},"url":"https://www.notion.so/47658e5920124998938071838a7403d9","public_url":null},{"object":"page","id":"05832978-d565-4a40-b23b-d5d520b60a08","created_time":"2023-10-14T10:45:00.000Z","last_edited_time":"2023-10-14T10:47:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"忙しい日でもおいしい食事:時短調理のコツ","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"忙しい日でもおいしい食事:時短調理のコツ","href":null}]}},"url":"https://www.notion.so/05832978d5654a40b23bd5d520b60a08","public_url":null},{"object":"page","id":"9741abf3-495f-4b9c-82be-f78660ea05b1","created_time":"2023-10-14T10:47:00.000Z","last_edited_time":"2023-10-14T10:47:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"おしゃれな食卓:料理の盛り付けとデコレーションのアイデア","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"おしゃれな食卓:料理の盛り付けとデコレーションのアイデア","href":null}]}},"url":"https://www.notion.so/9741abf3495f4b9c82bef78660ea05b1","public_url":null},{"object":"page","id":"a5e23d83-2674-4b08-81f3-0f66e565d05e","created_time":"2023-10-14T10:47:00.000Z","last_edited_time":"2023-10-14T10:54:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"スーパーフードの料理法:体に良い食材の活用法","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"スーパーフードの料理法:体に良い食材の活用法","href":null}]}},"url":"https://www.notion.so/a5e23d8326744b0881f30f66e565d05e","public_url":null},{"object":"page","id":"df60c8ba-1d66-4424-bd70-febac6bd16da","created_time":"2023-10-14T10:42:00.000Z","last_edited_time":"2023-10-14T10:54:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"プロが教えるシェフの秘密:レストランのような料理を家庭で作る方法","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"プロが教えるシェフの秘密:レストランのような料理を家庭で作る方法","href":null}]}},"url":"https://www.notion.so/df60c8ba1d664424bd70febac6bd16da","public_url":null},{"object":"page","id":"5ea786bf-1edf-49b9-8fe6-2151fb84da2d","created_time":"2023-10-14T10:23:00.000Z","last_edited_time":"2023-10-14T10:54:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"美味しい夕食のアイデア:簡単な家庭料理レシピ集","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"美味しい夕食のアイデア:簡単な家庭料理レシピ集","href":null}]}},"url":"https://www.notion.so/5ea786bf1edf49b98fe62151fb84da2d","public_url":null},{"object":"page","id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5","created_time":"2023-10-14T10:15:00.000Z","last_edited_time":"2023-10-14T10:55:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":{"type":"emoji","emoji":"🍳"},"parent":{"type":"workspace","workspace":true},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"料理アイデア","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"料理アイデア","href":null}]}},"url":"https://www.notion.so/210e5f7a25fe4178b34a3b8f30ce0bb5","public_url":null},{"object":"page","id":"f6e00e8e-ea5c-4f72-aeff-2d304f517c63","created_time":"2023-10-14T10:43:00.000Z","last_edited_time":"2023-10-14T13:33:00.000Z","created_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"last_edited_by":{"object":"user","id":"2865f273-863b-4d3f-bca9-8b1c1fb465f6"},"cover":null,"icon":null,"parent":{"type":"page_id","page_id":"210e5f7a-25fe-4178-b34a-3b8f30ce0bb5"},"archived":false,"properties":{"title":{"id":"title","type":"title","title":[{"type":"text","text":{"content":"季節の食材を活用:旬の食材を使った季節料理のアイデア","link":null},"annotations":{"bold":false,"italic":false,"strikethrough":false,"underline":false,"code":false,"color":"default"},"plain_text":"季節の食材を活用:旬の食材を使った季節料理のアイデア","href":null}]}},"url":"https://www.notion.so/f6e00e8eea5c4f72aeff2d304f517c63","public_url":null}],"next_cursor":null,"has_more":false,"type":"page_or_database","page_or_database":{},"request_id":"1591eefb-f4ac-4abd-b1ec-9adb0963feb0"}

確認ができれば、NotionAPIの準備は完了です!

AWS Lambdaのセットアップ

次にLambdaをセットアップをします。まずはLambdaのトリガーを設定しましょう。トリガーには、API Gatewayを設定しAPI endpointは控えておきます。

トリガーの設定例

この記事では、Pythonを使って関数を作成していきます。
LambdaからのNotionAPIへのリクエストで requests を使うため、ローカルで開発してzipファイルでアップロードします。

# ディレクトリ作成とrequestsのダウンロード
% mkdir notion-api-sample
% cd notion-api-sample
% pip install requests -t ./

メインのスクリプトでは、ゴールで示した②~⑤の処理を行っています。

# lambda_function.py

import requests
import json

NOTION_TOKEN = "<NOTION_TOKEN>"
HEADERS = {
    "Notion-Version": "2022-06-28",
    "Authorization": f"Bearer {NOTION_TOKEN}"
}

def lambda_handler(event, context):
    # ページ検索
    search_url = "https://api.notion.com/v1/search"

    body = json.loads(event["body"])
    query = body["query"]

    search_results = {}

    # 検索クエリをスペースで区切りそれぞれで検索をかける
    for q in query.split():
        json_data = {
            "query": q,
            "sort": {
                "direction": "ascending",
                "timestamp": "last_edited_time"
            }
        }
    
        search_results = requests.post(search_url, json=json_data, headers=HEADERS).json()
        # ページが見つかった段階でそれを採用する
        if len(search_results) != 0:
            break

    # 見つからなかった場合は、404で返却
    if len(search_results) == 0:
        return {
            "statusCode": 404,
        }

    # 上位1件を採用
    page_id = search_results["results"][0]["id"]

    # ページの本文情報を取得
    blocks_url = f"https://api.notion.com/v1/blocks/{page_id}/children"
    contents_results = requests.get(blocks_url, headers=HEADERS).json()

    # 本文部分のみ抽出
    output = []
    for res in contents_results["results"]:
        rich_text = res[res["type"]]["rich_text"]
        if len(rich_text) == 0:
            continue
        output.append(rich_text[0]["plain_text"])

    return {
        "statusCode": 200,
        "body": "\n".join(output)
    }

最後に、zip圧縮を行います

zip -r intercom_api.zip ./

最後にLambdaにzipファイルをアップロードすればAWS Lambdaのセットアップは完了です。

miiboのセットアップ

miiboの初期登録については、手軽に実現する会話AI作成ガイド:①チャットボットを作成しよう! をご覧ください。

外部サービス連携 > Webhookを利用して外部サービスと連携する の項目で、Webhookの設定ができます。

Webhookの項目

Webhookを追加して、Lambdaと接続します。以下に入力例を載せます。

miiboには、 ユーザの入力をWebhookなどで使う検索クエリーに変換する機能があり、@{query} という変数に自動的に挿入されます
この機能を使い、Function Callingで呼ばれた際に、リクエストパラメータに@{query}を入れてLambda渡しています。

Webhookの設定例

また、処理をする際に、会話の設定 > AIの応答をカスタマイズ > プロンプトを補完するコンテンツの設定 の項目も設定しておくと、より便利になります!

検索クエリーの提示
  "検索時にクエリーをユーザに提示する" というオプションにチェックを入れると、対話時にどういうキーワードで検索したかがチャットに表示されます

検索クエリー生成プロンプト
 "検索クエリー生成プロンプト"というオプションでは、Webhookのリクエストで利用した@{query} に代入されるキーワードをどのように抽出するかを編集できます。

設定画面

アウトプット

最後にちゃんとNotionのページ情報が引けているか見てみましょう。

チャット例
抽出元のNotionの記事

ちゃんと会話の内容を汲み取りながら、ダイエットのレシピをNotionの記事から抽出し、プロンプトに挿入して返答を生成していることが分かります。

@{query}に代入された検索キーワードは、会話のログ(バージョン2 ※ベータ版)で、後から確認することもできます。

会話のログ

おわりに

miiboとNotionを繋ぐ方法を紹介しました。
今回は、AWS Lambdaを使いましたが、もちろん別のプラットフォームを使って実現することも可能です。また、今回と同じ方法でNotion以外にも様々なAPIとも繋ぐこともできます

ぜひ参考にしてみてください!

いいなと思ったら応援しよう!