intrect's picture
feat(space): CPU ONNX runtime build (v9.4, full-song sliding aggregation)
0020ddc
raw
history blame
6.72 kB
# Created: 2026-03-07
# Purpose: Radar chart for 7-channel forensic features
# Dependencies: plotly, numpy
"""Radar chart visualization for 7 forensic audio features."""
import numpy as np
import plotly.graph_objects as go
def plot_forensic_radar(feature_stats: dict) -> go.Figure:
"""7개 ν¬λ Œμ‹ ν”Όμ²˜λ₯Ό λ ˆμ΄λ” 차트둜 μ‹œκ°ν™”.
Args:
feature_stats: Dict with feature names as keys and normalized values (0-1)
Returns:
plotly Figure (radar/polar chart)
"""
# 7개 ν¬λ Œμ‹ ν”Όμ²˜ μ •μ˜
features = [
("Residual Energy", "μž”μ°¨ μ—λ„ˆμ§€ (AI 코덱 흔적)"),
("Harmonic Strength", "ν•˜λͺ¨λ‹‰ 강도 (μŒμ•… ꡬ쑰)"),
("Percussive Strength", "타악기 강도 (리듬 μš”μ†Œ)"),
("Temporal Delta", "μ‹œκ°„ λ³€ν™”μœ¨ (λ‹€μ΄λ‚˜λ―ΉμŠ€)"),
("Temporal Accel", "μ‹œκ°„ 가속도 (λ³€ν™” 일관성)"),
("H/P Ratio", "ν•˜λͺ¨λ‹‰/타악기 λΉ„μœ¨"),
("Spectral Flux", "μŠ€νŽ™νŠΈλŸΌ λ³€ν™”λŸ‰ (질감)"),
]
# κΈ°λ³Έκ°’ (feature_statsκ°€ μ—†μœΌλ©΄ 쀑간값)
if not feature_stats:
values = [0.5] * 7
else:
values = [
feature_stats.get("residual_energy", 0.5),
feature_stats.get("harmonic_strength", 0.5),
feature_stats.get("percussive_strength", 0.5),
feature_stats.get("temporal_delta", 0.5),
feature_stats.get("temporal_accel", 0.5),
feature_stats.get("hp_ratio", 0.5),
feature_stats.get("spectral_flux", 0.5),
]
# λ ˆμ΄λ” 차트용 데이터 (첫 값을 λ§ˆμ§€λ§‰μ— λ°˜λ³΅ν•΄μ„œ 폐곑선 생성)
categories = [f[0] for f in features]
values_closed = values + [values[0]]
categories_closed = categories + [categories[0]]
fig = go.Figure()
# ν˜„μž¬ μ˜€λ””μ˜€ νŒ¨ν„΄
fig.add_trace(go.Scatterpolar(
r=values_closed,
theta=categories_closed,
fill='toself',
fillcolor='rgba(255, 71, 87, 0.3)',
line=dict(color='#ff4757', width=2),
name='Audio Pattern',
hovertemplate="<b>%{theta}</b><br>Score: %{r:.2f}<extra></extra>"
))
fig.update_layout(
polar=dict(
radialaxis=dict(
visible=True,
range=[0, 1],
tickfont=dict(size=10, color='#aaa'),
gridcolor='#333',
),
angularaxis=dict(
tickfont=dict(size=11, color='white'),
gridcolor='#333',
),
bgcolor='#16213e',
),
plot_bgcolor='#1a1a2e',
paper_bgcolor='#1a1a2e',
font=dict(color='white'),
margin=dict(l=80, r=80, t=40, b=40),
height=400,
showlegend=True,
legend=dict(
x=0.5, xanchor='center',
y=-0.15, yanchor='top',
orientation='h',
font=dict(size=10)
),
title=dict(
text="Forensic Feature Profile",
font=dict(size=14),
x=0.5, xanchor='center'
)
)
return fig
def forensic_features_explanation() -> str:
"""7개 ν¬λ Œμ‹ ν”Όμ²˜μ— λŒ€ν•œ 상세 μ„€λͺ… HTML λ°˜ν™˜."""
return """
<div style="background:#16213e;padding:20px;border-radius:12px;margin-top:10px;">
<h3 style="color:#00d2ff;margin-top:0;font-size:16px;">πŸ”¬ 7-Channel Forensic Features</h3>
<div style="font-size:13px;color:#ccc;line-height:1.6;">
<details style="margin-bottom:10px;">
<summary style="cursor:pointer;color:#ffa502;font-weight:bold;">
πŸ“Š 1. Residual Energy (μž”μ°¨ μ—λ„ˆμ§€)
</summary>
<p style="margin:8px 0 0 20px;color:#aaa;">
AI λ‰΄λŸ΄ 코덱이 λ‚¨κΈ°λŠ” λ―Έμ„Έν•œ 코덱 흔적.
AI μŒμ•…μ€ 인간이 λ§Œλ“  μŒμ•…κ³Ό λ‹€λ₯Έ <b>μ–‘μžν™” νŒ¨ν„΄</b>을 λ³΄μž…λ‹ˆλ‹€.
</p>
</details>
<details style="margin-bottom:10px;">
<summary style="cursor:pointer;color:#ffa502;font-weight:bold;">
🎡 2-3. Harmonic/Percussive Strength (ν•˜λͺ¨λ‹‰/타악기 강도)
</summary>
<p style="margin:8px 0 0 20px;color:#aaa;">
μŒμ•…μ„ λ©œλ‘œλ”” μ„±λΆ„κ³Ό 리듬 μ„±λΆ„μœΌλ‘œ 뢄리.
AIλŠ” 두 μš”μ†Œμ˜ <b>μ—λ„ˆμ§€ λΉ„μœ¨</b>이 λΆ€μžμ—°μŠ€λŸ½κ²Œ μΌμ •ν•©λ‹ˆλ‹€.
</p>
</details>
<details style="margin-bottom:10px;">
<summary style="cursor:pointer;color:#ffa502;font-weight:bold;">
⚑ 4-5. Temporal Delta & Accel (μ‹œκ°„ λ³€ν™”μœ¨/가속도)
</summary>
<p style="margin:8px 0 0 20px;color:#aaa;">
μŠ€νŽ™νŠΈλŸΌμ˜ μ‹œκ°„μΆ• λ³€ν™” νŒ¨ν„΄.
AI μŒμ•…μ€ λ³€ν™”κ°€ <b>λ„ˆλ¬΄ λΆ€λ“œλŸ½κ³  κ·œμΉ™μ </b>μž…λ‹ˆλ‹€ (생성 κ³Όμ •μ˜ smoothing 효과).
</p>
</details>
<details style="margin-bottom:10px;">
<summary style="cursor:pointer;color:#ffa502;font-weight:bold;">
🎚️ 6. H/P Ratio (ν•˜λͺ¨λ‹‰/타악기 λΉ„μœ¨)
</summary>
<p style="margin:8px 0 0 20px;color:#aaa;">
λ©œλ‘œλ””μ™€ λ¦¬λ“¬μ˜ κ· ν˜•.
AIλŠ” μž₯λ₯΄μ™€ λ¬΄κ΄€ν•˜κ²Œ <b>νŠΉμ • λΉ„μœ¨λ‘œ 수렴</b>ν•˜λŠ” κ²½ν–₯을 λ³΄μž…λ‹ˆλ‹€.
</p>
</details>
<details>
<summary style="cursor:pointer;color:#ffa502;font-weight:bold;">
🌊 7. Spectral Flux (μŠ€νŽ™νŠΈλŸΌ λ³€ν™”λŸ‰)
</summary>
<p style="margin:8px 0 0 20px;color:#aaa;">
주파수 μ„±λΆ„μ˜ ν”„λ ˆμž„κ°„ λ³€ν™” μ ˆλŒ“κ°’.
AIλŠ” λ³€ν™”κ°€ <b>일관적이고 예츑 κ°€λŠ₯</b>ν•©λ‹ˆλ‹€ (ν™•λ₯ μ  μƒμ„±μ˜ νŠΉμ„±).
</p>
</details>
</div>
<div style="margin-top:15px;padding:12px;background:#1a1a2e;border-radius:8px;border-left:3px solid #00d2ff;">
<p style="margin:0;font-size:12px;color:#aaa;">
<b style="color:#00d2ff;">πŸ’‘ 핡심 원리:</b>
AI 생성 λͺ¨λΈμ€ <b>물리적 μ•…κΈ°μ˜ λΆˆκ·œμΉ™μ„±</b>을 μ™„λ²½νžˆ μž¬ν˜„ν•˜μ§€ λͺ»ν•©λ‹ˆλ‹€.
이 7개 ν”Όμ²˜λŠ” κ·ΈλŸ¬ν•œ λ―Έμ„Έν•œ 차이λ₯Ό μ •λŸ‰ν™”ν•˜μ—¬ AI μ‹œκ·Έλ‹ˆμ²˜λ₯Ό νƒμ§€ν•©λ‹ˆλ‹€.
</p>
</div>
</div>
"""