20230705
며칠동안 바빠서 chat gpt 프로젝트를 진행 못했다가 진행하려니 자꾸 에러 메세지가 날아왔다.
cors 문제 해결과정을 포스팅하려고 했는데, cors 문제 해결한 다음에도 계속 에러가 나오길래 뭐지 했는데, chat gpt api 무료 사용기간이 초과돼서 그런거였다....
그냥 재미로 하는 side project에 돈을 쓰고싶지는 않은데 ...
무료 credit도 얼마 써보지도 못하고 끝나버렸다... 빨리빨리 할 걸 ....
나중에 여유가되면 유료 결제하고 한 번 해봐야겠다.
ChatGPT 채팅을 웹으로 배포해보자.
프론트엔드 구성
vite를 사용해서 프로젝트 빌드를 구성하고, 질문을 받을 수 있는 인풋 제어 컴포넌트를 만들었다.
import { useState } from "react";
function App() {
const [question, setQuestion] = useState<string>("");
return (
<>
<div>
<div>
<label>Question </label>
<input
type="text"
onChange={(e) => {
setQuestion(e.target.value);
}}
/>
</div>
<button>질문하기</button>
</div>
</>
);
}
export default App;
그 다음 질문하기 버튼을 눌렀을 때 질문 요청에 대한 응답을 받을 수 있도록 해보자.
import { useState } from "react";
function App() {
const [question, setQuestion] = useState<string>("");
const fetchAnswer = async () => {
try {
const res = await fetch("http://localhost:4000/question", {
method: "GET",
});
setQuestion(res.data);
} catch (error) {
console.log(error);
}
};
const handleQuestionButton = () => {
fetchAnswer();
};
return (
<>
<div>
<div>
<label>Question </label>
<input
type="text"
onChange={(e) => {
setQuestion(e.target.value);
}}
/>
</div>
<button onClick={handleQuestionButton}>질문하기</button>
</div>
</>
);
}
export default App;
백엔드 구성
nodejs를 이용한 간단한 api 서버를 만들어보자.
- 작업 폴더 생성(backend)
- npm init
- lint, formmater 설정
- typescript 설정
간략한 순서만 나열했고, 자세한 설치법은 다른 블로그나 구글링을 참고해주세요.
import * as http from "http";
const server = http.createServer((request, response) => {
const { headers, method, url } = request;
request.on("error", (error) => {
console.log(error);
});
response.statusCode = 200;
response.end(() => {
console.log("Hello World");
});
});
const PORT = 4000;
server.listen(PORT, () => {
console.log(`The server is listening at ${PORT}.`);
});
위와 같이 간단하게 nodejs를 이용한 서버를 구동시킬 수 있다.
앞에서 프론트엔드에서 api서버에 question path로 get 요청을 했으니 그에 대한 응답을 한 번 보내보자.
import * as http from "http";
const server = http.createServer((request, response) => {
const { headers, method, url } = request;
if (url === "/question" && method === "GET") {
response.end("answer is xxxx");
}
request.on("error", (error) => {
console.log(error);
});
response.statusCode = 200;
response.end();
});
const PORT = 4000;
server.listen(PORT, () => {
console.log(`The server is listening at ${PORT}.`);
});
request의 메소드인 url을 이용하여 어떤 path로 요청이 왔는지 확인하고, method를 이용하여 어떤 방법으로 요청이 왔는지 확인 할 수 있다.
위와 같이 4000포트에 서버를 켜둔 후 curl로 question path로 요청해보면 아래와 같다.
잘 작동하는 것 같다. 그런데 xxxx뒤에 %는 뭘까, 예전에 minishell을 만들면서 겪었던 현상이었던거같은데 뭐였지 .. 개행관련인가..
body parsing
express나 다른 프래임워크 없이 서버를 구현할 때 힘든점은 쌩으로 다해야된다는 것이다...
프론트에서 보낸 question의 값을 body에 넣어서 백에 post 요청을 했을때 nodejs 환경에서는 request.on 메서드를 사용해야 한다.
import * as http from "http";
import { chat } from "./chat";
const server = http.createServer((request, response) => {
const { headers, method, url } = request;
if (url === "/question" && method === "POST") {
request.on("data", (data) => console.log(data));
response.end("question");
}
request.on("error", (error) => {
console.log(error);
});
response.statusCode = 200;
response.end();
});
const PORT = 4000;
server.listen(PORT, () => {
console.log(`The server is listening at ${PORT}.`);
});
위와 같이 코드를 작성 후 curl로 확인해보면 buffer에 담겨있는 모습을 확인할 수 있다.
이를 해결하는 방법은 request의 인코딩을 utf-8로 설정해주면 된다.
...
if (url === "/question" && method === "POST") {
request.setEncoding("utf-8");
request.on("data", (data) => console.log(data));
response.end("question");
}
...
chat gpt에게 질문하기
저번 포스트에서 진행했던 chat gpt api를 이용해서 "안녕?"에 대한 질문을 받아보자.
// chat.ts
export const chat = async (question: string) => {
return await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
// Authorization: `Bearer ${process.env.OPEN_API_KEY}`,
Authorization: `Bearer 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`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "gpt-3.5-turbo",
messages: [{ role: "user", content: question }],
}),
})
.then((res) => res.json())
.then((data) => data.choices[0].message.content);
};
import * as http from "http";
import { chat } from "./chat";
const server = http.createServer((request, response) => {
const { headers, method, url } = request;
if (url === "/question" && method === "POST") {
request.setEncoding("utf-8");
request.on("data", async (data) => {
const body: { question: string } = JSON.parse(data);
const answer = await chat(body.question);
console.log(answer);
});
response.end("question");
}
request.on("error", (error) => {
console.log(error);
});
response.statusCode = 200;
response.end();
});
const PORT = 4000;
server.listen(PORT, () => {
console.log(`The server is listening at ${PORT}.`);
});
"안녕?"에 대한 질문이 잘 돌아오는 것을 확인할 수 있다.
다음 포스트에서 받아온 데이터를 프론트로 보내주어 답변을 표시해주는 기능을 만들자.