Spaces:
Running
Running
| # code/utils.py | |
| import os | |
| import urllib.request | |
| import re | |
| from core.constants import FONTS_FOLDER | |
| import subprocess | |
| def load_api_keys(prefix): | |
| try: | |
| prefix_lower = prefix.lower() | |
| keys = [] | |
| for k, v in os.environ.items(): | |
| if k.lower().startswith(prefix_lower): | |
| clean_key = v.strip().strip('"').strip("'") | |
| if clean_key: | |
| keys.append(clean_key) | |
| if keys: | |
| print(f"✅ API Key Check: '{prefix}' के लिए {len(keys)} कीज़ मिलीं।") | |
| else: | |
| print(f"❌ API Key Check: '{prefix}' के लिए कोई कीज़ नहीं मिलीं!") | |
| return keys | |
| except Exception as e: | |
| print(f"🚨 एनवायरनमेंट वेरिएबल्स लोड करते समय त्रुटि: {e}") | |
| return [] | |
| def ensure_hindi_font(): | |
| font_path = os.path.join(FONTS_FOLDER, 'NotoSansDevanagari-Bold.ttf') | |
| if not os.path.exists(font_path): | |
| print("-> 📥 Hindi Subtitle Font (Noto Sans) डाउनलोड किया जा रहा है...") | |
| url = "https://raw.githubusercontent.com/googlefonts/noto-fonts/main/hinted/ttf/NotoSansDevanagari/NotoSansDevanagari-Bold.ttf" | |
| try: | |
| urllib.request.urlretrieve(url, font_path) | |
| print("-> ✅ फ़ॉन्ट सफलतापूर्वक डाउनलोड हो गया!") | |
| except Exception as e: | |
| print(f"🚨 फ़ॉन्ट डाउनलोड एरर: {e}") | |
| return FONTS_FOLDER, "sans-serif" # Fallback | |
| return FONTS_FOLDER, "Noto Sans Devanagari" | |
| def smart_text_chunker(text, max_words=150): | |
| """ | |
| Splits the script into logical chunks of roughly 'max_words' length. | |
| It ensures splits only happen at sentence boundaries (. or । or ? or !). | |
| """ | |
| # Clean up multiple spaces or newlines | |
| clean_text = re.sub(r'\s+', ' ', text.strip()) | |
| # Split by Hindi and English sentence terminators, keeping the delimiters | |
| # We use a regex that splits after the punctuation mark and optional spaces. | |
| sentences = re.split(r'(?<=[।\.!\?])\s+', clean_text) | |
| chunks = [] | |
| current_chunk = [] | |
| current_word_count = 0 | |
| for sentence in sentences: | |
| if not sentence.strip(): | |
| continue | |
| words = sentence.split() | |
| word_count = len(words) | |
| # If adding this sentence exceeds the limit AND we already have content, cut the chunk here | |
| if current_word_count + word_count > max_words and current_chunk: | |
| chunks.append(" ".join(current_chunk)) | |
| current_chunk = [sentence] | |
| current_word_count = word_count | |
| else: | |
| current_chunk.append(sentence) | |
| current_word_count += word_count | |
| # Add the last remaining chunk | |
| if current_chunk: | |
| chunks.append(" ".join(current_chunk)) | |
| return chunks | |
| # ============================================================================== | |
| # 🕵️♂️ THE MATH TEACHER (FFmpeg Pause Detector) | |
| # ============================================================================== | |
| def get_audio_silences(audio_path, min_silence_len=0.4, silence_thresh=-35): | |
| """FFmpeg का उपयोग करके ऑडियो के 100% सटीक सन्नाटे (Pauses) निकालता है।""" | |
| cmd = ['ffmpeg', '-i', audio_path, '-af', f'silencedetect=n={silence_thresh}dB:d={min_silence_len}', '-f', 'null', '-'] | |
| result = subprocess.run(cmd, capture_output=True, text=True) | |
| silences = [] | |
| starts = re.findall(r'silence_start:\s+([\d\.]+)', result.stderr) | |
| ends = re.findall(r'silence_end:\s+([\d\.]+)', result.stderr) | |
| for s, e in zip(starts, ends): | |
| silences.append({'start': float(s), 'end': float(e)}) | |
| return silences | |