Skip to content

Commit

Permalink
Backend/feature/95 add location coordinate
Browse files Browse the repository at this point in the history
Backend/feature/95 add location coordinate
  • Loading branch information
yo0oni authored Jun 19, 2024
2 parents dc59ac4 + a55688c commit 4fed5ad
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ public WebClient webClient() {
HttpClient httpClient = HttpClient.create()
.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 30000)
.doOnConnected(conn -> conn
.addHandlerLast(new ReadTimeoutHandler(10))
.addHandlerLast(new WriteTimeoutHandler(10)));
.addHandlerLast(new ReadTimeoutHandler(30))
.addHandlerLast(new WriteTimeoutHandler(30)));
return WebClient.builder()
.clientConnector(new ReactorClientHttpConnector(httpClient))
.build();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.isp.backend.domain.gpt.entity;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class Coordinate {
private Double latitude;
private Double longitude;

public Coordinate(Double latitude, Double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
@NoArgsConstructor
public class GptSchedule {
private String date;
private List<String> scheduleDetail;
private List<GptScheduleDetail> scheduleDetail;

public GptSchedule(String date, List<String> scheduleDetail) {
public GptSchedule(String date, List<GptScheduleDetail> scheduleDetail) {
this.date = date;
this.scheduleDetail = scheduleDetail;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.isp.backend.domain.gpt.entity;

import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class GptScheduleDetail {
private String detail;
private Coordinate coordinate;

public GptScheduleDetail(String detail, Coordinate coordinate) {
this.detail = detail;
this.coordinate = coordinate;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,70 @@ public class GptScheduleParser {

public List<GptSchedule> parseScheduleText(String scheduleText) {
List<GptSchedule> schedules = new ArrayList<>();
Pattern datePattern = Pattern.compile(ParsingConstants.DATE_REGEX);

List<String> lines = List.of(scheduleText.split(ParsingConstants.NEW_LINE_REGEX));
List<String> currentScheduleDetail = new ArrayList<>();
List<GptScheduleDetail> currentScheduleDetail = new ArrayList<>();
String currentDate = ParsingConstants.CURRENT_DATE;

for (String line : lines) {
Matcher dateMatcher = datePattern.matcher(line);
if (dateMatcher.find()) {
if (!currentDate.isEmpty()) {
schedules.add(new GptSchedule(currentDate, currentScheduleDetail));
currentScheduleDetail = new ArrayList<>();
}
currentDate = dateMatcher.group(ParsingConstants.GROUP_MATCH);
} else if (!line.trim().isEmpty() && ParsingConstants.FILTER_STRINGS.stream().noneMatch(line::contains)) {
currentScheduleDetail.add(line.trim().substring(ParsingConstants.BEGIN_INDEX)); // Remove leading index
}
currentDate = processLine(line, currentDate, currentScheduleDetail, schedules);
}

if (!currentDate.isEmpty()) {
schedules.add(new GptSchedule(currentDate, currentScheduleDetail));
addSchedule(schedules, currentDate, currentScheduleDetail);
}

return schedules;
}

}
private String processLine(String line, String currentDate, List<GptScheduleDetail> currentScheduleDetail, List<GptSchedule> schedules) {
if (isDateLine(line)) {
if (!currentDate.isEmpty()) {
addSchedule(schedules, currentDate, currentScheduleDetail);
currentScheduleDetail.clear();
}
return extractDate(line);
} else if (shouldProcessLine(line)) {
addDetail(line, currentScheduleDetail);
}
return currentDate;
}

private boolean isDateLine(String line) {
Pattern datePattern = Pattern.compile(ParsingConstants.DATE_REGEX);
Matcher dateMatcher = datePattern.matcher(line);
return dateMatcher.find();
}

private String extractDate(String line) {
Pattern datePattern = Pattern.compile(ParsingConstants.DATE_REGEX);
Matcher dateMatcher = datePattern.matcher(line);
if (dateMatcher.find()) {
return dateMatcher.group(ParsingConstants.GROUP_MATCH);
}
return ParsingConstants.CURRENT_DATE;
}

private boolean shouldProcessLine(String line) {
return !line.trim().isEmpty() && ParsingConstants.FILTER_STRINGS.stream().noneMatch(line::contains);
}

private void addDetail(String line, List<GptScheduleDetail> currentScheduleDetail) {
Pattern detailPattern = Pattern.compile("^(?:\\d+\\.\\s*)?(.*?)(\\d+\\.\\d{1,8}),\\s*(\\d+\\.\\d{1,8})$");
Matcher detailMatcher = detailPattern.matcher(line.trim());
if (detailMatcher.find()) {
String detail = detailMatcher.group(1).trim();
Double latitude = Double.valueOf(detailMatcher.group(2));
Double longitude = Double.valueOf(detailMatcher.group(3));

String formattedLatitude = String.format("%.8f", latitude);
String formattedLongitude = String.format("%.8f", longitude);

Coordinate coordinate = new Coordinate(Double.parseDouble(formattedLatitude), Double.parseDouble(formattedLongitude));
currentScheduleDetail.add(new GptScheduleDetail(detail, coordinate));
}
}

private void addSchedule(List<GptSchedule> schedules, String date, List<GptScheduleDetail> details) {
schedules.add(new GptSchedule(date, details));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
import com.isp.backend.domain.gpt.entity.GptScheduleParser;
import com.isp.backend.domain.schedule.service.ScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
Expand All @@ -30,10 +29,10 @@
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Slf4j
@RequiredArgsConstructor
@Service
@RequiredArgsConstructor
public class GptService {

private final GptScheduleParser gptScheduleParser;
private final ScheduleService scheduleService;
private final WebClient webClient;
Expand All @@ -42,7 +41,6 @@ public class GptService {
private String apiKey;

public GptScheduleResponse getResponse(HttpHeaders headers, GptRequest gptRequest) {

GptResponse response = webClient.post()
.uri(GptConfig.CHAT_URL)
.headers(h -> h.addAll(headers))
Expand All @@ -52,78 +50,67 @@ public GptScheduleResponse getResponse(HttpHeaders headers, GptRequest gptReques
.bodyToMono(GptResponse.class)
.block();

List<GptSchedule> gptSchedules = gptScheduleParser.parseScheduleText(getScheduleText(response));
List<GptSchedule> gptSchedules = gptScheduleParser.parseScheduleText(extractScheduleText(response));
return new GptScheduleResponse(gptSchedules);
}

private String getScheduleText(GptResponse gptResponse) {
return getGptMessage(gptResponse).toString();
}

private GptMessage getGptMessage(GptResponse gptResponse) {
return gptResponse.getChoices().get(0).getMessage();
private String extractScheduleText(GptResponse gptResponse) {
return gptResponse.getChoices().get(0).getMessage().getContent();
}

@Async
public CompletableFuture<GptSchedulesResponse> askQuestion(GptScheduleRequest questionRequestDTO) {
String question = makeQuestion(questionRequestDTO);
List<GptMessage> messages = Collections.singletonList(
GptMessage.builder()
.role(GptConfig.ROLE)
.content(question)
.build()
);

Country country = scheduleService.validateCountry(questionRequestDTO.getDestination());
public CompletableFuture<GptSchedulesResponse> askQuestion(GptScheduleRequest questionRequest) {
String question = formatQuestion(questionRequest);
List<GptMessage> messages = Collections.singletonList(createMessage(question));
Country country = scheduleService.validateCountry(questionRequest.getDestination());
String countryImage = country.getImageUrl();

ExecutorService executorService = Executors.newFixedThreadPool(5);
List<CompletableFuture<GptScheduleResponse>> futures = Arrays.asList(
sendRequestAsync(apiKey, messages, executorService),
sendRequestAsync(apiKey, messages, executorService),
sendRequestAsync(apiKey, messages, executorService)
sendRequestAsync(messages, executorService),
sendRequestAsync(messages, executorService),
sendRequestAsync(messages, executorService)
);

CompletableFuture<List<GptScheduleResponse>> combinedFuture = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList()));
.thenApply(v -> futures.stream().map(CompletableFuture::join).collect(Collectors.toList()));

return combinedFuture.thenApply(schedules -> new GptSchedulesResponse(countryImage, schedules));
}

private CompletableFuture<GptScheduleResponse> sendRequestAsync(String apiKey, List<GptMessage> messages, ExecutorService executor) {
private CompletableFuture<GptScheduleResponse> sendRequestAsync(List<GptMessage> messages, ExecutorService executor) {
HttpHeaders headers = buildHttpHeaders(apiKey);
GptRequest request = getGptRequest(messages);
GptRequest request = createGptRequest(messages);
return CompletableFuture.supplyAsync(() -> getResponse(headers, request), executor);
}

private GptRequest getGptRequest(List<GptMessage> messages) {
return new GptRequest(
GptConfig.CHAT_MODEL,
GptConfig.MAX_TOKEN,
GptConfig.TEMPERATURE,
GptConfig.STREAM,
messages
);
private GptRequest createGptRequest(List<GptMessage> messages) {
return new GptRequest(GptConfig.CHAT_MODEL, GptConfig.MAX_TOKEN, GptConfig.TEMPERATURE, GptConfig.STREAM, messages);
}

private HttpHeaders buildHttpHeaders(String key) {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.add(GptConfig.AUTHORIZATION, GptConfig.BEARER + key);
return httpHeaders;
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.add(HttpHeaders.AUTHORIZATION, GptConfig.BEARER + key);
return headers;
}

private String makeQuestion(GptScheduleRequest questionRequestDTO) {
private String formatQuestion(GptScheduleRequest questionRequest) {
return String.format(GptConfig.PROMPT,
questionRequestDTO.getDestination(),
questionRequestDTO.getPurpose(),
questionRequestDTO.getIncludedActivities(),
questionRequestDTO.getExcludedActivities(),
questionRequestDTO.getDepartureDate(),
questionRequestDTO.getReturnDate(),
String.join(ParsingConstants.COMMA, questionRequestDTO.getPurpose())
questionRequest.getDestination(),
questionRequest.getPurpose(),
questionRequest.getIncludedActivities(),
questionRequest.getExcludedActivities(),
questionRequest.getDepartureDate(),
questionRequest.getReturnDate(),
String.join(ParsingConstants.COMMA, questionRequest.getPurpose())
);
}

private GptMessage createMessage(String content) {
return GptMessage.builder()
.role(GptConfig.ROLE)
.content(content)
.build();
}
}

0 comments on commit 4fed5ad

Please sign in to comment.