126 lines
4.4 KiB
Python
126 lines
4.4 KiB
Python
#!/usr/bin/env python3
|
|
"""Pre-traduce a EN con Haiku los posts del gap que Gemma AÚN no ha alcanzado.
|
|
|
|
Crea el post EN + enlace Polylang (reutiliza fea_translate_helper.php, igual que
|
|
Gemma) ANTES de que Gemma llegue. Cuando Gemma llega, ve la traducción EN ya
|
|
enlazada en Polylang y la salta (translate_post.py:233), haciendo solo FR/IT/PT.
|
|
Así el EN se hace UNA vez y bien, sin el reprocesado posterior.
|
|
|
|
Coordinación: recorre los posts en el MISMO orden que Gemma, localiza por dónde
|
|
va (último :en en el state) y arranca `--margin` posts por delante para no
|
|
colisionar con el que Gemma está procesando ahora. Haiku (API) es mucho más
|
|
rápido que Gemma local, así que se aleja y nunca la alcanza.
|
|
|
|
Uso:
|
|
pretranslate_en_haiku.py # PLAN: muestra arranque y pendientes
|
|
pretranslate_en_haiku.py --apply # crea los EN
|
|
opciones: --margin N (def 2), --limit N
|
|
"""
|
|
import argparse
|
|
import json
|
|
import os
|
|
import sys
|
|
import time
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
sys.path.insert(0, HERE)
|
|
|
|
import translate_post as tp # read_post, translation_exists, create_translation, carta_article_ids
|
|
from translate_haiku import translate # Haiku
|
|
|
|
# Mismo orden que translate_gap.sh
|
|
CARTAS = "45018 44997 44975 44230 44229 44228 44090 44089 44088 44087 44086 44085 44084 44083 42590".split()
|
|
|
|
|
|
def read_state():
|
|
"""Lee el state de Gemma con reintentos (lo reescribe en vivo)."""
|
|
for _ in range(6):
|
|
try:
|
|
d = json.loads(open(tp.STATE_FILE).read())
|
|
if d.get("done"):
|
|
return d
|
|
except (json.JSONDecodeError, FileNotFoundError):
|
|
pass
|
|
time.sleep(0.5)
|
|
sys.exit("No pude leer el state de Gemma con contenido; aborto por seguridad.")
|
|
|
|
|
|
def build_order():
|
|
"""Lista global de post_ids en el orden exacto en que Gemma los procesa."""
|
|
g = []
|
|
for c in CARTAS:
|
|
g.append(int(c))
|
|
g.extend(tp.carta_article_ids(int(c)))
|
|
return g
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--apply", action="store_true")
|
|
ap.add_argument("--margin", type=int, default=2)
|
|
ap.add_argument("--limit", type=int, default=0)
|
|
args = ap.parse_args()
|
|
|
|
state = read_state()
|
|
done = state["done"]
|
|
order = build_order()
|
|
|
|
# Frente de Gemma = último índice con su :en ya hecho.
|
|
front = -1
|
|
for i, pid in enumerate(order):
|
|
if f"{pid}:en" in done:
|
|
front = i
|
|
if front < 0:
|
|
sys.exit("No encuentro el frente de Gemma en la lista; aborto.")
|
|
|
|
start = front + 1 + args.margin
|
|
work = order[start:]
|
|
if args.limit:
|
|
work = work[:args.limit]
|
|
|
|
cur = order[front]
|
|
print(f"Gemma va por #{cur} (índice {front}/{len(order)-1}).")
|
|
print(f"Margen {args.margin} → arranco en índice {start} (#{order[start] if start < len(order) else '—'}).")
|
|
print(f"Posts pendientes a pre-traducir: {len(work)}")
|
|
if work:
|
|
print(f" primeros: {work[:5]}")
|
|
print(f" últimos: {work[-5:]}")
|
|
if not args.apply:
|
|
print("\nMODO PLAN (no se crea nada). Añade --apply para ejecutar.")
|
|
return
|
|
|
|
tot_in = tot_out = 0.0
|
|
created = skipped = 0
|
|
for pid in work:
|
|
if tp.translation_exists(pid, "en"):
|
|
print(f"#{pid}: EN ya existe (Gemma se adelantó) — salto")
|
|
skipped += 1
|
|
continue
|
|
try:
|
|
src = tp.read_post(pid)
|
|
except Exception as e: # noqa: BLE001
|
|
print(f"#{pid}: no pude leer ({e}) — salto")
|
|
continue
|
|
if src.get("lang") and src["lang"] != "es":
|
|
continue
|
|
body, u1 = translate(src["content"], "en")
|
|
title, u2 = translate(src["title"], "en", is_title=True)
|
|
tot_in += u1.input_tokens + u2.input_tokens
|
|
tot_out += u1.output_tokens + u2.output_tokens
|
|
# Re-chequeo justo antes de crear (ventana de carrera con Gemma).
|
|
if tp.translation_exists(pid, "en"):
|
|
print(f"#{pid}: EN apareció mientras traducía — salto")
|
|
skipped += 1
|
|
continue
|
|
new_id = tp.create_translation(pid, "en", title, body, "draft")
|
|
created += 1
|
|
print(f"#{pid} → EN #{new_id} «{title[:45]}»")
|
|
|
|
cost = tot_in / 1e6 * 1.0 + tot_out / 1e6 * 5.0
|
|
print(f"\nCreados: {created} Saltados: {skipped}")
|
|
print(f"Tokens in={int(tot_in)} out={int(tot_out)} coste=${cost:.4f}")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|