[Spring/WebSocket] 웹소켓을 활용한 GPT AI 챗봇 만들기

·2025년 6월 22일

Spring

목록 보기
23/26

이전 포스트들과 이어집니다
1. [Spring/WebSocket] 순수 WebSocket으로 채팅방 만들기
2. [Spring/WebSocket] WebSocket + STOMP으로 귓속말 가능한 채팅방 만들기
3. [Spring/WebSocket] WebSocket + STOMP + DOCKER 실습 : 여러 서버 띄우기
4. [Spring/WebSocket] 웹소켓을 활용한 GPT AI 챗봇 만들기

💡웹소켓을 활용한 GPT AI 챗봇 만들기

🔍챗봇 구조

❓브라우저와 GPT 사이에 웹소켓이 중간에 끼는 이유

  • 브라우저에서 바로 GPT에 직접 보내게 되면 클라이언트에 API 키가 노출되며, 로깅과 제어가 불가하다.
  • 중간에 웹소켓이 끼게 되면 API 키 노출을 방지할 수 있고, 실시간 응답이 가능하다.

✅지피티 API 키 테스트

1. https://platform.openai.com/에서 API 키 생성

2. 테스트 형식 확인

curl https://api.openai.com/v1/responses \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $OPENAI_API_KEY" \
    -d '{
        "model": "gpt-4.1",
        "input": "Write a one-sentence bedtime story about a unicorn."
    }'
  • $OPENAI_API_KEY 에 본인의 api 키를 넣어주면 된다.

3. PostMan에서 작성

  • Authorization은 위에서 발급받은 api키를 넣어주면 된다. api 키 앞에 Bearer를 붙여주어야된다.

    -Body에는 gpt 모델과 질문을 써주면 된다.

4. 결과 확인

✅localhost:8080으로 AI봇 만들기

1. stompwebsocket 패키지 하위에 gpt 패키지 추가 후 GPTService.java 작성

@Service
public class GPTService {
    //json 문자열 <-> 자바객체, json 객체
    private final ObjectMapper mapper = new ObjectMapper();

    //@Value("${openai.api-key}")
    private String openaiApiKey;

    public String getMessage(String message) throws Exception {
        try {
            //API 호출을 위한 본문 작성
            Map<String, Object> requestBody = new HashMap<>();
            requestBody.put("model", "gpt-4o");
            requestBody.put("input", message);

            //http 요청 작성
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://api.openai.com/v1/responses"))
                    .header("Authorization", "Bearer {API키}")
                    .header("Content-Type", "application/json")
                    .POST(HttpRequest.BodyPublishers.ofString(mapper.writeValueAsString(requestBody)))  //본문 삽입
                    .build();

            //요청 전송 및 응답
            HttpClient client = HttpClient.newHttpClient();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            //응답을 JSON으로 파싱
            JsonNode jsonNode = mapper.readTree(response.body());
            System.out.println("get 응답 : " + jsonNode);

            //메시지 부분만 추출하여 반환(응답형태가 Json인데 json문자열 복잡함 -> 거기서 지피티의 대답만 추출)
            String gptMessageResponse = jsonNode.get("output").get(0).get("content").get(0).get("text").asText();
            return gptMessageResponse;
            
            //응답이 오지않으면 예외처리
        } catch (Exception e) {
            return "❗문제가 발생했습니다. 다시 시도해주세요.";
        }
    }
}

2. ChatController 수정

//환경 변수를 받아서 화면에 출력
    @Value("${PROJECT_NAME:web Server}")
    private String instansName;
    private final RedisPublisher redisPublisher;
    private ObjectMapper objectMapper  = new ObjectMapper();

    private final GPTService gptService;

     //단일 브로드 캐스트(방 동적 생성 불가)
    @MessageMapping("/gpt")
    public void sendMessageGPT(ChatMessage message) throws Exception{

        template.convertAndSend("/topic/gpt",message);//내가 보낸 메시지 출력

        //사용자가 보낸 메시지를 받음. gpt 목적지 반환
        String getResponse = gptService.getMessage(message.getMessage());

        ChatMessage chatMessage = new ChatMessage("난 GPT ", getResponse);

        template.convertAndSend("/topic/gpt", chatMessage);
  }

3. ChatMessage 생성자 추가

 public ChatMessage(String message, String from) {
       this.from =from;
       this.message = message;
   }

4. WebSocketConfig 수정

 public void registerStompEndpoints(StompEndpointRegistry registry) {
        //채팅방 엔드포인트
        registry.addEndpoint("/ws-chat")
                .setHandshakeHandler(new CustomHandshakeHandler()) //귓속말 가능하게 해줌
                .setAllowedOriginPatterns("*");

        //지피티 엔드포인트
        registry.addEndpoint("/ws-gpt")
                .setAllowedOriginPatterns("*");
    }

5. index.html, gpt.html 추가

6. 도커 컨테이너에서 redis, database 키기

  • docer compose up -d database reids

7. localhost:8080 에서 확인


✅localhost로 AI봇 만들기

nginx.conf 수정

worker_processes 1;

events {
    worker_connections 1024;
}

http {
    upstream spring_backend {
        server backend1:8080;
        server backend2:8080;
        server backend3:8080;
    }

    server {
        listen 80;

        location / {
            proxy_pass http://spring_backend;
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /ws-chat {
            proxy_pass http://spring_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }

        location /ws-gpt {
                    proxy_pass http://spring_backend;
                    proxy_http_version 1.1;
                    proxy_set_header Upgrade $http_upgrade;
                    proxy_set_header Connection "Upgrade";
                    proxy_set_header Host $host;
                    proxy_set_header X-Real-IP $remote_addr;
                    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                }

    }
}

2. bootjar -> docker build -t backend . -> docker compose up -d

3. localhost에서 확인

profile
배우고 기록하며 성장하는 백엔드 개발자입니다!

0개의 댓글