Spaces:
Runtime error
Runtime error
File size: 6,716 Bytes
0020ddc | 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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 | # 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>
"""
|