Add separate logs per run and remove retry functionality that was making things more expensive
This commit is contained in:
parent
7bcc1b4e7b
commit
7ef200c13a
5 changed files with 123 additions and 25 deletions
|
|
@ -179,7 +179,6 @@ if errorlevel 1 (
|
||||||
|
|
||||||
echo.
|
echo.
|
||||||
echo GUI closed successfully.
|
echo GUI closed successfully.
|
||||||
pause
|
|
||||||
|
|
||||||
:: End of main flow - prevent falling through into subroutines below
|
:: End of main flow - prevent falling through into subroutines below
|
||||||
goto :eof
|
goto :eof
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,12 @@ class LogViewer(QWidget):
|
||||||
self._tail_timer.timeout.connect(self._poll_tail)
|
self._tail_timer.timeout.connect(self._poll_tail)
|
||||||
self._tail_interval = 300 # ms
|
self._tail_interval = 300 # ms
|
||||||
self._tail_f = None
|
self._tail_f = None
|
||||||
self._tail_path = Path("log/translationHistory.txt")
|
# Default: prefer the most recent file in log/history, else legacy path
|
||||||
|
try:
|
||||||
|
latest = self._latest_history_file()
|
||||||
|
except Exception:
|
||||||
|
latest = None
|
||||||
|
self._tail_path = latest or Path("log/translationHistory.txt")
|
||||||
|
|
||||||
def toggle_auto_refresh(self, enabled):
|
def toggle_auto_refresh(self, enabled):
|
||||||
"""Toggle auto-refresh functionality."""
|
"""Toggle auto-refresh functionality."""
|
||||||
|
|
@ -124,8 +129,9 @@ class LogViewer(QWidget):
|
||||||
def start_tail(self, file_path: str | Path = None, interval_ms: int = None):
|
def start_tail(self, file_path: str | Path = None, interval_ms: int = None):
|
||||||
"""Start tailing the given log file and append new lines as they arrive.
|
"""Start tailing the given log file and append new lines as they arrive.
|
||||||
|
|
||||||
By default tails `log/translationHistory.txt`. Seeks to the end so
|
By default tails the most recent file in `log/history/` (if present),
|
||||||
only new lines after this call are shown.
|
otherwise falls back to `log/translationHistory.txt`.
|
||||||
|
Seeks to the end so only new lines after this call are shown.
|
||||||
"""
|
"""
|
||||||
if file_path:
|
if file_path:
|
||||||
self._tail_path = Path(file_path)
|
self._tail_path = Path(file_path)
|
||||||
|
|
@ -213,3 +219,16 @@ class LogViewer(QWidget):
|
||||||
"""Handle widget hide event - pause refresh to save resources."""
|
"""Handle widget hide event - pause refresh to save resources."""
|
||||||
super().hideEvent(event)
|
super().hideEvent(event)
|
||||||
# No-op for simplified viewer
|
# No-op for simplified viewer
|
||||||
|
|
||||||
|
def _latest_history_file(self):
|
||||||
|
"""Return the most recent file in log/history or None if not found."""
|
||||||
|
try:
|
||||||
|
hist_dir = Path("log") / "history"
|
||||||
|
# Ensure history directory exists so callers can rely on it
|
||||||
|
hist_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
files = [p for p in hist_dir.iterdir() if p.is_file()]
|
||||||
|
if not files:
|
||||||
|
return None
|
||||||
|
return max(files, key=lambda p: p.stat().st_mtime)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ Simple file management and translation execution with console log display.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import datetime
|
||||||
import subprocess
|
import subprocess
|
||||||
import threading
|
import threading
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -1549,13 +1550,53 @@ class TranslationTab(QWidget):
|
||||||
self.translation_worker.progress_signal.connect(self.update_file_progress)
|
self.translation_worker.progress_signal.connect(self.update_file_progress)
|
||||||
self.translation_worker.item_progress_signal.connect(self.update_item_progress)
|
self.translation_worker.item_progress_signal.connect(self.update_item_progress)
|
||||||
self.translation_worker.finished_signal.connect(self.on_translation_finished)
|
self.translation_worker.finished_signal.connect(self.on_translation_finished)
|
||||||
# Clear and start tailing the translation history so only new
|
# Prepare a per-run log file in log/history and start tailing it so
|
||||||
# lines are shown in the right-hand log panel.
|
# the right-hand log panel shows only this run's new lines.
|
||||||
try:
|
try:
|
||||||
|
history_dir = self.project_root / 'log' / 'history'
|
||||||
|
history_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
# Use timestamp (safe filename) for sorting
|
||||||
|
fname = datetime.datetime.now().strftime('translationHistory_%Y%m%d_%H%M%S.txt')
|
||||||
|
run_log_path = history_dir / fname
|
||||||
|
# Create/touch the file so tailer can open and seek to end
|
||||||
|
run_log_path.touch(exist_ok=True)
|
||||||
|
|
||||||
|
# Export env var so subprocess workers inherit the path
|
||||||
|
try:
|
||||||
|
os.environ['TRANSLATION_RUN_LOG'] = str(run_log_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Try to create a hard link at legacy location so modules that
|
||||||
|
# still write to log/translationHistory.txt end up in this file.
|
||||||
|
legacy = self.project_root / 'log' / 'translationHistory.txt'
|
||||||
|
try:
|
||||||
|
# Remove any existing legacy file and create hard link
|
||||||
|
if legacy.exists():
|
||||||
|
try:
|
||||||
|
legacy.unlink()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
os.link(str(run_log_path), str(legacy))
|
||||||
|
except Exception:
|
||||||
|
# If hard link fails (Windows permissions or cross-device),
|
||||||
|
# fallback to ensuring the legacy file exists but do not fail.
|
||||||
|
try:
|
||||||
|
legacy.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
legacy.touch(exist_ok=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Clear UI log and start tailing the per-run file
|
||||||
self.translation_log_viewer.clear_log()
|
self.translation_log_viewer.clear_log()
|
||||||
self.translation_log_viewer.start_tail(self.project_root / 'log' / 'translationHistory.txt')
|
self.translation_log_viewer.start_tail(run_log_path)
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
# Fallback to legacy file if anything goes wrong
|
||||||
|
try:
|
||||||
|
self.translation_log_viewer.clear_log()
|
||||||
|
self.translation_log_viewer.start_tail(self.project_root / 'log' / 'translationHistory.txt')
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
# Start the worker
|
# Start the worker
|
||||||
self.translation_worker.start()
|
self.translation_worker.start()
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
import sys
|
import sys
|
||||||
import os
|
import os
|
||||||
import traceback
|
import traceback
|
||||||
|
import datetime
|
||||||
|
from pathlib import Path
|
||||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||||
from colorama import Fore
|
from colorama import Fore
|
||||||
from tqdm import tqdm
|
from tqdm import tqdm
|
||||||
|
|
@ -132,6 +134,37 @@ files to translate are in the /files folder and that you picked the right game e
|
||||||
setSpeakerParseMode(True)
|
setSpeakerParseMode(True)
|
||||||
|
|
||||||
# Open File (Threads) - recursively walk 'files' and preserve directory structure
|
# Open File (Threads) - recursively walk 'files' and preserve directory structure
|
||||||
|
# Prepare per-run log file so CLI runs also write to a run-specific history file
|
||||||
|
try:
|
||||||
|
hist_dir = Path("log") / "history"
|
||||||
|
hist_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
fname = datetime.datetime.now().strftime("translationHistory_%Y%m%d_%H%M%S.txt")
|
||||||
|
run_log_path = hist_dir / fname
|
||||||
|
run_log_path.touch(exist_ok=True)
|
||||||
|
# Export env var so other modules/util functions pick it up
|
||||||
|
try:
|
||||||
|
os.environ['TRANSLATION_RUN_LOG'] = str(run_log_path)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Try to create a hard link from legacy path to this run file for compatibility
|
||||||
|
legacy = Path("log") / "translationHistory.txt"
|
||||||
|
try:
|
||||||
|
if legacy.exists():
|
||||||
|
try:
|
||||||
|
legacy.unlink()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
os.link(str(run_log_path), str(legacy))
|
||||||
|
except Exception:
|
||||||
|
# Fallback: ensure legacy file exists so modules writing to it won't fail
|
||||||
|
try:
|
||||||
|
legacy.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
legacy.touch(exist_ok=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
with ThreadPoolExecutor(max_workers=THREADS) as executor:
|
||||||
futures = []
|
futures = []
|
||||||
files_root = "files"
|
files_root = "files"
|
||||||
|
|
|
||||||
|
|
@ -611,7 +611,23 @@ def translateAI(text, history, fullPromptFlag, config, filename=None, pbar=None,
|
||||||
"""
|
"""
|
||||||
if not text:
|
if not text:
|
||||||
return [text, [0, 0]]
|
return [text, [0, 0]]
|
||||||
|
|
||||||
|
# If a per-run log file is specified via environment variable, prefer it.
|
||||||
|
run_log = os.getenv("TRANSLATION_RUN_LOG")
|
||||||
|
if run_log:
|
||||||
|
# Make sure parent dir exists
|
||||||
|
try:
|
||||||
|
Path(run_log).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
config.logFilePath = run_log
|
||||||
|
|
||||||
|
# Ensure log directory exists for the configured path
|
||||||
|
try:
|
||||||
|
Path(config.logFilePath).parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
with open(config.logFilePath, "a+", encoding="utf-8") as logFile:
|
with open(config.logFilePath, "a+", encoding="utf-8") as logFile:
|
||||||
totalTokens = [0, 0]
|
totalTokens = [0, 0]
|
||||||
|
|
||||||
|
|
@ -693,27 +709,17 @@ def translateAI(text, history, fullPromptFlag, config, filename=None, pbar=None,
|
||||||
if cleaned_text:
|
if cleaned_text:
|
||||||
if isinstance(tItem, list):
|
if isinstance(tItem, list):
|
||||||
extracted = extractTranslation(cleaned_text, True, pbar)
|
extracted = extractTranslation(cleaned_text, True, pbar)
|
||||||
|
|
||||||
# Check 1: Mismatch in length
|
# Check 1: Mismatch in length -> still a hard failure
|
||||||
if extracted is None or len(tItem) != len(extracted):
|
if extracted is None or len(tItem) != len(extracted):
|
||||||
is_valid = False
|
is_valid = False
|
||||||
|
|
||||||
# Check 2: Untranslated content
|
|
||||||
else:
|
else:
|
||||||
# Set translations first (line count matches)
|
# Set translations (line count matches)
|
||||||
final_translations = extracted
|
final_translations = extracted
|
||||||
|
|
||||||
# Then check for untranslated content as a warning, not a blocker
|
|
||||||
for line in extracted:
|
|
||||||
if re.search(config.langRegex, str(line)):
|
|
||||||
is_valid = False
|
|
||||||
break
|
|
||||||
else:
|
else:
|
||||||
# Check for untranslated content in single string
|
# Single string: accept output even if it contains characters
|
||||||
if re.search(config.langRegex, cleaned_text):
|
# matching langRegex (allow names or untranslated tokens).
|
||||||
is_valid = False
|
final_translations = cleaned_text.replace("Placeholder Text", "")
|
||||||
else:
|
|
||||||
final_translations = cleaned_text.replace("Placeholder Text", "")
|
|
||||||
else:
|
else:
|
||||||
is_valid = False
|
is_valid = False
|
||||||
if pbar: pbar.write(f"AI Refused: {tItem}\n")
|
if pbar: pbar.write(f"AI Refused: {tItem}\n")
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue