Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +929,12 @@ def to_bps(x):
sad = to_bps(probs.get("sad", 0))
neutral = to_bps(probs.get("neutral", 0))
angry = to_bps(probs.get("angry", 0))
fear = to_bps(probs.get("fear", 0))
# preview API에서도 fear/anxiety 계열을 합산해서 fear_bps로 보여준다.
fear_prob = (
float(probs.get("fear", 0) or 0)
+ float(probs.get("anxiety", 0) or 0)
)
fear = to_bps(fear_prob)
Comment on lines +933 to +937
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
surprise = to_bps(probs.get("surprise", 0))
total = happy + sad + neutral + angry + fear + surprise
if total == 0:
Expand Down
2 changes: 1 addition & 1 deletion app/services/analyze_chat_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ async def _send_to_chatbot(
raise InternalServerException("CHATBOT_API_URL not configured")

try:
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

  1. Adding a comment explaining why this timeout increase was necessary
  2. Monitoring the actual response times to ensure they don't consistently approach the timeout
  3. 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:
Suggested change
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.

Copilot uses AI. Check for mistakes.
async with httpx.AsyncClient(timeout=30.0) as client:
async with httpx.AsyncClient(timeout=60.0) as client:
response = await client.post(
chatbot_url,
json=request_payload,
Expand Down
18 changes: 17 additions & 1 deletion app/services/va_fusion.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ def apply_zero_prob_mask(

def fuse_VA(audio_probs: Dict[str, float], text_score: float, text_magnitude: float) -> Dict[str, object]:
"""Fuse audio (emotion probabilities) and text (score,magnitude) into composite VA.

Returns dict with keys:
- V_final, A_final, intensity, V_audio, A_audio, V_text, A_text, alpha, beta (float)
- per_emotion_bps (dict[str,int], sum=10000), top_emotion (str), top_confidence_bps (int)
Expand Down Expand Up @@ -273,6 +273,22 @@ def fuse_VA(audio_probs: Dict[str, float], text_score: float, text_magnitude: fl
t_sc = float(text_emotion_weight.get(emo, 0.0))
composite_score[emo] = alpha_prob * a_sc + beta_prob * t_sc

# Audio에서 분노 비율이 매우 낮은 경우(angry_bps <= 2000 → angry_prob <= 0.2),
# voice_composite에서 분노가 과도하게 top으로 나오는 것을 방지하기 위해
# audio angry 정보의 최종 기여도를 완만하게 줄인다.
try:
angry_p = float(audio_probs.get("angry", 0.0))
if angry_p <= 0.2:
neg = max(0.0, -float(v_text))
mag = max(0.0, min(1.0, float(a_text)))
base_factor = 0.7
extra_down = 0.15 * neg * mag # 최대 약 0.15 추가 감쇠
factor = max(0.5, base_factor - extra_down) # 최소 0.5배까지
composite_score["angry"] = composite_score.get("angry", 0.0) * factor
except Exception:
# 로직 실패 시에는 안전하게 무시
pass
Comment on lines +288 to +290
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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))
    pass

This helps with debugging and monitoring the stability of this emotion adjustment algorithm.

Copilot uses AI. Check for mistakes.

# 감정별 가중치 조정: neutral은 더 강하게 억제(긍정일수록 추가 억제)
neutral_base_factor = 0.6
if v_text > 0:
Expand Down
9 changes: 8 additions & 1 deletion app/voice_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,14 @@ def to_bps(v: float) -> int:
sad = to_bps(probs.get("sad", probs.get("sadness", 0)))
neutral = to_bps(probs.get("neutral", 0))
angry = to_bps(probs.get("angry", probs.get("anger", 0)))
fear = to_bps(probs.get("fear", probs.get("fearful", 0)))
# fear_bps 컬럼에는 'fear' + 'anxiety' 계열을 모두 합산해서 저장한다.
# emotion_service에서 "불안"은 anxiety, "두려움/공포"는 fear 로 매핑되므로 둘을 같은 버킷으로 취급.
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)
Comment on lines +459 to +464
Copy link

Copilot AI Dec 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copilot uses AI. Check for mistakes.
surprise = to_bps(probs.get("surprise", probs.get("surprised", 0)))

# 모델 응답 키 보정: emotion_service는 기본적으로 "emotion"을 반환
Expand Down