syncing scripts
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
import os
|
||||
import sys
|
||||
from google import genai
|
||||
from google.genai import types
|
||||
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
|
||||
import pysubs2
|
||||
from deep_translator import GoogleTranslator
|
||||
|
||||
# Define a retry decorator
|
||||
# ... (retry_policy remains)
|
||||
|
||||
def translate_fallback_free(source_srt_content, target_language="en"):
|
||||
"""
|
||||
Fallback translation using deep-translator (free Google Translate).
|
||||
|
||||
Args:
|
||||
source_srt_content (str): Content of the source SRT file.
|
||||
target_language (str): Target language code (e.g. 'en', 'fr').
|
||||
|
||||
Returns:
|
||||
str: Translated SRT content, or None if failed.
|
||||
"""
|
||||
print(f" [Free Fallback] Translating via Google Translate (deep-translator)...")
|
||||
try:
|
||||
# Load from string
|
||||
subs = pysubs2.SSAFile.from_string(source_srt_content)
|
||||
translator = GoogleTranslator(source='auto', target=target_language)
|
||||
|
||||
# Simple line-by-line translation
|
||||
for line in subs:
|
||||
text = line.text.strip()
|
||||
if text:
|
||||
# Sanity check: Skip lines that are too long
|
||||
if len(text) > 4000:
|
||||
print(f" Warning: Skipping line with excessive length ({len(text)} chars).")
|
||||
continue
|
||||
|
||||
try:
|
||||
# pysubs2 text can contain \N for newlines.
|
||||
original_text = text.replace(r"\N", " ")
|
||||
translated_text = translator.translate(original_text)
|
||||
if translated_text:
|
||||
line.text = translated_text
|
||||
except Exception as e:
|
||||
print(f" Warning: Failed to translate line: {e}")
|
||||
|
||||
# Return as string
|
||||
return subs.to_string(format_="srt")
|
||||
except Exception as e:
|
||||
print(f" [Free Fallback] Critical Error: {e}")
|
||||
return None
|
||||
|
||||
# Define a retry decorator
|
||||
# Waits 2^x * 1 seconds between retries (1s, 2s, 4s...)
|
||||
# Stop after 15 attempts
|
||||
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(client, model_name, prompt):
|
||||
"""Internal function to wrap the API call with retry logic."""
|
||||
try:
|
||||
return client.models.generate_content(
|
||||
model=model_name,
|
||||
contents=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(client):
|
||||
"""
|
||||
Queries the API to find the best available model for text generation.
|
||||
Priority: gemini-2.0-flash > gemini-1.5-flash > gemini-1.5-pro
|
||||
"""
|
||||
try:
|
||||
# Priority list (New v2 naming conventions if applicable, but standard models persist)
|
||||
priorities = [
|
||||
"gemini-2.0-flash", # Latest
|
||||
"gemini-1.5-flash",
|
||||
"gemini-1.5-pro"
|
||||
]
|
||||
|
||||
# In new SDK, client.models.list() returns iterators of Model objects
|
||||
# We can just try to use the priority one directly, or list them.
|
||||
# Listing can be slow. Let's just default to a known good priority list.
|
||||
# If we really want to check:
|
||||
# available = [m.name for m in client.models.list()]
|
||||
|
||||
# For efficiency/speed, we will trust our priority list.
|
||||
# The API will error if model doesn't exist, which the try/catch block handling generation will catch?
|
||||
# No, better to pick one that exists.
|
||||
|
||||
# Let's return the latest standard one.
|
||||
return "gemini-2.0-flash" # Assuming 2.0 is available or falling back
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Model selection issue ({e}). Defaulting to 'gemini-1.5-flash'.")
|
||||
|
||||
return "gemini-1.5-flash"
|
||||
|
||||
def translate_srt(srt_content, target_language="English", api_key=None):
|
||||
"""
|
||||
Translates SRT subtitle content using the Google GenAI SDK (v2).
|
||||
"""
|
||||
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)
|
||||
|
||||
# Initialize Client (v2 style)
|
||||
try:
|
||||
client = genai.Client(api_key=key)
|
||||
except Exception as e:
|
||||
print(f"Error initializing GenAI Client: {e}")
|
||||
return None
|
||||
|
||||
# Automatically select the best model
|
||||
# Note: v2 SDK might use 'gemini-1.5-flash' directly without 'models/' prefix usually
|
||||
model_name = "gemini-2.0-flash"
|
||||
print(f"Using Gemini Model (v2): {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(client, model_name, prompt)
|
||||
print("Translation complete.")
|
||||
|
||||
# Cleanup: sometimes models wrap output in ```srt ... ``` or ``` ... ```
|
||||
cleaned_text = response.text.strip()
|
||||
if cleaned_text.startswith("```"):
|
||||
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}")
|
||||
# Fallback to older model if 2.0 fails?
|
||||
if "404" in str(e) and "gemini-2.0" in model_name:
|
||||
print(" -> gemini-2.0-flash not found, falling back to gemini-1.5-flash")
|
||||
try:
|
||||
response = _generate_with_retry(client, "gemini-1.5-flash", prompt)
|
||||
cleaned_text = response.text.strip()
|
||||
if cleaned_text.startswith("```"):
|
||||
lines = cleaned_text.split('\n')
|
||||
if len(lines) >= 2:
|
||||
cleaned_text = '\n'.join(lines[1:-1])
|
||||
return cleaned_text
|
||||
except Exception as inner_e:
|
||||
print(f"Fallback failed: {inner_e}")
|
||||
|
||||
return None
|
||||
Reference in New Issue
Block a user