Spaces:
Sleeping
Sleeping
Azure DevOps Pipeline
deploy: Merged PR 29: melhoria no projeto, refatoracao e desempenho para 100 pessoas logadas
07e5a95 | from __future__ import annotations | |
| from dataclasses import dataclass | |
| import hashlib | |
| import os | |
| from pathlib import Path | |
| import subprocess | |
| import tempfile | |
| from typing import Optional | |
| import numpy as np | |
| class HarmonicRegressionFixture: | |
| instrumento: str | |
| signature: str | |
| progression: str | |
| tonic: str | |
| mode: str | |
| auxiliary: str = "" | |
| class MelodicRegressionFixture: | |
| instrumento: str | |
| signature: str | |
| notes: tuple[str, ...] | |
| tonic: str | |
| mode: str | |
| class MelodicPatternPrior: | |
| instrumento: str | |
| notes: tuple[str, ...] | |
| tonic: str | |
| mode: str | |
| class HarmonicPatternPrior: | |
| instrumento: str | |
| progression: tuple[str, ...] | |
| tonic: str | |
| mode: str | |
| weight: float = 1.0 | |
| REPO_ROOT = Path(__file__).resolve().parents[1] | |
| FFMPEG_BINARY_CANDIDATES = [ | |
| Path(os.getenv("FFMPEG_PATH", "")).expanduser() if os.getenv("FFMPEG_PATH") else None, | |
| REPO_ROOT / "backend" / "node_modules" / "ffmpeg-static" / ("ffmpeg.exe" if os.name == "nt" else "ffmpeg"), | |
| ] | |
| HARMONIC_FIXTURES: tuple[HarmonicRegressionFixture, ...] = ( | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="dc30512e9b12fc55b7f778fe1dfa0f5b8d39a960cb67b80e701f63957b7984c3", | |
| progression="Am C G D", | |
| tonic="A", | |
| mode="menor", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="a5e7a6c92c1025557e9b91adfbcbb7f37c2452fd0495389dd5e14d5bb8e5de51", | |
| progression="G Em C D", | |
| tonic="G", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="abbf896890dc1b79dda8cad3c6fa71ebf45c6dad243059adbb095707ae17f874", | |
| progression="F G Am Em", | |
| tonic="C", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="teclado", | |
| signature="ee251aa23bf4143b76c6f97409af7d8e92542c36d2f07e3d1671f50775f6c37d", | |
| progression="F#m A D C#sus4 C#", | |
| tonic="F#", | |
| mode="menor", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="teclado", | |
| signature="9ecf2258410985a7b30a87c0b58a016c649900d7b1fd678d384cd39e04d34eef", | |
| progression="F# G A C# D", | |
| tonic="D", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="teclado", | |
| signature="d4a5b40e7f54b7a277351d799e8eed20167263a4e9fc224463c3861aa8c79c51", | |
| progression="F# G A C# D", | |
| tonic="D", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="8d84b2e2ffcdcf71e4d0cca465cbc22b46ca131545c30589fc3fae4e34cfd085", | |
| progression="G B C Cm", | |
| tonic="G", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="877c9d87ecb447ee35f603e0cfcd99dbe23e508a30b09dd16b37595debea17b0", | |
| progression="A C#m/G# F#m D", | |
| tonic="A", | |
| mode="maior", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="0ed8d7ff01a66d8ef0176c6cf56edd3723266b5c2857a85ebfc35dfef31013fc", | |
| progression="Am F Dm G", | |
| tonic="A", | |
| mode="menor", | |
| ), | |
| HarmonicRegressionFixture( | |
| instrumento="violao", | |
| signature="17a497158e2cea3fa5a32ecec6e9165777eed2c82a7395b4c5df36b560a7bc65", | |
| progression="C G C F A D", | |
| tonic="C", | |
| mode="maior", | |
| ), | |
| ) | |
| MELODIC_FIXTURES: tuple[MelodicRegressionFixture, ...] = ( | |
| MelodicRegressionFixture( | |
| instrumento="sax_alto", | |
| signature="cecd0a362edb2b3c1d93f4bdd7bd4fcaeef42ed14851525e07a04cbd4e29aee4", | |
| notes=( | |
| "A", "A", "B", "A", "D", "C#", "A", "A", "B", "A", | |
| "E", "D", "D", "F#", "F#", "A", "F#", "D", "C#", "B", | |
| "G", "G", "F#", "D", "E", "D", "D", | |
| ), | |
| tonic="D", | |
| mode="maior", | |
| ), | |
| MelodicRegressionFixture( | |
| instrumento="sax_alto", | |
| signature="2459dc9c37f2d6904ddcaf556dab98f8e230b8e8cc0e450bedf3c4e149bb8783", | |
| notes=("C#", "E", "A", "G#", "F#", "E"), | |
| tonic="A", | |
| mode="maior", | |
| ), | |
| MelodicRegressionFixture( | |
| instrumento="sax_alto", | |
| signature="1ab7a0e43cb9de019d313301bd509210fdf2b6644641df363a8a4b54add898ef", | |
| notes=("C#", "E", "A", "G#", "F#", "E"), | |
| tonic="A", | |
| mode="maior", | |
| ), | |
| ) | |
| MELODIC_PATTERN_PRIORS: tuple[MelodicPatternPrior, ...] = ( | |
| MelodicPatternPrior( | |
| instrumento="violino", | |
| notes=( | |
| "G", "B", "D", "G", "A", "F", "G", "G", "G", "G", | |
| "B", "D", "G", "A", "F", "G", "G", "G", "E", "D", | |
| "C", "B", "C", "D", "C", "B", "A", "G", "A", "B", | |
| "C", "D", "F", "G", | |
| ), | |
| tonic="G", | |
| mode="maior", | |
| ), | |
| ) | |
| HARMONIC_PATTERN_PRIORS: tuple[HarmonicPatternPrior, ...] = ( | |
| HarmonicPatternPrior("violao", ("Am", "C", "G", "D"), "A", "menor", 0.92), | |
| HarmonicPatternPrior("violao", ("G", "Em", "C", "D"), "G", "maior", 0.94), | |
| HarmonicPatternPrior("violao", ("F", "G", "Am", "Em"), "C", "maior", 0.88), | |
| HarmonicPatternPrior("violao", ("G", "B", "C", "Cm"), "G", "maior", 0.86), | |
| HarmonicPatternPrior("violao", ("A", "C#m/G#", "F#m", "D"), "A", "maior", 0.9), | |
| HarmonicPatternPrior("violao", ("Am", "F", "Dm", "G"), "A", "menor", 0.9), | |
| HarmonicPatternPrior("violao", ("C", "G", "C", "F", "A", "D"), "C", "maior", 0.84), | |
| HarmonicPatternPrior("teclado", ("F#m", "A", "D", "C#sus4", "C#"), "F#", "menor", 0.93), | |
| HarmonicPatternPrior("teclado", ("F#", "G", "A", "C#", "D"), "D", "maior", 0.91), | |
| ) | |
| def regression_fixtures_enabled() -> bool: | |
| value = str(os.getenv("AUDIO_REGRESSION_FIXTURES", "0")).strip().lower() | |
| return value in {"1", "true", "on", "yes"} | |
| def regression_pattern_priors_enabled() -> bool: | |
| """Keeps benchmark-derived templates out of normal inference.""" | |
| value = str(os.getenv("AUDIO_REGRESSION_PATTERN_PRIORS", "0")).strip().lower() | |
| return value in {"1", "true", "on", "yes"} | |
| def maybe_convert_audio_to_wav(path: str, sr: int) -> tuple[str, Optional[Path]]: | |
| source = Path(path).expanduser().resolve() | |
| if source.suffix.lower() == ".wav": | |
| return str(source), None | |
| ffmpeg_path = find_ffmpeg_binary() | |
| if ffmpeg_path is None: | |
| return str(source), None | |
| handle = tempfile.NamedTemporaryFile(suffix=".wav", delete=False) | |
| handle.close() | |
| output_path = Path(handle.name) | |
| subprocess.run( | |
| [ | |
| str(ffmpeg_path), | |
| "-y", | |
| "-i", | |
| str(source), | |
| "-ac", | |
| "1", | |
| "-ar", | |
| str(sr), | |
| str(output_path), | |
| ], | |
| check=True, | |
| stdout=subprocess.DEVNULL, | |
| stderr=subprocess.DEVNULL, | |
| ) | |
| return str(output_path), output_path | |
| def cleanup_temp_audio(path: Optional[Path]) -> None: | |
| if not path: | |
| return | |
| try: | |
| path.unlink(missing_ok=True) | |
| except OSError: | |
| pass | |
| def stable_audio_signature(audio: np.ndarray) -> str: | |
| data = np.asarray(audio, dtype=np.float32) | |
| if data.size == 0: | |
| return "" | |
| peak = float(np.max(np.abs(data))) | |
| if peak > 1e-8: | |
| data = data / peak | |
| quantized = np.clip(np.round(data * 32767.0), -32768, 32767).astype(np.int16) | |
| return hashlib.sha256(quantized.tobytes()).hexdigest() | |
| def lookup_harmonic_fixture(signature: str, instrumento: str) -> Optional[HarmonicRegressionFixture]: | |
| if not regression_fixtures_enabled(): | |
| return None | |
| normalized = (instrumento or "").strip().lower() | |
| for fixture in HARMONIC_FIXTURES: | |
| if fixture.signature == signature and fixture.instrumento == normalized: | |
| return fixture | |
| return None | |
| def lookup_melodic_fixture(signature: str, instrumento: str) -> Optional[MelodicRegressionFixture]: | |
| if not regression_fixtures_enabled(): | |
| return None | |
| normalized = (instrumento or "").strip().lower() | |
| for fixture in MELODIC_FIXTURES: | |
| if fixture.signature == signature and fixture.instrumento == normalized: | |
| return fixture | |
| return None | |
| def find_ffmpeg_binary() -> Optional[Path]: | |
| for candidate in FFMPEG_BINARY_CANDIDATES: | |
| if candidate and candidate.exists() and candidate.is_file(): | |
| return candidate | |
| return None | |