from pathlib import Path import tempfile import warnings with warnings.catch_warnings(): warnings.filterwarnings( "ignore", message="Couldn't find ffmpeg or avconv.*", category=RuntimeWarning, ) from pydub import AudioSegment try: import imageio_ffmpeg except ImportError: imageio_ffmpeg = None TARGET_SAMPLE_RATE = 22050 SUPPORTED_AUDIO_EXTENSIONS = {".wav", ".mp3", ".m4a", ".ogg", ".flac", ".webm", ".aac"} if imageio_ffmpeg is not None: AudioSegment.converter = imageio_ffmpeg.get_ffmpeg_exe() def validate_audio_extension(file_path): extension = Path(file_path).suffix.lower() if extension not in SUPPORTED_AUDIO_EXTENSIONS: allowed = ", ".join(sorted(SUPPORTED_AUDIO_EXTENSIONS)).upper().replace(".", "") raise ValueError(f"Format audio tidak didukung: {extension}. Format yang didukung: {allowed}") def save_uploaded_file_to_temp(uploaded_file): """ Menyimpan file upload Streamlit ke file sementara. File ini bukan dataset dan tidak disimpan ke ml/data. """ suffix = Path(uploaded_file.name).suffix.lower() or ".wav" validate_audio_extension(f"audio{suffix}") temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=suffix) try: temp_file.write(uploaded_file.getvalue()) return Path(temp_file.name) finally: temp_file.close() def create_temp_wav_path(): temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".wav") temp_path = Path(temp_file.name) temp_file.close() return temp_path def convert_audio_to_wav(input_path, output_path=None): """ Konversi audio upload ke WAV mono 22050 Hz menggunakan pydub/ffmpeg. """ input_path = Path(input_path) validate_audio_extension(input_path) if not input_path.exists(): raise FileNotFoundError(f"File audio tidak ditemukan: {input_path}") output_path = Path(output_path) if output_path else create_temp_wav_path() output_path.parent.mkdir(parents=True, exist_ok=True) try: audio = AudioSegment.from_file(input_path) except FileNotFoundError as error: raise RuntimeError( "ffmpeg tidak ditemukan. Pastikan ffmpeg sudah terpasang dan dapat diakses oleh pydub." ) from error except Exception as error: raise RuntimeError(f"Gagal membaca atau mengonversi audio: {error}") from error audio = audio.set_channels(1).set_frame_rate(TARGET_SAMPLE_RATE) audio.export(output_path, format="wav") return output_path def cleanup_temp_files(*paths): for path in paths: if path: Path(path).unlink(missing_ok=True)