prev pVectorSearch2023-06-02 parent pVectorSearch

NextJS

  • Getting Started: Installation | Next.js
    • $ npx create-next-app@latest
    • TypeScript使いますかとか聞いてくれる
    • vecsearch-serviceって名前にした
    • この名前のフォルダが作られてGit管理される
  • Githubに入れる
    • push an existing repository from the command line

    • privateにした

Vercel

  • ダッシュボードにログインする
  • 先ほどのリポジトリが表示されてるので選んでデプロイ
  • デプロイできた
  • あー、https://vecsearch-service.vercel.app/になるのか
  • 設定からすぐ変えられる

APIを作る

import { NextApiRequest, NextApiResponse } from "next";
 
const handle = async (_req: NextApiRequest, res: NextApiResponse) => {
  res.status(200).json({ data: "hello world" });
};
export default handle;
  • OK
  • うまく動かなくて混乱したがGPT-4に聞いたら「サーバを再起動してみろ」と言われたので再起動したら動いた、便利な時代

他のAPIを叩くAPI

import { NextApiRequest, NextApiResponse } from "next";
import axios from "axios";
 
const handle = async (_req: NextApiRequest, res: NextApiResponse) => {
  const otherApiUrl =
    "https://scrapbox.io/api/pages/nishio/pVectorSearch2023-06-05";
 
  try {
    const response = await axios.get(otherApiUrl, {});
    res.status(200).json(response.data);
  } catch (error) {
      res
        .status(500)
        .json({ error: "An error occurred while calling the other API" });
  }
};
export default handle;
- OK

OpenAIを叩く embed.ts

import axios from "axios";
 
export const embed = async (textToEmbed: string) => {
  const model = "text-embedding-ada-002";
  const URL = "https://api.openai.com/v1/embeddings";
  // Call OpenAI Embedding API
  const openAIResponse = await axios.post(
    URL,
    { input: textToEmbed, model: model },
    {
      headers: {
        Authorization: `Bearer ${process.env.OPENAI_API_KEY}`,
        "Content-Type": "application/json",
      },
    }
  );
  const openAIEmbedding = openAIResponse.data.data[0].embedding; // assuming the embedding is in this path
  return openAIEmbedding;
};

embed.ts

import { NextApiRequest, NextApiResponse } from "next";
import { embed } from "../../utils/embed";
 
const handle = async (req: NextApiRequest, res: NextApiResponse) => {
  const textToEmbed = req.body.text;
  const openAIEmbedding = await embed(textToEmbed);
  res.status(200).json(openAIEmbedding);
};
export default handle;
  • OK

Qdrantを叩く search.ts

import { NextApiRequest, NextApiResponse } from "next";
import { embed } from "../../utils/embed";
import { QdrantClient } from "@qdrant/js-client-rest";
 
const handle = async (req: NextApiRequest, res: NextApiResponse) => {
  const textToEmbed = req.body.text;
  const openAIEmbedding = await embed(textToEmbed);
 
  const COLLECTION_NAME = process.env.QDRANT_COLLECTION_NAME!;
 
  const client = new QdrantClient({
    url: process.env.QDRANT_ENDPOINT,
    apiKey: process.env.QDRANT_API_KEY,
  });
 
  const grdantResult = await client.search(COLLECTION_NAME, {
    vector: openAIEmbedding,
    limit: 3,
  });
 
  res.status(200).json(grdantResult);
};
export default handle;
  • OK

フォームから検索文字列を取る :

Error: Event handlers cannot be passed to Client Component props.
 <button id="search" onClick={function} children=...>
                             ^^^^^^^^^^
If you need interactivity, consider converting part of this to a Client Component.

レスポンスを整形する

  • ScrapboxのタイトルからURLを作る
  • image
  • 見た目はさておき、検索はできた
    • タイトルをクリックするとScrapboxの該当ページにジャンプする
    • TailwindCSSが初めてなので見た目をどうするかわからない
      • ChatGPTに聞こうw
    • Make the result looks better.って言ったらいい感じにしてくれたw
      • image
    • 全体的に直させた
      • image
      • こだわりがないウェブアプリの外見デザインに関してはChatGPTで十分だな…

次回のためのメモ

  • ページタイトル画像

    • /api/pages/:projectName/:pageTitle/icon
  • 管理者用の画面

    • 検索クエリは保管して管理者が見れるようにする
      • そういう旨の説明が書いてあるページを作る
      • 検索した時点で結果をFirebaseに入れてパーマリンクを出すか
    • 公開する
      • 自分でスマホから使ってみたりする
      • スマホから見たら背景が黒くなかった
      • 検索したときに、検索中なのかエラーで死んだのかわからない ✅fixed
      • スマホでエラーになる件 ✅fixed
        • 環境変数の設定し忘れ!
        • .env.localはデプロイ先の環境変数に入らない(そもそも.gitignoreしててリポジトリに入ってない!)
    • URL Fragment Text Directivesをつける
      • これ厄介だな
        • 例えばScrapbox記法が混じってるとブラウザのテキストには記法がないからヒットしない
        • 真面目にやるならプレーンテキストにする必要がある

GPT next: pVectorSearch2023-06-06

ベクトル検索で関連ページ