openAI로 반려동물 이름 짓는 Web App 만들기 1

차차·2023년 3월 9일
1
post-thumbnail

시작하기

개발 공부를 하다가 급 무료해지기도 하고, 뭔가 리프레시가 될 수 있는 재밌는 게 없을까 ! 하다가 이 강의를 발견했다.

Build A ChatGPT AI in JavaScript

마침 내가 약하다고 생각했던 API 데이터 왔다갔다 부분이기도 했고, ChatGPT 라는 용어에 홀리듯이 강의를 결제하고 시작해버렸다 !

만들어야하는 기능은 다음과 같았다.

입력창에 동물에 관한 설명을 입력하고, Generate name 버튼을 누르거나 엔터키를 입력하면 동물의 이름이 촤라란~ 하고 뜨는 기능이다. 강의에 나온 기능만 정리하자면 (이것저것 추가해볼 예정)

  • 사용자 입력을 받아 enter 키로 정보 넘겨주기
  • 사용자 입력을 받아 버튼 클릭으로 정보 넘겨주기
  • 입력이 완료되면 입력창 초기화하기
  • openAI API 로 추천하는 동물 이름 result 받아오기
  • 받아온 result 화면에 보여주기

NextJS 로 개발하는 강의였고, 간단한 앱이라서 고대로 진행했다 !


Client-Side 개발하기

client side 에서 개발해야 하는 기능은 아무리도 입력창이 있기 때문에 대부분이 state 관련 기능이었다.

  • 사용자 입력을 받아 enter 키로 정보 넘겨주기
  • 사용자 입력을 받아 버튼 클릭으로 정보 넘겨주기
  • 입력이 완료되면 입력창 초기화하기
  • 받아온 result 화면에 보여주기

useState 로 사용자 입력을 담는 animalInput 을 만들어주고, 화면을 참고해서 아래처럼 form 을 구성하기

const [animalInput, setAnimalInput] = useState('');
// 컴포넌트가 form 이 전부라서 요고만 기록..!
<form>
  <input
         type = 'text'
         name = 'animal'
         value = {animalInput}
         onChange = {(e)=>{setAnimalInput(e.target.value);}}
  		 placeholder = 'Enter an animal'
  />
  <input
         type = 'submit'
         value = 'Generate names'
    	 onClick = {handleSubmit} // handleSubmit : 나중에 animalInput POST 하게 될 함수
  />
</form>

요기까지 하고 enter 키 기능은 onKeyPress 메서드를 사용해야 하나? 하고 고민하고 있었다.
근데 강의에서 유용한 정보를 배울 수 있었다.

<form onSubmit={handleSubmit}>
  // ...
</form>

이렇게 form 컴포넌트에 onSubmit 프로퍼티로 클릭과 엔터키 이벤트 모두를 제어할 수 있다는 것!!
다음에도 활용해야지 싶었다 너무 좋은 정보 !

그리고 임시로 result state 도 만들어준 후, result 를 화면에 뿌리는 영역을 작성해줬다.

const [result, setResult] = useState('...')
<div>
  {result}
</div>

jsx 언어는 화면구성하다가 갑자기 '아 잠만잠만 변수 넣을래 나' 하고 묻지도 따지지도 않고 넣을 수 있어서 재밌따. 아무튼 result 를 이렇게 넣어준다.

그다음에는 아래처럼 임시로 작성해놨던 handleSubmit 함수를 수정해줬다.

const handleSubmit = (e) => {
  console.log(animalInput)
}
const handleSubmit = async(e) => {
    e.preventDefault(); // 자동 전송 막아주는 메서드
    try{
       // app\api\generate.js 에 api 가 작성될 예정!
       const response = await fetch('./api/generate', {
        method: 'POST',
        headers: {
          "Content-Type" : "application/json"
        },
        // animalInput 보내기
        body: JSON.stringify({animal: animalInput})
      })
      const data = await response.json(); // http 통신 응답 data 에 저장
      if(response.status !== 200){ // 200 은 http 요청이 성공적으로 되었다는 응답코드이다.
        // status 로 http 요청의 응답코드를 알 수 있따.
        throw data.error
      }
      setResult(data.result);
      setAnimalInput('');
    }
    catch(error){ // try 에서 throw 한 error 를 catch
      console.error(error)
      alert(error.message) // 프롬프트로 error 알려주기
    }
  }

[ 새로 배운 것들 & 원래 알던 내용 복기 ]

  • http 요청의 응답코드를 status 로 바로 접근할 수 있다.
  • 응답코드가 200 인 경우, 성공적이라는 신호이므로 200 이 아니라면 에러처리를 해주는 방법이 있다.
  • try, catch 문법을 복습할 수 있었다. 늘 느끼는데 try, catch, throw 키워드 너무 웃기다. 던지고 받고 마구마구..
	try{
      // 처리하고 싶은 코드
      // 이상한 응답은 던져버리기
    }
	catch(err){
      // try 에서 던져진 친구 err 로 catch 하기
    }

당연히 여기까지만 하면 빈 껍데기였다. 강의를 들으면서 천천히 server side 개발을 따라갔다.

하찮고 귀여운 껍데기..곧 꾸며줄게 미안해

Server-side 개발하기

Server-side 에서는, animalInput을 포함한 요청이 오면 openAI API 를 통해 result 를 만들어야한다.
프로젝트를 처음 생성하면 생기는 generate.js 를 api 폴더 안에 넣어서 기능을 작성했다.

1. 준비물 챙기기

일단 OpenAI 친구를 모셔와야 한다. OpenAI 에 들어가면, 여기서 사용할 product name generator 말고도 다양한 기능의 친구들이 있다.

Examples - OpenAI API

여기로 들어가면 키워드뽑기, Q&A, 텍스트를 컬러로 바꾸기, 등등 신기한 것들이 많이 있으니 꼭꼭 구경하기!
구경하고 있으면 다양한 생각이 마구마구 샘솟는 것 같다. 아직은 생각뿐..

product name generator 를 찾아서 눌러주면 아래와 같은 화면이 나온다.

이거 보고 이름짓기? 이게 동물이름을 지을 수 있나? 했는데 Prompt 에 적혀있는 정보들을 참고해서 response 를 만들어내는 AI 이다. Prompt 에 suggest pet name 이런 식의 명령을 입력해주면 되었다. 각종 실험은 우측 상단 버튼 Open In Playground 를 해보면 알 수 있다.
다 확인했다면 API request 에 나와있는 코드 복사하기 !

그리고 늘 그랬던 것 처럼 API key 를 발급받아야 한다.
가입 후, 우측상단 프로필을 누르면 나오는 드롭다운 메뉴에서 view API Keys 로 들어가면 엄청 쉽게 발급받을 수 있다.

마지막으로 프로젝트에 openai 패키지를 추가해주면 준비물은 다 챙겼다.
(npm i openai 또는 yarn add openai)


2. API key 숨기기

API key 는 매우 중요하고 중요한 암호라고 했다.. 따라서 숨겨야한다.

  • 루트 경로에 .env 파일 생성
  • API key 넣어주기
OPENAI_API_KEY = " 발급받은 키 복사해서 붙여넣기 "
  • dotenv 패키지 설치
    dotenv 는 .env 안의 정보들을 환경변수로 설정해주는 패키지이다.
    .env 안에 API key 를 넣어줬기 때문에, generate 에서 바로 사용할 수 있다.

  • generate.js 에서 불러오기

import * as dotenv from 'dotenv';
dotenv.config({path:__dirname + '../../.env'})
// process.env.OPENAI_API_KEY 로 key 에 접근할 수 있다.

3. API 작성

이제 본격적으로 기능을 구현하는 단계 ! 복사해놓은 API request 샘플 코드를 generate.js 에 붙여넣기 했다.
강의에서는 이 프로젝트에 top_p, frequency_penalty, presence_penalty 는 필요없다구 하셔서 지워줬다.
그리고 원래 엄청 길게 되어있었던 프롬프트를 목적에 맞게 바꿨다 !

const { Configuration, OpenAIApi } = require("openai");

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

const response = await openai.createCompletion({
  model: "text-davinci-003",
  //원래 prompt : "Product description: A home milkshake maker\nSeed words: fast, healthy, compact.\nProduct ..."
  prompt: `suggest three pet names for the follow ${animal}`,
  temperature: 0.8,
  max_tokens: 60
});

근데 여기서, prompt에 들어가는 animal 은 client-side 에서 요청할때 넘겨준 animalInput 이어야 한다.
response 전체를 비동기 처리 함수 안에 다시 넣어주어야 했다 !

export default async function(req, res){ // request, response
  // ...
  const animal = req.body.animal || '';
  try{
    const response = await openai.createCompletion({
      model: "text-davinci-003",
      prompt: `suggest three pet names for the follow ${animal}`,
      temperature: 0.8,
      max_tokens: 60
    });
    res.status(200).json({result : response.data.choices[0].text })  
  }
  catch(error){
    // ...
  }
}

request 에 들어있는 animal 을 저장해주고, openai prompt 에 넣어 명령하는 방식이다.
response 를 openai api 에서 받아와주면 원하는 result 를 보내줄 수 있다 !

[ 새로 배운 것 ]

  • 사전 발생 에러 처리
    위의 코드에서는 생략되어 있지만, try-catch 로 openai 로 가기 전에 일어날 수 있는 에러 처리를 강사님이 많이 해주셨다. animal 문자열 변수를 trim 해서 빈 문자열이라면 error 를 response 한 후 return 해주었고, configuration 의 api key 가 잘못되었다면 마찬가지로 에러처리를 해주었다.

  • api request 과정 에러 처리
    catch문 안에서도 두가지 분기로 에러를 처리했다.
    error.response 라면 openai 안에서 에러가 난 것이고, 그게 아니라면 request 과정에서 에러가 난 것이기 때문에 이 두개를 따로 처리했다.

평소 api 를 가져다가 쓸 때, 이런식으로 에러처리를 꼼꼼하게 안해서 어디서 에러가 나는지 한참 찾았었던 기억이 있다. 이 강의를 들으면서 에러 처리의 중요성을 너무 배웠다 ㅠㅠ 그냥 요청이 성공한다고 해서 다가 아니었다!!


회고

처음에는 재밌는 게 하고싶어서 무작정 시작했는데, 하다보니 정말 많은 것을 배울 수 있었다 !
특히 에러 처리 과정은 다른 프로젝트에도 적용하고 싶을 만큼 깔끔했다. request 를 하기 전 발생할 수 있는 에러들을 방지하는 습관을 들여야겠다.
그리고 개발하면서 개선하고 싶은 부분들이 많이 생겼다.

  1. 한글로 기능하도록 하기
    한글 input 값을 주면 영어 output 이 나온다! 그치만 난 한국인이기 때문에 한글 output이 나오도록 바꾸고 싶다.
  2. CSS 개선하기
    만들면서 개발하고 싶은 기능들이 생겼기 때문에 스타일은 남겨두었다. 기능을 완성하고 나면 스타일도 작성해볼 생각이다.
  3. input을 여러개로 나누기
    막상 pet 을 입력하라고 하니까 생각이 안났다. 사용자 입장에서 어떤 정보를 입력해야할 지 단계적으로 알려주고, 특정 정보만 입력하게 한 후 정보들을 합쳐서 request 를 하면 사용자 경험이 더 좋아질 것 같다.
  4. 꼭 반려동물 이름이어야 하는가?
    prompt 명령을 자유자재로 바꾼 것을 보니, product generator ai 가 할 수 있는 일은 많아보였다. 연구를 좀 더 한 뒤 이 ai 를 최대한으로 이용할 수 있는 주제를 찾으면 좋을 것 같다!
  5. fetch 말고 axios 로도 해보기
    리액트에서 api 통신을 할 때 주로 axios 를 사용했었다. fetch 와 axios 를 비교한 뒤, axios 로도 구현해봐야겠다.

얘네들은 2탄으로 진행할 수 있,,겠,,지 ?

0개의 댓글