실전 프로젝트를 위해 이미지 생성형 AI에 대해 스스로 배우다.
안녕하십니까, 프롬프트 연구소장 이뮨01입니다.
실전 프로젝트에서 이미지 생성형 AI를 사용하게 되었다. 생성형 AI 모델은 카카오에서 제작한 Karlo와 스테이블 디퓨전(Stable Diffusion), 미드저니(Midjourney) 등이 있다. 미드저니는 디스코드에서만 사용할 수 있어서 후보에서 제외했다.
Karlo가 가장 접근성이 쉬운대신 품질이 스테이블 디퓨전에 비해 안좋다. 스테이블 디퓨전은 접근성이 칼로에 비해 어려운 대신 품질이 꽤나 좋다. 가장 처음에는 접근성이 쉬운 Karlo 모델을 사용해서 이미지 생성을 시도했다.
https://developers.kakao.com/product/karlo
1. Karlo 모델로 이미지 생성
React.js
# React.js
import "./App.css";
import axios from "axios";
import React, { useState } from "react";
function App() {
const [inputValue, setInputValue] = useState();
const [imageData, setImageData] = useState();
const handleSubmit = (e) => {
e.preventDefault();
console.log(inputValue);
sendDataToNodeServer(inputValue);
};
const sendDataToNodeServer = (inputValue) => {
axios
.post("http://localhost:3001/react2node", { inputData: inputValue })
.then((response) => {
console.log("데이터", response.data.inputData); // 노드 서버의 응답 처리
const image = new Image();
image.src = 'data:image/png;base64,' + response.data.inputData;
setImageData(image); // 이미지 데이터 스테이트에 저장
})
.catch((error) => {
console.error("Failed to send data to Node.js server:", error);
});
};
return (
<div className="App">
<form onSubmit={handleSubmit} method="post">
<input
type="text"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
/>
<button type="submit">전송</button>
</form>
{imageData && <img src={imageData.src} alt="Generated AI Image" />}
</div>
);
}
export default App;
React.js 프론트에서 사용자에게 prompt (프롬프트)를 입력받는다. 프롬프트란 사용자가 제작하고 싶어하는 이미지를 표현할 수 있는 키워드, 문장, 분위기, 모양 등을 AI에게 입력하기위해 사용하는 것이다. 프롬프트는 긍정 프롬프트, 부정 프롬프트로 나눠진다. 긍정 프롬프트는 제작되는 이미지에 적용됐으면 하는 것들을 적는다. 반면, 부정 프롬프트에는 제작되는 이미지에 적용되지 않았으면 하는 것들을 적는다. 예를 들어서 내가 검정색 고양이 이미지를 얻고 싶다면 긍정 프롬프트에는 black, cat 이런식으로 들어가면 될 것 같고 부정 프롬프트에는 안좋은 퀄리티와 같은 긍정 프롬프트와는 반대되는 부정적인 단어들을 적으면 된다. ex) worst quality, low quality, ugly..
테스트용으로 만든 것이기 때문에 긍정프롬프트만 입력으로 받아준다. 입력받은 프롬프트 값이 최종적으로 Flask 서버로 가야하기 때문에 중간 서버 역할인 Node로 axios를 사용해서 보내준다.
Node.js
const express = require("express");
const app = express();
const axios = require("axios");
const cors = require("cors");
const bodyParser = require("body-parser");
app.use(cors());
app.use(bodyParser.json()); //요청 본문을 json 형태로 파싱
app.use(bodyParser.urlencoded({ extended: true }));
// 데이터를 주고받을 엔드포인트 설정
app.post("/react2node", (req, res) => {
console.log("data exchange router", req.body.inputData);
// POST 요청으로 받은 데이터
const userInput = req.body.inputData;
console.log(userInput);
// 노드 서버에서 받은 데이터를 Flask 서버로 전송
axios.post('http://d5ad-35-240-224-193.ngrok.io/node2flask', { data: userInput })
.then(response => {
// Flask 서버의 응답 처리
console.log("응답옴?", response.data);
res.status(200).json({ inputData: response.data });
})
.catch(error => {
console.error('Failed to send data to Flask server:', error);
res.status(500).json({ error: 'Failed to send data to Flask server' });
});
// react.js 보낼 데이터
// res.status(200).json(response.data);
});
app.listen(3001, () => {
console.log("Node.js server is running on port 3001");
});
React에서 넘어온 프롬프트 값을 그대로 Flask 서버로 axios를 사용해서 넘겨준다
Flask
from flask import Flask, request, jsonify
from flask_cors import CORS
# REST API 호출, 이미지 파일 처리에 필요한 라이브러리
import requests
import json
import urllib
from PIL import Image
# [내 애플리케이션] > [앱 키] 에서 확인한 REST API 키 값 입력
REST_API_KEY = 'YOUR API KEY'
app = Flask(__name__)
CORS(app) # 모든 엔드포인트에 대해 CORS를 활성화
# 데이터를 주고받을 엔드포인트 설정
@app.route('/node2flask', methods=['POST'])
def data_exchange():
user_input = request.json['data'] # 사용자 입력값 프롬프트
r = requests.post(
'https://api.kakaobrain.com/v2/inference/karlo/t2i',
json = {
'prompt': user_input,
'negative_prompt': negative_prompt
},
headers = {
'Authorization': f'KakaoAK {REST_API_KEY}',
'Content-Type': 'application/json'
}
)
# 응답 JSON 형식으로 변환
response1 = json.loads(r.content)
images = response1.get("images")[0]
print("생성된 이미지 데이터",images)
# Flask에서 node.js로 데이터 전송
return jsonify(images)
if __name__ == '__main__':
app.run()
Node에서 넘어온 사용자의 프롬프트 값을 이미지 생성하기 위해 사용되는 prompt 인자로 사용해서 이미지를 생성해준다.
생성된 이미지 데이터의 URL을 사용해서 화면에 띄울 것이다. 화면에 띄우는 역할은 React에서 해야하기 때문에 이미지 데이터를 Flask - Node - React 순으로 보내준다. 직접 이미지를 만들어보면 품질이 별로 안좋고 워터마크도 있어서 스테이블 디퓨전을 사용하기로 결정했다.