add translation cache and queue
This commit is contained in:
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user