생산형 AI 기능을 쓰고 싶은 개발자는 어디에나 있을 것이다. 오늘은 Spring에서 AI를 사용하는 법을 알아보자.
AI 기능을 빌려오는 느낌이고 직접 구현이 아니다. 참고 바란다.
1. 의존성 추가
implementation 'org.springframework.ai:spring-ai-openai-spring-boot-starter:0.8.0-SNAPSHOT'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
maven { url 'https://repo.spring.io/snapshot' }
}
해당 의존성은 Spring Boot 프로젝트에 OpenAI와 연동할 수 있는 기능을 제공한다.
2. OpenAI API 설정
https://platform.openai.com/usage
위 페이지에 들어가서 key를 발급받아야 한다.
API-Key 를 애플리케이션 단에 적용시킬 때 꼭 주의해야 되는 사항이 있다.
API-Key는 특정 사용자가 OpenAI 를 원활하게 사용하기 위해 인증받는 키로써, 절대 퍼블릭으로 유출되어선 안 된다. 예를 들어 깃허브 레포지토리에 공개로 절대 유출시키면 안되는 것이다.
최대한 보안 문제를 위해 본인 로컬에서만 사용하거나, 또는 레포지토리에 소스코드를 올린다면 .git ignore 로 yml 파일을 제외시켜 주자.
+ 추가로 빨간색으로 꽉 차 있는 상태면 쓸 수 없으니 결제를 해야 사용이 가능하다..... 아마 433인가 423인가 에러가 나오면서 진행이 불가할 것이다.
3. 코드 작성
- domain 코드
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Entity
public class GPTResponse {
@Id
@Column(name = "response_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "gpt_question", columnDefinition = "TEXT")
private String gptQuestion;
@Column(name = "gpt_answer", columnDefinition = "TEXT")
private String gptAnswer;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User user;
}
질문과 답변 컬럼을 간단하게 만들었다.
- repository 코드
@Repository
public interface ResponseRepository extends JpaRepository<GPTResponse, Long> {
List<GPTResponse> findAllByUserId(Long userId);
}
- service 코드
@Service
@RequiredArgsConstructor
public class GPTService {
private final ChatClient chatClient;
private final ResponseRepository responseRepository;
private final UserRepository userRepository;
private ChatResponse callChat(String question) {
return chatClient.call(
new Prompt(
(question + "위 아래 문단의 잡설은 하지 말고, 짧은 분량의 내용을 보여줘"),
OpenAiChatOptions.builder()
.withTemperature(0.4F)
.withFrequencyPenalty(0.7F)
.withModel("gpt-3.5-turbo")
.build()
));
}
//request answer to openai.
public AiResDto getAnswer(Long userId, AiReqDto aiReqDto) {
User user = userRepository.findById(userId).orElseThrow();
ChatResponse response = callChat(aiReqDto.getQuestion());
if (response == null) {
response = callChat(aiReqDto.getQuestion());
}
GPTResponse gptResponse = GPTResponse.builder()
.user(user)
.gptQuestion(aiReqDto.getQuestion())
.gptAnswer(response.getResult().getOutput().getContent())
.build();
responseRepository.save(gptResponse);
return AiResDto.builder()
.question(aiReqDto.getQuestion())
.answer(response.getResult().getOutput().getContent()).build();
}
@Transactional(readOnly = true)
public List<AiResDto> provideResponseList(Long userId) {
try {
List<GPTResponse> gptResponses = responseRepository.findAllByUserId(userId);
List<AiResDto> aiResDtoList = new ArrayList<>();
for (GPTResponse gptResponse : gptResponses) {
aiResDtoList.add(AiResDto.builder()
.question(gptResponse.getGptQuestion())
.answer(gptResponse.getGptAnswer())
.build());
}
return aiResDtoList;
} catch (Exception e) {
throw new IllegalArgumentException("Not Found Response Data In Database.");
}
}
}
처음부터 천천히 읽어보면 어떻게 돌아가는지 대충 알 것이다.
간단하게 말하자면 callChat으로 질문에 대한 답을 받고, getAnswer로 반환Dto에 넣어주고, provideResponseList로 반환 값들을 보여주는 것이다.
- dto
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class AiReqDto {
private String question;
}
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class AiResDto {
private String question;
private String answer;
}
정말 간단하지 않나??????
'springboot' 카테고리의 다른 글
[SpringBoot] IoC/DI 가 뭘까? (0) | 2024.08.28 |
---|---|
[SpringBoot] orElse와 orElseGet 차이점 (0) | 2024.08.10 |
[SpringBoot] KOMORON을 이용해서 형태소 분석하기 (0) | 2024.03.23 |
[SpringBoot] 인텔리제이 안에서 데이터베이스 접근하기 (0) | 2024.03.23 |
[SpringBoot] Swagger 간편 어노테이션 정리 (0) | 2024.03.21 |