원래 디자인 먼저 하고 기능을 만드는데 GPT API를 사용해야해서 일단 기능 구현부터 해보고 디자인을 하겠다.
기능 기획은 간단하다. 내가 원하는 언어(JS, Java, Python)을 선택하고, 어떤 변수를 생성할 지 관련 주제를 인풋창에 입력하고, 제출 버튼을 클릭하면 응답데이터를 표출하는, 아주 간단한 앱이다.
또한 기능 하나를 추가하고 싶은데 질문했던 데이터에 맘에 들지 않는다면 '더 생성하기'라는 버튼을 추가해서 그 다음 데이터를 가져오고싶다.
22/02/20
GPT가 생각보다 한글을 잘 못알아듣고, 반응도 영어보다 늦기에 네이버 파파고 API를 가져와서 번역 후 API에게 전송하게 만드는 기능을 추가할 것이다. 한글 사랑해줘..
이번에 Next.js를 써보고 싶어 Next.js를 써보기로 했다.
Next.js를 쓰는 이유가 있다.
즉, SEO를 잘 가진 SPA 앱을 만들 수 있다는 말이다. 여기서 의문이 생긴다. 엥? 한개의 페이지만 가진 앱이지 않느냐? 굳이 Next.js를 써서 얻는 이점이 별로 없지 않느냐. 리액트 하나로 SPA 만들어도 된다라고 생각이 든다.
근데 왜 Next.js로 만들까? 뭐.. 그 이유는 그냥 해보고 싶기도 하고 배우고 싶어서 그렇다.
그래서 간단한 프로젝트지만 써보고 싶었다. 거기에 Varcel도 바로 쓸 수 있으니 얼마나 편할까. 그래서 써보기로 했다! 화이팅! 공식문서 엄청 팔 생각이다.
npx create-next-app --typescript
치고 앱 이름, src/, app/ 등등 디렉토리 설정
npm install next react react-dom
이러면 Next.js 사용 준비 끝!
되게 쉽다. 당연히 회원가입은 필수겠지?
Preset
을 선택해 자신이 구현하고싶은 기능 찾기View Code
버튼을 선택해 자신이 고른 것들 가져오기간단하지 않는가? 실제로 해보자.
나는 다빈치-3, 생성 토큰의 맥시멈을 100으로 했다. preset
은 'Text to command'로 했다.
'Create 10 list-related variables in the React environment'라고 질문을 던졌을때 저렇게 나온다. 내가 원한 결과물이 아니다. 다른 질문을 해보자
뭔가 내 맘에 쏙 들진 않지만 저 형태로 질문의 원형을 만들어야겠다.
이제 view code를 눌러 복사해 가져오자.
api/chatai.ts 디렉토리를 만들어 구현
import axios from "axios";
interface ChatResponseData {
resText: string;
resId: string;
}
export const getChatResponse = async (prompt: string): Promise<ChatResponseData> => {
const response = await axios.post(
"https://api.openai.com/v1/completions",
{
model: "text-davinci-003",
prompt,
temperature: 0.9,
max_tokens: 100,
top_p: 1,
frequency_penalty: 0,
presence_penalty: 0.6,
stop: [" Human:", " AI:"],
},
{
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.NEXT_PUBLIC_OPEN_API}`,
},
}
);
const resText = response.data.choices[0].text;
const resId = response.data.id;
return { resText, resId };
};
prompt
를 파라미터로 받기resText
, 나중에 map으로 돌릴 수 있어서 resId
추출index.tsx에 가져온 반환값을 렌더링하자!
import Head from "next/head";
import { getChatResponse } from "./api/chatai";
import { QueryClient, QueryClientProvider, useQuery } from "react-query";
interface ChatResponseProps {
prompt: string;
}
export default function Home() {
const queryClient = new QueryClient();
const ChatResponse = ({ prompt }: ChatResponseProps) => {
const { data } = useQuery(["chatResponse", prompt], () => getChatResponse(prompt));
console.log(data);
return <div>{data?.resText}</div>;
};
return (
<QueryClientProvider client={queryClient}>
<Head>
<title>Vargen</title>
<meta name="description" content="변수 생성 앱" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" href="/favicon.ico" />
</Head>
<ChatResponse prompt={`Create 10 login related variable names with React`} />
</QueryClientProvider>
);
}
특이점은 리액트쿼리를 사용한 점이다. 사용한 이유는 api 통신 데이터와 응답 받은 후 리스트를 클라이언트 상태에 분리하기 위함과 그리고 학습해보고 싶어 사용했다.
QueryClient
, QueryClientProvider
로 리액트쿼리 기초 세팅getChatResponse
를 가져와 useQuery
를 사용해 data
를 추출한다.data
는 객체이므로 resText
를 추출하여 리턴한다.prompt
를 파라미터로 받는 ChatResponse
를 입력한다.이렇게 나온다! 다음에는 이 데이터를 가지고 입력폼을 만들어 입력값으로 요청하는 식으로 정보를 받아오겠다.
진전이 있었군요! 정말 기대되는 프로젝트입니다! 리액트 쿼리와 타입스크립트의 조합이라니, useQuery 부분 너무 똑같아서 깜짝 놀랐습니다!