add translation cache and queue

This commit is contained in:
2025-05-29 13:53:25 +03:00
parent bcee61a817
commit 5b76a0dcbd
8 changed files with 307 additions and 24 deletions

View File

@@ -30,6 +30,9 @@ from urllib.parse import urljoin
from apscheduler.schedulers.background import BackgroundScheduler
import time
from config import BASE_URL
from utils import notify_telegram
import threading
from translation_queue import add_to_queue, translate_from_queue
# Добавляем в начало файла
login_manager = LoginManager()
@@ -457,6 +460,8 @@ def start_translation(filename: str):
translation_status["processed_items"] = 0
translation_status["error"] = None
notify_telegram(f"[🚀] Початок перекладу: {filename}")
try:
os.makedirs("output/translated", exist_ok=True)
@@ -499,16 +504,23 @@ def start_translation(filename: str):
) as f:
json.dump(translated_products, f, ensure_ascii=False, indent=2)
print(f"[OK] Збережено переклад: {output_filename}")
notify_telegram(
f"[✅] Переклад завершено: {filename} ({len(translated_products)} товарів)"
)
else:
print(f"[SKIP] Жодного перекладеного товару: {filename}. Файл не створено.")
notify_telegram(f"[⚠️] Жодного товару не перекладено: {filename}")
except Exception as e:
translation_status["error"] = str(e)
print(f"Ошибка перевода: {e}")
notify_telegram(f"[❌] Помилка перекладу: {filename}\n{e}")
add_to_queue(filename)
raise e
finally:
translation_status["is_running"] = False
active_translations.discard(filename)
print(f"[DONE] Переклад завершено: {filename}")
def refresh_all_categories_daily():
@@ -555,31 +567,66 @@ def refresh_all_categories_daily():
def translate_all_parsed_once():
"""Одноразово запускає переклад для всіх ще не перекладених файлів"""
print("[START] Одноразовий переклад всіх категорій...")
"""Розумне оновлення перекладу: неперекладені → найстаріші перекладені"""
print("[START] Розумне оновлення перекладу...")
parsed_folder = "output"
translated_folder = "output/translated"
for filename in os.listdir(parsed_folder):
if filename.endswith("_products.json") and not filename.endswith(
"_translated_products.json"
):
parsed_path = os.path.join(parsed_folder, filename)
translated_name = filename.replace(
"_products.json", "_translated_products.json"
)
translated_path = os.path.join(translated_folder, translated_name)
parsed_files = {
f: os.path.getmtime(os.path.join(parsed_folder, f))
for f in os.listdir(parsed_folder)
if f.endswith("_products.json") and not f.endswith("_translated_products.json")
}
if os.path.exists(translated_path):
print(f"[SKIP] Вже перекладено: {filename}")
continue
translated_files = {
f.replace("_translated_products.json", "_products.json"): os.path.getmtime(
os.path.join(translated_folder, f)
)
for f in os.listdir(translated_folder)
if f.endswith("_translated_products.json")
}
print(f"[TRANSLATE] Запускаємо переклад: {filename}")
threading.Thread(target=start_translation, args=(filename,)).start()
time.sleep(2) # трохи затримки між потоками, щоб не навантажувати
# Спочатку неперекладені
untranslated = [f for f in parsed_files if f not in translated_files]
# Потім найстаріші з перекладених
outdated_translations = sorted(
(f for f in parsed_files if f in translated_files),
key=lambda f: translated_files[f],
)
print("[DONE] Запуск перекладу завершено.")
to_translate = untranslated + outdated_translations
for filename in to_translate:
try:
print(f"[TRANSLATE] {filename}")
start_translation(filename) # ⬅️ БЕЗ ПОТОКУ
time.sleep(1) # щоб трохи розвантажити
except Exception as e:
error_text = str(e).lower()
if (
"too many requests" in error_text
or "you are allowed to make" in error_text
or "5 requests per second" in error_text
):
notify_telegram(
f"[🛑] Переклад зупинено після помилки ліміту на файлі: {filename}.\n"
f"Повтор заплановано через 30 хвилин."
)
add_to_queue(filename)
threading.Timer(1800, translate_from_queue).start()
break
else:
notify_telegram(f"[⚠️] Помилка перекладу {filename}:\n{str(e)}")
print("[DONE] translate_all_parsed_once завершено.")
@app.route("/translate-from-queue", methods=["POST"])
def run_translate_from_queue():
threading.Thread(target=translate_from_queue, args=(start_translation,)).start()
return jsonify({"status": "Запущено переклад з черги"})
@app.route("/manual-translate-all", methods=["POST"])