👨‍🎨

ChatGPTとReplicateを使って無料でAIに画像生成してもらう

2023/03/28に公開

今回以下の無料の画像生成クラウドを利用させてもらいました。
https://replicate.com/collections/diffusion-models

最初に見つけたのが、Openjourneyモデルを使うnodeのクライアントだったのでOpenjourneyを画像生成に使ってますが、replicateが対応しているモデルであればなんでもOKだと思います。

仕組み

  • ChatGPTのUI上でMarkdownが解釈されること
  • ChatGPTはMarkdownを指定すれば出力できること
  • ローカルの画像サーバーを用意すれば、ブラウザはその画像を表示できること
  • (制限付きではあるが)無料で画像生成させてくれるAPIが存在すること

を組合わせました。

セットアップ

無料枠だけで良ければ以下の様にmidjourney-clientを利用します。

npm i express midjourney-client node-fetch

or

無料枠を使い切った場合は、以下の様にreplicateを直接叩きます。

npm i express replicate node-fetch

サーバーソースコード

index.mjs
import express from "express";
import midjourney from "midjourney-client";
import fetch from "node-fetch";
import fs from "fs";
import * as path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();
const PORT = 3000;

const OUTPUT_DIR = "./outputs/mdjrny/";

if (!fs.existsSync(OUTPUT_DIR)) {
	fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

app.get("/mdjrny", async (req, res) => {
	const { prompt } = req.query;
	console.log({ prompt })

	const imagePath = `${OUTPUT_DIR}${prompt.replace(/ /g, "-")}.jpg`;

	// キャッシュに結果がある場合は、すぐにファイルを返す
	if (fs.existsSync(imagePath)) {
		res.sendFile(path.join(__dirname, imagePath));
		return;
	}

	// 画像生成
	const imageUrl = await midjourney(prompt);
	console.log({ imageUrl })

	const imageBuffer = await fetch(imageUrl).then((res) => res.arrayBuffer());
	fs.writeFile(imagePath, Buffer.from(imageBuffer), (err) => {
		if (err) {
			console.error(err);
			res.status(500).send("Error saving image");
		} else {
			res.sendFile(path.join(__dirname, imagePath));
		}
	});
});

app.listen(PORT, () => {
	console.log(`Server listening on port ${PORT}`);
});

replicateを直接使い場合

index.mjs
import express from "express";
import Replicate from "replicate";
import fetch from "node-fetch";
import fs from "fs";
import * as path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();
const PORT = 3000;

const OUTPUT_DIR = "./outputs/mdjrny/";

if (!fs.existsSync(OUTPUT_DIR)) {
	fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}

async function mdjrny(prompt) {
	const replicate = new Replicate({
		auth: process.env.REPLICATE_API_TOKEN,
	});

	const output = await replicate.run(
		"prompthero/openjourney:9936c2001faa2194a261c01381f90e65261879985476014a0a37a334593a05eb",
		{
			input: {
				prompt: `mdjrny-v4 style ${prompt}}`,
			},
		},
	);

	return output[0];
}

app.get("/mdjrny", async (req, res) => {
	const { prompt } = req.query;
	console.log({ prompt });

	const imagePath = `${OUTPUT_DIR}${prompt.replace(/ /g, "-")}.jpg`;

	// キャッシュに結果がある場合は、すぐにファイルを返す
	if (fs.existsSync(imagePath)) {
		res.sendFile(path.join(__dirname, imagePath));
		return;
	}

	// 画像生成
	const imageUrl = await mdjrny(prompt);
	console.log({ imageUrl });

	const imageBuffer = await fetch(imageUrl).then((res) => res.arrayBuffer());
	fs.writeFile(imagePath, Buffer.from(imageBuffer), (err) => {
		if (err) {
			console.error(err);
			res.status(500).send("Error saving image");
		} else {
			res.sendFile(path.join(__dirname, imagePath));
		}
	});
});

app.listen(PORT, () => {
	console.log(`Server listening on port ${PORT}`);
});

実行

最初にサーバーを立ち上げておきます。

node index.mjs

replicateを直接使う場合は、APIキーを取得し、exportしておきます。

export REPLICATE_API_TOKEN="..."
node index.mjs

そしてあとはChatGPT上で以下の様なプロンプトを唱えるだけです。

あなたは以下の3のプロンプトを作成し、マークダウン形式で以下の様に出力してください。プロンプトの先頭には "mdjrny-v4 style "を付けてください。またプロンプトは英語です。

> ![image](http://localhost:3000/mdjrny?prompt=mdjrny-v4+style+....)

作成するプロンプトは
- りんごを頭に乗せた猫
- 宇宙を旅する猫
- 滅びた未来都市
です。

出力形式は

- タイトル
> mdjrny-v4 style プロンプトの内容
![image](http...)

です。コードブロックを使うのは禁止です。それではどうぞ。

https://twitter.com/kazuph/status/1640613326765043712

おわり

仕組みとしては単純ですが、ブラウザアプリであるChatGPTがMarkdownを解釈できることを利用しています。
これで今までできなかったChatGPT上での画像生成が簡単に楽しめるのは良いですね。

注意事項としてreplicate側の制限がかかったあとは、サインインが必要だとErrorが出るのですが、それが出た後の対策はまだできていません><
解決策がわかったら追記します(おそらく十分な時間を置く or サインインして何らかの認証情報を追加することになると思います)。

おまけ

こういうプロンプトを使えば自動で絵本の生成もできますね。やばい(^q^)

絵本の物語を考えます。登場人物は小さい少女、大きな森のくま、悪い魔女、その他森の動物たちです。
少女が悪い魔女に狙われるけど、最終的にくまや森の動物達に助けられる物語を考えてください。
最後はハッピーエンドです。

全体で7ページを想定しています。

以下の列を持つ表形式で出力をお願いします。

> ページ番号, 登場人物, 場面の様子(人の立ち位置や背景), 画面の絵を生成するmidjourny用のプロンプト, 画像

注意事項
- プロンプト列はスペース区切りの英語です。
- 画像列の形式は以下であり、プロンプト列で生成した英語のプロンプトが入ります。ただし `prompt.join("+")`とする必要がありまます。

> ![image](http://localhost:3000/mdjrny?prompt={prompt})


それではお願いします。

https://twitter.com/kazuph/status/1640631176242270208

Discussion