Mejora: Optimización radical de carga del panel mediante pre-calentamiento asíncrono de caché UI (#5)
This commit is contained in:
@@ -1,5 +1,8 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import glob
|
||||||
|
import re
|
||||||
|
import asyncio
|
||||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException, status
|
from fastapi import FastAPI, HTTPException, status
|
||||||
@@ -67,12 +70,82 @@ def translate_filter(text, lang="es"):
|
|||||||
|
|
||||||
templates.env.filters["translate"] = translate_filter
|
templates.env.filters["translate"] = translate_filter
|
||||||
|
|
||||||
|
_warmed_languages = set()
|
||||||
|
|
||||||
|
async def pre_warm_ui_translations(lang: str):
|
||||||
|
if lang == "es" or lang in _warmed_languages:
|
||||||
|
return
|
||||||
|
|
||||||
|
_warmed_languages.add(lang)
|
||||||
|
print(f"[Panel] Pre-calentando traducciones para idioma UI: {lang}...")
|
||||||
|
|
||||||
|
strings_to_translate = set()
|
||||||
|
for f in glob.glob(os.path.join(os.path.dirname(__file__), "templates", "*.html")):
|
||||||
|
try:
|
||||||
|
with open(f, "r", encoding="utf-8") as fd:
|
||||||
|
content = fd.read()
|
||||||
|
strings_to_translate.update(re.findall(r'\"([^\"]+)\"\s*\|\s*translate', content))
|
||||||
|
strings_to_translate.update(re.findall(r'\'([^\']+)\'\s*\|\s*translate', content))
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
missing_strings = []
|
||||||
|
for text in strings_to_translate:
|
||||||
|
norm_text = _normalize_text(text)
|
||||||
|
if not norm_text: continue
|
||||||
|
|
||||||
|
cache_key = f"{lang}:{norm_text}"
|
||||||
|
if cache_key in _ui_memory_cache: continue
|
||||||
|
|
||||||
|
cached = get_ui_translation(norm_text, lang)
|
||||||
|
if cached:
|
||||||
|
_ui_memory_cache[cache_key] = cached
|
||||||
|
else:
|
||||||
|
missing_strings.append(norm_text)
|
||||||
|
|
||||||
|
if not missing_strings:
|
||||||
|
print(f"[Panel] Pre-calentamiento completo: 0 cadenas faltantes para {lang}")
|
||||||
|
return
|
||||||
|
|
||||||
|
print(f"[Panel] Falta traducir {len(missing_strings)} cadenas UI al {lang}. Empezando concurrencia...")
|
||||||
|
|
||||||
|
from botdiscord.translate import translate_text
|
||||||
|
|
||||||
|
async def _fetch_and_save(text):
|
||||||
|
translated = await translate_text(text, lang)
|
||||||
|
if translated and translated != text:
|
||||||
|
save_ui_translation(text, lang, translated)
|
||||||
|
_ui_memory_cache[f"{lang}:{text}"] = translated
|
||||||
|
|
||||||
|
tasks = [_fetch_and_save(t) for t in missing_strings]
|
||||||
|
await asyncio.gather(*tasks)
|
||||||
|
print(f"[Panel] Pre-calentamiento terminado para {lang}.")
|
||||||
|
|
||||||
|
@app.middleware("http")
|
||||||
|
async def translation_pre_warm_middleware(request: Request, call_next):
|
||||||
|
# Detectamos el idioma que va a usar la página para asegurarnos de que esté cargado
|
||||||
|
if request.url.path.startswith("/static") or request.url.path.startswith("/api"):
|
||||||
|
return await call_next(request)
|
||||||
|
|
||||||
|
lang = request.cookies.get("panel_lang")
|
||||||
|
if not lang:
|
||||||
|
accept_lang = request.headers.get("accept-language", "es")
|
||||||
|
lang = accept_lang.split(",")[0].split("-")[0]
|
||||||
|
|
||||||
|
if lang and len(lang) == 2:
|
||||||
|
await pre_warm_ui_translations(lang)
|
||||||
|
|
||||||
|
return await call_next(request)
|
||||||
|
|
||||||
@app.get("/set-lang/{lang}")
|
@app.get("/set-lang/{lang}")
|
||||||
async def set_lang(lang: str, request: Request):
|
async def set_lang(lang: str, request: Request):
|
||||||
# Validamos que el idioma sea de 2 letras
|
# Validamos que el idioma sea de 2 letras
|
||||||
if len(lang) != 2:
|
if len(lang) != 2:
|
||||||
return RedirectResponse(url="/dashboard")
|
return RedirectResponse(url="/dashboard")
|
||||||
|
|
||||||
|
# Ejecutamos el calentamiento asíncrono para que la redirección sea instantánea
|
||||||
|
await pre_warm_ui_translations(lang)
|
||||||
|
|
||||||
response = RedirectResponse(url=request.headers.get("referer", "/dashboard"))
|
response = RedirectResponse(url=request.headers.get("referer", "/dashboard"))
|
||||||
response.set_cookie(key="panel_lang", value=lang, max_age=31536000) # 1 año
|
response.set_cookie(key="panel_lang", value=lang, max_age=31536000) # 1 año
|
||||||
return response
|
return response
|
||||||
|
|||||||
Reference in New Issue
Block a user