Skip to content

Commit

Permalink
feat: 스케줄 응답 프롬프트 작성
Browse files Browse the repository at this point in the history
  • Loading branch information
ez23re committed Oct 24, 2024
1 parent 971b8c9 commit b79c9f7
Show file tree
Hide file tree
Showing 8 changed files with 131 additions and 34 deletions.
9 changes: 0 additions & 9 deletions src/main/java/com/splanet/splanet/gpt/ChatResponse.java

This file was deleted.

8 changes: 0 additions & 8 deletions src/main/java/com/splanet/splanet/gpt/Choice.java

This file was deleted.

9 changes: 4 additions & 5 deletions src/main/java/com/splanet/splanet/gpt/Message.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.splanet.splanet.gpt;

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
public class Message {
@AllArgsConstructor
class Message {
private String role; // 메시지의 역할 (user, assistant 등)
private String content; // 메시지 내용

public Message(String content) {
this.content = content;
}
}
36 changes: 24 additions & 12 deletions src/main/java/com/splanet/splanet/gpt/OpenAiChatClient.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.splanet.splanet.gpt;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;
Expand All @@ -11,35 +13,45 @@ public class OpenAiChatClient {

private final WebClient webClient;
private final OpenAiProperties openAiProperties;
private final SchedulePromptGenerator promptGenerator;

public OpenAiChatClient(WebClient.Builder webClientBuilder, OpenAiProperties openAiProperties) {
public OpenAiChatClient(WebClient.Builder webClientBuilder, OpenAiProperties openAiProperties, SchedulePromptGenerator promptGenerator) {
this.webClient = webClientBuilder.baseUrl("https://api.openai.com/v1").build();
this.openAiProperties = openAiProperties;
this.promptGenerator = new SchedulePromptGenerator();
}

public String call(String message) {
Message userMessage = new Message(message);
Prompt prompt = new Prompt(List.of(userMessage));
// 스케줄 생성 요청 처리 메소드
public ScheduleResponse createSchedule(ScheduleRequest scheduleRequest) throws JsonProcessingException {
String jsonResponse = call(scheduleRequest);
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(jsonResponse, ScheduleResponse.class);
}

private String call(ScheduleRequest scheduleRequest) throws JsonProcessingException {
String jsonRequest = new ObjectMapper().writeValueAsString(new RequestBody("gpt-4o-mini", List.of(
new Message("user", promptGenerator.generateSchedulePrompt(scheduleRequest))
)));

ChatResponse response = webClient.post()
// OpenAI API 호출
String responseJson = webClient.post()
.uri("/chat/completions")
.header("Authorization", "Bearer " + openAiProperties.getApiKey())
.bodyValue(prompt)
.bodyValue(jsonRequest)
.retrieve()
.bodyToMono(ChatResponse.class)
.bodyToMono(String.class)
.block();

return response != null && response.getChoices() != null && !response.getChoices().isEmpty()
? response.getChoices().get(0).getMessage().getContent()
: "No response";
return responseJson;
}

public Flux<ChatResponse> stream(Prompt prompt) {
// 스트리밍 메소드
public Flux<ScheduleResponse> stream(Prompt prompt) {
return webClient.post()
.uri("/chat/completions")
.header("Authorization", "Bearer " + openAiProperties.getApiKey())
.bodyValue(prompt)
.retrieve()
.bodyToFlux(ChatResponse.class);
.bodyToFlux(ScheduleResponse.class);
}
}
13 changes: 13 additions & 0 deletions src/main/java/com/splanet/splanet/gpt/RequestBody.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.splanet.splanet.gpt;

import lombok.AllArgsConstructor;
import lombok.Getter;

import java.util.List;

@Getter
@AllArgsConstructor
public class RequestBody {
private String model; // 모델 이름
private List<Message> messages; // 메시지 리스트
}
38 changes: 38 additions & 0 deletions src/main/java/com/splanet/splanet/gpt/SchedulePromptGenerator.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.splanet.splanet.gpt;

import org.springframework.stereotype.Component;

@Component
public class SchedulePromptGenerator {

public String generateSchedulePrompt(ScheduleRequest request) {
StringBuilder prompt = new StringBuilder();

prompt.append("splanet은 사용자가 입력한 스케줄 정보에 맞춰 맞춤형 플래너를 제공하는 서비스입니다. 사용자가 음성으로 입력한 정보를 분석하여 최적의 스케줄을 제시해야 합니다.\n\n")
.append("사용자가 다음과 같은 정보를 입력했습니다. 이 정보를 바탕으로 3개의 서로 다른 스케줄을 추천해 주세요. 각 스케줄은 고유한 컨셉을 가져야 하며, 하루 24시간을 30분 단위로 쪼개고, 각 업무의 시작 시간과 종료 시간을 포함해야 합니다.\n\n")
.append("요청 정보:\n")
.append("- 스케줄 기간: \"").append(request.getSchedulePeriod()).append("\"\n")
.append("- 업무 목록: ").append(request.getTaskList()).append("\n")
.append("- 업무 소요 시간: ").append(request.getTaskDurations()).append("\n")
.append("- 우선순위: ").append(request.getPriority()).append("\n")
.append("- 스케줄 컨셉: \"").append(request.getScheduleConcepts().get(0)).append("\", \"")
.append(request.getScheduleConcepts().get(1)).append("\", \"")
.append(request.getScheduleConcepts().get(2)).append("\"\n") // 각 컨셉을 따로 넣도록
.append("- 하루를 30분 단위로 쪼갠 시간 목록: ").append(request.getTimeSlots()).append("\n")
.append("위 정보를 바탕으로 최적의 플래너 스케줄을 추천할 때 다음 사항을 준수해주세요:\n")
.append("1. 요청된 모든 일정을 사용해야 합니다.\n")
.append("2. 각 스케줄은 고유한 컨셉을 가져야 하며, 3개의 서로 다른 스케줄을 추천합니다.\n")
.append("3. 추천 예시: 사용자가 선택할 수 있도록 3개의 추천 스케줄을 제공합니다.\n")
.append("4. 응답 형식: 답변은 JSON 형식으로만 제공해야 하며, 다음과 같은 구조를 따라야 합니다:\n")
.append(" { \"schedules\": [{ \"concept\": \"스케줄 컨셉\", \"schedule\": [{ \"date\": \"MM-DD\", \"tasks\": [{ \"task\": \"업무명\", \"duration\": \"소요시간\", \"priority\": \"우선순위\", \"startTime\": \"시작시간\", \"endTime\": \"종료시간\" }] }] }] }] }\n")
.append("5. 형식 규칙:\n")
.append(" - 날짜는 MM-DD 형식으로, 시간은 24시간(30분 단위) 형식이어야 합니다.\n")
.append(" - 입력받은 업무를 지정된 일정 안에 모두 포함시켜야 합니다.\n")
.append(" - 우선순위는 고유한 정수 값이어야 합니다.\n")
.append(" - 업무 시간은 주어진 스케줄 기간 안에만 분할하여 채울 수 있습니다.\n")
.append(" - 입력받은 날짜 각각의 일정을 구현해야 합니다.\n")
.append("6. 제외할 내용: 일정 JSON 외에는 다른 내용이 포함되지 않아야 하며, 스케줄링과 관련 없는 질문에는 \"이와 관련된 질문에는 답변할 수 없습니다.\"라고 응답해야 합니다.\n");

return prompt.toString();
}
}
19 changes: 19 additions & 0 deletions src/main/java/com/splanet/splanet/gpt/ScheduleRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.splanet.splanet.gpt;

import lombok.*;

import java.util.List;
import java.util.Map;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class ScheduleRequest {
private String schedulePeriod; // 스케줄 기간
private List<String> taskList; // 업무 목록
private Map<String, String> taskDurations; // 업무 소요 시간 (업무명: 소요시간)
private Map<String, Integer> priority; // 업무 우선순위 (업무명: 우선순위)
private List<String> scheduleConcepts; // 스케줄 컨셉 목록
private List<String> timeSlots; // 30분 단위 시간 목록
}
33 changes: 33 additions & 0 deletions src/main/java/com/splanet/splanet/gpt/ScheduleResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.splanet.splanet.gpt;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.util.List;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class ScheduleResponse {
private List<Schedule> schedules; // 스케줄 리스트

@Getter
@AllArgsConstructor
@NoArgsConstructor
public static class Schedule {
private String concept; // 스케줄 컨셉
private List<Task> tasks; // 업무 리스트

@Getter
@AllArgsConstructor
@NoArgsConstructor
public static class Task {
private String task; // 업무명
private String duration; // 소요 시간
private int priority; // 우선순위
private String startTime; // 시작 시간
private String endTime; // 종료 시간
}
}
}

0 comments on commit b79c9f7

Please sign in to comment.