s2v / core /utils.py
diwash-barla1's picture
Initial commit with clean history
aa642ce
Raw
History Blame Contribute Delete
3.97 kB
# 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