Spaces:
Running
Running
File size: 5,550 Bytes
24f95f0 5f91e0b 24f95f0 5f91e0b 24f95f0 5f91e0b 24f95f0 5f91e0b 24f95f0 5f91e0b 24f95f0 5f91e0b | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | """
Dissonance Engine β Unit / Integration Tests.
Tests the engine at three levels:
1. Pure logic: VAD projection and cosine divergence (no models needed)
2. API shape: dissonance_engine.analyze() returns expected keys (no models)
3. Calibration: refine_with_dataset() triggers CMU-MOSEI + CREMA-D lookup
Run from repo root:
cd backend && python3 tests/test_dissonance.py
"""
import logging
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("test_dissonance")
# ---------------------------------------------------------------------------
# Phase 1: Pure logic β VAD projection + cosine divergence (no models needed)
# ---------------------------------------------------------------------------
def test_vad_projection():
print("\nβββ Phase 1: VAD Projection Logic βββ")
import numpy as np
import scipy.spatial.distance as dist
from app.services.dissonance_engine import _probs_to_vad, EMOTION_TO_VAD
# Simulate: audio says "angry", text says "joy" β should be highly dissonant
audio_probs = {"angry": 0.8, "neutral": 0.1, "happy": 0.1}
text_probs = {"joy": 0.85, "love": 0.1, "surprise": 0.05}
audio_vad = _probs_to_vad(audio_probs)
text_vad = _probs_to_vad(text_probs)
score = float(dist.cosine(audio_vad, text_vad))
print(f" audio_vad = {audio_vad.round(3)}")
print(f" text_vad = {text_vad.round(3)}")
print(f" cosine div = {score:.4f}")
assert score > 0.08, f"Expected meaningful divergence for angry vs joy, got {score:.4f}"
print(" β
Meaningful divergence confirmed for angry-audio vs joy-text")
# Same emotion β near-zero divergence
audio_probs2 = {"happy": 0.9, "neutral": 0.1}
text_probs2 = {"joy": 0.9, "surprise": 0.1}
audio_vad2 = _probs_to_vad(audio_probs2)
text_vad2 = _probs_to_vad(text_probs2)
score2 = float(dist.cosine(audio_vad2, text_vad2))
print(f" happy-vs-joy cosine div = {score2:.4f}")
assert score2 < 0.05, f"Expected near-zero divergence for happy vs joy, got {score2:.4f}"
print(" β
Near-zero divergence confirmed for happy-audio vs joy-text")
# ---------------------------------------------------------------------------
# Phase 2: Engine init β no models, check env config and threshold
# ---------------------------------------------------------------------------
def test_engine_init():
print("\nβββ Phase 2: Engine Config & Threshold βββ")
from app.services.dissonance_engine import dissonance_engine
print(f" Initial threshold = {dissonance_engine.dissonance_threshold}")
print(f" Audio temperature T = {dissonance_engine.audio_temperature}")
print(f" Fusion weights = ({dissonance_engine.w_audio_text}, "
f"{dissonance_engine.w_prosody}, {dissonance_engine.w_text_conf})")
assert dissonance_engine.dissonance_threshold == 0.5
assert dissonance_engine.audio_temperature == 1.5
assert abs(dissonance_engine.w_audio_text + dissonance_engine.w_prosody
+ dissonance_engine.w_text_conf - 1.0) < 0.01, \
"Fusion weights should sum to ~1.0"
print(" β
Config OK")
# ---------------------------------------------------------------------------
# Phase 3: Dataset calibration (network call β may be skipped in CI)
# ---------------------------------------------------------------------------
def test_engine_calibration(skip_network: bool = False):
print("\nβββ Phase 3: Dataset Calibration (CMU-MOSEI + CREMA-D) βββ")
from app.services.dissonance_engine import dissonance_engine
before = dissonance_engine.dissonance_threshold
if skip_network:
print(" β οΈ Skipping network call (skip_network=True)")
return
dissonance_engine.refine_with_dataset()
after = dissonance_engine.dissonance_threshold
print(f" Before: {before} β After: {after}")
# If datasets were reachable, threshold should drop to 0.35
# If not reachable, it stays at its current value β both are fine
print(" β
Calibration completed (result depends on network access)")
# ---------------------------------------------------------------------------
# Phase 4: MMSA engine singleton check
# ---------------------------------------------------------------------------
def test_mmsa_wiring():
print("\nβββ Phase 4: MMSA β DissonanceEngine Wiring βββ")
from app.services.mmsa_engine import mmsa_engine
from app.services.dissonance_engine import dissonance_engine
# Verify mmsa_engine holds a reference to the same singleton
import app.services.mmsa_engine as mmsa_mod
assert hasattr(mmsa_mod, "dissonance_engine"), \
"mmsa_engine module must import dissonance_engine"
assert mmsa_mod.dissonance_engine is dissonance_engine, \
"mmsa_engine must use the same dissonance_engine singleton"
print(" β
mmsa_engine is wired to dissonance_engine singleton")
if __name__ == "__main__":
try:
test_vad_projection()
test_engine_init()
test_engine_calibration(skip_network="--skip-network" in sys.argv)
test_mmsa_wiring()
print("\nβ
All dissonance tests passed.")
except AssertionError as e:
print(f"\nβ Assertion failed: {e}")
sys.exit(1)
except Exception as e:
import traceback
print(f"\nβ Test error: {e}")
traceback.print_exc()
sys.exit(1)
|