diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceApi.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceApi.java index 571a1159..b9d16dcd 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceApi.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceApi.java @@ -1,8 +1,6 @@ package com.example.memetory.domain.voice.controller; import com.example.memetory.domain.voice.dto.request.GenerateVoiceRequestDto; -import com.example.memetory.domain.voice.dto.response.ElevenlabsVoiceLibraryResponse; -import com.example.memetory.domain.voice.dto.response.ElevenlabsVoiceResponse; import com.example.memetory.global.response.ResultResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -13,6 +11,7 @@ import org.springframework.http.ResponseEntity; import java.io.IOException; +import java.rmi.AlreadyBoundException; @Tag(name = "Voice") public interface VoiceApi { @@ -31,7 +30,7 @@ public interface VoiceApi { ResponseEntity register( @Parameter(hidden = true) String email, GenerateVoiceRequestDto generateVoiceRequestDto - ) throws IOException; + ) throws IOException, AlreadyBoundException; @Operation( summary = "멤버별 목소리 조회", @@ -46,18 +45,20 @@ ResponseEntity register( }) ResponseEntity findByMemberId( @Parameter(hidden = true) String email - ) throws IOException; + ); @Operation( - summary = "기본 라이브러리 목소리 조회", - description = "기본 라이브러리 목소리를 조회한다.", + summary = "목소리 삭제", + description = "voice_id에 해당하는 목소리를 삭제한다.", security = {@SecurityRequirement(name = "access_token")} ) @ApiResponses(value = { @ApiResponse( responseCode = "200", - description = "기본 라이브러리 목소리 조회!" + description = "목소리 삭제!" ) }) - ResponseEntity getVoiceLibrary() throws IOException; + void deleteVoice( + @Parameter(hidden = true) String email + ); } diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceController.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceController.java index 407e43e3..d679bb81 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceController.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/voice/controller/VoiceController.java @@ -2,8 +2,6 @@ import com.example.memetory.domain.voice.dto.VoiceServiceDto; import com.example.memetory.domain.voice.dto.request.GenerateVoiceRequestDto; -import com.example.memetory.domain.voice.dto.response.ElevenlabsVoiceLibraryResponse; -import com.example.memetory.domain.voice.dto.response.ElevenlabsVoiceResponse; import com.example.memetory.domain.voice.dto.response.GenerateVoiceResponseDto; import com.example.memetory.domain.voice.service.VoiceService; import com.example.memetory.global.annotation.LoginMemberEmail; @@ -36,18 +34,22 @@ public class VoiceController implements VoiceApi { @Value("${elevenlabs.api.url.get}") private String getApiUrl; - @Value("${elevenlabs.api.url.library}") - private String getLibraryApiUrl; + @Value("${elevenlabs.api.url.delete}") + private String deleteApiUrl; @Value("${elevenlabs.api.key}") private String apiKey; + // 보이스 추출 및 생성 @PostMapping @Override - public ResponseEntity register(@LoginMemberEmail String email, @RequestBody GenerateVoiceRequestDto generateVoiceRequestDto) throws IOException { + public ResponseEntity register(@LoginMemberEmail String email, @RequestBody GenerateVoiceRequestDto generateVoiceRequestDto) throws IOException{ // s3 url을 받아서 음성파일을 가져오는 ServiceDto 로직 1개 VoiceServiceDto voiceServiceDtoS3 = generateVoiceRequestDto.toServiceDtoS3(email); + + // 보이스가 이미 존재하는지 체크 + voiceService.isExistVoice(voiceServiceDtoS3); MultiValueMap formData = voiceService.generateVoice(voiceServiceDtoS3); return WebClient @@ -72,9 +74,10 @@ public ResponseEntity register(@LoginMemberEmail String email, @ .block(); } + // 멤버별 보이스 조회 @GetMapping("/member") @Override - public ResponseEntity findByMemberId(@LoginMemberEmail String email) throws IOException { + public ResponseEntity findByMemberId(@LoginMemberEmail String email){ VoiceServiceDto voiceServiceDto = VoiceServiceDto.create(email); String voiceId = voiceService.findVoiceByMemberId(voiceServiceDto); @@ -95,23 +98,19 @@ public ResponseEntity findByMemberId(@LoginMemberEmail String em .block(); } - @GetMapping("/library") + @DeleteMapping("/member") @Override - public ResponseEntity getVoiceLibrary() throws IOException { - return WebClient - .create(getLibraryApiUrl) - .get() + public void deleteVoice(@LoginMemberEmail String email) { + VoiceServiceDto voiceServiceDto = VoiceServiceDto.create(email); + String voiceId = voiceService.findVoiceByMemberId(voiceServiceDto); + + WebClient.create(deleteApiUrl + "/" + voiceId) + .delete() .header("xi-api-key", apiKey) .retrieve() - .bodyToMono(ElevenlabsVoiceLibraryResponse.class) - .flatMap(response -> { - // elevenlabs API 호출이 완료 되면 실행할 로직 - return Mono.just(ResponseEntity.ok(ResultResponse.of(ResultCode.GET_VOICE_LIBRARY_SUCCESS, response))); - }) - .onErrorResume(error -> { - System.out.println(("An error occurred while processing the request: {}" + error.getMessage())); - return Mono.just(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build()); - }) - .block(); + .bodyToMono(Void.class) + .subscribe(); + + voiceService.deleteVoice(voiceServiceDto); } } diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceLibraryResponse.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceLibraryResponse.java deleted file mode 100644 index 9f3e81f3..00000000 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceLibraryResponse.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.example.memetory.domain.voice.dto.response; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; - -import java.util.List; - -@Getter -@NoArgsConstructor -public class ElevenlabsVoiceLibraryResponse { - - @JsonProperty("voices") - private List voices; - - @JsonProperty("has_more") - private boolean hasMore; - - @JsonProperty("last_sort_id") - private String lastSortId; -} diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceResponse.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceResponse.java deleted file mode 100644 index a2961272..00000000 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/dto/response/ElevenlabsVoiceResponse.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.example.memetory.domain.voice.dto.response; - -import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Getter; -import lombok.NoArgsConstructor; - -@Getter -@NoArgsConstructor -public class ElevenlabsVoiceResponse { - - @JsonProperty("voice_id") - private String elevenlabsVoiceId; - - @JsonProperty("name") - private String name; - - @JsonProperty("description") - private String description; -} diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/exception/AlreadyExistVoiceException.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/exception/AlreadyExistVoiceException.java new file mode 100644 index 00000000..fe9ad226 --- /dev/null +++ b/backend/memetory/src/main/java/com/example/memetory/domain/voice/exception/AlreadyExistVoiceException.java @@ -0,0 +1,10 @@ +package com.example.memetory.domain.voice.exception; + +import com.example.memetory.global.exception.BusinessException; +import com.example.memetory.global.response.ErrorCode; + +public class AlreadyExistVoiceException extends BusinessException { + public AlreadyExistVoiceException() { + super(ErrorCode.VOICE_ALREADY_EXIST); + } +} diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/repository/VoiceRepository.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/repository/VoiceRepository.java index b31d6195..ec2cfed1 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/repository/VoiceRepository.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/voice/repository/VoiceRepository.java @@ -3,5 +3,7 @@ import com.example.memetory.domain.voice.entity.Voice; import org.springframework.data.jpa.repository.JpaRepository; -public interface VoiceRepository extends JpaRepository, VoiceQueryRepository{ +import java.util.Optional; + +public interface VoiceRepository extends JpaRepository, VoiceQueryRepository { } diff --git a/backend/memetory/src/main/java/com/example/memetory/domain/voice/service/VoiceService.java b/backend/memetory/src/main/java/com/example/memetory/domain/voice/service/VoiceService.java index ff5a6b9b..b7068a29 100644 --- a/backend/memetory/src/main/java/com/example/memetory/domain/voice/service/VoiceService.java +++ b/backend/memetory/src/main/java/com/example/memetory/domain/voice/service/VoiceService.java @@ -6,6 +6,7 @@ import com.example.memetory.domain.member.service.MemberService; import com.example.memetory.domain.voice.dto.VoiceServiceDto; import com.example.memetory.domain.voice.entity.Voice; +import com.example.memetory.domain.voice.exception.AlreadyExistVoiceException; import com.example.memetory.domain.voice.exception.NotFoundVoiceException; import com.example.memetory.domain.voice.repository.VoiceRepository; import lombok.RequiredArgsConstructor; @@ -17,6 +18,7 @@ import org.springframework.util.MultiValueMap; import java.io.*; +import java.util.Optional; @Service @@ -40,12 +42,20 @@ public void register(VoiceServiceDto voiceServiceDto) { @Transactional(readOnly = true) public String findVoiceByMemberId(VoiceServiceDto voiceServiceDto) { - Member foundMember = memberService.findMemberFromEmail(voiceServiceDto.getEmail()); - Voice foundVoice = voiceRepository.findByMemberId(foundMember.getId()).orElseThrow(NotFoundVoiceException::new); - + Voice foundVoice = findVoiceByMemberEmail(voiceServiceDto); return foundVoice.getElevenlabsVoiceId(); } + public void deleteVoice(VoiceServiceDto voiceServiceDto) { + Voice foundVoice = findVoiceByMemberEmail(voiceServiceDto); + voiceRepository.delete(foundVoice); + } + + private Voice findVoiceByMemberEmail(VoiceServiceDto voiceServiceDto) { + Member foundMember = memberService.findMemberFromEmail(voiceServiceDto.getEmail()); + return voiceRepository.findByMemberId(foundMember.getId()).orElseThrow(NotFoundVoiceException::new); + } + // 목소리 생성 public MultiValueMap generateVoice(VoiceServiceDto voiceServiceDto) throws IOException { S3Object s3Object = getS3File(voiceServiceDto); @@ -53,6 +63,16 @@ public MultiValueMap generateVoice(VoiceServiceDto voiceServiceD return createFormData(s3Object, voiceServiceDto); } + // 목소리가 이미 생성되어 있는지 체크 + public void isExistVoice(VoiceServiceDto voiceServiceDto) { + Member foundMember = memberService.findMemberFromEmail(voiceServiceDto.getEmail()); + Optional foundVoice = voiceRepository.findByMemberId(foundMember.getId()); + + if (foundVoice.isPresent()) { + throw new AlreadyExistVoiceException(); + } + } + // S3 파일 가져오기 private S3Object getS3File(VoiceServiceDto voiceServiceDto) { return amazonS3Client.getObject(bucketName, voiceServiceDto.getS3Key()); diff --git a/backend/memetory/src/main/java/com/example/memetory/global/response/ErrorCode.java b/backend/memetory/src/main/java/com/example/memetory/global/response/ErrorCode.java index cc2d1b92..dc6adbd6 100644 --- a/backend/memetory/src/main/java/com/example/memetory/global/response/ErrorCode.java +++ b/backend/memetory/src/main/java/com/example/memetory/global/response/ErrorCode.java @@ -39,6 +39,7 @@ public enum ErrorCode { // Voice VOICE_NOT_FOUND(404, "보이스 찾기 실패"), + VOICE_ALREADY_EXIST(404, "보이스 이미 존재") ; diff --git a/backend/memetory/src/main/java/com/example/memetory/global/response/ResultCode.java b/backend/memetory/src/main/java/com/example/memetory/global/response/ResultCode.java index 70a6b3d2..a28d353c 100644 --- a/backend/memetory/src/main/java/com/example/memetory/global/response/ResultCode.java +++ b/backend/memetory/src/main/java/com/example/memetory/global/response/ResultCode.java @@ -40,6 +40,7 @@ public enum ResultCode { // voice CREATE_VOICE_SUCCESS(201, "목소리 생성 성공"), + DELETE_VOICE_SUCCESS(200, "목소리 삭제 성공"), GET_MEMBER_VOICE_SUCCESS(200, "멤버별 목소리 조회 성공"), GET_VOICE_LIBRARY_SUCCESS(200, "기본 목소리 라이브러리 조회 성공"), ;