Spaces:
Runtime error
Runtime error
File size: 4,862 Bytes
9e3f5f9 449f013 6d8fa3b 449f013 9e3f5f9 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b 449f013 6d8fa3b | 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 | # audio_processor.py - Final definitive fix for Numba caching issue
import os
from dotenv import load_dotenv
import tempfile
from typing import List, Dict, Optional, Tuple
import json
import traceback
# --- DEFINITIVE NUMBA FIX ---
# This MUST be done BEFORE importing librosa
os.environ["NUMBA_CACHE_DIR"] = "/tmp"
# Now, import librosa safely
import librosa
# --- END OF FIX ---
from google import genai
from google.genai import types
class AudioProcessor:
def __init__(self):
self.client = None
self.init_error = None
self._initialize_gemini()
def _initialize_gemini(self):
try:
load_dotenv()
api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
raise ValueError("GEMINI_API_KEY not found in environment variables.")
self.client = genai.Client(api_key=api_key)
except Exception as e:
self.init_error = f"--- FATAL ERROR during Gemini Init: {str(e)} ---"
self.client = None
def transcribe_audio(self, audio_file_path: str) -> Tuple[Optional[str], Optional[str]]:
"""
Transcribes audio. Returns (text, error_message).
"""
if self.init_error:
return None, self.init_error
if not self.client:
return None, "--- ERROR: Gemini client is not available. ---"
try:
if not os.path.exists(audio_file_path):
return None, f"--- ERROR: Audio file for transcription not found at: {audio_file_path} ---"
with open(audio_file_path, 'rb') as f:
audio_bytes = f.read()
file_ext = os.path.splitext(audio_file_path)[1].lower()
mime_type = {'mp3': 'audio/mpeg', 'wav': 'audio/wav', 'm4a': 'audio/mp4'}.get(file_ext, 'audio/mpeg')
response = self.client.models.generate_content(
model="gemini-2.5-flash",
contents=[types.Part.from_bytes(data=audio_bytes, mime_type=mime_type), "Transcribe this audio."]
)
if response and response.text:
return response.text.strip(), None
else:
return None, "--- WARNING: Gemini returned an empty response for transcription. ---"
except Exception as e:
error_msg = f"--- FATAL ERROR during transcription: {traceback.format_exc()} ---"
return None, error_msg
def get_audio_duration(self, audio_file_path: str) -> Tuple[Optional[float], Optional[str]]:
"""
Gets audio duration. Returns (duration, error_message).
"""
try:
if not os.path.exists(audio_file_path):
return None, f"--- ERROR: Audio file for duration not found at: {audio_file_path} ---"
duration = librosa.get_duration(path=audio_file_path)
if duration is None or duration < 0.1:
return None, f"--- ERROR: librosa returned an invalid duration: {duration}s ---"
return duration, None
except Exception as e:
error_msg = f"--- FATAL ERROR getting audio duration with librosa: {traceback.format_exc()} ---"
return None, error_msg
def get_word_timestamps(self, audio_file_path: str) -> Tuple[List[Dict], List[str]]:
"""
Generates timestamps. Returns (timestamps, log_messages).
"""
logs = ["--- INFO: Starting get_word_timestamps... ---"]
transcription, error = self.transcribe_audio(audio_file_path)
if error:
logs.append(error)
return [], logs
logs.append(f"--- DEBUG: Transcription successful. Text: '{transcription[:50]}...'")
audio_duration, error = self.get_audio_duration(audio_file_path)
if error:
logs.append(error)
return [], logs
logs.append(f"--- DEBUG: Audio duration successful. Duration: {audio_duration:.2f}s")
words = transcription.split()
if not words:
logs.append("--- WARNING: Transcription resulted in zero words. ---")
return [], logs
logs.append(f"--- INFO: Distributing {len(words)} words across the duration. ---")
word_timestamps = []
total_words = len(words)
usable_duration = max(0, audio_duration - 1.0)
for i, word in enumerate(words):
start_time = 0.5 + (i * (usable_duration / total_words))
end_time = 0.5 + ((i + 1) * (usable_duration / total_words))
word_timestamps.append({'word': word.strip(), 'start': round(start_time, 3), 'end': round(end_time, 3)})
logs.append(f"--- SUCCESS: Generated {len(word_timestamps)} word timestamps. ---")
return word_timestamps, logs |