Spaces:
Running on Zero
Running on Zero
Update app.py
Browse files
app.py
CHANGED
|
@@ -49,10 +49,18 @@ except ImportError:
|
|
| 49 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 50 |
# Constants
|
| 51 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
N_FFT = 2048
|
| 57 |
HOP = 512
|
| 58 |
MAX_DUR_S = 300 # clip to 5 min for HuggingFace timeout safety
|
|
@@ -151,7 +159,7 @@ def _make_fig(nrows=1, ncols=1, figsize=(12, 4)):
|
|
| 151 |
|
| 152 |
|
| 153 |
def _style(ax, title="", xlabel="", ylabel=""):
|
| 154 |
-
ax.set_facecolor(
|
| 155 |
ax.set_title(title, color=ACCENT, fontsize=12, fontweight="bold", pad=8)
|
| 156 |
ax.set_xlabel(xlabel, color=TEXT_COLOR, fontsize=9)
|
| 157 |
ax.set_ylabel(ylabel, color=TEXT_COLOR, fontsize=9)
|
|
@@ -262,11 +270,11 @@ def analyze(file_path):
|
|
| 262 |
fig3, axes3 = _make_fig(3, 1, figsize=(13, 12))
|
| 263 |
|
| 264 |
# PSD
|
| 265 |
-
axes3[0].plot(f_psd[1:], psd_db[1:], color=
|
| 266 |
marine_bands = [
|
| 267 |
-
(20, 1000,
|
| 268 |
-
(1000, 5000,
|
| 269 |
-
(5000, min(sr / 2, 20000),
|
| 270 |
]
|
| 271 |
for flo, fhi, color, label in marine_bands:
|
| 272 |
if fhi <= sr / 2 and flo < sr / 2:
|
|
@@ -278,8 +286,8 @@ def analyze(file_path):
|
|
| 278 |
facecolor=BG_COLOR, edgecolor=GRID_COLOR, labelcolor=TEXT_COLOR)
|
| 279 |
|
| 280 |
# Spectral centroid
|
| 281 |
-
axes3[1].plot(c_times, centroid, color=
|
| 282 |
-
axes3[1].fill_between(c_times, centroid, alpha=0.12, color=
|
| 283 |
axes3[1].set_xlim(0, duration)
|
| 284 |
_style(axes3[1], "Spectral Centroid Over Time", "Time (s)", "Frequency (Hz)")
|
| 285 |
|
|
@@ -289,7 +297,7 @@ def analyze(file_path):
|
|
| 289 |
ax=axes3[2], cmap="coolwarm"
|
| 290 |
)
|
| 291 |
_style(axes3[2], "MFCCs (20 coefficients)", "Time (s)", "MFCC Coefficient")
|
| 292 |
-
axes3[2].set_facecolor(
|
| 293 |
_colorbar(fig3, im_mfcc, axes3[2], label="Amplitude")
|
| 294 |
|
| 295 |
fig3.tight_layout(pad=1.2)
|
|
@@ -325,22 +333,22 @@ def analyze(file_path):
|
|
| 325 |
_style(ax, title, "Time (s)", ylabel)
|
| 326 |
ax.set_xlim(0, duration)
|
| 327 |
|
| 328 |
-
bar_plot(axes4[0, 0], aci_v,
|
| 329 |
-
bar_plot(axes4[0, 1], bi_v,
|
| 330 |
|
| 331 |
# NDSI β colour by sign
|
| 332 |
-
ndsi_colors = [
|
| 333 |
axes4[1, 0].bar(centers, ndsi_v, width=bw, color=ndsi_colors, alpha=0.82)
|
| 334 |
axes4[1, 0].axhline(0, color=TEXT_COLOR, linewidth=0.8, linestyle="--", alpha=0.6)
|
| 335 |
_style(axes4[1, 0], "NDSI (green > 0 = biotic dominated)", "Time (s)", "NDSI")
|
| 336 |
axes4[1, 0].set_xlim(0, duration)
|
| 337 |
|
| 338 |
-
bar_plot(axes4[1, 1], adi_v,
|
| 339 |
|
| 340 |
# RMS energy
|
| 341 |
-
axes4[2, 0].plot(centers, rms_v, "o-", color=
|
| 342 |
markersize=5, alpha=0.9)
|
| 343 |
-
axes4[2, 0].fill_between(centers, rms_v, alpha=0.15, color=
|
| 344 |
_style(axes4[2, 0], "RMS Energy Over Time", "Time (s)", "RMS Amplitude")
|
| 345 |
axes4[2, 0].set_xlim(0, duration)
|
| 346 |
|
|
@@ -369,19 +377,19 @@ def analyze(file_path):
|
|
| 369 |
|
| 370 |
fig5, axes5 = _make_fig(3, 2, figsize=(14, 11))
|
| 371 |
|
| 372 |
-
axes5[0, 0].plot(c_times, bandwidth, color=
|
| 373 |
_style(axes5[0, 0], "Spectral Bandwidth Over Time", "Time (s)", "Bandwidth (Hz)")
|
| 374 |
axes5[0, 0].set_xlim(0, duration)
|
| 375 |
|
| 376 |
-
axes5[0, 1].plot(c_times, rolloff, color=
|
| 377 |
_style(axes5[0, 1], "Spectral Rolloff (85%) Over Time", "Time (s)", "Frequency (Hz)")
|
| 378 |
axes5[0, 1].set_xlim(0, duration)
|
| 379 |
|
| 380 |
-
axes5[1, 0].plot(c_times, flatness, color=
|
| 381 |
_style(axes5[1, 0], "Spectral Flatness Over Time", "Time (s)", "Flatness [0β1]")
|
| 382 |
axes5[1, 0].set_xlim(0, duration)
|
| 383 |
|
| 384 |
-
axes5[1, 1].plot(c_times, zcr_frame, color=
|
| 385 |
_style(axes5[1, 1], "Zero Crossing Rate Over Time", "Time (s)", "ZCR")
|
| 386 |
axes5[1, 1].set_xlim(0, duration)
|
| 387 |
|
|
@@ -389,19 +397,19 @@ def analyze(file_path):
|
|
| 389 |
axes5[2, 0].plot(c_times, rms_db_frame[0], color=ACCENT, linewidth=0.7, alpha=0.7,
|
| 390 |
label="RMS (dBFS)")
|
| 391 |
for ot in onset_times:
|
| 392 |
-
axes5[2, 0].axvline(ot, color=
|
| 393 |
axes5[2, 0].set_xlim(0, duration)
|
| 394 |
_style(axes5[2, 0], f"Onset Detection ({len(onset_times)} events)", "Time (s)", "RMS (dB)")
|
| 395 |
axes5[2, 0].text(0.01, 0.96, f"{len(onset_times)} onsets detected",
|
| 396 |
transform=axes5[2, 0].transAxes,
|
| 397 |
-
color=
|
| 398 |
|
| 399 |
# MFCC delta (showing change)
|
| 400 |
im_delta = librosa.display.specshow(
|
| 401 |
mfcc_delta, sr=sr, hop_length=HOP, x_axis="time",
|
| 402 |
ax=axes5[2, 1], cmap="RdBu_r"
|
| 403 |
)
|
| 404 |
-
axes5[2, 1].set_facecolor(
|
| 405 |
_style(axes5[2, 1], "MFCC Delta (Rate of Change)", "Time (s)", "MFCC Coefficient")
|
| 406 |
_colorbar(fig5, im_delta, axes5[2, 1], label="Ξ Amplitude")
|
| 407 |
|
|
@@ -521,18 +529,54 @@ def analyze(file_path):
|
|
| 521 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 522 |
|
| 523 |
CSS = """
|
| 524 |
-
@import url('https://fonts.googleapis.com/css2?family=
|
| 525 |
|
| 526 |
body, .gradio-container {
|
| 527 |
-
background:
|
| 528 |
-
font-family: '
|
|
|
|
| 529 |
}
|
| 530 |
-
h1, h2, h3, h4
|
| 531 |
-
font-family: '
|
|
|
|
| 532 |
}
|
| 533 |
-
h1 { font-size: 2.2rem !important; font-weight:
|
| 534 |
-
h2, h3 { font-weight:
|
| 535 |
-
.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 536 |
footer { display: none !important; }
|
| 537 |
"""
|
| 538 |
|
|
@@ -550,10 +594,11 @@ EXAMPLES = [e for e in EXAMPLES if os.path.isfile(e[0])]
|
|
| 550 |
|
| 551 |
with gr.Blocks(title="π Marine Soundscape Analyzer", css=CSS,
|
| 552 |
theme=gr.themes.Base(
|
| 553 |
-
primary_hue="
|
| 554 |
-
secondary_hue="
|
| 555 |
-
neutral_hue="
|
| 556 |
-
font=gr.themes.GoogleFont("
|
|
|
|
| 557 |
)) as demo:
|
| 558 |
|
| 559 |
gr.Markdown("""
|
|
|
|
| 49 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 50 |
# Constants
|
| 51 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 52 |
+
# Coral Stay palette (https://designmd.ai/chef/coral-stay)
|
| 53 |
+
BG_COLOR = "#FFFFFF" # Background β clean page/figure background
|
| 54 |
+
SURFACE = "#F7F7F7" # Surface β card/plot-axes fill
|
| 55 |
+
GRID_COLOR = "#DDDDDD" # Border β dividers, plot grids
|
| 56 |
+
TEXT_COLOR = "#222222" # Text Primary β Hof Dark
|
| 57 |
+
TEXT_MUTED = "#717171" # Text Secondary
|
| 58 |
+
ACCENT = "#FF5A5F" # Primary β Rausch Coral
|
| 59 |
+
ACCENT_HOVER = "#E04E52" # Primary hover
|
| 60 |
+
SECONDARY = "#00A699" # Secondary β Kazan Teal
|
| 61 |
+
SUCCESS = "#008A05"
|
| 62 |
+
WARNING = "#E07912"
|
| 63 |
+
ERROR = "#C13515"
|
| 64 |
N_FFT = 2048
|
| 65 |
HOP = 512
|
| 66 |
MAX_DUR_S = 300 # clip to 5 min for HuggingFace timeout safety
|
|
|
|
| 159 |
|
| 160 |
|
| 161 |
def _style(ax, title="", xlabel="", ylabel=""):
|
| 162 |
+
ax.set_facecolor(SURFACE)
|
| 163 |
ax.set_title(title, color=ACCENT, fontsize=12, fontweight="bold", pad=8)
|
| 164 |
ax.set_xlabel(xlabel, color=TEXT_COLOR, fontsize=9)
|
| 165 |
ax.set_ylabel(ylabel, color=TEXT_COLOR, fontsize=9)
|
|
|
|
| 270 |
fig3, axes3 = _make_fig(3, 1, figsize=(13, 12))
|
| 271 |
|
| 272 |
# PSD
|
| 273 |
+
axes3[0].plot(f_psd[1:], psd_db[1:], color=SECONDARY, linewidth=1.3)
|
| 274 |
marine_bands = [
|
| 275 |
+
(20, 1000, SUCCESS, "Fish & low-freq (20β1 kHz)"),
|
| 276 |
+
(1000, 5000, ACCENT, "Snapping shrimp (1β5 kHz)"),
|
| 277 |
+
(5000, min(sr / 2, 20000), WARNING, "High-freq biotic (5β20 kHz)"),
|
| 278 |
]
|
| 279 |
for flo, fhi, color, label in marine_bands:
|
| 280 |
if fhi <= sr / 2 and flo < sr / 2:
|
|
|
|
| 286 |
facecolor=BG_COLOR, edgecolor=GRID_COLOR, labelcolor=TEXT_COLOR)
|
| 287 |
|
| 288 |
# Spectral centroid
|
| 289 |
+
axes3[1].plot(c_times, centroid, color=ACCENT, linewidth=1.1, alpha=0.9)
|
| 290 |
+
axes3[1].fill_between(c_times, centroid, alpha=0.12, color=ACCENT)
|
| 291 |
axes3[1].set_xlim(0, duration)
|
| 292 |
_style(axes3[1], "Spectral Centroid Over Time", "Time (s)", "Frequency (Hz)")
|
| 293 |
|
|
|
|
| 297 |
ax=axes3[2], cmap="coolwarm"
|
| 298 |
)
|
| 299 |
_style(axes3[2], "MFCCs (20 coefficients)", "Time (s)", "MFCC Coefficient")
|
| 300 |
+
axes3[2].set_facecolor(SURFACE)
|
| 301 |
_colorbar(fig3, im_mfcc, axes3[2], label="Amplitude")
|
| 302 |
|
| 303 |
fig3.tight_layout(pad=1.2)
|
|
|
|
| 333 |
_style(ax, title, "Time (s)", ylabel)
|
| 334 |
ax.set_xlim(0, duration)
|
| 335 |
|
| 336 |
+
bar_plot(axes4[0, 0], aci_v, SECONDARY, "Acoustic Complexity Index (ACI)", "ACI")
|
| 337 |
+
bar_plot(axes4[0, 1], bi_v, SUCCESS, "Bioacoustic Index (BI)", "BI")
|
| 338 |
|
| 339 |
# NDSI β colour by sign
|
| 340 |
+
ndsi_colors = [SUCCESS if v >= 0 else ERROR for v in ndsi_v]
|
| 341 |
axes4[1, 0].bar(centers, ndsi_v, width=bw, color=ndsi_colors, alpha=0.82)
|
| 342 |
axes4[1, 0].axhline(0, color=TEXT_COLOR, linewidth=0.8, linestyle="--", alpha=0.6)
|
| 343 |
_style(axes4[1, 0], "NDSI (green > 0 = biotic dominated)", "Time (s)", "NDSI")
|
| 344 |
axes4[1, 0].set_xlim(0, duration)
|
| 345 |
|
| 346 |
+
bar_plot(axes4[1, 1], adi_v, WARNING, "Acoustic Diversity Index (ADI)", "ADI")
|
| 347 |
|
| 348 |
# RMS energy
|
| 349 |
+
axes4[2, 0].plot(centers, rms_v, "o-", color=ACCENT, linewidth=1.6,
|
| 350 |
markersize=5, alpha=0.9)
|
| 351 |
+
axes4[2, 0].fill_between(centers, rms_v, alpha=0.15, color=ACCENT)
|
| 352 |
_style(axes4[2, 0], "RMS Energy Over Time", "Time (s)", "RMS Amplitude")
|
| 353 |
axes4[2, 0].set_xlim(0, duration)
|
| 354 |
|
|
|
|
| 377 |
|
| 378 |
fig5, axes5 = _make_fig(3, 2, figsize=(14, 11))
|
| 379 |
|
| 380 |
+
axes5[0, 0].plot(c_times, bandwidth, color=SECONDARY, linewidth=0.9, alpha=0.9)
|
| 381 |
_style(axes5[0, 0], "Spectral Bandwidth Over Time", "Time (s)", "Bandwidth (Hz)")
|
| 382 |
axes5[0, 0].set_xlim(0, duration)
|
| 383 |
|
| 384 |
+
axes5[0, 1].plot(c_times, rolloff, color=WARNING, linewidth=0.9, alpha=0.9)
|
| 385 |
_style(axes5[0, 1], "Spectral Rolloff (85%) Over Time", "Time (s)", "Frequency (Hz)")
|
| 386 |
axes5[0, 1].set_xlim(0, duration)
|
| 387 |
|
| 388 |
+
axes5[1, 0].plot(c_times, flatness, color=TEXT_MUTED, linewidth=0.9, alpha=0.9)
|
| 389 |
_style(axes5[1, 0], "Spectral Flatness Over Time", "Time (s)", "Flatness [0β1]")
|
| 390 |
axes5[1, 0].set_xlim(0, duration)
|
| 391 |
|
| 392 |
+
axes5[1, 1].plot(c_times, zcr_frame, color=ACCENT_HOVER, linewidth=0.7, alpha=0.9)
|
| 393 |
_style(axes5[1, 1], "Zero Crossing Rate Over Time", "Time (s)", "ZCR")
|
| 394 |
axes5[1, 1].set_xlim(0, duration)
|
| 395 |
|
|
|
|
| 397 |
axes5[2, 0].plot(c_times, rms_db_frame[0], color=ACCENT, linewidth=0.7, alpha=0.7,
|
| 398 |
label="RMS (dBFS)")
|
| 399 |
for ot in onset_times:
|
| 400 |
+
axes5[2, 0].axvline(ot, color=ERROR, linewidth=0.6, alpha=0.6)
|
| 401 |
axes5[2, 0].set_xlim(0, duration)
|
| 402 |
_style(axes5[2, 0], f"Onset Detection ({len(onset_times)} events)", "Time (s)", "RMS (dB)")
|
| 403 |
axes5[2, 0].text(0.01, 0.96, f"{len(onset_times)} onsets detected",
|
| 404 |
transform=axes5[2, 0].transAxes,
|
| 405 |
+
color=ERROR, fontsize=9, va="top")
|
| 406 |
|
| 407 |
# MFCC delta (showing change)
|
| 408 |
im_delta = librosa.display.specshow(
|
| 409 |
mfcc_delta, sr=sr, hop_length=HOP, x_axis="time",
|
| 410 |
ax=axes5[2, 1], cmap="RdBu_r"
|
| 411 |
)
|
| 412 |
+
axes5[2, 1].set_facecolor(SURFACE)
|
| 413 |
_style(axes5[2, 1], "MFCC Delta (Rate of Change)", "Time (s)", "MFCC Coefficient")
|
| 414 |
_colorbar(fig5, im_delta, axes5[2, 1], label="Ξ Amplitude")
|
| 415 |
|
|
|
|
| 529 |
# ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 530 |
|
| 531 |
CSS = """
|
| 532 |
+
@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@400;600;700;800&family=DM+Sans:wght@400;500;600;700&display=swap');
|
| 533 |
|
| 534 |
body, .gradio-container {
|
| 535 |
+
background: #FFFFFF !important;
|
| 536 |
+
font-family: 'DM Sans', sans-serif !important;
|
| 537 |
+
color: #222222 !important;
|
| 538 |
}
|
| 539 |
+
h1, h2, h3, h4 {
|
| 540 |
+
font-family: 'Nunito Sans', sans-serif !important;
|
| 541 |
+
color: #222222 !important;
|
| 542 |
}
|
| 543 |
+
h1 { font-size: 2.2rem !important; font-weight: 800 !important; }
|
| 544 |
+
h2, h3 { font-weight: 700 !important; }
|
| 545 |
+
label, .tab-nav button {
|
| 546 |
+
font-family: 'DM Sans', sans-serif !important;
|
| 547 |
+
font-weight: 600 !important;
|
| 548 |
+
color: #222222 !important;
|
| 549 |
+
}
|
| 550 |
+
p, .prose, .markdown-body { color: #717171 !important; }
|
| 551 |
+
|
| 552 |
+
/* Cards / surfaces β rounded, soft-bordered like Coral Stay cards */
|
| 553 |
+
.gr-panel, .gr-box, .gr-form, .tabitem, .block {
|
| 554 |
+
background: #F7F7F7 !important;
|
| 555 |
+
border: 1px solid #DDDDDD !important;
|
| 556 |
+
border-radius: 12px !important;
|
| 557 |
+
}
|
| 558 |
+
|
| 559 |
+
/* Buttons β Coral Stay primary (Rausch Coral) */
|
| 560 |
+
.gr-button, button.primary {
|
| 561 |
+
background: #FF5A5F !important;
|
| 562 |
+
border: none !important;
|
| 563 |
+
color: #FFFFFF !important;
|
| 564 |
+
font-weight: 700;
|
| 565 |
+
letter-spacing: 0.01em;
|
| 566 |
+
border-radius: 12px !important;
|
| 567 |
+
min-height: 48px;
|
| 568 |
+
transition: background 0.15s ease-in-out;
|
| 569 |
+
}
|
| 570 |
+
.gr-button:hover, button.primary:hover {
|
| 571 |
+
background: #E04E52 !important;
|
| 572 |
+
}
|
| 573 |
+
|
| 574 |
+
/* Tabs β coral active state */
|
| 575 |
+
.tab-nav button.selected {
|
| 576 |
+
color: #FF5A5F !important;
|
| 577 |
+
border-color: #FF5A5F !important;
|
| 578 |
+
}
|
| 579 |
+
|
| 580 |
footer { display: none !important; }
|
| 581 |
"""
|
| 582 |
|
|
|
|
| 594 |
|
| 595 |
with gr.Blocks(title="π Marine Soundscape Analyzer", css=CSS,
|
| 596 |
theme=gr.themes.Base(
|
| 597 |
+
primary_hue="red",
|
| 598 |
+
secondary_hue="teal",
|
| 599 |
+
neutral_hue="gray",
|
| 600 |
+
font=gr.themes.GoogleFont("Nunito Sans"),
|
| 601 |
+
font_mono=gr.themes.GoogleFont("JetBrains Mono"),
|
| 602 |
)) as demo:
|
| 603 |
|
| 604 |
gr.Markdown("""
|