📌

wix-blog-backend(Velo by Wix)とOpenAI APIで色々作ってみる[1]

2023/07/25に公開

はじめに

今回はwix-blog-backendとOpenAI APIを使って、ブログの記事にアドバイスしてもらう機能をWix Chatに追加したいと思います。

まず、wix-blog-backendについて調べたことを共有させていただき、それから作るものを選定した経緯をお話しし、実装の話に移りたいと思います。

前提

Velo by WixやWixの使い方の詳細は省きます。

検証用のサイトにWix Blog、Wix Chatをインストールしておく必要があります。

Wix Blog
Wix Chat

上記は割とスタンダードな機能なのでサイト作成中にインストールしている方が多いと思いますが、見つからない場合はインストールしてください。

Wixの開発モードの使い方や Velo by Wix については以前の記事で基本的な説明をしています。
必要であれば参考にしてみてください。

OpenAI APIで遊ぶのにWix Chatと Velo by Wixが意外に便利-予備知識編
OpenAI APIで遊ぶのにWix Chatと Velo by Wixが意外に便利-本編
Wix ChatからDALL·E を呼び出し画像を作ってもらう
Wix 会員エリア の権限に関する機能を使って、WixChatに機能の制限を加える

wix-blog-backend でできそうなこと

wix-blog-backend
を早速チェックすると大きく以下種類の記載があります。

  • wix-search・・・これはサイト検索をする機能のようです。wix-dataとの違いはコレクション以外も含むということでしょうか。気になりますが今回は扱いません。厳密には wix-blog-backend とは別APIかと思いますが関連機能として紹介されているようです。
  • Categories
    ブログ記事のカテゴリに関するものです。
  • Events
    記事作成、更新、削除などのイベントのハンドラです。イベント発生時に実行させたい処理を記載します。
    今回はWix Chat経由で起動するシステムなので使いません。
  • Tags
    ブログ記事のタグに関するものです。
  • Posts
    こちらが今回の本命です。大きく分けて記事の取得とメタ情報(閲覧数、like数、コメント数)の取得があります。残念ながら全てデータ取得に関するもの限定で、データの作成や更新、削除についての機能は用意されていないようです。
    ※ちなみに、公開記事はサイトエディッタで閲覧できるので、Wix-data を使って直接データを投入できないか、検討したのですが、公開されてないコレクションに影響が出たり、不整合が出かねないのでやめておきました。(軽く試してみたのですができませんでした)
    これができたら、生成AIで記事を作成して投稿するといった記事を書きたかったのですが、残園です。
    記事取得については、取得方法でいくつか種類があります。
    • getPost()・・・ID指定で取得。
    • getPostBySlug()・・・スラッグ指定で取得
    • listPosts()・・・通常の一覧取得
    • queryPosts()・・・複雑な検索条件での記事取得
      また、いくつか試用している時気が付いたんですが、下書きは非公開のコレクションに保存されているようで、取得することができません。公開記事にして、それを下書きに変更しても、一度deleteされるようで、検索対象から外れます。

とりあえず、ここまで調べた内容で、できることの候補としては

  • ベクトルデータベースに記事を格納して質疑に使う
  • 投稿済みの記事の改善案を出してもらう

がありました。ただし、前者はSupabaseのSDKをVeloでinstallできないので、別の機能を使う必要があります。その機能については別の記事を書く予定なので後日としたいと思います。
今回は「投稿済みの記事の改善案を出してもらう」を選ぶことにしました。

仕様

仕様、処理の流れは、以下になります。

  • WixChatから「Slug: hogefuga の改善点を指摘して」と依頼
  • events.jsにて発言eventを捕捉し、OpenAI APIにメッセージを送信
  • OpenAI APIはFunction callingで 記事情報取得function実行のレスポンスを返す
  • wix-blog-backendで該当ブログの記事を取得(getPostBySlug)
  • OpenAI APIにブログ情報とプロンプトを与え呼び出し。
  • 成功したら結果をそのままwixchatに返す。

Function callingまで

以前記事に書いた部分についてはあまり説明しないつもりですが、以下のメッセージ受信イベントのハンドリングだけ少し触れておきます。
veloのバックエンドにて、 events.jsにて以下の実装をしています。
events.jsを肥大化させないため、処理のほとんどは chat.js に記載しています。

import { sendChatMessage, execChat } from 'backend/chat'
export async function wixChat_onMessage(event) {
  const chatMessage = event.payload.text;
  const channelId = event.channelId
  const participantId = event.participantId;
  // サイト訪問者からのメッセージのみに反応するようにする(この分岐がないと無限ループする)
  if(event.direction == "VisitorToBusiness") {
    const ans = await execChat(chatMessage, participantId)
    await sendChatMessage(channelId, ans)
  }
}

execChat(名前が微妙で少し後悔してますが)ではメッセージを受け取り、OpenAIのAPIを使った処理などを実行し、回答を sendChatMessageに渡しています。

ブログ記事改善案をもらうためのチャットメッセージは以下を設定しています。

Wix Blogの slug: 「初めてのブログ」を読んで改善案を出してください

このメッセージに対応し、ブログ記事を取得する関数定義します。

{
  name: "getWixBlogBySlug",
  description: "ブログ記事を読むために、slugを使ってブログ記事情報を取得する",
  parameters: {
    type: "object",
    properties: {
      slug: {
        type: "string",
        description: "ブログ記事を取得するための検索値",
      },
    },
    required: ["slug"],
  },
},

これを試しに組み込み単体で実行すると

{
  role: 'assistant',
  content: null,
  function_call: {
    name: 'getWixBlogBySlug',
    arguments: '{\n  "slug": "my-first-blog"\n}'
  }
}

このようにgetWixBlogBySlug関数の実行が選択され、パラメタとしてslugが取得できました。

※少し話が戻ってしまいますが、IDではなくslugでの検索を選んだ理由ですが、IDは開発モードで直接コレクションを覗き込んだり、URLから切り抜くことでしか取得できないためです。

wix-blog-backendで該当ブログの記事を取得

OpenAI APIの戻り値 completionから関数実行の有無と関数名の判定を行います。

const funcResponse = completion.data.choices[0].message.function_call;
if (funcResponse) {
  if (funcResponse && funcResponse.name == "getWixBlogBySlug") {
    const { slug } = JSON.parse(funcResponse.arguments || "{}");

(略)

先ほど定義した getWixBlogBySlugが実行されていた場合、slugの値が取得できるので、その値を使ってWix Blogの情報を取得します。
今回はタイトルと本文のみ利用しますが、プロンプトを調整しつつ他の項目を加えても有効な助言が得られると思います。

async function getWixBlogBySlug(slug) {
    const result = await posts.getPostBySlug(slug, {
        //本文取得したい場合は明示的に指定
        fieldsets: [
            'CONTENT_TEXT'
        ]
    });
    const title = result.post.title;
    const content = result.post.contentText
    return "タイトル: " + title + "\n本文: " + content;
}

APIリファレンスに記載されていますが、記事の本文はデフォルトのパラメタ指定では取得できません。第二引数で指定してあげる必要があります。

また、さまざまなスラッグでテストしていたのですが、スラッグが日本語の場合値の取得に失敗してしまいました。ログを見ると

System error occurred

というエラーが出ていて、少し不可解ですが(制御できてない?)、今回の方法で実装する場合はスラッグは英語で指定してただく必要があります。

後日別の記事で扱いたいと思っていますが、記事の取得方法は

  • listPosts()
  • queryPosts()
    で記事タイトルを検索させるなどといった方法でも良かったかもしれませんね。
    記事が長くなってきたので深追いは諦めます。

OpenAIにブログ記事を添えて改善案を質問

最後に、取得したブログ情報を使って再度OpenAPIのAIを呼び出すのですが、2つ問題に気がつきました。

1つ目は、チャットから入力時のプロンプトの扱いです。ブログ記事の取得を依頼し、その結果を使って助言依頼をしているのですが、このままプロンプトを渡すと処理が混乱するようで、結果が安定しませんでした。
※記事がないのでわかりませんと答えてきたり、記事に基づかない一般論の回答が戻ってくる

2回目のプロンプトは固定してしまって

次の記事を読んで改善点を指摘してください

でも良いかなと思ったのですが、プロンプトでアドバイス内容を調整することができなくなるので面白くありません。
そこで、履歴として表現してみることにしました。
具体例としては以下になります。

mesgはチャットから入力したプロンプト。textはブログのタイトルと本文です。

messages: [
	{ role: "user", content: mesg, },
	{ role: "system", content: "指定されたslugのブログを取得しました。ブログの内容は下記になります。\n####\n" + text},
	{ role: "user", content: "取得した文章を読んで回答を続けてください。"},
], 

こうすることで、API側が次に実行すべき処理がどこの段階にあるのか把握できるようで、処理が安定しました。

結果、処理が安定させた上で

次のスラッグのブログを読んでみて、改善点を教えてください。
slug: my-first-blog

だけでなく

次のスラッグのブログを読んでみて、SEOの観点から改善点を教えてください。
slug: my-first-blog

のように、助言内容にチャット入力から調整を加えられるようになります。

もう1つ起きた問題は初歩的なもので、ブログ記事なのでtoken数の超過です。

  • gpt-3.5-turbo・・・4096
  • gpt-3.5-turbo-16k・・・16384
    です。

これはtiktoken系のライブラリを使って事前にtoken数の見積もりをし、modelを切り替えたり、エラーメッセージを返したりで対応できそうです。
ただし、長くなってしまうので、別に記事を作成したいと思います。

使ってみる

せっかくなので実行例を掲載します。

典型的な「ブログ始めました!よろしくお願いします」という短い文章をアップした例です。

次のスラッグのブログを読んでみて、改善点を教えてください。
slug: my-first-blog

このブログの内容を改善するためには、以下の点に注意してみてください:

1. タイトルの充実化:タイトルは読者の興味を引き付ける重要な要素です。"my first blog"よりも、具体的で興味を引くタイトルを考えてみましょう。例えば、最初の投稿のテーマや内容に関連したタイトルにすると良いでしょう。「私の初めてのブログ:料理のレシピを紹介します!」など具体的なタイトルが良いでしょう。

2. 本文の充実化:本文は読者に有益な情報や面白い内容を提供することが重要です。ただ単に「ブログを始めました」と伝えるだけでなく、読者に何か価値や興味を持ってもらえるような内容を追加しましょう。例えば、ブログのテーマや毎日投稿する予定の内容、読者が期待できることなどを具体的に説明すると良いでしょう。

3. 読者参加型のアプローチ:ブログを成功させるためには、読者とのコミュニケーションを活発化させることも重要です。読者がコメントや質問をしやすいような環境を作ってみましょう。また、読者の要望やフィードバックに対して真摯に対応することも大切です。

以上の3点に注意しながら、ブログの内容を改善していくことをおすすめします。

別のパターンとしては青空文庫から「夢十夜」をChatGPTで現代風にアレンジしてもらい、それをブログに掲載した上で次の依頼をしてみました。長いので面白いものだけ抜粋しています。

次のslug記事の続編のアイデアをください。
slug: dream-diary

続編のアイデアを考えてみます。

(略)

2.「夢の続き」-主人公はこの夢の中で出会った彼女と現実世界でも再会する機会を得ます。彼女は実在する人物であり、彼女が現実世界で抱えている秘密や問題が明らかになります。主人公は彼女を助けるために奮闘し、彼女の運命を変えるために力を尽くします。

3.「交差する夢の世界」-主人公は他の人々とも同じような夢を共有していることに気づきます。彼らも同じ彼女に会っており、同じような体験をしています。主人公は彼らと協力して、夢の世界と現実世界が交差する謎を解き明かし、その背後にある意味や目的を探求します。

(略)

以上のアイデアを元に、続編を書くことができます。どのアイデアが最も興味深いか、あるいは他のアイデアが浮かんだ場合はお知らせください。

2つ目の例は極端かもしれませんが、プロンプトの工夫次第で覆わぬ活用方法が見つかるかもしれませんね。

まとめ

今回はwix-blog-backendについて概要を確認し、OpenAI APIを使って、ブログの記事にアドバイスしてもらう機能をWix Chatに追加してみました。

最近記事がどんどん長くなっているので、コードの掲載や細かいエラーハンドリングなどは端折ってしまいましたが、1つの具体例として参考になれば幸いです。

本文中にも書きましたが

  • Wix Blogの内容をベクトルデータベースに格納し質疑に利用する機能
  • Velo by Wixで外部APIを呼ぶための wix-fetchについて
  • OpenAI APIを呼び出す前にtoken数をチェックする方法(tik-token)
    については後日記事にする予定なので、よければそちらもご参照ください。

Discussion