Amazon Bedrockでテキスト&画像生成してみた[with Node.js]

2023.10.02

育休を4ヶ月取っていた吉川@広島です。9月に復帰しました。

Amazon Bedrock が一般利用可能に – 基盤モデルを利用した生成系 AI アプリケーションの構築とスケール | Amazon Web Services ブログ

GAされたAmazon BedrockをAWS SDK for JS v3+TypeScriptから使ってみました。

環境

  • node 20.5.1
  • typescript 5.2.2
  • @aws-sdk/client-bedrock-runtime 3.422.1
  • esbuild 0.19.4
  • esbuild-register" 3.5.0

AI21 Labs

早速ですが、まずAI21 Labsを試してみます。こちらはイスラエルのAI企業みたいです。テキスト生成ができるようなので言葉を投げてみます。

コード

// main.ts
import { BedrockRuntime } from "@aws-sdk/client-bedrock-runtime";

const client = new BedrockRuntime({ region: "us-east-1" });

const main = async () => {
  const res = await client.invokeModel({
    // Model IDsを参照 https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html
    modelId: "ai21.j2-ultra-v1",
    body: JSON.stringify({
      prompt: "Knock, knock!",
      maxTokens: 200,
      temperature: 0.7,
      topP: 1,
    }),
    accept: "application/json",
    contentType: "application/json",
  });

  const body = JSON.parse(Buffer.from(res.body).toString("utf-8"));
  console.log(body.completions[0].data.text.trim());
};

main();
  const res = await client.invokeModel({
    // Model IDsを参照 https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html
    modelId: "ai21.j2-ultra-v1",
    body: JSON.stringify({
      prompt: "Knock, knock!",
      maxTokens: 200,
      temperature: 0.7,
      topP: 1,
    }),
    accept: "application/json",
    contentType: "application/json",
  });

v2互換スタイルで書いてみました(v3スタイルはバンドルサイズの優位性があるんでしょうが、どうしてもこっちを使う癖が抜けず)。v3スタイルの場合は

import { BedrockRuntimeClient, InvokeModelCommand } from "@aws-sdk/client-bedrock-runtime";

const client = new BedrockRuntimeClient({ region: "us-east-1" });

const main = async () => {
  const res = await client.send(new InvokeModelCommand({/* 省略... */}))

// 省略...

のようになるでしょう。

実行

esbuild-registerでビルド+実行します。

node -r esbuild-register main.ts
# 以下出力:
# Who's there?
# Boo
# Boo who?
# Don't cry, it's just a joke!

Stability AI

続いてStability AIを試してみます。こちらは画像生成ができます。

コード

// main.ts
import { BedrockRuntime } from "@aws-sdk/client-bedrock-runtime";
import { writeFileSync } from "fs";

const client = new BedrockRuntime({ region: "us-east-1" });

const main = async () => {
  const res = await client.invokeModel({
    // Model IDsを参照 https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html
    modelId: "stability.stable-diffusion-xl-v0",
    body: JSON.stringify({
      text_prompts: [
        {
          // プロンプト
          text: "crazy mad gorilla",
        },
      ],
      cfg_scale: 10,
      seed: 20,
      steps: 50,
    }),
    accept: "application/json",
    contentType: "application/json",
  });

  const body = JSON.parse(Buffer.from(res.body).toString("utf-8"));
  if (body.result !== "success") {
    throw new Error("Failed to invoke model");
  }

  writeFileSync("./out.png", body.artifacts[0].base64, { encoding: "base64" });
};

実行

同じように実行します。

node -r esbuild-register main.ts

./out.png に画像が出力されます。

今回はこんな出力でした。

なかなかイケてますね(?)

感想

ということで楽しく遊べそうな雰囲気でした。AWSアカウントが1つあれば色々な会社のAI製品のAPIを叩けるのが良いですね。

少し気になったのは、SDKなのに .invokeModel() に渡す引数がfetch APIやAxiosを使う場合と同じ程度の型安全性しかないように見える点です。acceptcontentType まで指定するので通信処理を隠蔽できていない感があります。

これはおそらく使いたいAI製品によって入出力のフォーマットが全く違うからだと思いますが、ユニオンやジェネリクスを活用したり、使うAIによってメソッドを変えるなどで型付けできそうな気はします。このあたりをより良くするために @aws-sdk/client-bedrock-runtime をラップするOSSとか作ってみると面白いかもしれませんね。もしくは公式からラッパーが出るかも?

以上、参考になれば幸いです。

参考