🐨CoalaCoding
DocsExamplesTry itBoardB반B반
🐨CoalaCoding

개발자를 위한 한국어 웹 기술 문서

문서

  • JavaScript
  • Web Publishing
  • React
  • Python

커뮤니티

  • 게시판
  • 예제 모음
  • Try it 에디터

기타

  • GitHub
  • 관리자
© 2026 CoalaCoding. All rights reserved.
  • start
  • class
  • ai이미지-생성기-구현
  • 자료형
  • async--await
  • 변수와자료형
  • xmlhttprequest-부터axios-까지
  • 1-자바스크립트와-ecma
  • reduce
  • 캘린더-만들기
  • generator
  • destructuring
  • spread-operator
  • module-export-import
  • http-통신-이란
  • 시작
  • 2-자바스크립트-코드-실행-과정-및-용어정리
  • map
  • 동기와-비동기
  • 연산자
  • promise-thencatch
  • 3-실행컨텍스트와-스코프
  • 콜백-함수
  • 제어문
  • 4-클로저
  • windowlocation
  • 함수
  • 5-객체
  • 이벤트
  1. 홈
  2. 문서
  3. JavaScript
  4. JavaScript 기초
  5. ai이미지-생성기-구현

ai이미지-생성기-구현

openAI의 DALL-E 모델을 사용하여 웹페이지에 AI 기반 이미지 생성기를 자바스크립트로 구현합니다.

코드 블록의 Try it Yourself 버튼으로 직접 실행할 수 있다.

구문

자바스크립트로 웹페이지에 AI기반 이미지 생성 서비스를 구현해 봅시다.

Chat-GPT 의 DALL-E 모델을 활용할 것입니다. DALL-E는 텍스트 설명을 기반으로 이미지를 생성하는 AI 모델로, 자연어를 기반으로 그림을 생성합니다. 현재 버전은 DALL-E-3 이며 DALL-E-2 와 DALL-E-3 모델 중 선택하여 사용할수 있습니다.

오픈ai api 문서https://platform.openai.com/docs/overview
이미지생성기 가이드 링크https://platform.openai.com/docs/api-reference/images

🔗완성화면

1. html 구조작성

Info: 💡 html,css, 아이콘 모두 부트스트랩 시스템을 사용하겠습니다.

1.1.라이브러리로드

  1. 아래 코드를 붙여 넣어 라이브러리를 로드하고 폰트를 세팅합니다.
  2. 기본적인 css 코드를 작성합니다. 🔗bootstrap-cheatsheet
<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <title>Bootstrap demo</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.3/font/bootstrap-icons.min.css"
    />
    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
      crossorigin="anonymous"
    />
    <style>
      @import url("https://cdn.jsdelivr.net/gh/orioncactus/pretendard@v1.3.9/dist/web/variable/pretendardvariable.min.css");

      body {
        font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;

        a {
          font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;
        }

        h1 {
          font-weight: 900;
        }

        p {
          font-weight: 500;
        }

        .message,
        #spinner {
          display: none;
        }
      }
    </style>
  </head>

  <body>
    <h1>Hello, world!</h1>
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz"
      crossorigin="anonymous"
    ></script>
  </body>
</html>

1.2. container 추가

<body>
  
  <div class="container-fluid">
    <div class="row justify-content-center">
      <div class="col-12 col-md 10 col-lg-8 col-xl-6 mt-5">
        <p class="lead">API 키가 필요 합니다.<a href="http://platform.openai.com" target="_blank" rel="noopener noreferrer">여기서 발급 받으실수 있습니다.</a></p>
      </div>
    </div>
  </div>  
  ...

1.3. button 추가

</div>  
<div class="position-absolute top-0 end-0 mt-2 me-3"><button type="button" id="api" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#Keymodal">API키 입력하기</button>
</div> 
...

🔗1.3.완성화면

1.4. 메인영역추가

  1. 모달팝업

<div class="container mt-5">
  <div class="modal fade" id="Keymodal" tabindex="-1">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
          <h5 class="modal-title" id="ModalLabel">
            입력하신 API키는 웹브라우저의 로컬 스토리지에 저장되며 창을 닫는
            즉시 삭제됩니다.
          </h5>
        </div>
        <div class="modal-body">
          <div class="form-group">
            <label for="apikey">API KEY 입력창</label
            ><input
              type="text"
              class="form-control"
              id="apikey"
              placeholder="GPT에서 발급받은 API키를 입력해주세요."
            />
          </div>
        </div>
        <div class="modal-footer">
          <button
            type="button"
            class="btn btn-secondary"
            data-bs-dismiss="modal"
          >
            창닫기</button
          ><button type="button" class="btn btn-primary">저장하기</button>
        </div>
      </div>
    </div>
  </div>
</div>

  1. 메인영역
<div class="container mt-5">
  <div class="row justify-content-center">
    
    <div class="col-md-8">
      <div class="message alert alert-danger text-center" id="message"></div>
    </div>
  </div>
  
</div>



<header class="mt-5">
  <h1 class="text-center">AI 이미지 생성기</h1>
  <p class="lead text-center">
    Generative AI로 생각을 그림으로 그려 보세요. 머릿속의 생각을 간단히
    설명하세요!
  </p>
</header>


<section class="mt-5">
  <form id="generate-form">
    <div class="row">
      <div class="col-md-9">
        <div class="form-group">
          <input
            type="text"
            id="prompt"
            class="form-control py-2 pb-2"
            placeholder="신분이 공주인데 성격은 개구쟁이인 몰티즈 강아지를 그려줘"
          />
        </div>
      </div>
      <div class="col-md-3">
        <div class="form-group">
          <button type="submit" class="btn btn-primary btn-lg" id="generate">
            나와라 뿅!
          </button>
        </div>
      </div>
    </div>
  </form>
</section>

<div class="spinner-border text-danger" id="spinner"></div>

<section class="container mt-5">
  <div class="row justify-content-center" id="gallery">
    
  </div>
</section>
</div> 

🔗1.4.완성화면

2. 스크립트 작성

2.1. 외부 스크립트 연결

  </div> 
  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
  
**  <script src="dalle.js"></script>**
  
</body>

2.2. 모달팝업 구현

Info: 💡 모달기능은 부트스트랩의 메서드를 활용하겠습니다

const keyModalEl = document.querySelector('#Keymodal');
//부트스트랩 모달 인스턴스로 keyModalEl 등록
const keyModal = new bootstrap.Modal(keyModalEl);
//keyModalEl에 이벤트핸들러 작성. 이벤트는 모달인스턴스의 것을 사용
keyModalEl.addEventListener('shown.bs.modal', () => {
	const saveBtn = document.querySelector('.btn-primary');
	const keyInput = document.querySelector('#apikey');
	saveBtn.addEventListener('click', () => {
		const keyVal = keyInput.value;
		//로컬스토리지에 키값 저정
		localStorage.setItem('API_KEY', keyVal);
		//모달창 닫음
		keyModal.hide();
	});
});

🔗2.2.완성화면

  1. shown.bs.modal : 부트스트랩에서 제공하는 속성입니다.
  2. 아래 그림은 html 과 자바스크립트의 해당 코드로 연관된 속성끼리 같은 색상의 테두리로 표시하였습니다. 빨간 테두리의 속성은 토글관련 기능/디자인을 만들어 주고 파란 테두리의 속성은 모달관련 기능/디자인을 구현합니다. 부트스트랩을 사용하여 컴포넌트 제작시 html 태그에서 표시된 속성을 필수로 작성해야 하며 속성의 값을 같게 작성해야 자바스크립트에 표시된 부트스트랩의 속성이나 메서드를 사용할수 있습니다.

🔗부트스트랩 공식문서

  1. 이후의 스크립트는 주석을 참고하세요
  2. 실행화면에서 API키 입력하기 버튼을 클릭하고 API 키가 로컬스토리지에 저장되는지 확인합니다.

2.3. 더미이미지 추가하기

Info: 💡 달리가 그려줄 이미지를 예시를 추가하겠습니다.

사용할 이미지의 데이터는 아래의 코드를 복사하세요

const images = [
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog1.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog2.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog3.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog4.png",
];
const images = [
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog1.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog2.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog3.png",
  "https://qwerewqwerew.github.io/source/js/dall-E/ai/dog4.png",
];

const imageGallery = document.querySelector("#gallery");
function displayImage() {
  const imageMarkUp = images
    .map((image) => {
      return `
       <div class="col-12 col-sm-6 col-md-3 mb-4 position-relative" id ="image-container ">
          <img src="${image}" class="img-fluid" alt="Placeholder Image">
        </div>
        `;
    })
    .join("");
  imageGallery.innerHTML = imageMarkUp;
}
displayImage();

🔗2.3.완성화면 displayImage 함수를 선언하고 함수 바디에 imageMarkUp 변수로 images 배열 변수내의 원소를 순회하며 img 요소로 반환하는 로직을 작성합니다.

아래는 실행 화면에서 소스코드 순서로 추적한 이미지입니다. alt 속성의 값은 더미 이미지 이므로 상황에 따라 생략 가능합니다.

2.4. 나와라뿅! 구현하기

2.4.1. 검색창의 입력값 받아오기

  1. 입력을 시작하면 더미이미지 삭제
const promptInp = document.querySelector('#prompt');
promptInp.addEventListener('input', () => {
	imageGallery.innerHTML = '';
});

promptInp는 input 요소입니다. promptInp에 input 이벤트가 감지되면 imageGallery 내의 HTML은 공백문자로 바뀌므로 예쁜 말티즈는 없어집니다.

  1. 입력한 텍스트를 전달받아 openai api 에 전달하여 이미지를 생성하는 로직을 작성합니다. 🔗https://platform.openai.com/docs/api-reference/images/create?lang=node.js
  2. 나와라뿅 버튼 클릭 이벤트함수
const generateForm = document.querySelector('#generate-form');
generateForm.addEventListener('submit', async (e) => {
	e.preventDefault();
	//input#prompt 의 입력값을 취득하여 prompt 변수에 할당
	const prompt = promptInp.value;
	//로컬스토리지의 API_KEY에 저장된 값을 변수 key에 할당
	const key = localStorage.getItem('API_KEY');
	//비동기식으로 fetchImage 함수를 호출하여 변수에 저장한 값을 인자로 전달
	await fetchImage(prompt, key);
});
  1. fetchImage 함수작성
const fetchImage = async (prompt, API_KEY) => {
  //openai의 이미지생성 api 앤드포인트. 해당 주소는 2번의 링크 참조
  const url = "https://api.openai.com/v1/images/generations";
  // 요청주소에 함께 보낼 옵션 객체
  // 통신 방법과 통신요청 헤더와 바디에 넣을 데이터 작성
  const opt = {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${API_KEY}`,
    },
    body: JSON.stringify({
      model: "dall-e-3", //생성모델 dall e 3
      prompt, //이미지설명(프롬프트)포함
      n: 1, //이미지생성 갯수 1
      size: "1024x1024", //이미지크기 1024x1024
    }),
  };
  try {
    //try 문에 요청함수 작성
    //fetch 함수로 비동기 통신을 요청하면서 인자로 url,opt 전달하고 응답내용을 response 변수에 할당
    const response = await fetch(url, opt);
    // response 의 값을 json 형식으로 변환후 result 변수에 할당
    const result = await response.json();
    //콘솔창에 확인
    console.log(result);
    const newImageURL = result.data[0].url;
    imageGallery.innerHTML += `<div class="col-12 col-sm-6 col-md-3 mb-4 position-relative">
      <img src="${newImageURL}" class="img-fluid" alt="Generated Image">
    </div>`;
  } catch (error) {
    console.error(error);
  }
};

🔗4.완성화면

2.4.3 테스트해보기

  1. 🔗3번으로 이동하여 API 키를 발급 받습니다.
  2. 작성한 웹문서를 라이브서버로 열어 실행하여 테스트 합니다.
  3. API 키 입력 버튼을 클릭하고 발급받은 키를 붙여넣습니다.
  4. 저장하기 버튼을 클릭하고 콘솔메시지에 아래와 같은 오류가 뜰 경우 6번으로 가세요.

 축하합니다. 당첨 되었습니다.

  1. 우선 제대로 된 API 키를 입력할 경우 아래의 이미지 실행됩니다.

  1. 당신은 왜 당첨 되었을까요? 바로 신용카드 번호를 입력하지 않아서 입니다. GPT는 미제이므로 기브앤테이크가 확실합니다. 무료티어는 1분동안 5번 이미지 요청 가능. 하루 최대 200번 요청 가능 합니다. 한도가 초과되면 자동 결제가 되는데 이때 결제될 신용카드 등록이 필요합니다. 신용카드 등록후 API 키를 재발급 받고 확인하면 이미지가 생성됩니다. 🔗신용카드 등록하기

2.4.4. 테스트해보기

  1. API키를 발급 받습니다.
  2. 발급받은 키를 입력창에 붙여 넣습니다→저장하기 클릭

로컬 스토리지에 저장되었는지 확인합니다.

  1. 그리고 싶은 그림을 서술하고 나와라 뿅을 클릭하세요

시간이 좀 걸리더라도 가만히 기다리세요. 얘 한테도 그릴 시간을 주셔야죠!!! 던져주고 바로 결과물을 내놓으라는 것은 나쁜사람 이에요.

  1. 결과물이 나왔습니다.

험한 말이 나올것 같아요. 제 생각을 AI는 어떻게 시각적으로 녹여낼지 내심 기대 하고 기다렸습니다. 그런데 어디서 코알라 사진 주워와서 유칼립투스 나무와 합성하고 텍스트로 채우다니요.

2.4.5. 결과코드 분석하기

Info: 💡 위에서 작성한 fetchImage 함수의 console.log(result); 다음 라인 부터 확인해 보겠습니다.

  1. 스폰지밥의 뚱이를 그려줘 라는 프롬프트를 작성 후 콘솔메시지로 반환값을 확인했습니다.

  1. result변수의 data[0] 에 저희에게 필요한 값이 저장된 것이 보입니다. 프롬프트는 영어로 번역되었네요. url 키에 달리가 생성한 이미지의 주소가 저장되어 있습니다.
  2. 이미지의 주소가 저장된 키를 새 변수에 할당후 이전 더미이미지를 추가하듯 imageGallery 변수의 하위요소로 추가합니다.

  1. catch 문은 try 문의 요청 실패시 실행할 내용을 작성할수 있습니다. 통신 요청 실패시 error 매개변수를 전달받아 console.error 메서드를 호출하며 매개변수 error 을 전달하는 로직입니다.

2.5. 생성중,실패 UI 만들기

Info: 💡 생성중과 생성실패를 표시하는 UI를 구현 하겠습니다.

이미지 생성중에는 스피너를 표시하고 생성실패시 메시지를 화면에 띄우도록 하겠습니다.

2.5.1. displayMsg 함수작성

const spinner = document.querySelector('#spinner');
let message = document.querySelector('#message');
generateForm.addEventListener('submit', async (e) => {
	e.preventDefault();
	const prompt = document.querySelector('#prompt').value;
	const key = localStorage.getItem('API_KEY');
	//프롬프트 값이 false
	if (!prompt) {
		displayMsg('프롬프트(명령어)를 입력하세요');
		return;
	}
	//key 값이 false
	if (!key) {
		displayMsg('APIKEY를 입력하고 저장버튼을 클릭해주세요.');
		return;
	}
	await fetchImage(prompt, key);
});
function displayMsg(msg) {
	message.textContent = msg;
	message.style.display = 'block';
	setTimeout(() => {
		message.style.display = 'none';
	}, 3000);
}
  1. generateForm.addEventListener 의 이벤트 핸들러 함수 바디에 prompt와 key 변수의 값이 false 일때 보여줄 메시지를 작성합니다.
  2. displayMsg 함수는 매개변수를 전달받아 textContent 속성에 #message 요소에 전달받은 매개변수를 동적할당 합니다. 3초후 메시지는 화면에서 사라집니다.

2.5.2. fetchImage 함수 수정

  1. fetchImage함수는 이 프로그램에서 핵심적인 역할을 합니다. generateForm의 이벤트 핸들러에서 전달하는 인자를 매개변수로 받아 서버에 통신을 요청하고 응답받는 로직이 여기 들어있습니다. 그러므로 요청과 응답동안 대기하는 스피너는 이 함수에서 표시하도록 하겠습니다.
const fetchImage = async (prompt, API_KEY) => {
	const url = 'https://api.openai.com/v1/images/generations';
	const opt = {
		method: 'POST',
		headers: {
			'Content-Type': 'application/json',
			Authorization: `Bearer ${API_KEY}`,
		},
		body: JSON.stringify({
			model: 'dall-e-3',
			prompt,
			n: 1,
			size: '1024x1024',
		}),
	};

	try {
		// 스피너 보임
		spinner.style.display = 'block';
		const response = await fetch(url, opt);
		console.log(response);
		if (!response.ok) {
			const error = await response.json();
			const errormsg = error.error.message ? error.error.message : '이미지 생성에 실패했습니다.';
			displayMsg(errormsg);
			return;
		}
		const result = await response.json();
		const newImageURL = result.data[0].url;
		imageGallery.innerHTML += `<div class="col-12 col-sm-6 col-md-3 mb-4 position-relative">
      <img src="${newImageURL}" class="img-fluid" alt="Generated Image">
    </div>`;
	} catch (error) {
		console.error(error);
		displayMsg('일시적인 문제가 발생했습니다. 잠시후 다시 시도해 주세요.');
	} finally {
		spinner.style.display = 'none';
	}
};

🔗완성화면

  1. 완성한 프로젝트를 깃허브에 push 후 배포하세요. 이용자들의 동선을 추적하며 테스트 해보겠습니다.
  2. 1→2→A→B→3→4 의 순서로 진행이 될 것입니다.

  1. spinner 확인하기

  1. error 확인하기

유효하지 않은 인증키 입력시 표시되는 메시지는 openai 의 응답메시지 입니다.

3. 사용자용 API 키발급

3.1. openai.com 회원가입

로그인 후 대시보드로 이동한다.

3.2. api키 발급

  1. 아래 순서대로 클릭한다.

  1. 다음 페이지에서 반드시 표시된 부분을 클릭하세요

  1. 키 이름 입력

4. 신용카드 등록

Info: ⚠️ 들어가는 말씀

발급 받은 API키가 유효하려면 계정에 결제 가능한 카드정보가 저장되어 있어야 합니다. 이때 최초 한번 5.5달러를 결제해야 합니다.


  1. openai.com 에 로그인 후 아래 이미지의 순서대로 클릭하세요.

  1. 비자,마스터 카드정보입력하세요 - 화면에 보이는 정보는 더미데이터 입니다. 본인의 카드 정보 입력 후 Continue 버튼을 클릭하세요

  1. 결제 설정 창입니다. 대충 눈치껏 최소 금액을 작성한후 Continue 버튼을 클릭합니다.

  1. 통장의 잔고를 0으로 비우고 과감히 결제를 허락했습니다.

  1. 잔액부족 결제 실패로 문자가 왔습니다. (이 방법이 안된다는… ) 제가 사용하는 BC 카드사의 페이북은 해외결제용 가상카드 번호 생성 기능이 있습니다. 이 기능은 유효 기간 한달 짜리 가상 카드번호 를 생성해줍니다. 사용하시는 페이나 카드사 앱에 이런 기능이 있는지 확인해 보는것도 좋을것 같습니다. 추가로 더미 데이터를 사용해서 어떻게 화면은 넘어가도 실제 카드사 결제승인 과정을 거치기 때문에 실패합니다.

  2. 최초 5달러 결제 완료 후에는 추가 결제 없이 무료 사용이 가능합니다. 프로젝트 별 limit 에서 제한을 설정하여 조절 할 수도 있습니다.

  1. 다시 이전으로 돌아가서 코드를 작성하겠습니다

5. 문제

AI 이미지 생성기 앱을 리액트로 구현해보세요.

목차

  • 구문