Repository navigation
feat(session): STT 실패한 음성 답변 재전사 - #245
Merged
Merged
Conversation
STT 가 실패하면 답변이 "음성 인식에 실패했습니다" 로 확정되고 끝이었다. 오디오는 S3 에 그대로 남아 있는데 꺼낼 경로가 없어서, 사용자는 방금 말한 답변을 통째로 다시 입력해야 했다. 실패의 대부분은 Deepgram 이 간헐적으로 멎는 것이고 같은 파일을 재전송하면 대체로 전사된다(PR #244 의 자동 재시도가 1차 방어선). 이건 그마저 소진됐을 때 사용자가 직접 당기는 2차 방어선이다. - POST /api/sessions/{sid}/messages/voice/{mid}/retranscribe (VoiceRetranscribeService) — placeholder 상태로 되돌리고 업로드와 같은 VoiceAnswerUploadedEvent + AFTER_COMMIT 경로로 analyze.voice 재발행 - 실패 메시지가 세션의 마지막일 때만 허용. 이미 다시 답변했다면 뒤늦은 전사가 지나간 턴을 덮어쓴다(VOICE_RETRANSCRIBE_NOT_ALLOWED) - content_type 은 저장하지 않으므로 S3 key 확장자에서 역산(buildKey 의 역함수) - 프론트: 스테이지 인라인 배너 + 대화 기록 드로어 양쪽에 '다시 인식하기'. 스테이지에는 실패 안내가 아예 없어서, 사용자는 왜 답변이 사라졌는지 모른 채 컴포저만 다시 열리는 걸 봐야 했다 - 녹음이 남아 있을 때는 문구도 "다시 답변해 주세요" 대신 "녹음은 남아 있어요" 로
5 tasks done
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
작업 내용
POST /api/sessions/{sessionId}/messages/voice/{messageId}/retranscribe(VoiceRetranscribeService)InterviewMessage.retryVoiceTranscription()— placeholder 상태로 되돌림VoiceAnswerUploadedEvent+ AFTER_COMMIT 경로로analyze.voice재발행변경 이유 / 배경
STT 가 실패하면
failVoiceTranscription()이 content 를 실패 문구로 덮고 FAILED 로 확정합니다. 턴은 풀리지만 오디오는 S3 에 그대로 남아 있는데 꺼낼 경로가 없어서, 사용자는 방금 말한 답변을 통째로 다시 입력해야 했습니다.실패의 대부분은 Deepgram 이 간헐적으로 멎는 것이고, 같은 파일을 재전송하면 대체로 전사됩니다 (운영 실패 파일 6개 중 5개가 재전송에서 1.2~4.0초에 성공 — #244 참고). #244 의 자동 재시도가 1차 방어선이고, 이 PR 은 그마저 소진됐을 때 사용자가 직접 당기는 2차 방어선입니다.
스테이지에 실패 안내가 없던 문제
STT 실패 시
currentTurn이AWAITING_ANSWER로 풀려 컴포저만 다시 열립니다. 그런데 실패 안내(AnswerBubble)는 대화 기록 드로어 안에만 있어서, 몰입형 스테이지에서는 사용자가 왜 답변이 사라졌는지 모른 채 같은 질문을 다시 마주합니다. 배너를 컴포저 위에 두어 실패 사실과 복구 수단을 같은 자리에서 보이게 했습니다.마지막 메시지일 때만 허용하는 이유
실패 뒤 이미 다시 답변했다면 그 답변이 이 턴의 진짜 답입니다. 여기서 전사를 되살리면 뒤늦은 콜백이 지나간 턴의 내용을 덮어씁니다. 서버가
VOICE_RETRANSCRIBE_NOT_ALLOWED로 거절하고, 프론트도 마지막 메시지가 아니면 버튼 자체를 내지 않습니다.content_type 역산
interview_messages는 content_type 을 저장하지 않습니다. 업로드 때buildKey가 확장자로 인코딩한 정보를 되읽어 복원했습니다(.webm→audio/webm). 알 수 없는 확장자는application/octet-stream으로 넘겨 Deepgram 이 컨테이너를 스스로 판별하게 합니다.테스트
vitest run45 files / 191 tests passed,tsc --noEmit,eslint --max-warnings=0clean./gradlew test— 로컬에 Docker 가 없어 Testcontainers 기반 17건은 컨텍스트 로드 실패(이 변경과 무관, CI 에서 검증). 나머지 269건 통과영향 범위
backend/openapi.json+frontend/src/shared/api/generated.ts재생성 (추가만, 삭제 없음)리뷰어 체크포인트
/messages/voice/{messageId}/retranscribe입니다.VoiceAnswerController의@RequestMapping("/api/sessions/{sessionId}/messages/voice")를 따른 결과인데,/messages/{messageId}/voice/retranscribe가 더 자연스럽다면 컨트롤러를 나누겠습니다.disabled와analyze.voice의 멱등(LruIdempotencyStore)에 기대고 있는데, 서버에서 "이미 transcribing 이면 무시" 를 넣는 편이 나을지 봐주세요.🤖 Generated with Claude Code