ねえ、一緒にかっこいいAI POWEREDの画像生成ウェブサイトをReactで作らない?
今暇でしょう? 作ろう! いいじゃん!
これです:
あ、テンション上がりすぎて挨拶を忘れました、すみません、金曜日だし。。。
¡Hola! こんにちは! テラーノベルのオスカルです。Webの開発をしてます。いつも言うんだけど、日本語はまだまだ勉強してますので、応援してください!
ai-love-images
react app
Create 最初から始めましょう、まずはcreate-react-app
を使って新しいフレッシュなReact
プロジェクトを作成します。
npx create-react-app ai-love-images
いい名前でしょう?w
おそらく既知ですが、念のために説明します。前のコマンドは非常にシンプルなReactアプリケーションの構造を作成し、ai-love-images
フォルダに移動してnpm start
を実行すると、ブラウザで標準のReact
プロジェクトウェルカム画面が表示され、http://localhost:3000
でアクセスできます。
メインのアプリケーションレイアウトは app.js
にあり、スタイルは app.css
にあります。 TypeScript
を実装し、Chakra や Ant Design のような UI フレームワークを追加するのが理想的でしたが、これは素早いコンセプト証明プロジェクトですので、標準の React コンポーネントを使用します。まずは、素敵な背景グラデーションスタイルを追加しましょう。
Basic UI
app.js
はこんな感じでわかりやすいだろう?
import './app.css';
const App = () => {
return (
<div className="app">
<h1>¡Hola!</h1>
</div>
)
}
export default App;
メニューやその他の要素は必要ありませんので、メインのラッパーは利用可能なスペース全体を使い、内部のコンテンツを水平および垂直に中央に配置します。
app.css
はこんな感じ:
.app {
text-align: center;
background: rgb(2,0,36);
background: linear-gradient(90deg, rgba(2,0,36,1) 0%, rgba(9,9,121,1) 35%, rgba(0,212,255,1) 100%);
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
h1 {
color: white;
}
あ、この背景グラデーションCSSは、特定のウェブサイト、CSS Gradient から直接取得しました。
good enough !
src
フォルダ内に components
という名前のフォルダを作成しましょう。
components
フォルダ内にもう1つのフォルダを作成し、それに image-showcase
という名前を付けましょう。これは OpenAI API を使用して生成されるメインの大きな画像をレンダリングするコンポーネントになります。
assets
フォルダ内に、私たちの愛される「テノちゃん」の写真を追加し、次のような 3 つのファイルを追加しました:
以下の内容:
index.js
// コンポーネントのインポートを簡略化するために
export * from "./image-showcase"
image-showcase.jsx
import tenoChanImage from "./assets/teno-chan-photo.png"
import "./image-showcase.css"
export const ImageShowcase = () => {
return (
<div className="imageWrapper">
<img src={tenoChanImage} alt="Everybody loves TenoChan" />
</div>
)}
image-showcase.css
.imageWrapper > img {
max-width: 300px;
border-radius: 40px;
border: 3px solid white;
box-shadow: 0 1px 1px rgba(0,0,0,0.12), 0 2px 2px rgba(0,0,0,0.12);
}
ボックスシャドウのCSSを生成するためにこのページを使用してください。
次に、テキスト入力コンポーネントを作成しましょう。この場合、text-input-box
という名前のフォルダを追加し、以下のファイルを追加しました:
index.js
// コンポーネントのインポートを簡略化するために
export * from "./text-input-box"
text-input-box.jsx
import tenoChanIcon from "./assets/teno-chan.png"
import "./text-input-box.css";
export const TextInputBox = () => {
return (
<form onSubmit={() => alert("TODO")}>
<div className="input-box">
<button className="btn-input">
<img src={tenoChanIcon} width="50" alt="tenochan" />
</button>
<input type="text" className="input-text" placeholder="テラーノベルの可愛いテノちゃん" />
</div>
</form>
)}
text-input-box.css
.input-box{
margin-top: 50px;
box-sizing: border-box;
width: fit-content;
height: fit-content;
position: relative;
font-family: 'Lato' !important;
}
.input-text{
height: 50px;
width: 50px;
border-style: none;
padding: 10px;
font-size: 18px;
letter-spacing: 2px;
outline: none;
border-radius: 25px;
transition: all .5s ease-in-out;
background-color: rgb(22,90,172);
border: 2px solid white;
color: transparent;
}
.input-text::placeholder{
font-size: 18px;
letter-spacing: 2px;
font-weight: 100;
color: transparent;
}
.btn-input{
width: 50px;
height: 50px;
border-style: none;
font-size: 20px;
font-weight: bold;
outline: none;
cursor: pointer;
border-radius: 50%;
position: absolute;
right: 16px;
top: 10px;
color:#ffffff ;
background-color:transparent;
pointer-events: painted;
}
.btn-input:focus ~ .input-text{
width: 300px;
border-radius: 0px;
background-color: transparent;
border: none;
padding-right: 60px;
border-bottom:1px solid rgba(255,255,255,.5);
transition: all 500ms cubic-bezier(0, 0.110, 0.35, 2);
color: #fff;
}
.btn-input:focus ~ .input-text::placeholder {
color:rgba(255,255,255,.5);
}
.input-text:focus{
width: 300px;
border-radius: 0px;
background-color: transparent;
border: none;
border-bottom:1px solid rgba(255,255,255,.5);
transition: all 500ms cubic-bezier(0, 0.110, 0.35, 2);
padding-right: 60px;
color: #fff;
}
.input-text:focus::placeholder {
color:rgba(255,255,255,.5);
}
あ、すみません! このCSSはかなり高度です(100%理解していない部分もあります 😅 )。実はこのリンクからインスパイアを受け、それを私たちのテノちゃんを追加するために変更しました。
ところでfreefrontend.comとtympanus.netはとても便利です!
app.js
にコンポーネントを入れたら:
import './app.css';
import { TextInputBox } from './components/text-input-box';
import { ImageShowcase } from './components/image-showcase';
const App = () => {
return (
<div className="app">
<ImageShowcase />
<TextInputBox />
</div>
)
}
export default App;
現時点では、プレーンなCSS + HTML
コンポーネントしかありませんが、今のところユーザープロンプトを取得するためのコードを追加しましょう。このために、各コンポーネントに use-local-hook.js
ファイルを追加することをお勧めします。それでは、text-input-box
フォルダでそれを行いましょう:
/text-input-box/use-local-hook.js
import { useCallback, useRef } from 'react';
export const useLocalHook = () => {
const promptRef = useRef();
const handleSubmit = useCallback((e) =>{
e.preventDefault();
console.log(promptRef.current.value);
}, []);
return {
handleSubmit,
promptRef
}
}
フォームの送信イベントを処理し、ページのリロードを防止します(これはフォームの標準動作です)。また、useRef
を使用して入力テキストの値を取得します。これはテキストの値を取得する方法の1つであり、他のアイデアについてはこのリンクをご確認ください。より複雑なフォームに対しては、useForm ライブラリをお勧めします。
TextInputBox
コンポーネントから私たちのフックをインポートし、入力への参照とフォームの送信処理を追加しましょう:
text-input-box.jsx
import tenoChanIcon from "./assets/teno-chan.png"
import "./text-input-box.css";
import { useLocalHook } from "./use-local-hook";
export const TextInputBox = () => {
const { promptRef, handleSubmit} = useLocalHook();
return (
<form onSubmit={handleSubmit}> // <-- ここ
<div className="input-box">
<button className="btn-input">
<img src={tenoChanIcon} width="50" alt="tenochan"/>
</button>
// ↓ ここ
<input ref={promptRef} type="text" className="input-text" placeholder="テラーノベルの可愛いテノちゃん" />
</div>
</form>
)}
何かを入力してENTERキーを押すと、フォームが送信され、入力値がコンソールにログとして表示されます。
OPEN-AI APIを入れましょう!
基本的なUIができましたので、ユーザープロンプトを使用してAI APIにリクエストを送信し、レスポンスで受け取る生成された画像を待ちましょう。この際、私たちはChatGPTやDALL-Eの作者であるOpenAIのAPIを使用しますが、注意が必要です。APIは無料では提供されていないため、料金が発生しますが、高額ではありません。
まず、https://platform.openai.com/ にアカウントを作成しましょう。アカウントの作成自体は無料です。
アカウントが作成されたら、私たちの小さなアプリケーションでリクエストを送信するために使用されるAPIキーを取得する必要があります。個人のメニューから、View API keys に移動してください。あそこからCreate new secret key
で新しいキーを生成し、どこかに記録してください。
APIは無料ではないため、APIリクエストが400エラーを返さないようにするために、クレジットカード情報を追加し、初期資金を入れる必要があります。これはサイドメニューの「Billing - Overview」セクションで行えます。
テスト用に10ドルを追加し、テスト中に1ドルも使用されていないことを確認しました。試してみるにはかなり安価ですが、本番サービスに使用する前に必ず価格のウェブサイトを確認してください!。
APIキーを直接クライアント側から使用すると、それを公開し、セキュリティのリスクとなります。詳細についてはこちらをご覧ください。そのため、Honoを使用して異なるプロジェクトを作成し、独自のAPIを実装します。このAPIは、OpenAI APIに対するリクエストを代行します。
「え?別のプロジェクト?」 😅
はいはい、心配しないでください。とても簡単でシンプルです。ただ水を飲んで、私についてきてください。💪
こんな感じですね:
ai-love-open-ai
app
Create Hono では、ai-love-images
プロジェクトフォルダの外に出て、非常にシンプルなHono
プロジェクトを作成するために、このコマンドを実行してください。また、事前に定義されたテンプレートを要求します。簡単にするために、bun を選択してください。
npm create hono@latest ai-love-open-ai
ai-love-open-ai
フォルダ内に、.env
ファイルを作成し、OpenAI APIキーをOPENAI_API_KEY
キーと一緒に追加してください。このキーは共有せず、どんなリポジトリにもコミットしないようにしてください!
.env
OPENAI_API_KEY = "sk-****"
OpenAIには私たちにとって作業を簡略化するためのパッケージもありますので、どうぞインストールしてください。
bun install openai
hono
はAPIハンドラの作成を非常に簡単にします。単に/src/index.ts
にいくつかのコードを追加すれば、すぐに動作します。
コード内にコメントを追加して、理解しやすくしました。基本的に、リクエストを受け取り、APIキーが正しく設定され、ユーザーのプロンプトがあるかどうかを確認し、すべてが正しければ、OpenAIパッケージを使用して彼らのAPIにリクエストを送信し、レスポンスを処理します。
/src/index.ts
import { Hono } from "hono";
import OpenAI from "openai";
// .envファイルに設定されたAPIキーを使用してオブジェクトをインスタンス化します
const openAI = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
const app = new Hono();
app.post("/api/open-ai/image-generator", async (c) => {
const body = await c.req.json();
const { prompt } = body;
if (!openAI.apiKey) {
return c.json({ error: "OpenAI API key not set" }, { status: 500 });
}
if (!prompt) {
return c.json({ error: "Prompt not provided" }, { status: 400 });
}
// https://platform.openai.com/docs/api-reference/images/object
const openAIResponse = await openAI.images.generate({
prompt, // ユーザーのプロンプト
n: 1, // 生成する画像の数
size: "512x512" // 画像サイズ
})
// OpenAIの応答を記録して、何が来ているか確認する
console.log(openAIResponse);
return c.json({ ok: true }); // for now
});
export default app;
このサーバーをポート3001で起動して、確認しましょう:
PORT=3001 bun run dev
可愛い猫をプロンプトとして画像生成のために、http://localhost:3001/api/open-ai/image-generator
にPOST
リクエストを送信しましょう。この curl
コマンドを使えば、ターミナルから簡単に行うことができます。
curl -X POST -H "Content-Type: application/json" -d '{"prompt": "可愛い猫"}' http://localhost:3001/api/open-ai/image-generator
少し時間がかかるかもしれませんが、curlコマンドには{"ok":true}
の応答が返ります。しかし、Hono
アプリケーションのログを確認すると、OpenAI APIからの応答が表示されます。
{
created: 1696552736,
data: [
{
url: 'https://oaidalleapiprodscus.blob.core.windows.net/private/org-GHrdXOF8ECjVKbsAPk6EJyjF/user-HKqdJ2Flf0qv4Qdc7vNx6F5u/img-b8BAvSH2lef46vgGGw6Ejc2T.png?st=2023-10-05T23%3A38%3A56Z&se=2023-10-06T01%3A38%3A56Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2023-10-05T22%3A19%3A10Z&ske=2023-10-06T22%3A19%3A10Z&sks=b&skv=2021-08-06&sig=Diew4BsgCDfoTFlAPhDhQPuIJ/MY6zcGNLcbpJj71f4%3D'
}
]
}
これですね:
デフォルトでは、CORS
の設定により、異なるオリジンからのリクエストは許可されません。私たちのReact
アプリケーションはポート3000で実行されているため、/api/open-ai/image-generator
エンドポイントにアクセスできません。これを正しく設定するためにはさまざまな方法がありますが、この例では簡単に保つことにします。index.ts
ファイルの先頭に次のコードを追加してください:
/src/index.ts
import { Hono } from "hono";
import OpenAI from "openai";
import { cors } from "hono/cors"; // <-- ここ
[..]
const app = new Hono();
// ↓ これ
app.use(
"/api/*",
cors({
origin: "http://localhost:3000",
allowMethods: ["POST"],
})
);
[..]
これにより、プロジェクトはhttp://localhost:3000
からのAPIエンドポイントへのPOST
リクエストを許可するように設定されます。OpenAI APIが返すデータの種類をすでに知っているため、画像のURLを返すことができます。エンドポイントの戻り値部分を置き換えましょう:
/src/index.ts
[..]
// https://platform.openai.com/docs/api-reference/images/object
const openAIResponse = await openAI.images.generate({
prompt, // ユーザーのプロンプト
n: 1, // 生成する画像の数
size: "512x512" // 画像サイズ
})
// ↓ ここ
if(!openAIResponse.data || !openAIResponse.data[0] || !openAIResponse.data[0].url) {
return c.json({ error: "OpenAI API response invalid" }, {status:500});
}
return c.json({ url: openAIResponse.data[0].url})
});
export default app;
それで当分のHono
アプリケーションは完了ですね!それほど悪くなかったですね、そうでしょう? 😊
ai-love-images
app!
Back to React 使えそう! アプリにAPIキーとユーザープロンプトを含むリクエストを送信するための機能を追加し、簡略化のために、src/hooks
フォルダ内にカスタムの一般的なフックを作成します:
/src/hooks/use-image-generate-request-hook.js
const IMAGE_GENERATOR_API_ENDPOINT = "http://localhost:3001/api/open-ai/image-generator";
const sendRequest = async (prompt) => {
const response = await fetch(
IMAGE_GENERATOR_API_ENDPOINT,
{
method: "POST",
headers: {
"Content-Type":"application/json",
},
body: JSON.stringify({
prompt,
})
}
)
return(response.json());
}
次の操作は、ユーザーが入力した内容をリンクし、sendRequest
関数を介して送信し、レスポンスを確認することです。
この機能をフックコード内に追加し、それを返して TextInputBox
コンポーネントから直接使用できるようにします。
/src/hooks/use-image-generate-request-hook.js
const IMAGE_GENERATOR_API_ENDPOINT = "http://localhost:3001/api/open-ai/image-generator";
const sendRequest = async (prompt) => {
[..] // 変わらず
}
export const useImageGenerateRequestHook = () => {
const sendPrompt = useCallback(async (prompt) => {
if (!prompt) return; // 空のリクエストを送信しないように
const response = await sendRequest(prompt);
console.log(response);
}, []);
return {
sendPrompt
}
}
この関数を TextInputBox
コンポーネントのプロパティとして受け取り、コンポーネントのローカルフックに渡します。
text-input-box.jsx
import tenoChanIcon from "./assets/teno-chan.png"
import "./text-input-box.css";
import { useLocalHook } from "./use-local-hook";
export const TextInputBox = ({sendPrompt}) => {
const { promptRef, handleSubmit} = useLocalHook(sendPrompt);
return (
<form onSubmit={handleSubmit}>
[..] // 変わらず
/text-input-box/use-local-hook.js
import { useCallback, useRef } from 'react';
export const useLocalHook = (sendPrompt) => {
const promptRef = useRef();
const handleSubmit = useCallback((e) =>{
e.preventDefault();
sendPrompt(promptRef.current.value);
}, [sendPrompt]);
return {
handleSubmit,
promptRef
}
}
app.js
を介してすべてを結びつけるプロセスを説明します:
app.js
import { useCallback, useState } from 'react';
import './app.css';
import { TextInputBox } from './components/text-input-box';
import { ImageShowcase } from './components/image-showcase';
import { useImageGenerateRequestHook } from './hooks/use-image-generate-request-hook';
const App = () => {
const { sendPrompt } = useImageGenerateRequestHook();
return (
<div className="app">
<ImageShowcase/>
<TextInputBox sendPrompt={sendPrompt} />
</div>
)
}
export default App;
テストしましょう! 可愛い猫
と入力し、Enter キーを押して少し待つと、次のような応答が表示されます:
{
"url": "https://oaidalleapiprodscus.blob.core.windows.net/private/org-GHrdXOF8ECjVKbsAPk6EJyjF/user-HKqdJ2Flf0qv4Qdc7vNx6F5u/img-v6pVbc5hutdWduWvX7Y8nmPi.png?st=2023-10-04T10%3A00%3A11Z&se=2023-10-04T12%3A00%3A11Z&sp=r&sv=2021-08-06&sr=b&rscd=inline&rsct=image/png&skoid=6aaadede-4fb3-4698-a8f6-684d7786b067&sktid=a48cca56-e6da-484e-a814-9c849652bcb3&skt=2023-10-04T01%3A37%3A31Z&ske=2023-10-05T01%3A37%3A31Z&sks=b&skv=2021-08-06&sig=tpLwtG%2BsPtLVjTOdkdMut6WGXLvHDXy2GWxmWDFK3EU%3D"
}
これですね!
Joining response from API to image component
生成された画像のURLを取得し、それを ImageShowcase
コンポーネントに渡して、送信ごとに変更されるようにします。
use-image-generate-request-hook.js
import { useCallback, useState } from "react";
const sendRequest = async (prompt) => {
[..]
}
export const useImageGenerateRequestHook = () => {
const [img, setImgUrl] = useState(null); // <-- ここ
const sendPrompt = useCallback(async (prompt) => {
if (!prompt) return;
const response = await sendRequest(prompt);
setImgUrl(response.url) // <-- ここ
}, []);
return {
sendPrompt,
img // <-- ここ
}
}
image-showcase.jsx
import tenoChanImage from "./assets/teno-chan-photo.png"
import "./image-showcase.css"
export const ImageShowcase = ({src}) => {
return (
<div className="imageWrapper"}>
<img src={src || tenoChanImage} alt="Everybody loves TenoChan" />
</div>
)}
app.js
import { useCallback, useState } from 'react';
import './app.css';
import { TextInputBox } from './components/text-input-box';
import { ImageShowcase } from './components/image-showcase';
import { useImageGenerateRequestHook } from './hooks/use-image-generate-request-hook';
const App = () => {
const { sendPrompt, img } = useImageGenerateRequestHook();
return (
<div className="app">
<ImageShowcase src={img} />
<TextInputBox sendPrompt={sendPrompt} />
</div>
)
}
export default App;
この追加により、APIからの応答が受け取られた後に画像が更新されます!
Add loading animation
出たけど、結構時間かかりますね。。。ちょっとあれだからローディングアニメーションを入れましょう!
use-image-generate-request-hook.js
import { useCallback, useState } from "react";
const sendRequest = async (prompt) => {
[..]
}
export const useImageGenerateRequestHook = () => {
const [img, setImgUrl] = useState(null);
const [isLoading, setLoading] = useState(false); // <-- ここ
const sendPrompt = useCallback(async (prompt) => {
if (!prompt) return;
setLoading(true); // <-- ここ
const response = await sendRequest(prompt);
setLoading(false); // <-- ここ
setImgUrl(response.url)
}, []);
return {
sendPrompt,
img,
isLoading // <-- ここ
}
}
ImageShowcase
コンポーネント内で、ローディングフラグに応じてCSSアニメーションを追加しましょう:
image-showcase.jsx
import tenoChanImage from "./assets/teno-chan-photo.png"
import "./image-showcase.css"
export const ImageShowcase = ({src, isLoading}) => {
return (
<div className="imageWrapper">
<img src={src || tenoChanImage} alt="Everybody loves TenoChan" />
<div className={isLoading ? "loading full" : "loading"}></div> // <-- ここ
</div>
)}
image-showcase.css
.loading {
width: 0;
margin-left: 30px;
height: 8px;
background: red;
}
.loading.full {
width: 256px;
transition: 15s;
}
このシンプルなアニメーション技術では、赤い背景を持つ div 要素が、0から256pxまでの幅に15秒かけて展開されます。これはAPIの平均応答時間を表しています。
また、isLoading
フラグを app.js
からコンポーネントに渡す必要があります
app.js
const App = () => {
const { sendPrompt, img, isLoading } = useImageGenerateRequestHook();
return (
<div className="app">
<ImageShowcase src={img} isLoading={isLoading} />
<TextInputBox sendPrompt={sendPrompt} />
</div>
)
}
export default App;
良くなりました (英語かスペイン語か日本語。。。どちらでもかまいません!):
Let's add some more animations
アニメーションが好きなので、もっとクールなエフェクトを追加させてください 😄
text-input-box.jsx
// ここもisLoadingを使います ↓
export const TextInputBox = ({sendPrompt, isLoading }) => {
const { promptRef, handleSubmit} = useLocalHook(sendPrompt);
return (
<form onSubmit={handleSubmit}>
<div className="input-box">
<button className="btn-input">
<img src={tenoChanIcon} width="50" alt="tenochan" className={`${isLoading ? "animate" : ""}`}/> // <-- ここ
</button>
<input ref={promptRef} type="text" className="input-text" placeholder="テラーノベルの可愛いテノちゃん" />
</div>
</form>
)}
text-input-box.css
@keyframes tada {
0% {
transform: scale3d(1, 1, 1);
}
10%, 20% {
transform: scale3d(.9, .9, .9) rotate3d(0, 0, 1, -3deg);
}
30%, 50%, 70%, 90% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, 3deg);
}
40%, 60%, 80% {
transform: scale3d(1.1, 1.1, 1.1) rotate3d(0, 0, 1, -3deg);
}
100% {
transform: scale3d(1, 1, 1);
}
}
img.animate {
animation-name: tada;
animation-duration: 1s;
animation-iteration-count: infinite;
animation-delay: 1s;
}
app.js
const App = () => {
const { sendPrompt, img, isLoading } = useImageGenerateRequestHook();
return (
<div className="app">
<ImageShowcase src={img} isLoading={isLoading} />
<TextInputBox sendPrompt={sendPrompt} isLoading={isLoading} />
</div>
)
}
export default App;
↑これはテノちゃんのアイコンのアニメーションです。
次は新しい画像に変更しそうとき、ImageShowcase
も動かす:
image-showcase.jsx
import tenoChanImage from "./assets/teno-chan-photo.png"
import "./image-showcase.css"
export const ImageShowcase = ({src, isLoading}) => {
return (
// ここ ↓
<div className={`imageWrapper ${isLoading === false ? "animate" : ""}`}>
<img src={src || tenoChanImage} alt="Everybody loves TenoChan" />
<div className={isLoading ? "loading full" : "loading"}></div>
</div>
)}
image-showcase.css
@keyframes gelatine {
from, to { transform: scale(1, 1); }
25% { transform: scale(0.9, 1.1); }
50% { transform: scale(1.1, 0.9); }
75% { transform: scale(0.95, 1.05); }
}
.imageWrapper > img {
max-width: 300px;
border-radius: 40px;
border: 3px solid white;
box-shadow: 0 1px 1px rgba(0,0,0,0.12), 0 2px 2px rgba(0,0,0,0.12);
}
.imageWrapper.animate > img {
animation: gelatine 1s;
}
.loading {
width: 0;
margin-left: 30px;
height: 8px;
background: red;
}
.loading.full {
width: 256px;
transition: 15s;
}
これが現時点での最終結果です、どう思いますか?
Ghe?!? なんか、GOOD BYEじゃないよね。。。w 😅
ところで、こんなテストいっぱいしたけど、まだ$10から$9.51があります。。。全然使えそう!
そして、今のところはこれで終わりかなと思います... もっと改善のアイデアがあります。例えば、類義語を追加し、テキスト解析を行い、ユーザープロンプトのさまざまなバージョンを生成し、複数の画像を一度に生成することも考えています。さらに、他のAPIを使用して、1つのプロンプトから異なるスタイルの多くの異なる画像を取得することもできます(以下の2つはかなり面白いです:EmojiGen および AI Emojis)。しかし、この記事はすでに長くなってしまったので、これらのアイデアはまた別の機会に取り組むことにしましょう。
Clone the code from Github!
あ!コードはここにあります、是非clone
して遊んでください!
ai-love-open-ai
ai-love-images
Adios! Happy generating! .
読んでいただき、ありがとうございます!
Discussion