From 3f02b1b1466a8ea750152392081487f5133774fd Mon Sep 17 00:00:00 2001 From: Dfour <91110-Dfour@users.noreply.gitgud.io> Date: Mon, 1 Jun 2026 18:57:01 +0000 Subject: [PATCH] Main --- .env.example | 15 +- .gitignore | 2 +- README.md | 4 +- START.bat | 482 ++++++++++++++++++++++---------------------- gui/config_tab.py | 17 ++ util/translation.py | 19 +- 6 files changed, 283 insertions(+), 256 deletions(-) diff --git a/.env.example b/.env.example index f43d41a..0a83caf 100644 --- a/.env.example +++ b/.env.example @@ -9,20 +9,21 @@ # - Leave this variable out to use the model's default setting. GEMINI_THINKING_BUDGET= -# Set to "gemini" to use the Gemini API or "openai" for OpenAI (If empty it will default to openai.) +# Set to "gemini" to use the Gemini API or "openai" for OpenAI-compatible APIs (If empty it will default to openai.) API_PROVIDER=openai -#API link, leave blank to use OpenAI API +# API URL, leave blank to use OpenAI API. +# Nvidia example: "https://integrate.api.nvidia.com/v1/" api="" -#API key +# API key key="" -#Oranization key, make something up for self hosted or other API +#Oranization key, make something up for self hosted or other API. If using Nvidia API, leave it blank or it can get wonky organization="" -#LLM model name, use gpt-3.5-turbo-1106 or gpt-3.5-turbo or gpt-4-1106-preview for OpenAI API -#For text generation webui use gpt-3.5-turbo, for other API's consult their documentation +# LLM model name. +# Default below works for OpenAI; for Gemini/Nvidia set your provider model name. model="gpt-4.1" #The language to translate TO, Don't forget to change the prompt @@ -59,4 +60,4 @@ output_cost= 0.002 batchsize="10" # Frequency penalty - adjust according to your needs -frequency_penalty= 0.2 \ No newline at end of file +frequency_penalty= 0.2 diff --git a/.gitignore b/.gitignore index 5849736..1369fcb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.env + *.tmp *.json *.js diff --git a/README.md b/README.md index af86efb..4632d37 100644 --- a/README.md +++ b/README.md @@ -109,9 +109,11 @@ This means Python wasn't added to your PATH. You have two options: 1. Inside the tool folder, find `.env.example` and make a copy of it named `.env`. 2. Open `.env` in any text editor (Notepad works fine) and fill in your API details: + - `api` — Your API base URL (for Nvidia use `https://integrate.api.nvidia.com/v1/`). - `key` — Your API key. - `organization` — Your organization key (make something up if using a self-hosted or non-OpenAI API). - - `API_PROVIDER` — Set to `openai` or `gemini` depending on your provider. + - `API_PROVIDER` — Use `openai` for OpenAI-compatible providers (including Nvidia), or `gemini` for Gemini. + - `model` — For Nvidia/custom OpenAI-compatible endpoints, enter the model name manually (example: `deepseek-ai/deepseek-v4-pro`). 3. The rest of the settings (wordwrap, batch size, etc.) can be left as defaults for now. You can tweak them later. ### 3. Launch the GUI diff --git a/START.bat b/START.bat index c55457f..e2e3f3f 100644 --- a/START.bat +++ b/START.bat @@ -1,242 +1,242 @@ -@echo off -setlocal EnableDelayedExpansion - -echo ========================================== -echo DazedMTLTool Startup Script -echo ========================================== -echo. - -:: Track whether we actually need to create a new venv -set "NEED_VENV_CREATE=0" - -:: Determine which venv directory to use (.venv or venv) -set "VENV_DIR=" -if exist ".venv" set "VENV_DIR=.venv" -if not defined VENV_DIR if exist "venv" set "VENV_DIR=venv" -set "CREATE_VENV_DIR=" - - -:: Step 1: Check if a virtual environment exists (.venv or venv) -echo [1/4] Checking for a virtual environment... -if defined VENV_DIR ( - echo !VENV_DIR! found. Checking its Python version... - if not exist "!VENV_DIR!\Scripts\python.exe" ( - echo ERROR: Python executable not found at "!VENV_DIR!\Scripts\python.exe". - set "CREATE_VENV_DIR=!VENV_DIR!" - call :BackupVenv "!VENV_DIR!" - set "NEED_VENV_CREATE=1" - ) else ( - for /f "tokens=2" %%i in ('"!VENV_DIR!\Scripts\python.exe" --version 2^>^&1') do set VENV_PYTHON_VERSION=%%i - if not defined VENV_PYTHON_VERSION ( - echo ERROR: Could not determine Python version from "!VENV_DIR!\Scripts\python.exe". - set "CREATE_VENV_DIR=!VENV_DIR!" - call :BackupVenv "!VENV_DIR!" - set "NEED_VENV_CREATE=1" - ) else ( - echo Detected Python version: !VENV_PYTHON_VERSION! - for /f "tokens=1,2 delims=." %%a in ("!VENV_PYTHON_VERSION!") do ( - set VENV_MAJOR=%%a - set VENV_MINOR=%%b - ) - if !VENV_MAJOR! EQU 3 if !VENV_MINOR! GEQ 12 if !VENV_MINOR! LSS 15 ( - echo !VENV_DIR! Python version !VENV_PYTHON_VERSION! is compatible ^(^>^=3.12 and ^<3.15^). - goto :activate_venv - ) else ( - echo !VENV_DIR! Python version !VENV_PYTHON_VERSION! is not supported ^(requires ^>^=3.12 and ^<3.15^) - echo Backing up !VENV_DIR!... - set "CREATE_VENV_DIR=!VENV_DIR!" - call :BackupVenv "!VENV_DIR!" - set "NEED_VENV_CREATE=1" - ) - ) - ) -) else ( - echo No existing virtual environment found. - set "CREATE_VENV_DIR=.venv" - set "NEED_VENV_CREATE=1" -) -echo. - -:: If we don't need to create a new venv, skip straight to activation -if "%NEED_VENV_CREATE%"=="0" goto :activate_venv - -:: Step 2: Find suitable global Python and create a virtual environment - -set "FOUND_PYTHON=" -for /f "delims=" %%p in ('where python 2^>nul') do ( - call :CheckPythonVersion "%%p" -) - -:: Fallback: try 'python' directly if 'where' found nothing (handles Windows Store alias) -if not defined FOUND_PYTHON ( - python --version >nul 2>&1 - if not errorlevel 1 ( - call :CheckPythonVersion "python" - ) -) - -if not defined FOUND_PYTHON ( - echo ERROR: No suitable Python ^(>=3.12 and <3.15^) found in PATH. - echo Please install Python 3.12, 3.13, or 3.14 and ensure it is in your PATH. - pause - exit /b 1 -) - -:create_venv -if not defined CREATE_VENV_DIR set "CREATE_VENV_DIR=.venv" -echo Creating new !CREATE_VENV_DIR! using !FOUND_PYTHON! ... -"!FOUND_PYTHON!" -m venv !CREATE_VENV_DIR! -if errorlevel 1 ( - echo ERROR: Failed to create virtual environment. - pause - exit /b 1 -) -echo Virtual environment created -echo. - -:: Proceed to activation after creating the venv to avoid falling through into subroutines -set "VENV_DIR=!CREATE_VENV_DIR!" -goto :activate_venv - -:CheckPythonVersion -rem -- %1 is the python executable path -rem -- Skip if we already found a suitable Python -if defined FOUND_PYTHON goto :eof -set "PYTHON_VERSION=" -set "MAJOR=" -set "MINOR=" -for /f "tokens=2" %%i in ('"%~1" --version 2^>nul') do set PYTHON_VERSION=%%i -if not defined PYTHON_VERSION goto :eof -for /f "tokens=1,2 delims=." %%a in ("%PYTHON_VERSION%") do ( - set MAJOR=%%a - set MINOR=%%b -) -if not defined MAJOR goto :eof -if not defined MINOR goto :eof -if !MAJOR! EQU 3 if !MINOR! GEQ 12 if !MINOR! LSS 15 ( - set "FOUND_PYTHON=%~1" -) -goto :eof - -:activate_venv -echo Activating virtual environment... -call !VENV_DIR!\Scripts\activate.bat -if errorlevel 1 ( - echo ERROR: Failed to activate virtual environment at "!VENV_DIR!". - echo Attempting to recreate the virtual environment with a compatible Python... - set "CREATE_VENV_DIR=!VENV_DIR!" - call :BackupVenv "!VENV_DIR!" - set "FOUND_PYTHON=" - for /f "delims=" %%p in ('where python') do ( - call :CheckPythonVersion "%%p" - ) - if not defined FOUND_PYTHON ( - echo ERROR: No suitable Python ^(^>^=3.12 and ^<3.15^) found in PATH for recreation. - pause - exit /b 1 - ) - echo Recreating !CREATE_VENV_DIR! using !FOUND_PYTHON! ... - "!FOUND_PYTHON!" -m venv !CREATE_VENV_DIR! - if errorlevel 1 ( - echo ERROR: Failed to create virtual environment during recreation. - pause - exit /b 1 - ) - set "VENV_DIR=!CREATE_VENV_DIR!" - echo Retrying activation... - call !VENV_DIR!\Scripts\activate.bat - if errorlevel 1 ( - echo ERROR: Activation failed after recreation. - pause - exit /b 1 - ) -) -echo Virtual environment activated -echo. - -:: (proceeding to dependency checks and launch) - -:: Check and install dependencies -echo Checking dependencies... -echo Checking if requirements are satisfied... - -:: Try importing key packages to see if they're installed -python -c "import PyQt5; import openai; import dotenv; import PIL; import anthropic; print('All dependencies satisfied')" >nul 2>&1 -if errorlevel 1 ( - echo Upgrading pip... - python -m pip install --upgrade pip >nul 2>&1 - echo Installing/updating requirements... - pip install -r requirements.txt - if errorlevel 1 ( - echo ERROR: Failed to install requirements. - pause - exit /b 1 - ) - echo Dependencies installed successfully -) else ( - echo All dependencies are already satisfied -) -echo. - -:: Launch the GUI -echo ========================================== -echo Launching DazedMTLTool GUI... -echo ========================================== -echo. - -:: Ensure vocab.txt exists (create from example if available) -if not exist "vocab.txt" ( - if exist "vocab.txt.example" ( - echo vocab.txt not found - creating from vocab.txt.example... - copy /Y "vocab.txt.example" "vocab.txt" >nul 2>&1 - if errorlevel 1 ( - echo ERROR: Failed to copy vocab.txt.example to vocab.txt. - ) else ( - echo Created vocab.txt from vocab.txt.example - ) - ) else ( - echo vocab.txt and vocab.txt.example not found - creating empty vocab.txt to avoid import errors... - type NUL > "vocab.txt" - if errorlevel 1 ( - echo ERROR: Failed to create empty vocab.txt. - ) else ( - echo Created empty vocab.txt - ) - ) -) - -python start_gui.py - -:: Check if GUI launched successfully -if errorlevel 1 ( - echo. - echo ERROR: Failed to launch GUI. - echo Check the error messages above. - pause - exit /b 1 -) - -echo. -echo GUI closed successfully. - -:: End of main flow - prevent falling through into subroutines below -goto :eof - -:: Backup venv subroutine (supports .venv or venv) -:BackupVenv -set "TARGET_DIR=%~1" -if not defined TARGET_DIR set "TARGET_DIR=.venv" -set BAK_IDX=1 -:BackupLoop -if exist "%TARGET_DIR%.bak_!BAK_IDX!" ( - set /a BAK_IDX+=1 - goto BackupLoop -) -move /Y "%TARGET_DIR%" "%TARGET_DIR%.bak_!BAK_IDX!" >nul 2>&1 -if errorlevel 1 ( - echo ERROR: Failed to back up %TARGET_DIR% to %TARGET_DIR%.bak_!BAK_IDX!. - echo Please ensure no files are locked and try again. - goto :eof -) -echo %TARGET_DIR% renamed to %TARGET_DIR%.bak_!BAK_IDX! +@echo off +setlocal EnableDelayedExpansion + +echo ========================================== +echo DazedMTLTool Startup Script +echo ========================================== +echo. + +:: Track whether we actually need to create a new venv +set "NEED_VENV_CREATE=0" + +:: Determine which venv directory to use (.venv or venv) +set "VENV_DIR=" +if exist ".venv" set "VENV_DIR=.venv" +if not defined VENV_DIR if exist "venv" set "VENV_DIR=venv" +set "CREATE_VENV_DIR=" + + +:: Step 1: Check if a virtual environment exists (.venv or venv) +echo [1/4] Checking for a virtual environment... +if defined VENV_DIR ( + echo !VENV_DIR! found. Checking its Python version... + if not exist "!VENV_DIR!\Scripts\python.exe" ( + echo ERROR: Python executable not found at "!VENV_DIR!\Scripts\python.exe". + set "CREATE_VENV_DIR=!VENV_DIR!" + call :BackupVenv "!VENV_DIR!" + set "NEED_VENV_CREATE=1" + ) else ( + for /f "tokens=2" %%i in ('"!VENV_DIR!\Scripts\python.exe" --version 2^>^&1') do set VENV_PYTHON_VERSION=%%i + if not defined VENV_PYTHON_VERSION ( + echo ERROR: Could not determine Python version from "!VENV_DIR!\Scripts\python.exe". + set "CREATE_VENV_DIR=!VENV_DIR!" + call :BackupVenv "!VENV_DIR!" + set "NEED_VENV_CREATE=1" + ) else ( + echo Detected Python version: !VENV_PYTHON_VERSION! + for /f "tokens=1,2 delims=." %%a in ("!VENV_PYTHON_VERSION!") do ( + set VENV_MAJOR=%%a + set VENV_MINOR=%%b + ) + if !VENV_MAJOR! EQU 3 if !VENV_MINOR! GEQ 12 if !VENV_MINOR! LSS 15 ( + echo !VENV_DIR! Python version !VENV_PYTHON_VERSION! is compatible ^(^>^=3.12 and ^<3.15^). + goto :activate_venv + ) else ( + echo !VENV_DIR! Python version !VENV_PYTHON_VERSION! is not supported ^(requires ^>^=3.12 and ^<3.15^) + echo Backing up !VENV_DIR!... + set "CREATE_VENV_DIR=!VENV_DIR!" + call :BackupVenv "!VENV_DIR!" + set "NEED_VENV_CREATE=1" + ) + ) + ) +) else ( + echo No existing virtual environment found. + set "CREATE_VENV_DIR=.venv" + set "NEED_VENV_CREATE=1" +) +echo. + +:: If we don't need to create a new venv, skip straight to activation +if "%NEED_VENV_CREATE%"=="0" goto :activate_venv + +:: Step 2: Find suitable global Python and create a virtual environment + +set "FOUND_PYTHON=" +for /f "delims=" %%p in ('where python 2^>nul') do ( + call :CheckPythonVersion "%%p" +) + +:: Fallback: try 'python' directly if 'where' found nothing (handles Windows Store alias) +if not defined FOUND_PYTHON ( + python --version >nul 2>&1 + if not errorlevel 1 ( + call :CheckPythonVersion "python" + ) +) + +if not defined FOUND_PYTHON ( + echo ERROR: No suitable Python ^(>=3.12 and <3.15^) found in PATH. + echo Please install Python 3.12, 3.13, or 3.14 and ensure it is in your PATH. + pause + exit /b 1 +) + +:create_venv +if not defined CREATE_VENV_DIR set "CREATE_VENV_DIR=.venv" +echo Creating new !CREATE_VENV_DIR! using !FOUND_PYTHON! ... +"!FOUND_PYTHON!" -m venv !CREATE_VENV_DIR! +if errorlevel 1 ( + echo ERROR: Failed to create virtual environment. + pause + exit /b 1 +) +echo Virtual environment created +echo. + +:: Proceed to activation after creating the venv to avoid falling through into subroutines +set "VENV_DIR=!CREATE_VENV_DIR!" +goto :activate_venv + +:CheckPythonVersion +rem -- %1 is the python executable path +rem -- Skip if we already found a suitable Python +if defined FOUND_PYTHON goto :eof +set "PYTHON_VERSION=" +set "MAJOR=" +set "MINOR=" +for /f "tokens=2" %%i in ('"%~1" --version 2^>nul') do set PYTHON_VERSION=%%i +if not defined PYTHON_VERSION goto :eof +for /f "tokens=1,2 delims=." %%a in ("%PYTHON_VERSION%") do ( + set MAJOR=%%a + set MINOR=%%b +) +if not defined MAJOR goto :eof +if not defined MINOR goto :eof +if !MAJOR! EQU 3 if !MINOR! GEQ 12 if !MINOR! LSS 15 ( + set "FOUND_PYTHON=%~1" +) +goto :eof + +:activate_venv +echo Activating virtual environment... +call !VENV_DIR!\Scripts\activate.bat +if errorlevel 1 ( + echo ERROR: Failed to activate virtual environment at "!VENV_DIR!". + echo Attempting to recreate the virtual environment with a compatible Python... + set "CREATE_VENV_DIR=!VENV_DIR!" + call :BackupVenv "!VENV_DIR!" + set "FOUND_PYTHON=" + for /f "delims=" %%p in ('where python') do ( + call :CheckPythonVersion "%%p" + ) + if not defined FOUND_PYTHON ( + echo ERROR: No suitable Python ^(^>^=3.12 and ^<3.15^) found in PATH for recreation. + pause + exit /b 1 + ) + echo Recreating !CREATE_VENV_DIR! using !FOUND_PYTHON! ... + "!FOUND_PYTHON!" -m venv !CREATE_VENV_DIR! + if errorlevel 1 ( + echo ERROR: Failed to create virtual environment during recreation. + pause + exit /b 1 + ) + set "VENV_DIR=!CREATE_VENV_DIR!" + echo Retrying activation... + call !VENV_DIR!\Scripts\activate.bat + if errorlevel 1 ( + echo ERROR: Activation failed after recreation. + pause + exit /b 1 + ) +) +echo Virtual environment activated +echo. + +:: (proceeding to dependency checks and launch) + +:: Check and install dependencies +echo Checking dependencies... +echo Checking if requirements are satisfied... + +:: Try importing key packages to see if they're installed +python -c "import PyQt5; import openai; import dotenv; import PIL; import anthropic; print('All dependencies satisfied')" >nul 2>&1 +if errorlevel 1 ( + echo Upgrading pip... + python -m pip install --upgrade pip >nul 2>&1 + echo Installing/updating requirements... + pip install -r requirements.txt + if errorlevel 1 ( + echo ERROR: Failed to install requirements. + pause + exit /b 1 + ) + echo Dependencies installed successfully +) else ( + echo All dependencies are already satisfied +) +echo. + +:: Launch the GUI +echo ========================================== +echo Launching DazedMTLTool GUI... +echo ========================================== +echo. + +:: Ensure vocab.txt exists (create from example if available) +if not exist "vocab.txt" ( + if exist "vocab.txt.example" ( + echo vocab.txt not found - creating from vocab.txt.example... + copy /Y "vocab.txt.example" "vocab.txt" >nul 2>&1 + if errorlevel 1 ( + echo ERROR: Failed to copy vocab.txt.example to vocab.txt. + ) else ( + echo Created vocab.txt from vocab.txt.example + ) + ) else ( + echo vocab.txt and vocab.txt.example not found - creating empty vocab.txt to avoid import errors... + type NUL > "vocab.txt" + if errorlevel 1 ( + echo ERROR: Failed to create empty vocab.txt. + ) else ( + echo Created empty vocab.txt + ) + ) +) + +python start_gui.py + +:: Check if GUI launched successfully +if errorlevel 1 ( + echo. + echo ERROR: Failed to launch GUI. + echo Check the error messages above. + pause + exit /b 1 +) + +echo. +echo GUI closed successfully. + +:: End of main flow - prevent falling through into subroutines below +goto :eof + +:: Backup venv subroutine (supports .venv or venv) +:BackupVenv +set "TARGET_DIR=%~1" +if not defined TARGET_DIR set "TARGET_DIR=.venv" +set BAK_IDX=1 +:BackupLoop +if exist "%TARGET_DIR%.bak_!BAK_IDX!" ( + set /a BAK_IDX+=1 + goto BackupLoop +) +move /Y "%TARGET_DIR%" "%TARGET_DIR%.bak_!BAK_IDX!" >nul 2>&1 +if errorlevel 1 ( + echo ERROR: Failed to back up %TARGET_DIR% to %TARGET_DIR%.bak_!BAK_IDX!. + echo Please ensure no files are locked and try again. + goto :eof +) +echo %TARGET_DIR% renamed to %TARGET_DIR%.bak_!BAK_IDX! goto :eof \ No newline at end of file diff --git a/gui/config_tab.py b/gui/config_tab.py index 8587b20..98b9f95 100644 --- a/gui/config_tab.py +++ b/gui/config_tab.py @@ -137,12 +137,27 @@ class ConfigTab(QWidget): self.reset_to_defaults() else: self.load_from_env() + self._update_model_placeholder() # Connect auto-save after initial load self.connect_auto_save() # Fetch latest models in the background once the UI is shown QTimer.singleShot(0, lambda: self.fetch_models(silent=True)) + + def _is_nvidia_api_url(self, api_url: str) -> bool: + """Return True when the configured URL points to Nvidia's OpenAI-compatible API.""" + return "integrate.api.nvidia.com" in (api_url or "").strip().lower() + + def _update_model_placeholder(self): + """Show a manual model-entry hint only when Nvidia API is selected.""" + line_edit = self.model_combo.lineEdit() + if not line_edit: + return + if self._is_nvidia_api_url(self.api_url_edit.text()): + line_edit.setPlaceholderText("Enter Nvidia model name (e.g., deepseek-ai/deepseek-v4-pro)") + else: + line_edit.setPlaceholderText("") def init_ui(self): """Initialize the user interface with horizontal icon navigation at top.""" @@ -326,11 +341,13 @@ class ConfigTab(QWidget): ("Claude (Anthropic)", "https://api.anthropic.com/v1"), ("Gemini", "https://generativelanguage.googleapis.com/v1beta/openai/"), ("DeepSeek", "https://api.deepseek.com/v1/"), + ("Nvidia", "https://integrate.api.nvidia.com/v1/"), ] for _name, _url in _url_presets: _action = api_url_menu.addAction(_name) _action.triggered.connect(lambda checked, u=_url: self.api_url_edit.setText(u)) api_url_preset_btn.setMenu(api_url_menu) + self.api_url_edit.textChanged.connect(self._update_model_placeholder) api_url_layout.addWidget(self.api_url_edit) api_url_layout.addWidget(api_url_preset_btn) diff --git a/util/translation.py b/util/translation.py index bdbae86..9a67263 100644 --- a/util/translation.py +++ b/util/translation.py @@ -88,6 +88,13 @@ def _write_request_debug_log(provider, request_payload, usage): except Exception: pass +def _normalize_openai_base_url(url: str) -> str: + """Ensure OpenAI SDK global base_url has a trailing slash.""" + _url = (url or "").strip() + if _url and not _url.endswith("/"): + _url += "/" + return _url + # Tracks which distinct batch sizes have already been cache-written during this estimate run. # Each unique numLines value maps to a distinct output_config schema → one write per size. # Persisted to disk so sequential GUI subprocesses share state. @@ -329,17 +336,17 @@ def validate_translation_content(original_items, translated_items, langRegex): return is_valid, invalid_indices, reasons # Load .env, strip accidental whitespace, set base URL / org / API key. -# Handles the Gemini compatibility layer as a special case. +# Gemini uses its compatibility endpoint only when no custom API URL is set. load_dotenv() api_provider = os.getenv("API_PROVIDER", "openai").lower() env_api = os.getenv("api", "").strip() -if api_provider == "gemini": - # Use Google Generative Language compatibility endpoint when running Gemini +if api_provider == "gemini" and not env_api: + # Use Google Generative Language compatibility endpoint only as fallback. openai.base_url = "https://generativelanguage.googleapis.com/v1beta/openai/" openai.organization = None else: if env_api: - openai.base_url = env_api + openai.base_url = _normalize_openai_base_url(env_api) # Support both 'organization' (gui/.env.example) and legacy 'org' names org = os.getenv("organization") or os.getenv("org") if org: @@ -1182,10 +1189,10 @@ def translateText(system, user, history, penalty, formatType, model, numLines=No _live_api = os.getenv("api", "").strip() _live_key = os.getenv("key", "").strip() _live_provider = os.getenv("API_PROVIDER", "openai").lower() - if _live_provider == "gemini": + if _live_provider == "gemini" and not _live_api: openai.base_url = "https://generativelanguage.googleapis.com/v1beta/openai/" elif _live_api: - openai.base_url = _live_api + openai.base_url = _normalize_openai_base_url(_live_api) if _live_key: openai.api_key = _live_key