20240516_ChatGPT 질문 만들기 + MSA 통합(1)
GPT에 어떻게 데이터를 대입할지 생각했는데
일정 양식을 부여하고, 그 안에 데이터를 넣어주기로 했다.
넣을 때 들어가는 데이터량을 줄여 소모되는 토큰을 줄이기 위해 DTO를 새로 구성했다.
GPT용 날씨 DTO
package org.weather;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serializable;
@Data
public class WQ implements Serializable {
@NotNull
String category;
@NotNull
String fcstValue;
}
GPT용 미세먼지 DTO
package org.weather;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import lombok.Value;
import java.io.Serializable;
/**
* DTO for {@link Paticulatemattervo}
*/
@Data
public class PQ implements Serializable {
@Size(max = 50)
String pm25grade;
@Size(max = 50)
String pm25value;
@Size(max = 50)
String pm10grade;
@Size(max = 50)
String pm10value;
}
GPT용 옷 데이터
package org.member;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Data;
import java.io.Serializable;
/**
* DTO for {@link ClothVO}
*/
@Data
public class CQ implements Serializable {
@Size(max = 50)
@NotBlank(message = "카테고리가 지정되어야 합니다.")
String category;
@Size(max = 100)
@NotBlank(message = "옷이 입력되어야 합니다.")
String clothdata;
}
예시 데이터
question = "1.\t오늘의 날씨를 보고 입을 옷을 옷 데이터 중에서 골라줘. 반드시 항목 중에서 골라야 해. \n" +
"모자, 겉옷, 상의, 하의, 양말, 신발이 서로 조화가 잘 되도록 골라줘.\n" +
"모자, 겉옷은 필요하면 안 입을 수 있어,\n" +
"하지만 상의, 하의, 양말, 신발은 반드시 골라야 해\n" +
"2.\t미세먼지 상태를 보고 마스크 착용 여부도 알려줘\n" +
"3.\t답변은 목록 형태로 액셀에 입력하기 좋은 목록 형태로 출력해줘\n" +
"ex) 모자 OO/없음 // 겉옷 OO//없음 // 상의 OO // 하의 OO // 양말 OO // 신발 OO // 마스크 착용 권장/필수/없음\n" +
"\n" +
"오늘의 날씨\n" +
"[WQ(category=1시간 기온, fcstValue=18℃), WQ(category=풍속(동서성분), fcstValue=4.7m/s), WQ(category=풍속(남북성분), fcstValue=-1.8m/s), WQ(category=풍향, fcstValue=WNW), WQ(category=풍속, fcstValue=5.1m/s), WQ(category=하늘상태, fcstValue=맑음), WQ(category=강수형태, fcstValue=강수없음), WQ(category=강수확률, fcstValue=0%), WQ(category=파고, fcstValue=0M), WQ(category=1시간 강수량, fcstValue=강수없음)]\n" +
"\n" +
"오늘의 미세먼지\n" +
"PQ(pm25grade=좋음, pm25value=9, pm10grade=점검 중, pm10value=25)\n" +
"옷 데이터\n" +
"[ClothDTO(id=14, userid=null, category=모자, clothdata=다채로운 블랙 볼캡), ClothDTO(id=15, userid=null, category=모자, clothdata=그레이 시크한 털 모피 장식 비니), ClothDTO(id=16, userid=null, category=모자, clothdata=베레모 레드 클래식한), ClothDTO(id=17, userid=null, category=모자, clothdata=네이비 우아한 플랫 브림 페도라), ClothDTO(id=18, userid=null, category=모자, clothdata=카모플라지 캐주얼한 가죽 스트랩 헌팅캡), ClothDTO(id=19, userid=null, category=상의, clothdata=화이트 심플한 캐주얼한 티셔츠), ClothDTO(id=20, userid=null, category=상의, clothdata=라이트 블루 포멀한 셔츠), ClothDTO(id=21, userid=null, category=상의, clothdata=그린 편안한 스웨터), ClothDTO(id=22, userid=null, category=상의, clothdata=후드티 고급스러운 핑크), ClothDTO(id=23, userid=null, category=상의, clothdata=블라우스 핑크 정장용), ClothDTO(id=30, userid=null, category=하의, clothdata=진청 데일리한 청바지), ClothDTO(id=31, userid=null, category=하의, clothdata=카키 클래식한 슬랙스), ClothDTO(id=32, userid=null, category=하의, clothdata=그레이 스포티한 조거 팬츠), ClothDTO(id=33, userid=null, category=하의, clothdata=블랙 유니크한 레깅스), ClothDTO(id=34, userid=null, category=하의, clothdata=네이비 캐주얼한 반바지), ClothDTO(id=35, userid=null, category=겉옷, clothdata=블랙 편안한 자켓), ClothDTO(id=36, userid=null, category=겉옷, clothdata=카멜 우아한 코트), ClothDTO(id=37, userid=null, category=겉옷, clothdata=네이비 클래식한 야상), ClothDTO(id=38, userid=null, category=겉옷, clothdata=다크 그린 따뜻한 패딩), ClothDTO(id=39, userid=null, category=겉옷, clothdata=베이지 스타일리시한 트렌치코트), ClothDTO(id=40, userid=null, category=양말, clothdata=화이트 베이직한 스니커즈 양말), ClothDTO(id=41, userid=null, category=양말, clothdata=블랙 심플한 드레스 양말), ClothDTO(id=42, userid=null, category=양말, clothdata=그레이 스포티한 스포츠 양말), ClothDTO(id=43, userid=null, category=양말, clothdata=파스텔 핑크 세련된 앵클 양말), ClothDTO(id=44, userid=null, category=양말, clothdata=스트라이프 유용한 무릎 양말), ClothDTO(id=46, userid=null, category=신발, clothdata=화이트 심플한 캔버스 스니커즈), ClothDTO(id=47, userid=null, category=신발, clothdata=브라운 클래식한 레더 구두), ClothDTO(id=48, userid=null, category=신발, clothdata=블랙 편안한 스웨이드 부츠), ClothDTO(id=49, userid=null, category=신발, clothdata=네이비 시크한 캔버스 플랫슈즈), ClothDTO(id=50, userid=null, category=신발, clothdata=골드 여성스러운 스트랩 샌들)]\n";
application.properties 개선하기(중복 코드 줄이기)
기존 application.properties(msa-gpt)
spring.application.name=gpt
server.port=9003
spring.datasource.url=jdbc:postgresql://localhost:5432/msatestdb
spring.datasource.username=msatestid
spring.datasource.password=msaTestPW
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
spring.mvc.static-path-pattern=/resources/**
openai.secret-key=**
개선 후
spring.application.name=gpt
server.port=9003
openai.secret-key=**
중복되는 코드를 모아둔 application-dev.properties
spring.application.name=core
spring.datasource.url=jdbc:postgresql://localhost:5432/msatestdb
spring.datasource.username=msatestid
spring.datasource.password=msaTestPW
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.properties.hibernate.use_sql_comments=true
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
spring.mvc.static-path-pattern=/resources/**
SpringBootApplication에서
System.setProperty("spring.config.name", "application,application-dev"); 추가
package org.gpt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class gptMain {
public static void main(String[] args) {
System.setProperty("spring.config.name", "application,application-dev");
SpringApplication.run(gptMain.class, args);
}
}
멀티모듈에서 core모듈의 패키지 사용하기
- Application 클래스의 위치한 곳의 패키지가 공통으로 맞춰져 있지 않은 경우
SpringBootApplication에서 scanBasePackages 세팅
SpringBootApplication (scanBasePackages = {"org.weather", "org.core"})
package org.weather;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = {"org.weather", "org.core"})
public class WeatherMain {
public static void main(String[] args) {
System.setProperty("spring.config.name", "application,application-dev");
SpringApplication.run(WeatherMain.class, args);
}
}
--> weather 모듈에서 core 모듈의 패키지 사용 가능해짐
멀티모듈에서 core모듈의 패키지 사용하기(2)
- Application 클래스의 위치한 곳의 패키지가 공통으로 맞춰져 있으면 사용 가능하다고 한다.
RestFul Api 통신
솔직히 이게 맞는지 모르겠다...개선이 필요하다
js코드
function viewTodayDust(){
const country = $("#country").val();
const area = $("#area").val();
const response_dustData = $("#response_dustData")
$.ajax({
type: "post",
url: weatherModuleURL + "/viewTodayDust",
data: {
country: country,
area: area
},
datatype: "json",
success: function(response){
let table = "<table><thead><tr><th>측정 시간</th><th>초미세먼지 상태</th><th>초미세먼지 수치</th><th>미세먼지 상태</th><th>미세먼지 수치</th></tr></thead><tbody>";
table += "<tr>";
table += "<td>" + response.datatime.substring(11, 16) + "</td>";
table += "<td>" + response.pm25grade + "</td>";
table += "<td>" + response.pm25value + "</td>";
table += "<td>" + response.pm10grade + "</td>";
table += "<td>" + response.pm10value + "</td>";
table += "</tr>";
table += "</tbody></table>";
response_dustData.html(table);
},
error: function(){
console.log("미세먼지 데이터 ajax 에러")
}
})
}
다른 모듈의 Controller
@CrossOrigin(origins = "http://localhost:9001")
@ResponseBody
@PostMapping("/viewTodayDust")
public PaticulatemattervoDto viewTodayDust(String country, String area){
PlaceDto placeDto = placeService.findByCountryAndArea(country, area);
return dustApiService.findByStationname(placeDto);
}
const weatherModuleURL = "http://localhost:9002";
로컬 호스트 포트 번호 지정
@CrossOrigin(origins = "http://localhost:9001")
CORS 정책 위반 해결
함께 읽으면 좋은 글
출력
개선점
1. GPT 답변을 매일 6시간 간격으로 생성
이후 정보 불러 올 때 최신 답변을 DB에서 불러옴
2. Kafka를 사용하여 모듈 간 통신(메시징 시스템 활용)
3. 공통 configuration 사용
4. RestFul Api 통신 개선
멀티 모듈 기본 맥락
https://techblog.woowahan.com/2637/
멀티 단계별 설계
https://velog.io/@devty/MSA-Phase-1.-Springboot2
멀티 모듈 설정
https://jojoldu.tistory.com/123
application.properties 설정
https://devlog-wjdrbs96.tistory.com/435