어떤 단어를 입력했을 때, 미리 입력해둔 스타일의 도안을 이미지로 받아볼 수 있도록 DALL.E API 를 사용해보았다.
DALL.E API key 발급 방법
아래 링크에 로그인 한 뒤 간단히 받아볼 수 있다.
https://platform.openai.com/api-keys
주의할 점
1. 한 번 생성하면 다시 열 수 없고, 지운 뒤 새로 받아야 하는 번거로움이 있으니 잘 저장해두자.
2. 현재 ChatGPT 구독 여부와는 별개로 플랜을 신청해야 한다.
(현 시점 ChatGPT 4o를 구독하고 있으나, API를 사용하기 위해서는 추가 결제를 해야했다.)
3. 이 점을 해결하지 않으면 API key를 적용하더라도 400 Error를 반환한다.
4. 분 당 5장의 이미지를 제공하니, 지나치게 잦은 생성은 지양해야 한다.
(현재 만드는 서비스는 테스트 용도이고, 생성 시간이 꽤 오래 걸려 아직은 걱정하지 않기로 했다)
1.
이제 자신의 프로젝트에 axios를 의존성 패키지로 설치한다.
yarn add axios
2.
GenerateImageApi.ts 파일을 생성한다.
이 파일에 아래처럼 api를 호출하는 로직을 작성한다.
//GenerateImageApi.ts
import axios from 'axios';
const GenerateImageApi = async (prompt: string, color: boolean): Promise<string> => {
// 전달할 props와 반환되는 Promise 객체의 타입 지정
const apiKey = process.env.REACT_APP_OPENAI_API_KEY;
// 프로젝트 루트 디렉토리의 .env 파일에 자신의 API키 저장
const url = 'https://api.openai.com/v1/images/generations';
// 생성될 이미지의 url
const headers = {
'Authorization': `Bearer ${apiKey}`,
// Bearer란? OAuth 2.0 인증에서 사용되는 방법. 토큰을 전달하여 서버에서 사용자의 인증 및 권한 확인
'Content-Type': 'application/json',
// JSON으로 데이터 형식 변환
};
const data = {
prompt: `${prompt} //추가 프롬프트를 고정하고 싶다면 여기에 작성//,
${color ? 'colorful' : 'black and white'}`, // 흑백, 컬러 여부
n: 1, // 생성할 이미지 수
size: '256x256', // 이미지 크기
response_format: 'url',
};
// fufilled
try {
const response = await axios.post(url, data, { headers }); // 요청을 보낼 url, 요청과 함께 보낼 data, 설정 객체(header)
return response.data.data[0].url;
}
// rejected
catch (error) {
console.error('Error generating image:', error);
throw error;
}
};
export default GenerateImageApi;
3.
이제 이미지 생성을 진행할 페이지 파일을 만들어 주고,
(루트 파일에 Routing 과정은 생략하겠다)
이미지 생성 요청의 성공 / 실패에 따른 handleSubmit 함수를 작성해준다.
//GenerateImage.tsx
import { useState } from 'react';
import GenerateImageApi from '../components/api/GenerateImageApi';
const GenerateImage: React.FC = () => {
const [prompt, setPrompt] = useState<string>('');
const [imageUrl, setImageUrl] = useState<string>('');
const handleSubmit = async (e: React.FormEvent) => {
// 단순히 제출이 아니라, 제출 후 데이터 요청을 해야하므로 async 처리
e.preventDefault();
// fufilled
try {
const url = await GenerateImageApi(prompt, color); // 위에서 작성한 api 호출 함수 실행
setImageUrl(url); // 생성한 이미지에 대한 url 생성
}
// rejected
catch (error) {
console.error('Error:', error);
}
};
}
4.
마지막으로 유저에게 보여질 ui에 이미지 생성용 input, img, button 태그 등을 구성하여 return문에 추가한다.
(아래 코드는 기능 구현만 이룬 것으로, 모든 스타일링은 default HTML 스타일이다)
GenerateImageApi.ts 파일에서 만든 흑백과 컬러 옵션을 checkbox를 통해 결정할 수 있도록 했다.
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Enter your prompt"
required
/>
<label>
<input
type="checkbox"
checked={color}
onChange={(e) => setColor(e.target.checked)}
/>
Color
</label>
<button type="submit">Generate Image</button>
</form>
{imageUrl && <img src={imageUrl} alt="Generated" />}
</div>
);
전체 코드
아래는 GenerateImage.tsx의 전체 코드이다.
import { useState } from 'react';
import GenerateImageApi from '../components/api/GenerateImageApi';
const GenerateImage: React.FC = () => {
const [prompt, setPrompt] = useState<string>('');
const [color, setColor] = useState<boolean>(false);
const [imageUrl, setImageUrl] = useState<string>('');
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
try {
const url = await GenerateImageApi(prompt, color);
setImageUrl(url);
}
catch (error) {
console.error('Error:', error);
}
};
return (
<div>
<form onSubmit={handleSubmit}>
<input
type="text"
value={prompt}
onChange={(e) => setPrompt(e.target.value)}
placeholder="Enter your prompt"
required
/>
<label>
<input
type="checkbox"
checked={color}
onChange={(e) => setColor(e.target.checked)}
/>
Color
</label>
<button type="submit">Generate Image</button>
</form>
{imageUrl && <img src={imageUrl} alt="Generated" />}
</div>
);
};
export default GenerateImage;
사족...
-오늘의 프롬프트 일기-
1. 영어로 입력한 경우 정확도가 현저히 올라간다. (이건 GPT와 마찬가지)
2. 간결하고 명확하게 작성해야한다.
- '~ 한 느낌', '마치 건축가처럼...' 보다는 '청사진 스타일', '앤디워홀 스타일' 이라고 써야 한다.
- 다만 이러한 명사가 들어가면 그 스타일에 매우 갇혀버리는 경향을 보인다.
3. 사이즈와 관계 없이 때때로 이미지가 잘린다.
- 'leaving empty spave around the edges at least 10px to avoid being cropped' 라고 작성하면 때때로 나아진다.
4. icon style이라고 입력하면 매우 단순화시킨다.
5. line style이라고 입력하면 목판화처럼 뚝딱거리거나, 목탄화 같은 이미지를 만든다.
개선해야할 점
1. 유저에게서 한글 입력이 들어오는 경우
2. 로컬에 저장된 값을 바탕으로 이미지를 임의로 생성하는 경우
- 나의 경우, '비행기'를 몇 번 시도한 후 refresh 했는데도 전혀 다른 input에 대해 몇 차례에 걸쳐 비행기를 그려냈다.
3. color 옵션에 대해 소극적으로 대처하는 경우
- 색을 조화롭게 입힌다기 보다는, 같은 그림을 그저 검정 잉크에서 주황 잉크로 그리듯이 단순한 변화만 나타났다
'React.ts' 카테고리의 다른 글
GSAP 활용하여 ScrollEvent 쉽게 구현하기 - 2 (0) | 2024.08.12 |
---|---|
GSAP 활용하여 ScrollEvent 쉽게 구현하기 - 1 (0) | 2024.08.07 |
React TypeScript - Custom Hook으로 모달창 관리하기 (0) | 2024.07.07 |
React TypeScript - Intersection Observer 활용 (0) | 2024.07.04 |
React TypeScript - 카카오맵 API 호출 : TypeError: Cannot read properties of null (reading 'currentStyle') (0) | 2024.06.12 |