Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dev backend #114

Merged
merged 27 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d4b4bce
Merge branch 'Dev-backend' into feat/#80-backend-debate-summary
yeonjy Apr 30, 2024
e0ff029
fix: νšŒμ› 정보 쀑볡 μ €μž₯ ν•΄κ²°
yeonjy May 5, 2024
05ba9a0
Merge pull request #110 from tukcomCD2024/fix/#109-backend-authservice
yeonjy May 5, 2024
3f721f3
Merge remote-tracking branch 'origin/Dev-backend' into feat/#80-backe…
yeonjy May 6, 2024
dfccd65
feat: Debate Message μš”μ•½ 둜직 κ΅¬ν˜„
yeonjy May 6, 2024
bc0e1c8
feat: summaryDebateMessage μš”μ²­ 및 κ²°κ³Ό λ°˜ν™˜ 둜직 κ΅¬ν˜„
yeonjy May 6, 2024
f069015
feat: getSummarizedDebate API κ΅¬ν˜„
yeonjy May 6, 2024
845d337
feat: response dto μ„€λͺ… μΆ”κ°€
yeonjy May 6, 2024
d088c04
fix: clova connection 였λ₯˜ ν•΄κ²°
yeonjy May 7, 2024
cbca7e6
refactor: stream().map() -> forEach()
yeonjy May 7, 2024
c44234b
chore: test κ΄€λ ¨ 라이브러리 μΆ”κ°€
yeonjy May 7, 2024
87764a5
fix: μš”μ•½ api 경둜 쀑볡 ν•΄κ²°
yeonjy May 7, 2024
04311fb
feat: DebateRoom isClosed & summary ν•„λ“œ μΆ”κ°€
yeonjy May 7, 2024
e5e024e
refactor: ν† λ‘  μš”μ•½ DebateRoomService둜 이동
yeonjy May 7, 2024
6dc5beb
feat: summary μ €μž₯ κ΄€λ ¨ 둜직 κ΅¬ν˜„
yeonjy May 7, 2024
20e3d19
rename: summaryDebateMessages -> summaryDebate 적용
yeonjy May 7, 2024
743e8b7
Merge pull request #111 from tukcomCD2024/feat/#80-backend-debate-sum…
yeonjy May 7, 2024
87893c6
feat: submodule update
yeonjy May 13, 2024
97fb416
Merge branch 'Dev-backend' into feat/#105-debate-complete
yeonjy May 14, 2024
2d62dbc
style: μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” import 제거
yeonjy May 14, 2024
fad44d5
refactor: summaryκ°€ μ‘΄μž¬ν•˜λ©΄ ν•΄λ‹Ή summary λ°˜ν™˜
yeonjy May 14, 2024
d3b5c08
refactor: ν† λ‘  μš”μ•½κ³Ό ν† λ‘  μš”μ•½ 쑰회 api 뢄리
yeonjy May 14, 2024
ff6eaa3
refactor: ν† λ‘  μš”μ•½κ³Ό ν† λ‘  μš”μ•½ 쑰회 둜직 뢄리
yeonjy May 14, 2024
819c51f
feat: ν† λ‘  μ’…λ£Œ api κ΅¬ν˜„
yeonjy May 14, 2024
09424d8
feat: ν† λ‘  μ’…λ£Œ 둜직 κ΅¬ν˜„
yeonjy May 14, 2024
bb5b422
feat: DebateRoom 응닡 DTO에 isClosed μΆ”κ°€
yeonjy May 14, 2024
7ac88e2
Merge pull request #113 from tukcomCD2024/feat/#105-debate-complete
yeonjy May 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions backend/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,12 @@ dependencies {
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'

testAnnotationProcessor "org.mapstruct:mapstruct-processor:1.5.5.Final"
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testCompileOnly 'org.projectlombok:lombok'
testAnnotationProcessor 'org.projectlombok:lombok'
}

tasks.named('bootBuildImage') {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
import com.rollthedice.backend.domain.debate.dto.request.DebateRoomRequest;
import com.rollthedice.backend.domain.debate.dto.response.DebateMessageResponse;
import com.rollthedice.backend.domain.debate.dto.response.DebateRoomResponse;
import com.rollthedice.backend.domain.debate.dto.response.DebateSummaryResponse;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.RequestBody;
Expand All @@ -21,7 +23,7 @@ public interface DebateApi {
summary = "ν† λ‘ λ°© 생성",
description = "μ£Όμ œκ°€ μ„ νƒλœ 토둠방을 μƒμ„±ν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_room"}
tags = {"ν† λ‘ λ°©"}
)
@ApiResponse(
responseCode = "201",
Expand All @@ -33,23 +35,23 @@ public interface DebateApi {
summary = "ν† λ‘ λ°© 전체 쑰회",
description = "νšŒμ›μ˜ 토둠방을 νŽ˜μ΄μ§€λ‘œ λ‚˜λˆ„μ–΄ μ‘°νšŒν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_room"}
tags = {"ν† λ‘ λ°©"}
)
@ApiResponse(
responseCode = "200",
description = "OK"
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
)
List<DebateRoomResponse> getDebateRooms(Pageable pageable);

@Operation(
summary = "ν† λ‘ λ°© μ‚­μ œ",
description = "토둠방을 μ‚­μ œν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_room"}
tags = {"ν† λ‘ λ°©"}
)
@ApiResponse(
responseCode = "204",
description = "No Content"
description = "ν† λ‘ λ°© μ‚­μ œμ— μ„±κ³΅ν•˜μ˜€μœΌλ©°, 응닡값은 μ—†μŠ΅λ‹ˆλ‹€."
)
void deleteDebateRoom(@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°© ID", required = true)
Long roomId
Expand All @@ -59,7 +61,7 @@ void deleteDebateRoom(@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°©
summary = "[인간] ν† λ‘  메세지 μ €μž₯",
description = "μ‚¬μš©μžκ°€ 보낸 ν† λ‘  메세지λ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_message"}
tags = {"ν† λ‘  메세지"}
)
@ApiResponse(
responseCode = "201",
Expand All @@ -76,7 +78,7 @@ void saveHumanDebateMessage(
summary = "[AI] ν† λ‘  메세지 μ €μž₯",
description = "ChatGPT OPENAIκ°€ 보낸 ν† λ‘  메세지λ₯Ό μ €μž₯ν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_message"}
tags = {"ν† λ‘  메세지"}
)
@ApiResponse(
responseCode = "201",
Expand All @@ -89,21 +91,82 @@ void saveAIDebateMessage(
@RequestBody DebateMessageRequest request
);

@Operation(
summary = "ν† λ‘  μ’…λ£Œ",
description = "토둠을 μ’…λ£Œν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"ν† λ‘ λ°©"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "204",
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μœΌλ©° 응닡값은 μ—†μŠ΅λ‹ˆλ‹€."
),
@ApiResponse(
responseCode = "404",
description = "토둠방을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€."
)
})
void finishDebate(
@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°© ID", required = true)
Long roomId
);

@Operation(
summary = "ν† λ‘  메세지 쑰회",
description = "ν† λ‘ λ°©μ˜ ν† λ‘  메세지 이λ ₯을 μ‘°νšŒν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"debate_message"}
tags = {"ν† λ‘  메세지"}
)
@ApiResponse(
responseCode = "200",
description = "OK"
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
)
List<DebateMessageResponse> getDebateMessages(
@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°© ID", required = true)
Long roomId
);

@Operation(
summary = "ν† λ‘  μš”μ•½",
description = "ν† λ‘ λ°©μ˜ ν† λ‘  메세지듀을 μš”μ•½ν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"ν† λ‘ λ°©"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "201",
description = "ν† λ‘  μš”μ•½μ΄ μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
),
@ApiResponse(
responseCode = "404",
description = "토둠방을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€."
)
})
DebateSummaryResponse summarizeDebate(
@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°© ID", required = true)
Long roomId
);

@Operation(
summary = "ν† λ‘  μš”μ•½ 쑰회",
description = "ν† λ‘  μš”μ•½ λ‚΄μš©μ„ μ‘°νšŒν•©λ‹ˆλ‹€.",
security = {@SecurityRequirement(name = "access_token")},
tags = {"ν† λ‘ λ°©"}
)
@ApiResponses(value = {
@ApiResponse(
responseCode = "200",
description = "μš”μ²­μ— μ„±κ³΅ν•˜μ˜€μŠ΅λ‹ˆλ‹€."
),
@ApiResponse(
responseCode = "404",
description = "토둠방을 찾지 λͺ»ν–ˆμŠ΅λ‹ˆλ‹€."
)
})
DebateSummaryResponse getSummarizedDebate(
@Parameter(in = ParameterIn.PATH, description = "ν† λ‘ λ°© ID", required = true)
Long roomId
);

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.rollthedice.backend.domain.debate.dto.request.DebateRoomRequest;
import com.rollthedice.backend.domain.debate.dto.response.DebateMessageResponse;
import com.rollthedice.backend.domain.debate.dto.response.DebateRoomResponse;
import com.rollthedice.backend.domain.debate.dto.response.DebateSummaryResponse;
import com.rollthedice.backend.domain.debate.service.DebateMessageService;
import com.rollthedice.backend.domain.debate.service.DebateRoomService;
import jakarta.validation.Valid;
Expand Down Expand Up @@ -56,10 +57,30 @@ public void saveAIDebateMessage(@PathVariable final Long roomId, @RequestBody fi
debateMessageService.saveAIDebateMessage(roomId, request);
}

@ResponseStatus(HttpStatus.OK)
@ResponseStatus(HttpStatus.NO_CONTENT)
@PatchMapping("/{roomId}")
public void finishDebate(@PathVariable final Long roomId) {
debateRoomService.closeDebate(roomId);
}

@ResponseStatus(HttpStatus.CREATED)
@GetMapping("/{roomId}")
@Override
public List<DebateMessageResponse> getDebateMessages(@PathVariable final Long roomId) {
return debateMessageService.getDebateMessages(roomId);
}

@ResponseStatus(HttpStatus.OK)
@PostMapping("/summary/{roomId}")
@Override
public DebateSummaryResponse summarizeDebate(@PathVariable final Long roomId) {
return debateRoomService.summaryDebate(roomId);
}

@ResponseStatus(HttpStatus.OK)
@GetMapping("/summary/{roomId}")
@Override
public DebateSummaryResponse getSummarizedDebate(@PathVariable final Long roomId) {
return debateRoomService.getSummarizedDebate(roomId);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
public class DebateRoomResponse {
private Long id;
private String topic;
private Boolean isClosed;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.rollthedice.backend.domain.debate.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class DebateSummaryResponse {
Long roomId;

@Schema(description = "4λ¬Έμž₯의 μš”μ•½λœ ν† λ‘  λ‚΄μš©")
String summary;
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.ColumnDefault;

@Getter
@Entity
Expand All @@ -17,6 +18,10 @@ public class DebateRoom extends BaseTimeEntity {
private Long id;

private String topic;
private String summary;

@ColumnDefault("false")
private boolean isClosed;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
Expand All @@ -27,4 +32,12 @@ public DebateRoom(Member member, String topic) {
this.member = member;
this.topic = topic;
}

public void closeDebate() {
this.isClosed = true;
}

public void updateSummary(String summary) {
this.summary = summary;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package com.rollthedice.backend.domain.debate.service;

import com.rollthedice.backend.global.error.ErrorCode;
import com.rollthedice.backend.global.error.exception.ExternalApiException;
import lombok.extern.slf4j.Slf4j;
import net.minidev.json.JSONObject;
import org.apache.tomcat.util.json.JSONParser;
import org.apache.tomcat.util.json.ParseException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatusCode;
import org.springframework.stereotype.Service;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;

@Slf4j
@Service
public class ClovaSummary {
private static final String KOREAN = "ko";
private static final int POLITE_TONE = 2;
private static final int SUMMARY_COUNT = 4;

private static final String API_URL = "https://naveropenapi.apigw.ntruss.com/text-summary/v1/summarize";


@Value("${clova.secret-key}")
private String SECRET;

@Value("${clova.client-id}")
private String CLIENT_ID;

public String summaryDebate(String messages) {
log.info("μš”μ•½ν•  메세지: {}" ,messages);
try {
URL url = new URL(API_URL);
HttpURLConnection connection = createRequestHeader(url);
createRequestBody(connection, messages);

log.info("정상1");
StringBuilder response = getResponse(connection);
log.info("정상2");
return parseResponse(response);
} catch (Exception e) {
e.printStackTrace();
throw new ExternalApiException(ErrorCode.CLOVA_API_ERROR);
}
}

private HttpURLConnection createRequestHeader(URL url) throws IOException {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json;");
connection.setRequestProperty("X-NCP-APIGW-API-KEY-ID", CLIENT_ID);
connection.setRequestProperty("X-NCP-APIGW-API-KEY", SECRET);
return connection;
}

private void createRequestBody(HttpURLConnection connection, String content) throws IOException {
JSONObject document = new JSONObject();
document.put("content", content);

JSONObject option = new JSONObject();
option.put("language", KOREAN);
option.put("tone", POLITE_TONE);
option.put("summaryCount", SUMMARY_COUNT);

JSONObject requestObject = new JSONObject();
requestObject.put("document", document);
requestObject.put("option", option);

connection.connect();
DataOutputStream outputStream = new DataOutputStream(connection.getOutputStream());
outputStream.write(requestObject.toString().getBytes(StandardCharsets.UTF_8));
outputStream.flush();
outputStream.close();
}


private StringBuilder getResponse(HttpURLConnection connection) throws IOException {
BufferedReader reader = checkResponse(connection);
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
reader.close();
return response;
}

private BufferedReader checkResponse(HttpURLConnection connection) throws IOException {
int responseCode = connection.getResponseCode();

return getResponseResult(connection, responseCode);
}

private BufferedReader getResponseResult(HttpURLConnection connection, int responseCode) throws IOException {
if (HttpStatusCode.valueOf(responseCode).is2xxSuccessful()) {
return new BufferedReader(new InputStreamReader(connection.getInputStream()));
}
log.error("Clova Api error response code: {}", responseCode);
return new BufferedReader(new InputStreamReader(connection.getErrorStream()));
}


private String parseResponse(StringBuilder response) throws ParseException {
JSONParser parser = new JSONParser(response.toString());
LinkedHashMap<String, String> hashMap = (LinkedHashMap<String, String>) parser.parse();
JSONObject parsed = new JSONObject(hashMap);
return parsed.get("summary").toString();
}
}
Loading
Loading