Files
personal_development/video_transcription/ai_transcriber/translator.py
T
2026-01-10 17:08:51 -05:00

128 lines
4.5 KiB
Python

import os
import sys
import google.generativeai as genai
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
# Define a retry decorator
# Waits 2^x * 1 seconds between retries (1s, 2s, 4s, 8s, 16s, 32s...)
# With max=60, it will cap at waiting 60s per try.
# Stop after 15 attempts (approx 15 minutes of trying before giving up)
retry_policy = retry(
stop=stop_after_attempt(15),
wait=wait_exponential(multiplier=1, min=2, max=60),
retry=retry_if_exception_type(Exception),
reraise=True
)
@retry_policy
def _generate_with_retry(model, prompt):
"""Internal function to wrap the API call with retry logic."""
try:
return model.generate_content(prompt)
except Exception as e:
if "429" in str(e) or "Resource has been exhausted" in str(e):
print(f" [Rate Limit Hit] Waiting for quota reset... ({e})")
raise e
def get_best_available_model():
"""
Queries the API to find the best available model for text generation.
Priority: gemini-1.5-flash > gemini-1.5-pro > gemini-pro > any 'generateContent' model
"""
try:
available_models = []
for m in genai.list_models():
if 'generateContent' in m.supported_generation_methods:
available_models.append(m.name)
# Priority list
priorities = [
"models/gemini-1.5-flash",
"models/gemini-1.5-pro",
"models/gemini-pro"
]
# Check for priorities first
for p in priorities:
if p in available_models:
return p
# Fallback: check for aliases without 'models/' prefix just in case
for p in priorities:
short_name = p.replace("models/", "")
# Some libraries might return short names, or custom handling
# But genai.list_models() usually returns 'models/name'
pass
# If priority not found, pick the first available gemini model
for m in available_models:
if "gemini" in m:
return m
if available_models:
return available_models[0]
except Exception as e:
print(f"Warning: Could not list models ({e}). Defaulting to 'gemini-pro'.")
return "gemini-pro"
def translate_srt(srt_content, target_language="English", api_key=None):
"""
Translates SRT subtitle content using the Gemini API, preserving timestamps.
Args:
srt_content (str): The raw text content of the SRT file.
target_language (str): The target language for translation.
api_key (str): Google Gemini API key. If None, checks env var GEMINI_API_KEY.
Returns:
str: The translated SRT content.
"""
if not srt_content:
return ""
key = api_key or os.getenv("GEMINI_API_KEY")
if not key:
print("Error: GEMINI_API_KEY not found. Please set the environment variable or pass the key.")
sys.exit(1)
genai.configure(api_key=key)
# Automatically select the best model
model_name = get_best_available_model()
print(f"Using Gemini Model: {model_name}")
model = genai.GenerativeModel(model_name)
prompt = (
"You are a professional subtitle translator. Your task is to translate the following SRT subtitle file "
f"into {target_language}.\n\n"
"RULES:\n"
"1. PRESERVE the SRT format exactly. Do not modify timestamps (e.g., 00:00:01,000 --> 00:00:04,000) or sequence numbers.\n"
"2. Only translate the dialogue text.\n"
"3. Maintain the original tone and context.\n"
"4. Output ONLY the translated SRT content, no markdown code blocks or explanations.\n\n"
"SRT Content:\n"
f"{srt_content}"
)
print(f"Translating subtitles to {target_language} (with retries)...")
try:
# Call the retried internal function
response = _generate_with_retry(model, prompt)
print("Translation complete.")
# Cleanup: sometimes models wrap output in ```srt ... ``` or ``` ... ```
cleaned_text = response.text.strip()
if cleaned_text.startswith("```"):
# Remove first line (```srt or ```) and last line (```)
lines = cleaned_text.split('\n')
if len(lines) >= 2:
cleaned_text = '\n'.join(lines[1:-1])
return cleaned_text
except Exception as e:
print(f"Error during translation after retries: {e}")
return None