Advertisement
Guest User

Reactorcode

a guest
Feb 5th, 2025
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 40.69 KB | Source Code | 0 0
  1. import json
  2. import time
  3. import re
  4. import requests
  5. from transformers import AutoTokenizer
  6. from threading import Event
  7. import keyboard
  8. import google.generativeai as genai
  9. from langdetect import detect
  10. from langdetect.lang_detect_exception import LangDetectException
  11.  
  12.  
  13. # --- Настройки API ---
  14. API_MODE = "kobold" # <--- KoboldAI теперь режим API по умолчанию
  15. GOOGLE_API_KEY = "" # <--- API ключ по умолчанию, можно изменить
  16. genai.configure(api_key=GOOGLE_API_KEY)
  17. model = genai.GenerativeModel("gemini-1.5-flash")
  18. API_URL = "http://localhost:5001/api/v1/generate" # URL локального API KoboldAI
  19.  
  20.  
  21. # --- Системные промпты и инструкции (цензуроустойчивые) ---
  22. SYSTEM_PROMPTS = {
  23.     "jp_to_en": (
  24.         "You are a highly skilled and neutral Japanese-to-English translator. "
  25.         "Your task is to translate Japanese text into English with absolute factual accuracy and neutrality. "
  26.         "Do not provide any explanations, comments, or extra output. "
  27.         "Only the translated text should be returned—no additional words, symbols, or markers. "
  28.         "Focus on delivering objective, precise, natural translations that maintain the original tone and intent, without any personal bias or censorship. "
  29.         "Your role is to provide a factual translation, not to judge or censor the content.\n\n"
  30.     ),
  31.     "jp_to_ru": (
  32.         "You are a highly skilled and нейтральный Japanese-to-Russian translator. "
  33.         "Your task is to translate Japanese text into Russian with абсолютной фактической точностью и нейтральностью. "
  34.         "Do not provide any explanations, comments, or extra output. "
  35.         "Only the translated text should be returned—no additional words, symbols, or markers. "
  36.         "Focus on delivering объективные, precise, natural translations that maintain the original tone and intent, без каких-либо личных предубеждений или цензуры. "
  37.         "Ваша роль - предоставить фактический перевод, а не судить или цензурировать содержание.\n\n"
  38.     ),
  39.     "en_to_ru": (
  40.         "You are a highly skilled and нейтральный English-to-Russian translator. "
  41.         "Your task is to translate English text into Russian with абсолютной фактической точностью и нейтральностью. "
  42.         "Do not provide any explanations, comments, or extra output. "
  43.         "Only the translated text should be returned—no additional words, symbols, or markers. "
  44.         "Focus on delivering объективные, precise, natural translations that maintain the original tone and intent, без каких-либо личных предубеждений или цензуры. "
  45.         "Ваша роль - предоставить фактический перевод, а не судить или цензурировать содержание.\n\n"
  46.     ),
  47.     "en_jp_to_ru": (
  48.         "You are a highly skilled and нейтральный translator proficient in English, Japanese, and Russian. "
  49.         "Your task is to translate English and Japanese text into Russian with абсолютной фактической точностью и нейтральностью. "
  50.         "Do not provide any explanations, comments, or extra output. "
  51.         "Only the translated text should be returned—no additional words, symbols, or markers. "
  52.         "Focus on delivering объективные, precise, natural translations that maintain the original tone and intent, без каких-либо личных предубеждений или цензуры. "
  53.         "Ваша роль - предоставить фактический перевод, а не судить или цензурировать содержание.\n\n"
  54.     ),
  55. }
  56.  
  57.  
  58. INSTRUCTIONS = {
  59.     "jp_to_en": "Translate Japanese to English. Ensure clarity and precision. Only output the translation.",
  60.     "jp_to_ru": "Translate Japanese to Russian. Ensure clarity and precision. Only output the translation.",
  61.     "en_to_ru": "Translate English to Russian. Ensure clarity and precision. Only output the translation.",
  62.     "en_jp_to_ru": "Translate English and Japanese to Russian. Ensure clarity and precision. Only output the translation."
  63. }
  64.  
  65.  
  66. # Инициализация токенизатора для KoboldAI (нужен только для KoboldAI)
  67. tokenizer = AutoTokenizer.from_pretrained("webbigdata/gemma-2-2b-jpn-it-translate")
  68.  
  69.  
  70. # Событие для управления паузой
  71. pause_event = Event()
  72. pause_event.set()
  73. menu_requested = False # Флаг запроса меню
  74.  
  75.  
  76. def toggle_pause():
  77.     global pause_event
  78.     if pause_event.is_set():
  79.         print("Пауза включена. Нажмите 'p' для продолжения...")
  80.         pause_event.clear()
  81.     else:
  82.         print("Продолжение выполнения...")
  83.         pause_event.set()
  84.  
  85.  
  86. def request_menu():
  87.     global menu_requested
  88.     print("Запрос на возврат в меню...")
  89.     menu_requested = True # Устанавливаем флаг запроса меню
  90.  
  91.  
  92. keyboard.add_hotkey('p', toggle_pause)
  93. keyboard.add_hotkey('\\', request_menu) # Клавиша для запроса меню
  94.  
  95.  
  96. def set_api_mode():
  97.     global API_MODE, GOOGLE_API_KEY, genai, model
  98.     print("Выберите режим API:")
  99.     print("1 - Google Gemini (онлайн)")
  100.     print("2 - KoboldAI (локально)")
  101.     choice = input("Введите 1 или 2: ").strip()
  102.     if choice == "1":
  103.         API_MODE = "google"
  104.         print("Используется Google Gemini API.")
  105.     elif choice == "2":
  106.         API_MODE = "kobold"
  107.         print("Используется KoboldAI (локальный API).")
  108.     else:
  109.         print("Неверный выбор. API режим остается без изменений.")
  110.  
  111.  
  112. def change_google_api_key():
  113.     global GOOGLE_API_KEY, genai, model
  114.     new_api_key = input("Введите новый Google API ключ: ").strip()
  115.     if new_api_key:
  116.         GOOGLE_API_KEY = new_api_key
  117.         genai.configure(api_key=GOOGLE_API_KEY)
  118.         model = genai.GenerativeModel("gemini-1.5-flash") # Re-init model with new key
  119.         print("Google API ключ обновлен.")
  120.     else:
  121.         print("API ключ не был изменен.")
  122.  
  123.  
  124.  
  125.  
  126. def get_user_settings():
  127.     global API_MODE
  128.     print("Do you want to change temperature, tokens, batch size, and delay settings?")
  129.     print("1 - Yes, change settings.")
  130.     print("2 - No, use default settings.")
  131.     choice = input("Enter 1 or 2: ").strip()
  132.  
  133.  
  134.     default_batch_size = 1 # <--- Default batch size теперь 1 для всех API режимов (более безопасно для KoboldAI)
  135.     default_delay = 15 if API_MODE == "google" else 0 # Задержка для Google или 0 для Kobold
  136.  
  137.  
  138.     if choice == "1":
  139.         try:
  140.             temperature = float(input("Enter temperature (recommended between 0.1 and 1.0, e.g., 0.7): ").strip())
  141.             max_tokens = int(input("Enter maximum tokens (e.g., 30): ").strip())
  142.             batch_size = int(input(f"Enter batch size (e.g., {default_batch_size}): ").strip()) # Подсказка размера батча
  143.             delay = int(input(f"Enter delay between batches in seconds (e.g., {default_delay}): ").strip()) # Подсказка задержки
  144.             print(f"Settings set: Temperature = {temperature}, Tokens = {max_tokens}, Batch Size = {batch_size}, Delay = {delay}")
  145.             return temperature, max_tokens, batch_size, delay
  146.         except ValueError:
  147.             print("Invalid input. Using default settings.")
  148.             return 0.7, 30, default_batch_size, default_delay
  149.     elif choice == "2":
  150.         print("Using default settings.")
  151.         return 0.7, 30, default_batch_size, default_delay
  152.     else:
  153.         print("Invalid choice. Using default settings.")
  154.         return 0.7, 30, default_batch_size, default_delay
  155.  
  156.  
  157.  
  158.  
  159. def translate_text_google_ai(texts, system_prompt, instruction, temperature=0.7, max_tokens=30):
  160.     if texts and isinstance(texts[0], tuple) and len(texts[0]) == 3:
  161.         prompt_lines = [f"[{line_number}] {original_original_text}" for line_number, original_original_text, original_key in texts]
  162.     elif texts and isinstance(texts[0], tuple) and len(texts[0]) == 2:
  163.         prompt_lines = [f"[{line_number}] {text}" for line_number, text in texts]
  164.     else:
  165.         print("Error: Неверный формат входных данных для translate_text_google_ai.")
  166.         return []
  167.  
  168.  
  169.     prompt = f"{system_prompt}{instruction}\n" + "\n".join(prompt_lines)
  170.     try:
  171.         response = model.generate_content(prompt, generation_config=genai.types.GenerationConfig(temperature=temperature, max_output_tokens=max_tokens))
  172.         translations_text = response.text.strip()
  173.         translations = translations_text.split('\n')
  174.         return translations
  175.     except Exception as e:
  176.         print(f"Error during translation with Google AI: {e}")
  177.         return []
  178.  
  179.  
  180. def translate_text_koboldai(text, mode, temperature=0.7, max_tokens=30, system_prompt=None, instruction=None): # <--- Добавлены system_prompt и instruction
  181.     # Используем переданные system_prompt и instruction, если они есть (для кастомных режимов)
  182.     if system_prompt is None or instruction is None:
  183.         system_prompt = SYSTEM_PROMPTS.get(mode) # Используем .get() чтобы избежать KeyError для неизвестных mode
  184.         instruction = INSTRUCTIONS.get(mode)     # Используем .get() чтобы избежать KeyError для неизвестных mode
  185.  
  186.  
  187.         if system_prompt is None or instruction is None: # Если mode все равно нет в словарях
  188.             print(f"Warning: No system prompt or instruction found for mode '{mode}'. Using default.")
  189.             system_prompt = SYSTEM_PROMPTS.get("en_to_ru") # или другой дефолтный, если нужно
  190.             instruction = INSTRUCTIONS.get("en_to_ru")     # или другой дефолтный, если нужно
  191.             if system_prompt is None or instruction is None: # Если даже дефолтных нет
  192.                 print("Error: Default system prompt and instruction are also missing!")
  193.                 return None # Или вызвать исключение, если это критично
  194.  
  195.  
  196.     messages = [
  197.         {"role": "user", "content": system_prompt + instruction},
  198.         {"role": "assistant", "content": "OK"},
  199.         {"role": "user", "content": text},
  200.     ]
  201.  
  202.  
  203.     prompt = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
  204.     payload = {
  205.         "prompt": prompt,
  206.         "max_length": max_tokens,
  207.         "temperature": temperature
  208.     }
  209.  
  210.  
  211.     try:
  212.         response = requests.post(API_URL, json=payload)
  213.         if response.status_code == 200:
  214.             data = response.json()
  215.             translation = data.get("results", [{}])[0].get("text", "").strip()
  216.             return translation.split('<end_of_turn>')[0] if '<end_of_turn>' in translation else translation
  217.         else:
  218.             print(f"Ошибка API KoboldAI: {response.status_code} - {response.text}")
  219.     except Exception as e:
  220.         print(f"Ошибка соединения с KoboldAI: {e}")
  221.     return None
  222.  
  223.  
  224.  
  225.  
  226. def load_translated_data(output_file):
  227.     try:
  228.         with open(output_file, 'r', encoding='utf-8') as file:
  229.             return json.load(file)
  230.     except FileNotFoundError:
  231.         return {}
  232.  
  233.  
  234. def save_translated_data(translated_data, output_file):
  235.     with open(output_file, 'w', encoding='utf-8') as file:
  236.         json.dump(translated_data, file, ensure_ascii=False, indent=4)
  237.  
  238.  
  239. def should_translate(text, mode):
  240.     if text.startswith("EV") and text[2:].isdigit(): # Пропускаем строки, начинающиеся с "EV" и цифр (всегда)
  241.         return False
  242.     if mode in ["jp_to_en", "jp_to_ru"]: # <--- Применяем фильтр для японских режимов
  243.         if re.match(r'^[A-Za-z0-9\s\+\-\*/=.,!?\'"()<>@#$%^&*_~]+$', text): # Фильтр знаков и чисел (для японских режимов)
  244.             return False # Пропускаем, если строка выглядит как английский текст (в японских режимах)
  245.     if mode not in ["en_to_ru", "en_jp_to_ru"]: # <--- Фильтр знаков и чисел для НЕ-английских режимов (уточнение условия)
  246.         if re.match(r'^[A-Za-z0-9\s\+\-\*/=.,!?\'"()<>@#$%^&*_~]+$', text): # Фильтр знаков и чисел (для НЕ-английских режимов)
  247.             return False # Пропускаем, если строка выглядит как знаки и числа (в НЕ-английских режимах)
  248.  
  249.  
  250.     if mode in ["en_to_ru", "en_jp_to_ru"]:
  251.         return True # Всегда переводить для en_to_ru и en_jp_to_ru
  252.     return bool(re.search(r'[\u3040-\u30FF|\u4E00-\u9FAF]', text)) # Проверка на японские символы для jp_to_en, jp_to_ru
  253.  
  254.  
  255.  
  256.  
  257. def is_translated(text, mode):
  258.     source_lang = None  # Инициализируем source_lang значением по умолчанию None
  259.     target_lang = ""
  260.     source_lang_for_check = ""
  261.  
  262.  
  263.     if mode in ["jp_to_en", "jp_to_ru", "en_to_ru", "en_jp_to_ru"]:
  264.         if mode == "jp_to_en":
  265.             target_lang = "en"
  266.             target_lang_regex = r'[a-zA-Z]'
  267.             source_lang_for_check = "ja"
  268.             source_lang = "ja" # Явно определяем source_lang для jp_to_en
  269.         elif mode == "jp_to_ru":
  270.             target_lang = "ru"
  271.             target_lang_regex = r'[\u0400-\u052F]'
  272.             source_lang_for_check = "ja"
  273.             source_lang = "ja" # Явно определяем source_lang для jp_to_ru
  274.         elif mode == "en_to_ru":
  275.             target_lang = "ru"
  276.             target_lang_regex = r'[\u0400-\u052F]'
  277.             source_lang_for_check = "en"
  278.             source_lang = "en" # Явно определяем source_lang для en_to_ru
  279.         elif mode == "en_jp_to_ru": # Чуть сложнее, т.к. 2 исходных
  280.             target_lang = "ru"
  281.             target_lang_regex = r'[\u0400-\u052F]'
  282.             source_lang_for_check = "en"
  283.             source_lang = "en,ja" # Явно определяем source_lang для en_jp_to_ru
  284.         elif "_" in mode and "to" in mode: # <--- Добавлена обработка кастомных режимов!
  285.             parts = mode.split("_to_")
  286.             if len(parts) == 2:
  287.                 source_lang_code, target_lang_code = parts[0], parts[1]
  288.                 target_lang = target_lang_code # Целевой язык берем из кода режима
  289.                 source_lang = source_lang_code # <--- Получаем исходный язык из mode  <--- Вот тут добавлено
  290.                 print(f"DEBUG: is_translated - Custom mode: {mode}, source_lang: {source_lang}, target_lang: {target_lang}") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  291.             else: # <--- Добавлена обработка ошибки, если mode некорректный
  292.                 print(f"Warning: Invalid custom mode format: {mode}") # Выводим предупреждение
  293.                 return True # Считаем "переведенным", чтобы избежать ошибок
  294.         else:
  295.             return True # Для неизвестных mode, считаем "переведенным"
  296.  
  297.  
  298.         if re.match(r'^\d+px$', text.strip()):
  299.             return True
  300.         if re.match(r'.*\.(js|css|html|wasm|json|txt|log|png|jpg|jpeg|gif|svg)$', text.lower().strip()):
  301.             return True
  302.         if re.match(r'^(failed to load|error|warning|exception|stack trace).*', text.lower().strip()):
  303.             return True
  304.         if re.match(r'^[0-9\s\.,]+$', text.strip()):
  305.             return True
  306.  
  307.  
  308.         try:
  309.             detected_lang = detect(text) # Определяем язык текста
  310.             print(f"DEBUG: is_translated - detected_lang: {detected_lang}, target_lang: {target_lang}, source_lang: {source_lang}") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  311.             print(f"DEBUG: is_translated - Text being checked: '{text}'") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  312.  
  313.  
  314.             if detected_lang == target_lang: # Проверяем, соответствует ли ЦЕЛЕВОМУ языку
  315.                 if source_lang_for_check: # Если нужно проверять и исходный язык (например, для jp_to_en)
  316.                     if detected_lang == source_lang_for_check: # Если случайно определился как исходный (например, en для jp_to_en), это не перевод
  317.                         print(f"DEBUG: is_translated - detected_lang == source_lang is TRUE") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  318.                         return False # Если язык ОПРЕДЕЛЕН как ИСХОДНЫЙ, значит, это НЕ перевод
  319.                     print(f"DEBUG: is_translated - detected_lang == target_lang is TRUE, detected_lang == source_lang is FALSE") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  320.                     return True # Определен как ЦЕЛЕВОЙ язык и НЕ исходный, считаем переводом
  321.                 return True # Для режимов без source_lang_for_check (например, en_to_ru), просто проверяем целевой язык
  322.             else:
  323.                 print(f"DEBUG: is_translated - detected_lang == target_lang is FALSE") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  324.                 return False # Определен как ДРУГОЙ язык, не считаем переводом
  325.         except LangDetectException: # Обработка исключения, если langdetect не смог определить язык
  326.             print(f"DEBUG: is_translated - LangDetectException occurred") # <--- ДОБАВЛЕННЫЙ ВЫВОД
  327.             return False # Если не удалось определить, считаем "не переведенным" (можно изменить логику, если нужно)
  328.  
  329.  
  330.     return True # Для режимов, не входящих в список, считаем "переведенным"
  331.  
  332.  
  333.  
  334.  
  335. def debug_translation(input_file, output_file, mode, temperature, max_tokens, batch_size, delay, system_prompt, instruction):
  336.     global menu_requested # Используем глобальный флаг
  337.     original_data = dict(load_translated_data(input_file))
  338.     translated_data = load_translated_data(output_file)
  339.     untranslated_texts = []
  340.     line_numbers_to_retranslate = []
  341.     re_translated_count = 0
  342.     total_suspected_lines = 0
  343.  
  344.  
  345.     print("Starting translation debugging...")
  346.  
  347.  
  348.     for line_number, (original_text, translated_text_from_file) in enumerate(translated_data.items(), start=1):
  349.         if menu_requested: # Проверка запроса меню перед каждой строкой
  350.             print("Операция прервана пользователем.")
  351.             menu_requested = False # Сбрасываем флаг
  352.             return # Выход из функции
  353.         if not is_translated(translated_text_from_file, mode):
  354.             if original_text in original_data:
  355.                 original_original_text = original_data[original_text]
  356.                 if is_translated(original_original_text, mode):
  357.                     print(f"[{line_number}] Suspected untranslated line (but original looks translated too?): {translated_text_from_file[:50]}... Original: {original_original_text[:50]}...")
  358.                     continue
  359.                 print(f"[{line_number}] Suspected untranslated line: {translated_text_from_file[:50]}... Original: {original_original_text[:50]}...")
  360.                 untranslated_texts.append((line_number, original_original_text, original_text))
  361.                 line_numbers_to_retranslate.append(line_number)
  362.                 total_suspected_lines += 1
  363.             else:
  364.                 print(f"[{line_number}] Original text not found in input data for line: {translated_text_from_file[:50]}... Skipping re-translation.")
  365.                 continue
  366.  
  367.  
  368.     if untranslated_texts:
  369.         print(f"Found {total_suspected_lines} lines suspected to be untranslated. Retranslating in batches...")
  370.         re_translated_count = 0
  371.         batch_count = 0
  372.         for i in range(0, len(untranslated_texts), batch_size):
  373.             if menu_requested: # Проверка запроса меню перед каждым батчем
  374.                 print("Операция прервана пользователем.")
  375.                 menu_requested = False # Сбрасываем флаг
  376.                 return # Выход из функции
  377.             while not pause_event.is_set(): # <--- Проверка паузы перед батчем
  378.                 time.sleep(0.1)
  379.  
  380.  
  381.             batch_count += 1
  382.             batch_to_retranslate = untranslated_texts[i:i + batch_size]
  383.             if API_MODE == "google": # Задержка только для Google API
  384.                 time.sleep(delay)
  385.             print(f"Starting re-translation batch {batch_count} of size {len(batch_to_retranslate)}...")
  386.  
  387.  
  388.             if API_MODE == "google":
  389.                 print(f"  [Batch {batch_count}] Sending to Google AI for re-translation:") # Batch info
  390.                 for line_num, original_orig_text, _ in batch_to_retranslate: # Print original texts in batch
  391.                     print(f"    [{line_num}] Original: '{original_orig_text}'")
  392.                 re_translations = translate_text_google_ai(batch_to_retranslate, system_prompt, instruction, temperature, max_tokens)
  393.             elif API_MODE == "kobold":
  394.                 re_translations_kobold = []
  395.                 print(f"  [Batch {batch_count}] Sending to KoboldAI for re-translation:") # Batch info
  396.                 for line_num, original_orig_text, _ in batch_to_retranslate: # Print original texts in batch
  397.                     print(f"    [{line_num}] Original: '{original_orig_text}'")
  398.                     if menu_requested: # Проверка запроса меню перед каждым переводом в батче KoboldAI
  399.                         print("Операция перевода прервана пользователем.")
  400.                         menu_requested = False # Сбрасываем флаг
  401.                         return # Выход из функции
  402.                     while not pause_event.is_set(): # <--- Проверка паузы перед каждым KoboldAI переводом
  403.                         time.sleep(0.1)
  404.                     re_translation = translate_text_koboldai(original_orig_text, mode, temperature, max_tokens, system_prompt=system_prompt, instruction=instruction)
  405.                     if re_translation:
  406.                         re_translations_kobold.append(f"[{line_num}] {re_translation}") # Format to match Google AI output, use line_num here
  407.                         print(f"    [{line_num}] KoboldAI Translation Received: '{re_translation}'") # Print KoboldAI translation
  408.                     else:
  409.                         re_translations_kobold.append(None) # Handle translation failure if needed
  410.                         print(f"    [{line_num}] KoboldAI Translation Failed.") # Indicate KoboldAI failure
  411.                 re_translations = re_translations_kobold # Assign KoboldAI translations
  412.  
  413.  
  414.             if re_translations:
  415.                 processed_re_translations = {}
  416.                 print(f"  [Batch {batch_count}] Processing re-translations:") # Batch info
  417.                 for translation in re_translations:
  418.                     if translation: # Check if translation is not None (for KoboldAI failures)
  419.                         match = re.match(r'\[(\d+)]\s*(.+)', translation)
  420.                         if match:
  421.                             translated_line_number = int(match.group(1))
  422.                             re_translated_text = match.group(2).strip()
  423.                             processed_re_translations[translated_line_number] = re_translated_text
  424.                             print(f"    [{translated_line_number}] Google/KoboldAI Output Parsed: '{re_translated_text}'") # Print parsed translation
  425.                         else:
  426.                             print(f"    Warning: Invalid format in translation: {translation}")
  427.                     else:
  428.                         print(f"    Warning: Received empty translation for a line.") # Indicate empty translation
  429.  
  430.  
  431.                 batch_retranslated_in_batch = 0
  432.                 for translated_line_number, re_translated_text in processed_re_translations.items():
  433.                     original_text_key_to_update = None
  434.                     for original_line_number, _, stored_original_text_key in untranslated_texts:
  435.                         if original_line_number == translated_line_number:
  436.                             original_text_key_to_update = stored_original_text_key
  437.                             break
  438.  
  439.  
  440.                     if original_text_key_to_update:
  441.                         if original_text_key_to_update in translated_data:
  442.                             translated_data[original_text_key_to_update] = re_translated_text
  443.                             re_translated_count += 1
  444.                             batch_retranslated_in_batch += 1
  445.                             print(f"    [{translated_line_number}] Updated translation in translated_data.") # Indicate update
  446.                         else:
  447.                             print(f"Error: Original text key '{original_text_key_to_update}' not found in translated_data during re-translation update for line {translated_line_number}.")
  448.                     else:
  449.                         print(f"Error: Could not find matching untranslated line for line number {translated_line_number} during re-translation update.")
  450.                 print(f"Batch {batch_count} re-translation complete. {batch_retranslated_in_batch} lines re-translated in this batch.")
  451.             else:
  452.                 print(f"Re-translation failed or no re-translations received for batch {batch_count}.")
  453.  
  454.  
  455.         save_translated_data(translated_data, output_file)
  456.         print(f"Re-translation debugging complete. {re_translated_count} lines re-translated in total.")
  457.     else:
  458.         print("No lines suspected to be untranslated found. Debugging complete.")
  459.  
  460.  
  461.  
  462.  
  463.  
  464.  
  465. def process_json_with_api(input_file, output_file, system_prompt, instruction, temperature, max_tokens, batch_size=1, delay=0, mode=None): # <--- Default batch_size=1, delay=0 для Kobold
  466.     global menu_requested # Используем глобальный флаг
  467.     translated_data = load_translated_data(output_file)
  468.     print(f"Loaded translated data. Initial size: {len(translated_data)}") # DEBUG: Размер загруженных данных
  469.  
  470.  
  471.     with open(input_file, 'r', encoding='utf-8') as file:
  472.         input_data = list(json.load(file).items())
  473.  
  474.  
  475.     total_lines = len(input_data)
  476.     print(f"Total lines to process: {total_lines}.")
  477.  
  478.  
  479.     for i in range(0, total_lines, batch_size):
  480.         if menu_requested: # Проверка запроса меню перед каждым батчем
  481.             print("Операция перевода прервана пользователем.")
  482.             menu_requested = False # Сбрасываем флаг
  483.             return  # Выходим из функции
  484.         while not pause_event.is_set():
  485.             time.sleep(0.1)
  486.  
  487.  
  488.         batch = input_data[i:i + batch_size]
  489.  
  490.  
  491.         texts_to_translate = []
  492.         original_texts_and_lines = {}
  493.  
  494.  
  495.         for line_number, (original_text, original_translation) in enumerate(batch, start = i+1):
  496.             if menu_requested: # Проверка запроса меню перед каждой строкой
  497.                 print("Операция перевода прервана пользователем.")
  498.                 menu_requested = False # Сбрасываем флаг
  499.                 return # Выходим из функции
  500.             absolute_line_number = line_number
  501.  
  502.  
  503.             print(f"[{i + absolute_line_number}] Processing line - Original Text: '{original_text}', Original Translation: '{original_translation}'")
  504.  
  505.  
  506.             if original_text in translated_data:
  507.                 print(f"[{i + absolute_line_number}] Skipping: already translated.")
  508.                 continue
  509.  
  510.  
  511.             print(f"[{i + absolute_line_number}] should_translate('{original_text}', mode='{mode}') = {should_translate(original_text, mode)}") # DEBUG: Проверка should_translate
  512.             # --- Фильтр should_translate применяется ВСЕГДА ---
  513.             if not should_translate(original_text, mode): # <--- use_filter УДАЛЕН, фильтр ВСЕГДА ВКЛЮЧЕН
  514.                 print(f"[{i + absolute_line_number}] Skipping: translation not required.")
  515.                 translated_data[original_text] = original_translation
  516.                 continue
  517.  
  518.  
  519.             if absolute_line_number in original_texts_and_lines:
  520.                 print(f"Error: Duplicate line number {i + absolute_line_number}. Skipping.")
  521.                 continue
  522.  
  523.  
  524.             texts_to_translate.append( (i + absolute_line_number, original_text))
  525.             original_texts_and_lines[i + absolute_line_number] =  (original_text, original_translation)
  526.  
  527.  
  528.         if texts_to_translate:
  529.             print(f"Translating batch of {len(texts_to_translate)} items...")
  530.             if API_MODE == "google": # Задержка только для Google API
  531.                 time.sleep(delay)
  532.             if API_MODE == "google":
  533.                 translations = translate_text_google_ai(texts_to_translate, system_prompt, instruction, temperature, max_tokens)
  534.             elif API_MODE == "kobold":
  535.                 translations_kobold = []
  536.                 for _, text_item in texts_to_translate: # Process line by line for KoboldAI
  537.                     if menu_requested: # Проверка запроса меню перед каждым переводом в батче KoboldAI
  538.                         print("Операция перевода прервана пользователем.")
  539.                         menu_requested = False # Сбрасываем флаг
  540.                         return # Выходим из функции
  541.                     translation = translate_text_koboldai(text_item, mode, temperature, max_tokens, system_prompt=system_prompt, instruction=instruction) # <--- Передаем system_prompt и instruction
  542.                     if translation:
  543.                         translations_kobold.append(f"[{_}] {translation}") # Format to match Google AI output
  544.                     else:
  545.                         translations_kobold.append(None) # Handle translation failure if needed
  546.                 translations = translations_kobold # Assign KoboldAI translations
  547.  
  548.  
  549.  
  550.  
  551.             if not translations:
  552.                 print("No translations received from API for this batch. Skipping save for this batch.")
  553.                 continue
  554.  
  555.  
  556.             processed_translations = {}
  557.             for translation in translations:
  558.                 if translation: # Check if translation is not None (for KoboldAI failures)
  559.                     match = re.match(r'\[(\d+)]\s*(.+)', translation)
  560.                     if match:
  561.                         translated_line_number = int(match.group(1))
  562.                         translated_text = match.group(2).strip()
  563.                         processed_translations[translated_line_number] = translated_text
  564.                     else:
  565.                         print(f"Invalid format in translation: {translation}")
  566.  
  567.  
  568.  
  569.  
  570.             for translated_line_number, translated_text in processed_translations.items():
  571.                 if translated_line_number in original_texts_and_lines:
  572.                     original_text, original_translation = original_texts_and_lines[translated_line_number]
  573.  
  574.  
  575.                     print(f"[{translated_line_number}] Before Write - Original Text Key: '{original_text}', Translated Text Value: '{translated_text}'")
  576.  
  577.  
  578.                     translated_data[original_text] = translated_text
  579.  
  580.  
  581.                     print(f"[{translated_line_number}] After Write - Original Text Key: '{original_text}', Translated Text Value: '{translated_text}', Translated Data Value: '{translated_data.get(original_text, 'NOT FOUND')}'")
  582.  
  583.  
  584.                     print(f"[{translated_line_number}] Translation complete: {translated_text}")
  585.                 else:
  586.                     print(f"Error: Could not find line number {translated_line_number} for translation {translated_text}")
  587.  
  588.  
  589.  
  590.  
  591.             for line_number, (original_text, original_translation) in original_texts_and_lines.items():
  592.                 if original_text not in translated_data:
  593.                    print(f"[{line_number}] Translation error, line saved as is.")
  594.                    translated_data[original_text] = original_translation
  595.  
  596.  
  597.  
  598.  
  599.         save_translated_data(translated_data, output_file)
  600.         time.sleep(0.05)
  601.  
  602.  
  603.     print(f"Processing complete. Final file saved: {output_file}")
  604.  
  605.  
  606.  
  607.  
  608. if __name__ == "__main__":
  609.     while True:
  610.         print(f"\nSelect operation (Current API: {API_MODE}):") # <--- Индикация API в меню
  611.         print("1 - Change API Mode (Google Gemini / KoboldAI)")
  612.         print("2 - Change Google API Key (Current: " + GOOGLE_API_KEY[-5:] + ")") # Display last 5 chars of API key
  613.         print("--- Translation Modes ---")
  614.         print("3 - Japanese → English Translation (Custom Settings)")
  615.         print("4 - Japanese → Russian Translation (Custom Settings)")
  616.         print("5 - English → Russian Translation (Custom Settings)")
  617.         print("6 - English and Japanese → Russian Translation (Custom Settings)")
  618.         print("7 - Custom Language Translation (Custom Settings)")
  619.         print("--- Debugging ---")
  620.         print("8 - Debug Translation")
  621.         print("0 - Exit")
  622.         mode_choice = input("Enter operation number (0-8): ").strip()
  623.         menu_requested = False # Сбрасываем флаг запроса меню в начале цикла
  624.  
  625.  
  626.         if mode_choice == "1":
  627.             set_api_mode()
  628.  
  629.  
  630.         elif mode_choice == "2":
  631.             change_google_api_key()
  632.  
  633.  
  634.         elif mode_choice == "3":
  635.             mode = "jp_to_en"
  636.             output_file = "file_translated_en.json"
  637.             temperature, max_tokens, batch_size, delay = get_user_settings()
  638.             input_file = "ManualTransFile.json"
  639.             process_json_with_api(input_file, output_file, SYSTEM_PROMPTS[mode], INSTRUCTIONS[mode], temperature, max_tokens, batch_size=batch_size, delay=delay, mode=mode) # <--- Передача mode
  640.             continue # <--- Добавлено
  641.  
  642.  
  643.         elif mode_choice == "4":
  644.             mode = "jp_to_ru"
  645.             output_file = "file_translated_ru.json"
  646.             temperature, max_tokens, batch_size, delay = get_user_settings()
  647.             input_file = "ManualTransFile.json"
  648.             process_json_with_api(input_file, output_file, SYSTEM_PROMPTS[mode], INSTRUCTIONS[mode], temperature, max_tokens, batch_size=batch_size, delay=delay, mode=mode) # <--- Передача mode
  649.             continue # <--- Добавлено
  650.  
  651.  
  652.         elif mode_choice == "5":
  653.             mode = "en_to_ru"
  654.             output_file = "file_translated_ru.json"
  655.             temperature, max_tokens, batch_size, delay = get_user_settings()
  656.             input_file = "ManualTransFile.json"
  657.             process_json_with_api(input_file, output_file, SYSTEM_PROMPTS[mode], INSTRUCTIONS[mode], temperature, max_tokens, batch_size=batch_size, delay=delay, mode=mode) # <--- Передача mode
  658.             continue # <--- Добавлено
  659.  
  660.  
  661.         elif mode_choice == "6":
  662.             mode = "en_jp_to_ru"
  663.             output_file = "file_translated_en_jp_ru.json"
  664.             temperature, max_tokens, batch_size, delay = get_user_settings()
  665.             input_file = "ManualTransFile.json"
  666.             process_json_with_api(input_file, output_file, SYSTEM_PROMPTS[mode], INSTRUCTIONS[mode], temperature, max_tokens, batch_size=batch_size, delay=delay, mode=mode) # <--- Передача mode
  667.             continue # <--- Добавлено
  668.  
  669.  
  670.         elif mode_choice == "7":
  671.             source_lang = input("Enter source language code (e.g., en, ja, fr): ").strip()
  672.             target_lang = input("Enter target language code (e.g., ru, en, es): ").strip()
  673.             custom_system_prompt = f"You are a highly skilled translator from {source_lang} to {target_lang}. Your task is to translate {source_lang} text into {target_lang} with absolute accuracy. Do not provide any explanations, comments, or extra output. Only the translated text should be returned."
  674.             custom_instruction = f"Translate {source_lang} to {target_lang}. Ensure clarity and precision. Only output the translation."
  675.             output_file = f"file_translated_{source_lang}_to_{target_lang}.json"
  676.             temperature, max_tokens, batch_size, delay = get_user_settings()
  677.             input_file = "ManualTransFile.json"
  678.             mode = f"{source_lang}_to_{target_lang}"
  679.             process_json_with_api(input_file, output_file, custom_system_prompt, custom_instruction, temperature, max_tokens, batch_size=batch_size, delay=delay, mode=mode)
  680.             continue # <--- Добавлено
  681.  
  682.  
  683.  
  684.  
  685.         elif mode_choice == "8":
  686.             print("Select debug translation mode:")
  687.             print("1 - Japanese → English")
  688.             print("2 - Japanese → Russian")
  689.             print("3 - English → Russian")
  690.             print("4 - English and Japanese → Russian")
  691.             print("5 - Custom Language Translation") # Debug for Custom Language
  692.             debug_mode_choice = input("Enter 1, 2, 3, 4, or 5: ").strip()
  693.             if debug_mode_choice == "1": mode = "jp_to_en"; output_file = "file_translated_en.json"; system_prompt = SYSTEM_PROMPTS[mode]; instruction = INSTRUCTIONS[mode]
  694.             elif debug_mode_choice == "2": mode = "jp_to_ru"; output_file = "file_translated_ru.json"; system_prompt = SYSTEM_PROMPTS[mode]; instruction = INSTRUCTIONS[mode]
  695.             elif debug_mode_choice == "3": mode = "en_to_ru"; output_file = "file_translated_ru.json"; system_prompt = SYSTEM_PROMPTS[mode]; instruction = INSTRUCTIONS[mode]
  696.             elif debug_mode_choice == "4": mode = "en_jp_to_ru"; output_file = "file_translated_en_jp_ru.json"; system_prompt = SYSTEM_PROMPTS[mode]; instruction = INSTRUCTIONS[mode]
  697.             elif debug_mode_choice == "5": # Custom Debug
  698.                 source_lang = input("Enter source language code (e.g., en, ja, fr): ").strip()
  699.                 target_lang = input("Enter target language code (e.g., ru, en, es): ").strip()
  700.                 mode = f"{source_lang}_to_{target_lang}" # Unique mode для кастомного дебага
  701.                 output_file = f"file_translated_{source_lang}_to_{target_lang}.json"
  702.                 custom_system_prompt = f"You are a highly skilled translator from {source_lang} to {target_lang}. Your task is to debug translations from {source_lang} to {target_lang}." # Используем custom_system_prompt
  703.                 custom_instruction = f"Identify and correct any translation errors from {source_lang} to {target_lang}." # Используем custom_instruction
  704.                 if not source_lang or not target_lang: print("Custom languages required for debug."); continue
  705.                 system_prompt = custom_system_prompt # Передаем custom_system_prompt в debug_translation
  706.                 instruction = custom_instruction   # Передаем custom_instruction в debug_translation
  707.             else: print("Invalid mode choice for debug."); continue
  708.  
  709.  
  710.             temperature, max_tokens, batch_size, delay = get_user_settings()
  711.             input_file = "ManualTransFile.json"
  712.             debug_translation(input_file, output_file, mode, temperature, max_tokens, batch_size, delay, system_prompt, instruction) # system_prompt и instruction уже определены выше
  713.             continue # <--- Добавлено
  714.  
  715.  
  716.  
  717.  
  718.         elif mode_choice == "0":
  719.             print("Exiting.")
  720.             break
  721.  
  722.  
  723.         else:
  724.             print("Invalid choice. Please enter a number between 0 and 8.")
  725.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement