Feature/sprint3 feedback rag#38
Merged
Merged
Conversation
Sprint 3 백엔드/AI 본 구현. US-24 (종합 피드백) + RAG 검색 활성화.
## 메시징 인프라
- ai.generate.feedback / core.callback.feedback 큐 + DLQ 추가
(infra/rabbitmq/definitions.json, RabbitMqConfig, RabbitMqProperties, application.yml)
## Core 피드백 도메인
- SessionEndedEvent (USER_REQUEST | MAX_QUESTIONS_REACHED)
- SessionService.end + QuestionsCallbackService.applyFollowup 자동 종료 시 발화
- SessionFeedbackRequester @TransactionalEventListener(AFTER_COMMIT, REQUIRES_NEW)
→ 메시지 시퀀스 + 컨텍스트 문서 ID 수집 → generate.feedback 발행
- FeedbackCallbackService + Handler — session_feedbacks INSERT + SSE FEEDBACK_READY
멱등: processed_messages + session_feedbacks UNIQUE(session_id)
- GET /api/sessions/{id}/feedback (SessionFeedbackQueryService)
- SessionFeedback.of() factory + JdbcType JSON 매핑
## Core embeddings search API
- POST /api/internal/embeddings/search (X-Internal-API-Key)
- JdbcDocumentEmbeddingRepository.search() — pgvector cosine `<=>` topK 검색
documentIds 필터 옵션, NamedParameterJdbcTemplate IN 절 동적 바인딩
## AI 서버
- generate.feedback consumer (LangChain Pro 모델, FeedbackResult Pydantic)
- 프롬프트: 시퀀스 흐름 우선, 4점 + 강점/약점/개선 키워드
- RAG: 마지막 INTERVIEWEE 답변을 쿼리로 임베딩 → Core search → topK 청크 주입
- CoreClient.search_embeddings() — 실패 시 빈 리스트 (RAG 보강용, fatal 아님)
## 테스트
- FeedbackCallbackServiceTest (Mockito): apply, 중복 messageId skip, 기존 feedback skip
- SessionFeedbackRequesterTest: publish 호출, 기존 feedback 시 skip
- AI test_feedback_consumer.py: 생성+발행, RAG 호출, 멱등 skip
- 백엔드 + AI 전 테스트 통과 (BUILD SUCCESSFUL, 132 passed)
## Sprint 4 분리
- 음성 모듈 (Whisper STT, WPM/filler/silence) — Phase 2
- WebSocket — Phase 1 in-memory SSE 단일화 유지
ai/CLAUDE.md §8 의 Phase 2 음성 모듈 본 구현. 텍스트 면접의 답변 흐름과 동일한
이벤트 모델 위에 음성 답변을 1급 시민으로 추가.
## 메시징 인프라
- ai.analyze.voice / core.callback.voice 큐 + DLQ + 라우팅 키
(infra/rabbitmq/definitions.json, RabbitMqProperties, application.yml, RabbitMqConfig)
## Core 음성 답변 흐름
- POST /api/sessions/{id}/messages/voice (multipart/form-data, Idempotency-Key)
- InterviewMessage placeholder INSERT (content="(transcribing)", status=CREATED)
- S3 PUT (`interview/voice/raw/{sid}/{mid}.{ext}`)
- analyze.voice 발행 (envelope: 메시지 id, S3 key, 직전 질문 hint, interview type 등)
- VoiceCallbackHandler/Service — callback.voice 수신
- completeWithTranscript(content) + markStatus(COMPLETED)
- MessageVoiceAnalysis INSERT (wpm/silence/filler/accuracy)
- SSE SESSION_MESSAGE transcribed 알림
- AnswerSubmittedEvent 발화 → 기존 SessionFollowupRequester 재사용 (텍스트와 동일 follow-up)
- 에러 코드 도착 시 message FAILED 마킹 + SSE 알림 (followup 미발화)
- 멱등: processed_messages + message_voice_analyses UNIQUE(message_id)
- 입력 검증: 25MB 캡, audio/webm·ogg·mp3·m4a·wav 화이트리스트
## AI 음성 모듈 신설 (`ai/src/ai_server/voice/`)
- stt/base.py — SttProvider Protocol + TranscriptionResult/Segment + SttError
- stt/openai_whisper.py — OpenAI `/audio/transcriptions` 직접 호출
(Mindlogic 게이트웨이가 STT 미지원이라 우회. response_format=verbose_json 으로
segment timestamps + logprob 회수)
- stt/mock.py — 더미 transcript (OPENAI_API_KEY 미발급 시 fallback)
- stt/factory.py — STT_PROVIDER 토글 + 키 누락 시 mock fallback
- analysis/metrics.py — WPM(어절/분), 한국어 간투어(`(?:음+|어+|그+|아+)`),
silence(앞/뒤 패딩 + segment 갭 합산), 발음 정확도(exp(avg_logprob) 평균)
- messaging/consumers/voice_consumer.py — S3 GET → STT → 분석 → callback.voice 발행
- 실패 분기: AUDIO_FETCH_FAILED / STT_AUTH_FAILED / TRANSCRIPTION_FAILED 등 코드 회신
## 환경변수 카탈로그
- STT_PROVIDER, OPENAI_API_KEY, OPENAI_BASE_URL, WHISPER_MODEL, WHISPER_LANGUAGE
(.env.example × 2, docker-compose.yml ai 서비스 매핑)
## 테스트
- AI 단위: test_voice_metrics.py (4) + test_voice_consumer.py (4)
- Backend 단위: VoiceCallbackServiceTest (3)
- 전체: backend BUILD SUCCESSFUL, AI 140 passed
- ArchUnit `entities_do_not_have_public_setters` 통과 — `attachAudio`,
`completeWithTranscript` 등 도메인 의미 메서드만 추가
## Sprint 4 후속 (별도 PR)
- WebSocket(RT3) 실시간 음성 청크 스트리밍 — 현재는 multipart 한 번에 업로드 MVP
- TTS provider
신규 큐(ai.generate.feedback, ai.analyze.voice 등) 는 운영 RabbitMQ 에 아직 없고 Spring RabbitMqConfig 가 부팅 시점에 declare 한다. AI runner.py 는 passive=true 로 큐 검색이라 큐 없으면 NOT_FOUND 로 즉시 종료. ai 의 depends_on 에 backend healthcheck 를 추가해 backend 가 큐 declare 마친 뒤 ai 가 시작하도록 순서 보장. 첫 배포 race 차단.
GitHub Repository Secret 에 OPENAI_API_KEY 가 등록돼 있어도 워크플로 매핑이 없으면 운영 .env 에 박히지 않아 STT 가 mock 으로 fallback. 매핑 + upsert 추가. 키가 실제 주입된 경우(secret 값 비어있지 않음)에만 STT_PROVIDER=openai_whisper 로 자동 전환. 누락 또는 빈 값이면 .env.example default(mock) 유지 — 안전한 fallback.
Deepgram (한국어 정확도 우선, $200 신규 크레딧) STT 추가. OpenAI Whisper API 유료 대비 비용 부담 ↓, 정확도 ≈ (model=whisper-large 사용 시). ## AI - voice/stt/deepgram.py — POST /v1/listen, utterances 우선 + alternative fallback, confidence → logprob 변환으로 기존 metrics.pronunciation_accuracy 그대로 호환 - factory.py — STT_PROVIDER=auto 시 deepgram > openai_whisper > mock 자동 선택, 명시 provider 의 키 누락 시 안전한 mock fallback - settings — deepgram_* 5종 + stt_provider Literal 에 auto/deepgram 추가 - 단위 테스트 4개 (성공/utterance 없음/auth 실패/5xx) — 총 144 passed ## 운영 자동 주입 - .env.example × 2, docker-compose.yml ai 서비스 환경변수 매핑 - deploy-app.yml: DEEPGRAM_API_KEY GitHub Secret 매핑 + upsert_env - STT_PROVIDER 는 키 1개라도 있으면 자동 'auto' (factory 가 우선순위로 결정) OPENAI_API_KEY 가 없어도 DEEPGRAM_API_KEY 만 있으면 Deepgram 으로 STT 동작. 둘 다 없으면 mock 유지 (안전한 fallback).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
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.
Summary
Sprint 3 — 종합 피드백(US-24) + RAG 검색 활성화 + 음성 면접 풀스택 구현
주요 변경
→ AnswerSubmittedEvent → 기존 followup 흐름 재사용)