Tags English

Blog - Yusuke Wada

Screenshot

Hono is now AI ready

#Hono

この記事は英語で書かれた原文をAIが翻訳したものです。

Hono is now AI ready

AI、特にChatGPTアプリケーションを作るために必要なWeb技術はOpenAPIStreamingです。

OpenAPIはOpenAIではありませんが、OpenAPIを使ってOpenAIアプリケーションを作ることができます。 アプリケーションにやってほしいことをOpenAPIで自然言語として書いておけば、ChatGPTがいい感じに解釈してくれます。

Streamingは、ChatGPTのようにテキストを少しずつ返すアプリケーションに向いています。レスポンスを一度に返すのに30秒かかるとしても、少しずつ返せばユーザーのストレスは減りますし、そのほうがユーザーと「会話している」感じになります。

そして今、Honoはその両方をサポートしています。Zod OpenAPIというHonoの拡張が使えますし、新しい**c.streamText()**でテキストをストリーミングできます。

Zod OpenAPI Hono

ZodOpen API HonoはHonoの拡張で、コードベースの中でOpenAPIを定義し、そのロジックをHonoアプリケーションとして書くことができます。

素晴らしいのは、スキーマをZodで定義できる点です。

超シンプルなブログを作ってみましょう。ユーザーからの入力を次のように想定し、バリデーションします。

const schema = z.object({
  title: z.string().min(1),
  content: z.string().min(1),
})

このZod OpenAPIでは.openapi()が使えます(この関数はZod to OpenAPIをベースにしています。ありがとうございます!)。

const schema = z.object({
  title: z.string().min(1).openapi({ example: 'About today' }),
  content: z.string().min(1).openapi({ example: 'Today is a good day...' }),
})

これを使って、パス、コンテンツタイプ、レスポンスの情報をルートとして定義します。

export const routeAddPost = createRoute({
  method: 'post',
  path: '/posts',
  request: {
    body: {
      content: {
        'application/json': {
          schema: schema,
        },
      },
    },
  },
  responses: {
    '200': {
      description: 'OK',
      content: {
        'application/json': {
          schema: z.object({
            ok: z.boolean(),
          }),
        },
      },
    },
  },
})

OpenAPIらしい」部分はこれで全部です。あとはいつも通りロジックを実装するだけ。 ここではデータベースにCloudflare D1を使っています。

app.openapi(routeAddPost, async (c) => {
  const { title, content } = c.req.valid('json')
  const id = crypto.randomUUID()
  await c.env.DB.prepare('INSERT INTO posts(id, title, content) values (?, ?, ?)')
    .bind(id, title, content)
    .run()
  return c.jsonT({
    ok: true,
  })
})

このZod OpenAPIのすごいところは、恐ろしくType-Safeなことです。リクエストのContent-Typeがapplication/jsonなら、c.req.valid()の第一引数としてjsonをサジェストしてくれますし、レスポンススキーマで定義した通りok:booleanを返すことを期待します。

output

APIスペックはJSONとして生成され、Swagger UIでドキュメントを閲覧できます。

SS

ChatGPT plugin

これをChatGPTのプラグインにしてみましょう。簡単です。マニフェストファイルに「This plugin is for Blogging」と書くだけです。

export const aiPluginJson = {
  schema_version: 'v1',
  name_for_model: 'Blog',
  description_for_model: 'Plug-ins for blogging',
  api: {
    type: 'openapi',
    url: 'http://localhost:8787/openapi.json',
  },
  //...
}

これで完成です。ヒントを与えると、ChatGPTがブログの内容を考えてデータベースに入れてくれます。しかもこれはCloudflare Workersのようなエッジにデプロイできます。

output

これがAIにまつわる2つの話のうちの1つ目です。

c.streamText()

Honoの新しい関数c.stream()c.streamText()を使うと、コンテンツのストリーミングが簡単にできます。 使い方はシンプル。コードを見てください。

app.get('/', (c) => {
  return c.streamText(async (stream) => {
    stream.writeln('Hello!')
    await stream.sleep(1000)
    stream.writeln('Hono!')
  })
})

ChatGPT Gateway

ChatGPT APIは「stream」をサポートしています。なので、エレガントなコードでChatGPT Gatewayを作れます。

app.post('/api', async (c) => {
  const body = await c.req.json<{ message: string }>()

  const openai = new OpenAI({ apiKey: c.env.OPENAI_API_KEY })
  const chatStream = await openai.chat.completions.create({
    messages: PROMPT(body.message),
    model: 'gpt-3.5-turbo',
    stream: true
  })

  return c.streamText(async (stream) => {
    for await (const message of chatStream) {
      await stream.write(message.choices[0]?.delta.content ?? '')
    }
  })
})

output

これはただのGatewayですが、適切なプロンプトを与えて、ユーザーごとに履歴を保存すれば、素晴らしいAIの出来上がりです!

AIは楽しい

こうしたAIアプリケーションを作るのはとても楽しいです! 特に、HonoのZod OpenAPI、c.streamText()、そしてCloudflare WorkersはAIと相性抜群です。

ちなみに、この記事は人間が書きました。