🐷 SlackにStable Diffusionの機能を追加してみた

2023-02-19 /Development #Slack

Stable Diffusionで画像生成してくれるSlackのボットを作成してみました。

せっかくなので手順をメモ。

DreamStudioのAPI keyを取得する

まずは DreamStudio でアカウントを作って、以下のURLからAPI Keyを取得します。

DreamStudio https://beta.dreamstudio.ai/membership?tab=apiKeys

取得ができたら.envに追加しておきます。

コピーしました
DREAMSTUDIO_API_KEY=

画像を生成するだけの関数を作成する

次にstability-tsを使用して、文章を渡したら画像を返してくれるだけの関数を作成します。

コピーしました
const { generateAsync } = require("stability-ts");
async function callStableDiffusion(prompt) {
  const size = 512;
  try {
    const { res, images } = await generateAsync({
      prompt: prompt,
      apiKey: process.env.DREAMSTUDIO_API_KEY,
      outDir: "./",
      width: size,
      height: size,
      steps: 50,
      samples: 5,
      engine: "stable-diffusion-v1-5",
    });
    return images;
  } catch (e) {
    return [];
  }
}

stability-tsは2023/2/19現在 最新のもの が動かなくなっていて(渡さなきゃいけないパラメータが増えたのにそれに対応してないっぽい感じ?) ISSUE もたっているのですが、その後修正の PR もあるもののメンテナンスが止まってるみたいでした。

なので修正されてPRを送っている方のリポジトリから落とさせていただきました。

コピーしました
"devDependencies": {
    ...
    "stability-ts": "git+https://github.com/ebarahona/stability-ts.git#hotfix/parameter-fix"
}

Slackへの画像アップロードを行う関数を作成する(これはいらないかも…)

Slackへの画像アップロードは Bolt を使っているのでfiles.uploadを使えば良いだけだったのですがなぜかCloud Run上で動かず(ローカルでは動いたのですが)…仕方がないので Axios でアップロードするようにしました。

コピーしました
const fs = require("fs");
const axios = require("axios").default;
const FormData = require("form-data");
async function uploadFile(filePath) {
  const form = new FormData();
  form.append("token", process.env.SLACK_BOT_TOKEN);
  form.append("channels", "CHANNELIDが入ります");
  form.append("file", fs.createReadStream(filePath), filePath);

  try {
    const res = await axios.post("https://slack.com/api/files.upload", form, {
      headers: form.getHeaders(),
    });
    console.log(res);
  } catch (err) {
    throw new Error(err);
  }
}

ボットを作成する

ボット自体は SlackにGPT-3の機能を追加して話し相手になってもらった 時と同じ感じで記述します。

コピーしました
const { App } = require("@slack/bolt");
require("dotenv").config();

const app = new App({
  token: process.env.SLACK_BOT_TOKEN,
  signingSecret: process.env.SLACK_SIGNING_SECRET,
});

(async () => {
    await app.start(8080);

    app.command("/stability", async ({ command, ack, say, respond }) => {

        let prompt = command.text;
        const images = await callStableDiffusion(prompt);

        let res = [];
        res.push(`prompt: ${prompt}`);

        for (let i = 0; i < images.length; i++) {
            const image = images[i];
            res.push(`seed: ${image.seed}`);
            res.push(`imageName: ${image.imageName}`);

            try {
                uploadFile(image.filePath);
            } catch (error) {
                res.push(error);
                console.log(error);
            }
        }

        // コマンドリクエストを確認
        await ack();
        await say(`${res.join("\n")}`);
    });
  
})();

所感

とりあえず動いたのは良いものの、なんか呪文通りのものが出ているのか疑わしい出力結果が返ってくるので微妙です…

月額ではなくデポジット的な感じで購入できるので安心感があります。$10で5000枚くらい?作成できそうです

Comment
comments powered by Disqus
Profile

石原 悠 / Yu Ishihara

デザインとプログラミングと編み物とヨーグルトが好きです。