Every fatal message told the user THAT something failed but not what to do
about it. The worst was "conda env create failed. See output above." --
useless when run_install_capture.bat redirects that output to a 56 KB log.
Each error now names the likely cause and the concrete next step:
- download failed -> the URL tried, firewall/proxy hint, manual-install
fallback that install.bat will detect on re-run
- truncated download -> got N bytes vs expected ~78 MB, bad file deleted
- installer failed -> antivirus/UAC hint, how to run it by hand
- conda found but dead -> the exact command to reproduce the real error
- env create failed -> disk/network/antivirus causes, plus the
"env remove -n botty -y" recovery for a half
finished install
- pip install failed -> notes the env itself is fine and a re-run resumes
- python.exe missing -> explains partial env, gives the recovery commands
- find_python.bat -> distinguishes "never installed" from "install.bat
did not finish", pointing at the capture log
Added a shared ":fail" exit so every fatal path ends with how to produce a
full log for a bug report, and states that nothing else was changed.
Also added a disk-space pre-flight before env creation: under 3 GB now
fails immediately with a clear message instead of letting conda die halfway
through with an opaque error; 3-6 GB warns. The environment needs ~4 GB
plus ~1 GB of downloads.
Verified: install.bat still completes with exit 0; the pre-flight was
exercised at real, simulated-2 GB and simulated-5 GB levels and all three
branches render and exit correctly; find_python.bat still resolves; 140
tests pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
625 lines
25 KiB
Batchfile
625 lines
25 KiB
Batchfile
@echo off
|
|
setlocal enabledelayedexpansion
|
|
|
|
:: Always run from the folder this script lives in
|
|
cd /d "%~dp0"
|
|
|
|
echo ============================================
|
|
echo Botty - Dependency Installer
|
|
echo ============================================
|
|
echo.
|
|
|
|
:: --- Detect Windows version ---
|
|
for /f "tokens=3" %%A in ('reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion" /v CurrentBuild 2^>nul') do set "WIN_BUILD=%%A"
|
|
if not defined WIN_BUILD (
|
|
echo WARNING: Could not detect Windows build number.
|
|
set "WIN_BUILD=0"
|
|
)
|
|
echo Detected Windows build: %WIN_BUILD%
|
|
set /a "WIN_BUILD_NUM=%WIN_BUILD%" 2>nul || set "WIN_BUILD_NUM=0"
|
|
if %WIN_BUILD_NUM% GEQ 22000 (
|
|
echo Detected Windows 11 -- using relative mouse mode ^(no ABSOLUTE flag^)
|
|
set "WIN11=1"
|
|
set "REQ_FILE=requirements-win11.txt"
|
|
set "ENV_FILE=environment-win11.yml"
|
|
) else (
|
|
echo Detected Windows 10 or earlier — using absolute mouse mode
|
|
set "WIN11=0"
|
|
set "REQ_FILE=requirements-win10.txt"
|
|
set "ENV_FILE=environment-win10.yml"
|
|
)
|
|
if not exist "%REQ_FILE%" set "REQ_FILE=requirements.txt"
|
|
if not exist "%ENV_FILE%" set "ENV_FILE=environment.yml"
|
|
echo Requirements profile: %REQ_FILE%
|
|
echo Environment profile: %ENV_FILE%
|
|
echo.
|
|
|
|
:: --- Find conda ---
|
|
:: Miniforge3 JustMe default: %LOCALAPPDATA%\miniforge3 (newer) or
|
|
:: %USERPROFILE%\miniforge3 (older)
|
|
set "CONDA_EXE="
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\Scripts\conda.exe"
|
|
"%USERPROFILE%\miniforge3\Scripts\conda.exe"
|
|
"%LOCALAPPDATA%\miniconda3\Scripts\conda.exe"
|
|
"%USERPROFILE%\miniconda3\Scripts\conda.exe"
|
|
"%USERPROFILE%\anaconda3\Scripts\conda.exe"
|
|
"%ProgramData%\miniforge3\Scripts\conda.exe"
|
|
"%ProgramData%\miniconda3\Scripts\conda.exe"
|
|
"%ProgramData%\anaconda3\Scripts\conda.exe"
|
|
) do (
|
|
if exist %%C (
|
|
set "CONDA_EXE=%%~C"
|
|
goto :found_conda
|
|
)
|
|
)
|
|
|
|
echo conda not found — installing Miniforge3 automatically...
|
|
echo This is a one-time setup (~100 MB). Please wait.
|
|
echo.
|
|
|
|
:: --- Method 1: winget (cleanest; available on Win10 1709+ and all Win11) ---
|
|
:: --scope user is critical: without it winget defaults to a machine-wide
|
|
:: install (lands in %ProgramData%) which REQUIRES admin. A normal double-click
|
|
:: (no elevation) then fails silently and conda never installs. --scope user
|
|
:: installs to %USERPROFILE%\miniforge3 with no admin needed — which is also one
|
|
:: of the locations :rescan_conda searches.
|
|
:: winget returns non-zero when the package is already installed, so don't
|
|
:: trust the exit code -- rescan for conda and only fall through to the direct
|
|
:: download if it's genuinely still missing. Keep this comment outside the block:
|
|
:: a "::" line inside a ( ) block is a parse error.
|
|
winget --version >nul 2>&1
|
|
if %errorlevel% equ 0 (
|
|
echo Installing via winget...
|
|
winget install --id CondaForge.Miniforge3 --exact --silent --scope user ^
|
|
--accept-package-agreements --accept-source-agreements
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\Scripts\conda.exe"
|
|
"%USERPROFILE%\miniforge3\Scripts\conda.exe"
|
|
"%ProgramData%\miniforge3\Scripts\conda.exe"
|
|
) do if exist %%C goto :rescan_conda
|
|
echo winget did not produce a usable conda — falling back to direct download.
|
|
echo.
|
|
)
|
|
|
|
:: --- Method 2: direct download + silent NSIS install ---
|
|
:: Uses curl (built into Win10/11) with PowerShell as fallback.
|
|
:: $ProgressPreference=SilentlyContinue is critical — without it PowerShell's
|
|
:: progress bar drops download speed from ~50 MB/s to ~1 MB/s.
|
|
:: start /wait "" is required: plain "installer /S" can return before install
|
|
:: finishes. /D= intentionally omitted — NSIS /D= breaks on paths with spaces.
|
|
set "MF_INSTALLER=%TEMP%\Miniforge3-installer.exe"
|
|
set "MF_URL=https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-Windows-x86_64.exe"
|
|
|
|
del /q "%MF_INSTALLER%" >nul 2>&1
|
|
echo Downloading Miniforge3...
|
|
curl -Lk --progress-bar "%MF_URL%" -o "%MF_INSTALLER%" 2>&1
|
|
if %errorlevel% neq 0 (
|
|
echo curl failed, trying PowerShell...
|
|
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
|
"$ProgressPreference='SilentlyContinue'; try { Invoke-WebRequest -Uri '%MF_URL%' -OutFile '%MF_INSTALLER%' -UseBasicParsing; exit 0 } catch { Write-Host $_.Exception.Message; exit 1 }"
|
|
)
|
|
if not exist "%MF_INSTALLER%" (
|
|
echo.
|
|
echo ERROR: Could not download Miniforge3 ^(the Python/conda runtime^).
|
|
echo.
|
|
echo Nothing was downloaded from:
|
|
echo %MF_URL%
|
|
echo Usual causes: no internet, or a firewall/proxy blocking github.com.
|
|
echo.
|
|
echo Workaround: install Miniforge yourself, then run install.bat again.
|
|
echo It will detect it and carry on:
|
|
echo https://github.com/conda-forge/miniforge/releases/latest
|
|
echo ^(pick Miniforge3-Windows-x86_64.exe and keep the default location^)
|
|
goto :fail
|
|
)
|
|
|
|
:: Verify the download is a real installer, not a truncated file or an HTML
|
|
:: error page served with a 200. The Miniforge installer is ~78 MB; anything
|
|
:: under 40 MB means the download failed even though a file exists.
|
|
for %%A in ("%MF_INSTALLER%") do set "MF_SIZE=%%~zA"
|
|
if not defined MF_SIZE set "MF_SIZE=0"
|
|
if %MF_SIZE% LSS 41943040 (
|
|
echo.
|
|
echo ERROR: The Miniforge3 download is incomplete and was not run.
|
|
echo Got: %MF_SIZE% bytes
|
|
echo Expected: about 78 MB
|
|
echo.
|
|
echo The connection dropped, or a proxy/filter returned an error page
|
|
echo instead of the file. The bad file has been deleted.
|
|
echo.
|
|
echo Try again on a different network, or install Miniforge yourself and
|
|
echo re-run install.bat:
|
|
echo https://github.com/conda-forge/miniforge/releases/latest
|
|
del /q "%MF_INSTALLER%" >nul 2>&1
|
|
goto :fail
|
|
)
|
|
|
|
echo Installing Miniforge3 (this takes ~1 minute)...
|
|
start /wait "" "%MF_INSTALLER%" /S /InstallationType=JustMe /AddToPath=0 /RegisterPython=0 /NoShortcuts=1 /NoRegistry=1
|
|
if %errorlevel% neq 0 (
|
|
echo.
|
|
echo ERROR: The Miniforge3 installer did not complete ^(exit code %errorlevel%^).
|
|
echo.
|
|
echo Usual causes: antivirus blocked it, or a UAC prompt was declined.
|
|
echo.
|
|
echo Run it by hand to see the real error, accepting any prompts:
|
|
echo %MF_INSTALLER%
|
|
echo then run install.bat again.
|
|
goto :fail
|
|
)
|
|
del /q "%MF_INSTALLER%" >nul 2>&1
|
|
echo Miniforge3 installed.
|
|
|
|
:rescan_conda
|
|
echo.
|
|
|
|
:: Re-scan for conda now that Miniforge is installed
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\Scripts\conda.exe"
|
|
"%USERPROFILE%\miniforge3\Scripts\conda.exe"
|
|
"%LOCALAPPDATA%\miniconda3\Scripts\conda.exe"
|
|
"%USERPROFILE%\miniconda3\Scripts\conda.exe"
|
|
"%USERPROFILE%\anaconda3\Scripts\conda.exe"
|
|
"%ProgramData%\miniforge3\Scripts\conda.exe"
|
|
"%ProgramData%\miniconda3\Scripts\conda.exe"
|
|
"%ProgramData%\anaconda3\Scripts\conda.exe"
|
|
) do (
|
|
if exist %%C (
|
|
set "CONDA_EXE=%%~C"
|
|
goto :found_conda
|
|
)
|
|
)
|
|
echo ERROR: Miniforge3 reported success but conda.exe cannot be found.
|
|
echo.
|
|
echo install.bat looked in every standard location, including:
|
|
echo %%LOCALAPPDATA%%\miniforge3\Scripts\conda.exe
|
|
echo %%USERPROFILE%%\miniforge3\Scripts\conda.exe
|
|
echo %%ProgramData%%\miniforge3\Scripts\conda.exe
|
|
echo.
|
|
echo If you installed conda somewhere custom, the simplest fix is to
|
|
echo install Miniforge to its default location:
|
|
echo https://github.com/conda-forge/miniforge/releases/latest
|
|
echo then run install.bat again.
|
|
goto :fail
|
|
|
|
:found_conda
|
|
echo Found conda: %CONDA_EXE%
|
|
echo.
|
|
|
|
:: --- Test conda works ---
|
|
echo Testing conda...
|
|
"%CONDA_EXE%" --version >nul 2>&1
|
|
if %errorlevel% neq 0 (
|
|
echo.
|
|
echo ERROR: conda was found but will not run.
|
|
echo Location: %CONDA_EXE%
|
|
echo.
|
|
echo The install is damaged or blocked. Try, in order:
|
|
echo 1. Run this by hand to see the real error:
|
|
echo "%CONDA_EXE%" --version
|
|
echo 2. Check antivirus is not quarantining conda
|
|
echo 3. Reinstall Miniforge, then run install.bat again:
|
|
echo https://github.com/conda-forge/miniforge/releases/latest
|
|
goto :fail
|
|
)
|
|
echo conda is working.
|
|
echo.
|
|
|
|
:: --- Find botty Python ---
|
|
set "PYTHON="
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\envs\botty\python.exe"
|
|
"%LOCALAPPDATA%\miniconda3\envs\botty\python.exe"
|
|
"%USERPROFILE%\miniforge3\envs\botty\python.exe"
|
|
"%USERPROFILE%\miniconda3\envs\botty\python.exe"
|
|
"%USERPROFILE%\anaconda3\envs\botty\python.exe"
|
|
"%ProgramData%\miniforge3\envs\botty\python.exe"
|
|
"%ProgramData%\miniconda3\envs\botty\python.exe"
|
|
"%ProgramData%\anaconda3\envs\botty\python.exe"
|
|
) do (
|
|
if exist %%C (
|
|
set "PYTHON=%%~C"
|
|
goto :check_env
|
|
)
|
|
)
|
|
|
|
:: --- Pre-flight: free disk space ---
|
|
:: The botty env is ~4 GB once conda unpacks it, plus ~1 GB of downloaded
|
|
:: package archives. Running out midway makes conda fail with a long, opaque
|
|
:: error, so check up front and say so plainly instead.
|
|
set "FREE_GB="
|
|
for /f "delims=" %%A in ('powershell -NoProfile -Command "[int]((Get-PSDrive %SystemDrive:~0,1%).Free/1GB)" 2^>nul') do set "FREE_GB=%%A"
|
|
if defined FREE_GB (
|
|
echo Free disk space: %FREE_GB% GB
|
|
if %FREE_GB% LSS 3 (
|
|
echo.
|
|
echo ERROR: Not enough free disk space on %SystemDrive%
|
|
echo Free now: %FREE_GB% GB
|
|
echo Needed: about 6 GB ^(the botty environment is ~4 GB, plus
|
|
echo ~1 GB of package downloads^)
|
|
echo.
|
|
echo Free up space and run install.bat again. Quick wins:
|
|
echo - Empty the Recycle Bin
|
|
echo - Windows Settings ^> System ^> Storage ^> Temporary files
|
|
echo - Uninstall apps you no longer use
|
|
goto :fail
|
|
)
|
|
if %FREE_GB% LSS 6 (
|
|
echo WARNING: Only %FREE_GB% GB free. The install needs about 6 GB and
|
|
echo may fail partway. Free up space if it does.
|
|
)
|
|
)
|
|
|
|
:: --- Create botty env ---
|
|
echo Creating 'botty' conda environment...
|
|
"%CONDA_EXE%" env create -f "%ENV_FILE%"
|
|
if %errorlevel% neq 0 (
|
|
echo.
|
|
echo ERROR: Could not create the 'botty' conda environment.
|
|
echo.
|
|
echo The detailed reason is in the conda output above this message.
|
|
echo Most common causes:
|
|
echo - Out of disk space ^(needs about 6 GB free^)
|
|
echo - No internet, or a company/school network blocking conda-forge
|
|
echo - Antivirus blocking conda while it unpacks files
|
|
echo - A previous half-finished install: run this to clear it, then retry
|
|
echo "%CONDA_EXE%" env remove -n botty -y
|
|
goto :fail
|
|
)
|
|
|
|
:check_env
|
|
:: Re-scan for Python after env creation
|
|
set "PYTHON="
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\envs\botty\python.exe"
|
|
"%LOCALAPPDATA%\miniconda3\envs\botty\python.exe"
|
|
"%USERPROFILE%\miniforge3\envs\botty\python.exe"
|
|
"%USERPROFILE%\miniconda3\envs\botty\python.exe"
|
|
"%USERPROFILE%\anaconda3\envs\botty\python.exe"
|
|
"%ProgramData%\miniforge3\envs\botty\python.exe"
|
|
"%ProgramData%\miniconda3\envs\botty\python.exe"
|
|
"%ProgramData%\anaconda3\envs\botty\python.exe"
|
|
) do (
|
|
if exist %%C (
|
|
set "PYTHON=%%~C"
|
|
goto :env_ready
|
|
)
|
|
)
|
|
|
|
echo.
|
|
echo ERROR: The 'botty' environment exists but its python.exe is missing.
|
|
echo.
|
|
echo This usually means the environment was only partly created -- often
|
|
echo because the install ran out of disk space, or antivirus removed files
|
|
echo while conda was unpacking them.
|
|
echo.
|
|
echo Fix: delete the environment and install again:
|
|
echo "%CONDA_EXE%" env remove -n botty -y
|
|
echo install.bat
|
|
goto :fail
|
|
|
|
:env_ready
|
|
echo Botty Python: %PYTHON%
|
|
|
|
:: --- Install pip requirements ---
|
|
:: --progress-bar off: pip's progress bar uses \r to redraw in place; when this
|
|
:: script's output is redirected to a file (e.g. run_install_capture.bat) those
|
|
:: redraws become millions of lines and the log balloons to many GB. Turning the
|
|
:: bar off keeps the install log small without hiding warnings/errors.
|
|
echo.
|
|
echo Installing Botty requirements from %REQ_FILE%...
|
|
"%CONDA_EXE%" run -n botty python -m pip install --progress-bar off -r "%REQ_FILE%"
|
|
if %errorlevel% neq 0 (
|
|
echo.
|
|
echo ERROR: Could not install the Python packages from %REQ_FILE%.
|
|
echo.
|
|
echo The failing package and reason are in the pip output above.
|
|
echo Most common causes:
|
|
echo - No internet, or a proxy/firewall blocking pypi.org
|
|
echo - Out of disk space
|
|
echo - Antivirus blocking pip while it writes files
|
|
echo.
|
|
echo The conda environment itself is fine -- you can just run
|
|
echo install.bat again; it will skip straight to this step.
|
|
goto :fail
|
|
)
|
|
|
|
echo.
|
|
echo Botty osdetect:
|
|
"%CONDA_EXE%" run -n botty python -c "import sys; sys.path.insert(0, 'src'); from utils.os_detect import describe_current_os; print(describe_current_os())"
|
|
|
|
:: --- OCR setup ---
|
|
:: Two OCR backends, tried in order at runtime:
|
|
:: 1. tesserocr — C extension calling tesseract DLLs directly (fast)
|
|
:: 2. pytesseract — subprocess calling tesseract.exe (always works if exe exists)
|
|
:: At least one must work. Install.bat sets up both and reports which is ready.
|
|
echo.
|
|
echo Setting up OCR...
|
|
|
|
:: Find the botty env directory
|
|
set "BOTTY_ENV_DIR="
|
|
for %%C in (
|
|
"%LOCALAPPDATA%\miniforge3\envs\botty"
|
|
"%LOCALAPPDATA%\miniconda3\envs\botty"
|
|
"%USERPROFILE%\miniforge3\envs\botty"
|
|
"%USERPROFILE%\miniconda3\envs\botty"
|
|
"%USERPROFILE%\anaconda3\envs\botty"
|
|
"%ProgramData%\miniforge3\envs\botty"
|
|
"%ProgramData%\miniconda3\envs\botty"
|
|
"%ProgramData%\anaconda3\envs\botty"
|
|
) do (
|
|
if exist %%C (
|
|
set "BOTTY_ENV_DIR=%%~C"
|
|
goto :env_found
|
|
)
|
|
)
|
|
echo ERROR: Could not locate the 'botty' environment folder.
|
|
echo.
|
|
echo Python was found but the environment directory around it was not,
|
|
echo which means the conda install is in an unexpected layout.
|
|
echo Fix: remove and recreate the environment:
|
|
echo "%CONDA_EXE%" env remove -n botty -y
|
|
echo install.bat
|
|
goto :fail
|
|
|
|
:env_found
|
|
set "TESS_PATH=%BOTTY_ENV_DIR%\Library\bin;%BOTTY_ENV_DIR%\Library\lib;%BOTTY_ENV_DIR%\DLLs;%BOTTY_ENV_DIR%\Scripts"
|
|
|
|
:: --- Backend 1: tesserocr (fast path, best-effort) ---
|
|
:: tesserocr uses the C++ API of tesseract and needs an MSVC-compiled tesseract DLL.
|
|
:: The bundled dependencies folder provides:
|
|
:: tesseract52.dll — MSVC tesseract 5.2.0 (conda-forge, compiled vs2019)
|
|
:: tesserocr.cp310-...pyd — MSVC tesserocr 2.5.2 linked against tesseract52.dll
|
|
:: (both require leptonica-1.78.0.dll from the conda tesseract=4.x install below)
|
|
:: If any step fails the bot still works via pytesseract below.
|
|
|
|
:: Remove any existing pip/wheel tesserocr
|
|
"%PYTHON%" -m pip uninstall tesserocr -y >nul 2>&1
|
|
|
|
:: conda tesseract 4.x provides leptonica-1.78.0.dll (MSVC) which tesseract52.dll needs.
|
|
:: libdeflate is required explicitly: the libtiff that ships with tesseract 4.x
|
|
:: imports libdeflate, and without it the whole chain below fails to load.
|
|
"%CONDA_EXE%" install -n botty "tesseract=4.*" libdeflate -c conda-forge -y >nul 2>&1
|
|
|
|
:: libdeflate.dll compatibility alias.
|
|
:: THIS IS WHAT MAKES tesserocr WORK. The DLL chain is:
|
|
:: tesserocr.pyd -> tesseract52.dll -> leptonica-1.78.0.dll -> tiff.dll -> libdeflate.dll
|
|
:: Current conda-forge libdeflate (>=1.20) installs the library as "deflate.dll",
|
|
:: but the older tiff.dll from the tesseract=4.x stack still imports the previous
|
|
:: name "libdeflate.dll". Nothing provides that name, so tiff.dll fails to load,
|
|
:: and every DLL above it in the chain fails with WinError 126 ("The specified
|
|
:: module could not be found") -- which surfaced as tesserocr being permanently
|
|
:: unavailable and the bot silently falling back to the slower pytesseract.
|
|
:: Copying deflate.dll to the old name satisfies the import; the exported symbols
|
|
:: are the same library, verified by tesserocr initialising and running real OCR.
|
|
if not exist "%BOTTY_ENV_DIR%\Library\bin\libdeflate.dll" (
|
|
if exist "%BOTTY_ENV_DIR%\Library\bin\deflate.dll" (
|
|
copy /y "%BOTTY_ENV_DIR%\Library\bin\deflate.dll" "%BOTTY_ENV_DIR%\Library\bin\libdeflate.dll" >nul
|
|
)
|
|
)
|
|
|
|
:: conda tesseract.exe crashes on Win10 and Win11 — disable it, keep the DLLs
|
|
if exist "%BOTTY_ENV_DIR%\Library\bin\tesseract.exe" (
|
|
rename "%BOTTY_ENV_DIR%\Library\bin\tesseract.exe" "tesseract_disabled.exe" >nul 2>&1
|
|
)
|
|
|
|
:: Deploy the MSVC tesseract52.dll (tesserocr.pyd imports exactly this name)
|
|
if exist "dependencies\tesseract52.dll" (
|
|
copy /y "dependencies\tesseract52.dll" "%BOTTY_ENV_DIR%\Library\bin\tesseract52.dll" >nul
|
|
)
|
|
|
|
:: Deploy the conda-forge tesserocr .pyd (compiled against tesseract52.dll)
|
|
if exist "dependencies\tesserocr.cp310-win_amd64.pyd" (
|
|
copy /y "dependencies\tesserocr.cp310-win_amd64.pyd" "%BOTTY_ENV_DIR%\lib\site-packages\tesserocr.cp310-win_amd64.pyd" >nul
|
|
) else if exist "dependencies\tesserocr-2.5.2-cp310-cp310-win_amd64.whl" (
|
|
"%CONDA_EXE%" run -n botty python -m pip install --quiet --force-reinstall --no-deps "dependencies\tesserocr-2.5.2-cp310-cp310-win_amd64.whl" >nul 2>&1
|
|
)
|
|
|
|
:: --- Backend 2: pytesseract (reliable fallback) ---
|
|
:: This is the backend that actually carries OCR on most machines (tesserocr's
|
|
:: MSVC DLL chain frequently fails), so it must install without admin rights and
|
|
:: without winget -- neither is guaranteed on a clean Win10 box.
|
|
"%CONDA_EXE%" run -n botty python -m pip install --progress-bar off pytesseract >nul 2>&1
|
|
if %errorlevel% neq 0 (
|
|
echo WARNING: Could not install pytesseract Python wrapper.
|
|
)
|
|
|
|
:: Try winget machine scope, then user scope -- the latter needs no admin.
|
|
:: winget's exit code is unreliable, being non-zero when the package is already
|
|
:: installed, so after each attempt we re-resolve tesseract.exe instead of
|
|
:: trusting errorlevel.
|
|
:: NOTE: comments must stay OUTSIDE the parenthesised blocks below. A "::" line
|
|
:: inside a ( ) block is a parse error, and any parenthesis in the comment text
|
|
:: closes the block early.
|
|
call :find_tesseract
|
|
if not defined TESS_EXE (
|
|
echo Installing Tesseract OCR...
|
|
winget --version >nul 2>&1
|
|
if !errorlevel! equ 0 (
|
|
winget install --id tesseract-ocr.tesseract --exact --silent ^
|
|
--accept-package-agreements --accept-source-agreements >nul 2>&1
|
|
call :find_tesseract
|
|
if not defined TESS_EXE (
|
|
winget install --id tesseract-ocr.tesseract --exact --silent --scope user ^
|
|
--accept-package-agreements --accept-source-agreements >nul 2>&1
|
|
call :find_tesseract
|
|
)
|
|
)
|
|
)
|
|
|
|
:: Last resort: direct download of the official NSIS installer. Covers clean
|
|
:: Win10 machines where winget is missing or fails.
|
|
:: The size check guards against a truncated download or an HTML error page;
|
|
:: the installer is ~50 MB.
|
|
:: NOTE on /D=: measured behaviour is that the official Tesseract installer
|
|
:: self-elevates (it requests admin) and the elevated relaunch DISCARDS /D=, so
|
|
:: it always lands machine-wide in "C:\Program Files\Tesseract-OCR" regardless
|
|
:: of TS_DEST. /D= is kept as best-effort only. The practical consequence is
|
|
:: that Tesseract needs admin/UAC -- there is no per-user install path with the
|
|
:: official installer. Either outcome is fine at runtime because find_tesseract
|
|
:: and src\d2r_image\ocr.py both search the machine-wide and per-user paths.
|
|
:: /D= must still come last and unquoted, and breaks on paths with spaces, so
|
|
:: it is only passed when the target path has none.
|
|
if not defined TESS_EXE (
|
|
echo winget unavailable or failed -- downloading Tesseract directly...
|
|
set "TS_INSTALLER=%TEMP%\tesseract-setup.exe"
|
|
set "TS_URL=https://github.com/tesseract-ocr/tesseract/releases/download/5.5.0/tesseract-ocr-w64-setup-5.5.0.20241111.exe"
|
|
set "TS_DEST=%LOCALAPPDATA%\Programs\Tesseract-OCR"
|
|
del /q "!TS_INSTALLER!" >nul 2>&1
|
|
curl -Lk --progress-bar "!TS_URL!" -o "!TS_INSTALLER!" 2>&1
|
|
if not exist "!TS_INSTALLER!" (
|
|
powershell -NoProfile -ExecutionPolicy Bypass -Command ^
|
|
"$ProgressPreference='SilentlyContinue'; try { Invoke-WebRequest -Uri '!TS_URL!' -OutFile '!TS_INSTALLER!' -UseBasicParsing; exit 0 } catch { exit 1 }"
|
|
)
|
|
set "TS_SIZE=0"
|
|
if exist "!TS_INSTALLER!" for %%A in ("!TS_INSTALLER!") do set "TS_SIZE=%%~zA"
|
|
if !TS_SIZE! GEQ 20971520 (
|
|
echo !TS_DEST! | find " " >nul
|
|
if !errorlevel! equ 0 (
|
|
start /wait "" "!TS_INSTALLER!" /S
|
|
) else (
|
|
start /wait "" "!TS_INSTALLER!" /S /D=!TS_DEST!
|
|
)
|
|
del /q "!TS_INSTALLER!" >nul 2>&1
|
|
call :find_tesseract
|
|
)
|
|
)
|
|
|
|
if defined TESS_EXE (
|
|
echo Tesseract: !TESS_EXE!
|
|
) else (
|
|
echo WARNING: Tesseract could not be installed automatically. Install manually:
|
|
echo https://github.com/tesseract-ocr/tesseract/releases
|
|
echo Download the win64 installer, run it, then re-run install.bat.
|
|
)
|
|
|
|
:: --- Verify OCR: at least one backend must work ---
|
|
echo.
|
|
echo Checking OCR backends...
|
|
set "PATH=%TESS_PATH%;%PATH%"
|
|
set "OCR_READY=0"
|
|
|
|
"%CONDA_EXE%" run -n botty python -c "import os; os.add_dll_directory(r'%BOTTY_ENV_DIR%\Library\bin'); from tesserocr import PyTessBaseAPI, OEM; PyTessBaseAPI(psm=7,oem=OEM.LSTM_ONLY,path='assets/tessdata',lang='hover-eng_inconsolata_inv_th_fast').End()" >nul 2>&1
|
|
if %errorlevel% == 0 (
|
|
echo tesserocr: OK ^(fast path^)
|
|
set "OCR_READY=1"
|
|
) else (
|
|
echo tesserocr: not available ^(DLL issue -- bot will use pytesseract instead^)
|
|
)
|
|
|
|
if defined TESS_EXE (
|
|
"%CONDA_EXE%" run -n botty python -c "import pytesseract; pytesseract.pytesseract.tesseract_cmd=r'!TESS_EXE!'; pytesseract.get_tesseract_version()" >nul 2>&1
|
|
if !errorlevel! == 0 (
|
|
echo pytesseract: OK ^(reliable fallback^)
|
|
set "OCR_READY=1"
|
|
) else (
|
|
echo pytesseract: tesseract.exe found but call failed
|
|
)
|
|
) else (
|
|
echo pytesseract: tesseract.exe not found -- install from link above if needed
|
|
)
|
|
|
|
if "%OCR_READY%"=="0" (
|
|
echo.
|
|
echo WARNING: No OCR backend is working. Item hover text will not be read.
|
|
echo Install Tesseract OCR: https://github.com/tesseract-ocr/tesseract/releases
|
|
echo Then re-run install.bat.
|
|
)
|
|
|
|
:: --- Verify all dependencies ---
|
|
echo.
|
|
echo Verifying all dependencies...
|
|
set "ALL_OK=1"
|
|
for %%M in (cv2 mss numpy transitions rapidfuzz pydantic pytesseract yaml) do (
|
|
set "PATH=%TESS_PATH%;%PATH%"
|
|
"%CONDA_EXE%" run -n botty python -c "import %%M" >nul 2>&1
|
|
if !errorlevel! neq 0 (
|
|
echo FAILED: %%M
|
|
set "ALL_OK=0"
|
|
) else (
|
|
echo %%M: OK
|
|
)
|
|
)
|
|
:: discord.py imports aiohttp which calls ssl.create_default_context() at import
|
|
:: time. A malformed cert in the Windows store triggers ASN1 NOT_ENOUGH_DATA.
|
|
:: The bot patches this at runtime via _patch_ssl(); check import with the patch.
|
|
set "PATH=%TESS_PATH%;%PATH%"
|
|
"%CONDA_EXE%" run -n botty python -c "import ssl; ssl.SSLContext.load_default_certs = lambda *a, **kw: None; import discord" >nul 2>&1
|
|
if !errorlevel! neq 0 (
|
|
echo FAILED: discord
|
|
set "ALL_OK=0"
|
|
) else (
|
|
echo discord: OK
|
|
)
|
|
if "%OCR_READY%"=="0" set "ALL_OK=0"
|
|
|
|
if "%ALL_OK%"=="1" (
|
|
echo.
|
|
echo All dependencies verified.
|
|
) else (
|
|
echo.
|
|
echo WARNING: Some dependencies failed above.
|
|
echo This is often a PATH issue. Try running from a fresh CMD/PowerShell:
|
|
echo conda activate botty
|
|
echo python -c "import cv2"
|
|
echo.
|
|
)
|
|
|
|
:install_done
|
|
echo.
|
|
echo ============================================
|
|
echo Installation complete!
|
|
echo Run botty with: run_botty.bat
|
|
echo ============================================
|
|
echo.
|
|
:: Hold the window open. Every failure path already pauses, but the success
|
|
:: path did not -- so a user double-clicking install.bat from Explorer saw the
|
|
:: console vanish the instant it finished and never got to read the result or
|
|
:: the dependency/OCR verification above. Redirected runs are unaffected:
|
|
:: run_install_capture.bat feeds stdin from the log redirect, and any
|
|
:: non-interactive run should invoke this script with "< nul".
|
|
pause
|
|
goto :eof
|
|
|
|
:: --- Shared failure exit ---
|
|
:: Every fatal path jumps here with "goto :fail" after printing what went wrong
|
|
:: and how to fix it. This adds the one instruction that makes a bug report
|
|
:: actionable: how to produce a full log.
|
|
:fail
|
|
echo.
|
|
echo ------------------------------------------------------------
|
|
echo INSTALL FAILED - nothing else was changed on your PC.
|
|
echo.
|
|
echo Still stuck? Produce a full log and include it when asking
|
|
echo for help:
|
|
echo 1. Double-click run_install_capture.bat
|
|
echo 2. Attach the install_log.txt it creates
|
|
echo ------------------------------------------------------------
|
|
echo.
|
|
pause
|
|
exit /b 1
|
|
|
|
:: --- Resolve tesseract.exe into TESS_EXE ---
|
|
:: Checks machine-wide (winget default / manual install) and per-user (winget
|
|
:: --scope user / our direct NSIS fallback) locations, plus PATH. Sets TESS_EXE
|
|
:: to the first hit, or clears it if none found.
|
|
:find_tesseract
|
|
set "TESS_EXE="
|
|
for %%T in (
|
|
"C:\Program Files\Tesseract-OCR\tesseract.exe"
|
|
"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe"
|
|
"%LOCALAPPDATA%\Programs\Tesseract-OCR\tesseract.exe"
|
|
"%ProgramData%\Tesseract-OCR\tesseract.exe"
|
|
) do (
|
|
if exist %%T (
|
|
set "TESS_EXE=%%~T"
|
|
goto :eof
|
|
)
|
|
)
|
|
for /f "delims=" %%T in ('where tesseract 2^>nul') do (
|
|
set "TESS_EXE=%%T"
|
|
goto :eof
|
|
)
|
|
goto :eof
|