diff --git a/backend/src/main/java/com/secondzip/backend/record/client/ClovaSpeechClient.java b/backend/src/main/java/com/secondzip/backend/record/client/ClovaSpeechClient.java index 06bce76..da3c715 100644 --- a/backend/src/main/java/com/secondzip/backend/record/client/ClovaSpeechClient.java +++ b/backend/src/main/java/com/secondzip/backend/record/client/ClovaSpeechClient.java @@ -12,6 +12,7 @@ import org.springframework.web.client.RestTemplate; import java.util.LinkedHashMap; +import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -89,6 +90,15 @@ private Map createRequestBody( requestBody.put("wordAlignment", true); requestBody.put("fullText", true); + Map diarization = new LinkedHashMap<>(); + + diarization.put("enable", true); + + requestBody.put( + "diarization", + diarization + ); + return requestBody; } @@ -125,34 +135,27 @@ private String extractTranscript( ClovaSpeechResponse.class ); - if (response.getText() != null - && !response.getText().isBlank()) { - return response.getText().trim(); - } - + // 화자 정보가 포함된 segments 우선 사용 if (response.getSegments() != null && !response.getSegments().isEmpty()) { String transcript = - response.getSegments() - .stream() - .map( - ClovaSpeechResponse - .Segment::getText - ) - .filter(text -> - text != null - && !text.isBlank() - ) - .collect( - Collectors.joining(" ") - ); + buildSpeakerTranscript( + response.getSegments() + ); if (!transcript.isBlank()) { return transcript.trim(); } } + // segments가 없는 경우에만 fullText 사용 + if (response.getText() != null + && !response.getText().isBlank()) { + return response.getText().trim(); + } + + throw new IllegalStateException( "CLOVA Speech 응답에서 녹취문을 찾을 수 없습니다. " + "result=" @@ -161,4 +164,57 @@ private String extractTranscript( + response.getMessage() ); } + + private String buildSpeakerTranscript(List segments) { + + StringBuilder transcript = new StringBuilder(); + + String previousSpeaker = null; + + for (ClovaSpeechResponse.Segment segment : segments) { + + String text = segment.getText(); + + if (text == null || text.isBlank()) { + continue; + } + + String speaker = null; + + if (segment.getDiarization() != null) { + speaker = segment + .getDiarization() + .getLabel(); + } + + if (speaker == null || speaker.isBlank()) { + speaker = "알 수 없음"; + } + + + // 같은 화자가 계속 말한 경우 한 줄로 연결 + if (speaker.equals(previousSpeaker)) { + + transcript + .append(" ") + .append(text.trim()); + + } else { + + if (transcript.length() > 0) { + transcript.append("\n"); + } + + transcript + .append("화자 ") + .append(speaker) + .append(": ") + .append(text.trim()); + } + + previousSpeaker = speaker; + } + + return transcript.toString().trim(); + } } \ No newline at end of file diff --git a/backend/src/main/java/com/secondzip/backend/record/dto/response/ClovaSpeechResponse.java b/backend/src/main/java/com/secondzip/backend/record/dto/response/ClovaSpeechResponse.java index 98180c9..f0ae4f0 100644 --- a/backend/src/main/java/com/secondzip/backend/record/dto/response/ClovaSpeechResponse.java +++ b/backend/src/main/java/com/secondzip/backend/record/dto/response/ClovaSpeechResponse.java @@ -21,6 +21,18 @@ public class ClovaSpeechResponse { @JsonIgnoreProperties(ignoreUnknown = true) public static class Segment { - private String text; //녹취 기록 분할 + private String text; + + // CLOVA 화자 분리 결과 + private Diarization diarization; + } + + @Getter + @NoArgsConstructor + @JsonIgnoreProperties(ignoreUnknown = true) + public static class Diarization { + + // "1", "2", ... + private String label; } } \ No newline at end of file