Conversation
둘러보기이 변경사항은 음성 파일 처리 파이프라인을 확장하여 S3 업로드, 생성된 URL 지원, 향상된 STT 서비스 및 정서 분석 로직을 추가합니다. 두려움/불안감 확률 집계, 챗봇 통합 개선, 상세한 로깅 및 파일 검증 기능이 포함됩니다. 변경사항
시퀀스 다이어그램sequenceDiagram
participant Client
participant AnalyzeChatService
participant S3Service
participant STTService
participant VoiceService
participant ChatbotIntegration
participant S3 as AWS S3
participant SQS as AWS SQS
Client->>AnalyzeChatService: 음성 파일 업로드
AnalyzeChatService->>AnalyzeChatService: 파일 확장자/컨텐츠 타입 검증
AnalyzeChatService->>AnalyzeChatService: 파일 읽기 및 크기 검증
AnalyzeChatService->>VoiceService: WAV 변환 (스레드)
VoiceService->>VoiceService: m4a/mp4 헤더 검증
VoiceService-->>AnalyzeChatService: WAV 컨텐츠 반환
AnalyzeChatService->>S3Service: WAV 파일 S3 업로드
S3Service->>S3: 파일 업로드
S3-->>S3Service: 업로드 확인
S3Service->>S3Service: 생성된 URL 생성 (7일 만료)
S3Service-->>AnalyzeChatService: s3_url 반환
AnalyzeChatService->>STTService: STT 처리 (WAV 컨텐츠)
STTService->>STTService: 음성 전처리 (단일채널, 16kHz)
STTService-->>AnalyzeChatService: 텍스트 및 신뢰도 반환
AnalyzeChatService->>VoiceService: 정서 분석
VoiceService->>VoiceService: 두려움+불안감 집계
VoiceService-->>AnalyzeChatService: 정서 데이터 반환
AnalyzeChatService->>ChatbotIntegration: STT, 정서, s3_url 전달
ChatbotIntegration->>ChatbotIntegration: SQS 메시지 본문 생성 (s3_url 포함)
ChatbotIntegration->>SQS: 메시지 전송
SQS-->>ChatbotIntegration: 확인
ChatbotIntegration-->>AnalyzeChatService: 성공 응답
AnalyzeChatService-->>Client: 결과 반환
예상 코드 리뷰 노력🎯 4 (복잡함) | ⏱️ ~60분 추가 주의가 필요한 영역:
관련 PR
제안 레이블
제안 리뷰어
시
Pre-merge checks and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (10)
app/services/va_fusion.py (1)
276-291: 빈except: pass블록은 디버깅을 어렵게 만듭니다.현재 구현은 모든 예외를 무시합니다. 문제가 발생해도 로그가 남지 않아 추후 디버깅이 어려워질 수 있습니다.
최소한 경고 로그를 남기는 것을 권장합니다:
except Exception: - # 로직 실패 시에는 안전하게 무시 - pass + # 로직 실패 시 경고 로그 남기고 안전하게 무시 + import logging + logging.getLogger(__name__).warning( + "Angry dampening logic failed, skipping adjustment", + exc_info=True + )또는 모듈 상단에
logger를 정의하고 사용하는 것이 더 좋습니다.app/stt_service.py (2)
88-114:robust_load함수가emotion_service.py와 중복됩니다.이 함수는
app/emotion_service.py(lines 73-95)에 있는robust_load와 거의 동일한 구현입니다. 코드 중복을 줄이기 위해 공통 유틸리티로 추출하는 것을 고려해 주세요.예를 들어
app/utils/audio_utils.py에 공통 함수를 정의할 수 있습니다:# app/utils/audio_utils.py def robust_load(path: str, target_sr: int = 16000, logger=None): """soundfile 우선, 실패 시 librosa로 폴백. 모노, 정규화 반환.""" # 공통 구현 ...
196-202: 예외 메시지 포맷 개선 가능
str(e)대신!s변환 플래그를 사용하면 더 명시적입니다.- return { - "error": f"STT 처리 중 오류 발생: {str(e)}", + return { + "error": f"STT 처리 중 오류 발생: {e!s}",app/main.py (1)
923-927:to_bps함수가 여러 곳에서 중복 정의되어 있습니다.이 함수가
app/voice_service.py(lines 445-449)에도 동일하게 정의되어 있습니다. 공통 유틸리티로 추출하면 유지보수가 용이해집니다.예를 들어
app/utils/conversion.py에 정의할 수 있습니다:# app/utils/conversion.py def to_bps(v: float) -> int: """float 값을 bps(basis points, 0-10000) 단위로 변환""" try: return max(0, min(10000, int(round(float(v) * 10000)))) except Exception: return 0app/voice_service.py (1)
46-58: 헤더 검증 및 로깅 추가가 적절합니다.M4A/MP4 파일의 ftyp atom 검증과 경고 로깅은 손상된 파일을 조기에 감지하는 데 유용합니다. 다만 57번 라인의 f-string에 플레이스홀더가 없습니다.
- print(f"[convert] WARNING: M4A 파일이지만 ftyp atom이 없음, 손상된 파일일 수 있음") + print("[convert] WARNING: M4A 파일이지만 ftyp atom이 없음, 손상된 파일일 수 있음")app/services/chatbot_integration.py (1)
19-19:Depends(get_db)가 일반 함수에서 사용되고 있습니다.
send_analysis_to_chatbot함수에서db: Session = Depends(get_db)를 기본값으로 사용하고 있지만, 이 함수는 FastAPI 엔드포인트가 아닙니다. 현재 코드에서는 호출 시db를 명시적으로 전달하고 있어 동작에는 문제가 없지만, 시그니처가 오해를 불러일으킬 수 있습니다.-def send_analysis_to_chatbot(voice_id: int, db: Session = Depends(get_db)): +def send_analysis_to_chatbot(voice_id: int, db: Session):app/services/analyze_chat_service.py (4)
71-71:not in연산자를 사용하세요.정적 분석 도구에서 지적한 대로,
not '.' in filename대신'.' not in filename을 사용해야 합니다.- if not '.' in filename or (not lower_name.endswith('.wav') and not lower_name.endswith('.m4a')): + if '.' not in filename or (not lower_name.endswith('.wav') and not lower_name.endswith('.m4a')):
113-118:_transcribe_audio에 전달된content_type파라미터가 사용되지 않습니다.
content_type을 전달하지만_transcribe_audio메서드 내부에서는filename기반으로 content_type을 결정합니다(line 180). 파라미터를 제거하거나 실제로 사용하도록 수정해주세요.content = await asyncio.to_thread( self._transcribe_audio, wav_content, - wav_filename, - content_type + wav_filename )메서드 시그니처도 함께 수정:
def _transcribe_audio( self, file_content: bytes, - filename: str, - content_type: str + filename: str ) -> str:
172-174: INFO 수준 로그에 WARNING 레벨 사용은 권장되지 않습니다.주석에서 "INFO 레벨은 출력되지 않을 수 있으므로 WARNING으로"라고 설명하지만, 이는 로깅 설정 문제입니다. WARNING 로그를 오염시키는 대신 로거 설정을 수정하여 INFO 레벨이 출력되도록 하는 것이 올바른 접근입니다.
- # INFO 레벨은 기본 로거 설정에 따라 출력되지 않을 수 있으므로 WARNING으로 남겨 확실히 보이게 한다. - logger.warning("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type) + logger.info("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type)
281-282: 명시적으로Optional[str]을 사용하세요.PEP 484에 따르면 암시적 Optional은 권장되지 않습니다. 코딩 가이드라인에서도 "Use
Optional[Type]for nullable values"를 요구합니다.파일 상단 imports에
Optional추가:from typing import Dict, Any, Optional그리고 파라미터 수정:
- s3_url: str = None # [추가] + s3_url: Optional[str] = None # [추가]
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
app/main.py(1 hunks)app/services/analyze_chat_service.py(8 hunks)app/services/chatbot_integration.py(3 hunks)app/services/va_fusion.py(2 hunks)app/stt_service.py(3 hunks)app/voice_service.py(3 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.py
📄 CodeRabbit inference engine (.cursorrules)
**/*.py: Always useDepends(get_db)to inject database sessions into FastAPI endpoints; never usenext(get_db())as it causes connection leaks by preventing the finally block from executing
Never directly instantiate Service or Repository in endpoints; always use FastAPI'sDepends()for dependency injection with dependency functions namedget_{service_name}_deporget_{repo_name}_dep
Never create database sessions directly usingSessionLocal(); sessions must only be created through theget_dbdependency function at the endpoint level
Useasync deffor all FastAPI endpoint functions
Define explicitresponse_modelparameter in FastAPI endpoints using Pydantic models
Organize imports in the following order: (1) standard library, (2) third-party libraries, (3) local modules
Usesnake_casefor endpoint function names,PascalCasefor class names, andUPPER_SNAKE_CASEfor constants
Add docstrings to all functions and complex logic comments in the code
Store sensitive information such as database credentials in environment variables, never hardcode them
Use custom exceptions inheriting fromAppExceptionbase class for consistent error handling and response formatting
Use global exception handlers to catchSQLAlchemyErrorand ensure consistent error response format for database errors
Use type hints on all function parameters and return values
UseOptional[Type]for nullable values and explicitly handleNonecases in code
Use Pydantic models for all request and response data transfer objects (DTOs)
Setautocommit=Falseand explicitly callcommit()for database transactions; callrollback()on exception to ensure data integrity
Use dependency function chaining: Session (top-level) → Service/Repository → endpoint injection
UseAnnotatedwithDependsfor complex dependency scenarios to improve code clarity and reduce repetition
Use streaming for large file processing to avoid excessive memory consumption
Monitor and log memory usage u...
Files:
app/main.pyapp/services/va_fusion.pyapp/services/chatbot_integration.pyapp/services/analyze_chat_service.pyapp/voice_service.pyapp/stt_service.py
**/services/**/*.py
📄 CodeRabbit inference engine (.cursorrules)
**/services/**/*.py: Define dependency functions in service and repository files or in a dedicateddependencies.pyfile with explicit type hints for all Service and Repository dependencies
Business logic and Service functions must be located in theservices/directory and receive database sessions through constructor parameters or function parameters, not by direct creation
Files:
app/services/va_fusion.pyapp/services/chatbot_integration.pyapp/services/analyze_chat_service.py
🧬 Code graph analysis (5)
app/main.py (1)
app/voice_service.py (1)
to_bps(446-450)
app/services/chatbot_integration.py (2)
app/s3_service.py (1)
get_presigned_url(45-57)app/exceptions.py (1)
InternalServerException(37-40)
app/services/analyze_chat_service.py (4)
app/s3_service.py (2)
upload_fileobj(26-32)get_presigned_url(45-57)app/auth_service.py (1)
get_auth_service(297-299)app/voice_service.py (2)
get_voice_service(953-955)_convert_to_wav(37-176)app/main.py (1)
FileWrapper(915-919)
app/voice_service.py (1)
app/main.py (1)
to_bps(923-927)
app/stt_service.py (1)
app/emotion_service.py (1)
robust_load(74-96)
🪛 Ruff (0.14.6)
app/services/va_fusion.py
288-290: try-except-pass detected, consider logging the exception
(S110)
288-288: Do not catch blind exception: Exception
(BLE001)
app/services/chatbot_integration.py
70-70: Consider moving this statement to an else block
(TRY300)
app/services/analyze_chat_service.py
71-71: Test for membership should be not in
Convert to not in
(E713)
282-282: PEP 484 prohibits implicit Optional
Convert to T | None
(RUF013)
app/voice_service.py
57-57: f-string without any placeholders
Remove extraneous f prefix
(F541)
app/stt_service.py
101-101: Do not catch blind exception: Exception
(BLE001)
199-199: Use explicit conversion flag
Replace with conversion flag
(RUF010)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Agent
🔇 Additional comments (8)
app/stt_service.py (1)
217-223: 모듈 레벨 인스턴스 생성 확인
stt_service = GoogleSTTService()가 모듈 임포트 시점에 실행됩니다. Google 인증 정보가 없으면client가None이 되어도 예외가 발생하지 않으므로 현재 구현은 안전합니다.app/main.py (1)
932-937: fear/anxiety 합산 로직이 일관성 있게 적용되었습니다.
voice_service.py의 변경사항과 일관되게 fear와 anxiety를 합산하여 처리하고 있습니다.app/voice_service.py (2)
77-83:fsync호출과 크기 검증이 파일 쓰기 신뢰성을 높입니다.임시 파일에 대한 강제 동기화와 쓰기 후 크기 검증은 데이터 무결성을 보장하는 좋은 방어적 프로그래밍입니다.
457-464: fear 관련 감정 통합 처리가 적절합니다.
fear,anxiety,fearful을 모두 합산하여fear_bps에 저장하는 것은 감정 모델의 출력을 일관되게 처리하는 합리적인 접근입니다.app/main.py와 일관성이 유지됩니다.app/services/chatbot_integration.py (2)
60-65: Presigned URL의 7일 만료 기간을 확인해 주세요.
expires_in=3600 * 24 * 7(7일)은 상당히 긴 기간입니다. 보안 요구사항에 따라 이 값이 적절한지 확인이 필요합니다. 또한get_presigned_url이 실패하면 빈 문자열을 반환하므로, 이 경우s3_url이 빈 문자열이 될 수 있습니다.# 현재 구현에서 get_presigned_url 실패 시 빈 문자열 반환 # s3_url이 "" (빈 문자열)인 경우와 None인 경우를 구분할 필요가 있는지 검토 if bucket and voice.voice_key: s3_url = get_presigned_url(bucket, voice.voice_key, expires_in=3600 * 24 * 7) if not s3_url: logger.warning(f"Failed to generate presigned URL for voice_id={voice_id}")
107-114: 메시지 페이로드 구조가 명확하게 개선되었습니다.사용자 이름, 질문, 콘텐츠, 녹음 시간, S3 URL, 감정 데이터가 포함된 페이로드는 챗봇 측에서 풍부한 컨텍스트를 활용할 수 있게 합니다.
app/services/analyze_chat_service.py (2)
106-110: Presigned URL 만료 시간이 7일로 설정되어 있습니다.
expires_in=3600 * 24 * 7은 7일입니다. 보안상 민감한 음성 파일의 URL이 7일간 유효한 것이 의도된 것인지 확인해주세요. 일반적으로 1시간(3600초) 정도가 적절합니다.
328-330: LGTM!의존성 함수가 코딩 가이드라인의
get_{service_name}_dep패턴을 따르고 있으며, 다른 서비스(get_auth_service, get_voice_service)와 일관된 구조입니다.
| s3_key = await asyncio.to_thread( | ||
| self._upload_to_s3, | ||
| file_content, | ||
| filename, | ||
| wav_content, | ||
| wav_filename, | ||
| session_id, | ||
| user_id, | ||
| file.content_type | ||
| content_type | ||
| ) |
There was a problem hiding this comment.
S3 업로드 시 Content-Type 불일치 버그.
wav_content(WAV 변환된 파일)를 업로드하면서 원본 파일의 content_type(예: audio/m4a)을 전달하고 있습니다. WAV 파일을 업로드하므로 content_type은 "audio/wav"여야 합니다.
s3_key = await asyncio.to_thread(
self._upload_to_s3,
wav_content,
wav_filename,
session_id,
user_id,
- content_type
+ "audio/wav"
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| s3_key = await asyncio.to_thread( | |
| self._upload_to_s3, | |
| file_content, | |
| filename, | |
| wav_content, | |
| wav_filename, | |
| session_id, | |
| user_id, | |
| file.content_type | |
| content_type | |
| ) | |
| s3_key = await asyncio.to_thread( | |
| self._upload_to_s3, | |
| wav_content, | |
| wav_filename, | |
| session_id, | |
| user_id, | |
| "audio/wav" | |
| ) |
🤖 Prompt for AI Agents
In app/services/analyze_chat_service.py around lines 97 to 104, the code uploads
wav_content but passes the original file's content_type (e.g., audio/m4a);
override or set the content_type to "audio/wav" when calling self._upload_to_s3
so the S3 object has the correct MIME type; update the caller to pass
content_type="audio/wav" (or assign a local variable content_type = "audio/wav"
before the await) and ensure downstream code that relies on content_type uses
the overridden value.
There was a problem hiding this comment.
Pull request overview
This PR includes fine-tuning adjustments for emotion analysis parameters and timeout configurations discovered during demo video recording. The changes focus on improving audio file handling, emotion analysis accuracy, and integration with external chatbot services.
Key Changes:
- Enhanced emotion analysis by aggregating fear/anxiety emotions into a single category for more accurate representation
- Improved audio file processing with better M4A header validation and file synchronization
- Extended STT transcript aggregation to combine all recognition results and added comprehensive logging
- Added S3 presigned URL generation for audio files sent to chatbot services
- Increased external API timeout from 30s to 60s to accommodate processing latency
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
app/voice_service.py |
Added M4A file header validation, file sync operations, and fear/anxiety emotion aggregation; includes debug print statements |
app/stt_service.py |
Enhanced with structured logging throughout STT pipeline, improved audio configuration (channel count, emoji handling), and full transcript aggregation from all results |
app/services/va_fusion.py |
Implemented angry emotion dampening logic to prevent over-representation when audio angry levels are low |
app/services/chatbot_integration.py |
Added S3 presigned URL generation for voice files and cleaned up documentation structure |
app/services/analyze_chat_service.py |
Improved file validation, added WAV conversion before processing, S3 URL generation, extended chatbot API timeout, and enhanced logging |
app/main.py |
Applied consistent fear/anxiety emotion aggregation in preview API to match changes in voice_service |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| else: | ||
| filename = (filename.rsplit('.', 1)[0] if '.' in filename else filename) + ".wav" | ||
|
|
||
| # 4. 파일 읽기 및 WAV 변환 (비동기로 처리하여 블로킹 방지) |
There was a problem hiding this comment.
This comment appears to be a leftover from a previous numbering scheme. The comment says "4. 파일 읽기 및 WAV 변환" (4. File reading and WAV conversion), but there are no preceding steps labeled 1, 2, and 3 in the visible code. This is misleading.
Either update the comment to reflect the actual step sequence or remove the numbering altogether. For example:
# 파일 읽기 및 WAV 변환 (비동기로 처리하여 블로킹 방지)| # 4. 파일 읽기 및 WAV 변환 (비동기로 처리하여 블로킹 방지) | |
| # 파일 읽기 및 WAV 변환 (비동기로 처리하여 블로킹 방지) |
| except Exception: | ||
| # 로직 실패 시에는 안전하게 무시 | ||
| pass |
There was a problem hiding this comment.
Silent exception handling without any logging or error indication is problematic. If the angry emotion dampening logic fails, it will silently fall back to the original behavior without any indication of what went wrong.
At minimum, add logging to track when this logic fails:
except Exception as e:
# 로직 실패 시에는 안전하게 무시
logger.debug("Angry dampening logic failed: %s", str(e))
passThis helps with debugging and monitoring the stability of this emotion adjustment algorithm.
| fear_prob = ( | ||
| float(probs.get("fear", 0) or 0) | ||
| + float(probs.get("anxiety", 0) or 0) | ||
| + float(probs.get("fearful", 0) or 0) | ||
| ) | ||
| fear = to_bps(fear_prob) |
There was a problem hiding this comment.
The fear/anxiety aggregation logic could produce probabilities exceeding 1.0 before conversion to BPS. While to_bps() clips the result to a max of 10000, this aggregation means the total emotion probabilities could exceed 100% before normalization.
For example, if fear=0.3, anxiety=0.4, and fearful=0.4, the sum would be 1.1 (110%), which gets converted to 11000 BPS. The to_bps() function clips this to 10000, but this could skew the emotion distribution before the later normalization step.
Consider capping the aggregated probability before conversion:
fear_prob = min(1.0,
float(probs.get("fear", 0) or 0)
+ float(probs.get("anxiety", 0) or 0)
+ float(probs.get("fearful", 0) or 0)
)
fear = to_bps(fear_prob)This ensures the aggregated probability stays within valid probability bounds before BPS conversion.
| fear_prob = ( | ||
| float(probs.get("fear", 0) or 0) | ||
| + float(probs.get("anxiety", 0) or 0) | ||
| ) | ||
| fear = to_bps(fear_prob) |
There was a problem hiding this comment.
Similar to the issue in voice_service.py, this fear/anxiety aggregation could produce probabilities exceeding 1.0. If both fear and anxiety probabilities are present and sum to more than 1.0, this creates an invalid probability distribution.
Consider capping the aggregated value:
fear_prob = min(1.0,
float(probs.get("fear", 0) or 0)
+ float(probs.get("anxiety", 0) or 0)
)
fear = to_bps(fear_prob)This ensures the aggregated probability stays within valid bounds before BPS conversion.
| for result in response.results | ||
| if result.alternatives[0].confidence > 0 | ||
| ] | ||
| # TODO : 추후 Confidence가 낮으면 인식에서 제외하는 로직 추가 |
There was a problem hiding this comment.
[nitpick] The TODO comment indicates planned functionality for filtering low-confidence results, but this is a behavior change that should be carefully considered. Currently, all transcription results are included regardless of confidence level.
If this TODO is implemented, ensure:
- There's a clear threshold for what constitutes "low confidence"
- Users are informed when parts of their audio are excluded from the transcript
- The confidence threshold is configurable
- There's appropriate logging when segments are filtered out
Consider the user experience impact - it might be better to return all transcripts with confidence scores and let the caller decide whether to use them, rather than silently filtering.
| # TODO : 추후 Confidence가 낮으면 인식에서 제외하는 로직 추가 | |
| # WARNING: Filtering out low-confidence results is a significant behavior change. | |
| # If implementing such filtering, ensure: | |
| # 1. The confidence threshold is clearly defined and configurable. | |
| # 2. Users are informed when parts of their audio are excluded from the transcript. | |
| # 3. There is appropriate logging when segments are filtered out. | |
| # 4. Consider returning all transcripts with confidence scores and letting the caller decide. |
| if not '.' in filename or (not lower_name.endswith('.wav') and not lower_name.endswith('.m4a')): | ||
| if "m4a" in content_type or "mp4" in content_type: | ||
| filename = (filename.rsplit('.', 1)[0] if '.' in filename else filename) + ".m4a" | ||
| else: | ||
| filename = (filename.rsplit('.', 1)[0] if '.' in filename else filename) + ".wav" |
There was a problem hiding this comment.
[nitpick] The file extension validation logic has redundant conditions. Line 71 checks if not '.' in filename, but then immediately uses the same condition if '.' in filename within the conditional block.
This can be simplified for clarity:
# 확장자 미포함/이상치인 경우 Content-Type 기반으로 보정
if not lower_name.endswith('.wav') and not lower_name.endswith('.m4a'):
base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename
if "m4a" in content_type or "mp4" in content_type:
filename = base_name + ".m4a"
else:
filename = base_name + ".wav"This makes the intent clearer: if the file doesn't have a valid audio extension, correct it based on content type.
| if not '.' in filename or (not lower_name.endswith('.wav') and not lower_name.endswith('.m4a')): | |
| if "m4a" in content_type or "mp4" in content_type: | |
| filename = (filename.rsplit('.', 1)[0] if '.' in filename else filename) + ".m4a" | |
| else: | |
| filename = (filename.rsplit('.', 1)[0] if '.' in filename else filename) + ".wav" | |
| if not lower_name.endswith('.wav') and not lower_name.endswith('.m4a'): | |
| base_name = filename.rsplit('.', 1)[0] if '.' in filename else filename | |
| if "m4a" in content_type or "mp4" in content_type: | |
| filename = base_name + ".m4a" | |
| else: | |
| filename = base_name + ".wav" |
| # INFO 레벨은 기본 로거 설정에 따라 출력되지 않을 수 있으므로 WARNING으로 남겨 확실히 보이게 한다. | ||
| logger.warning("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type) |
There was a problem hiding this comment.
Inconsistent logging practice: This warning-level log is used in a place where info-level logging would be more appropriate. The comment suggests using WARNING level "so it's definitely visible", but this circumvents the logging framework's purpose.
If you need to ensure certain logs are visible, configure the logger's level appropriately rather than artificially elevating the severity. This log statement is just tracking the start of an STT operation, which is informational, not a warning condition:
logger.info("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type)If visibility is truly a concern, consider using a dedicated logger configuration for this module rather than misusing log levels.
| # INFO 레벨은 기본 로거 설정에 따라 출력되지 않을 수 있으므로 WARNING으로 남겨 확실히 보이게 한다. | |
| logger.warning("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type) | |
| # STT 변환 시작 - 정보성 로그 | |
| logger.info("AnalyzeChat STT 시작 - filename=%s, content_type=%s", filename, content_type) |
| @@ -253,7 +299,7 @@ | |||
| raise InternalServerException("CHATBOT_API_URL not configured") | |||
|
|
|||
| try: | |||
There was a problem hiding this comment.
The timeout has been increased from 30.0 to 60.0 seconds without explanation. While this might resolve timeout issues, it could also mask performance problems or hide issues with the external chatbot API.
Consider:
- Adding a comment explaining why this timeout increase was necessary
- Monitoring the actual response times to ensure they don't consistently approach the timeout
- Ensuring the external API has appropriate performance expectations documented
Example:
# Increased timeout to 60s due to chatbot API processing latency for emotion analysis
async with httpx.AsyncClient(timeout=60.0) as client:| try: | |
| try: | |
| # Increased timeout to 60s due to observed latency with the external chatbot API. | |
| # Consider monitoring response times and reviewing this value if performance issues persist. |
| "[GoogleSTT] STT 요청 구성 완료 - sample_rate=%d, model=%s, enhanced=%s", | ||
| sample_rate, | ||
| "latest_long", | ||
| "enabled", |
There was a problem hiding this comment.
The log message shows enhanced=%s with a hardcoded string "enabled", but there's no indication that any enhancement is actually enabled in the configuration. The RecognitionConfig doesn't have an explicit use_enhanced parameter set.
This is misleading logging. Either:
- Remove the
enhanced=%sparameter from the log message if no enhancement is being used - Add actual enhancement configuration if it's intended
Example fix:
logger.info(
"[GoogleSTT] STT 요청 구성 완료 - sample_rate=%d, model=%s",
sample_rate,
"latest_long",
)| "[GoogleSTT] STT 요청 구성 완료 - sample_rate=%d, model=%s, enhanced=%s", | |
| sample_rate, | |
| "latest_long", | |
| "enabled", | |
| "[GoogleSTT] STT 요청 구성 완료 - sample_rate=%d, model=%s", | |
| sample_rate, | |
| "latest_long", |
|
테스트 시연 수고하셨습니다! 👍 |
🔎 Description
🔗 Related Issue
🏷️ What type of PR is this?
📋 Changes Made
🧪 Testing
📸 Screenshots (if applicable)
📝 Additional Notes
Summary by CodeRabbit
릴리스 노트
새로운 기능
버그 수정
개선사항
✏️ Tip: You can customize this high-level summary in your review settings.