fix(install): make Tesseract/OCR setup work on clean Win10/Win11
Follow-up to the conda scope fix: the same admin/winget assumptions broke the OCR backend, which is what actually carries item text reading since tesserocr's MSVC DLL chain commonly fails to load. - install.bat installed Tesseract via `winget install` with no --scope, i.e. machine-wide into "C:\Program Files", which requires admin. On a clean non-admin box this failed and left NO working OCR backend at all (tesserocr already fails), so OCR_READY=0 and item reading was dead. Now: winget machine scope -> winget --scope user -> direct download of the official NSIS installer with a per-user /D= target. Also stops trusting winget's exit code (non-zero when already installed) and re-resolves tesseract.exe after each attempt. - The downloaded installer is size-checked (~50 MB; <20 MB = failed download) before being executed, matching the Miniforge handling. - Added a :find_tesseract subroutine that resolves tesseract.exe from Program Files, Program Files (x86), %LOCALAPPDATA%\Programs, %ProgramData% and PATH. Verification now uses the resolved path instead of the hardcoded "C:\Program Files" one. - ocr.py: added Program Files (x86) and the per-user %LOCALAPPDATA%\Programs\Tesseract-OCR location to the runtime search order, since per-user installs are not on PATH. - run_botty.bat: only export PYTESSERACT_TESSERACT_CMD when the file exists, falling back to the per-user path, so a stale machine-wide value cannot shadow a valid per-user install. Verified on this machine: all install.bat dependency imports OK (cv2/mss/numpy/transitions/rapidfuzz/pydantic/pytesseract/yaml/discord), pytesseract resolves tesseract 5.5.0, osdetect reports the win11 profile, config loads, 140 tests pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
94
install.bat
94
install.bat
@@ -318,23 +318,71 @@ if exist "dependencies\tesserocr.cp310-win_amd64.pyd" (
|
||||
)
|
||||
|
||||
:: --- Backend 2: pytesseract (reliable fallback) ---
|
||||
:: Needs tesseract.exe from winget. Works on any Python version.
|
||||
:: On Win10: winget may not be available -- if install fails, offer manual link.
|
||||
:: 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.
|
||||
)
|
||||
|
||||
if not exist "C:\Program Files\Tesseract-OCR\tesseract.exe" (
|
||||
echo Installing Tesseract OCR via winget...
|
||||
winget install --id tesseract-ocr.tesseract --silent --accept-package-agreements --accept-source-agreements 2>nul
|
||||
if !errorlevel! neq 0 (
|
||||
echo winget failed -- on Windows 10 you may need to install manually:
|
||||
echo https://github.com/tesseract-ocr/tesseract/releases
|
||||
echo Download the win64 installer, run it, keep the default install path.
|
||||
call :find_tesseract
|
||||
if not defined TESS_EXE (
|
||||
echo Installing Tesseract OCR...
|
||||
:: Try winget machine scope, then user scope (no admin needed). winget's
|
||||
:: exit code is unreliable (non-zero when already installed), so after each
|
||||
:: attempt we re-resolve tesseract.exe rather than trusting errorlevel.
|
||||
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 and a per-user
|
||||
:: install. Covers clean Win10 machines with no winget and no admin rights.
|
||||
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 }"
|
||||
)
|
||||
:: Sanity-check the size (installer is ~50 MB) before executing it.
|
||||
set "TS_SIZE=0"
|
||||
if exist "!TS_INSTALLER!" for %%A in ("!TS_INSTALLER!") do set "TS_SIZE=%%~zA"
|
||||
if !TS_SIZE! GEQ 20971520 (
|
||||
:: NSIS /D= must be last and unquoted, and breaks on paths containing
|
||||
:: spaces -- so only use it when the target path has none.
|
||||
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...
|
||||
@@ -349,8 +397,8 @@ if %errorlevel% == 0 (
|
||||
echo tesserocr: not available ^(DLL issue -- bot will use pytesseract instead^)
|
||||
)
|
||||
|
||||
if exist "C:\Program Files\Tesseract-OCR\tesseract.exe" (
|
||||
"%CONDA_EXE%" run -n botty python -c "import pytesseract; pytesseract.pytesseract.tesseract_cmd=r'C:\Program Files\Tesseract-OCR\tesseract.exe'; pytesseract.get_tesseract_version()" >nul 2>&1
|
||||
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"
|
||||
@@ -414,3 +462,27 @@ echo Installation complete!
|
||||
echo Run botty with: run_botty.bat
|
||||
echo ============================================
|
||||
echo.
|
||||
goto :eof
|
||||
|
||||
:: --- 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
|
||||
|
||||
@@ -17,9 +17,16 @@ set "CONDA_PREFIX=%_ENV%"
|
||||
set "PYTHONUTF8=1"
|
||||
set "PYTHONIOENCODING=utf-8"
|
||||
set "SSL_CERT_DIR="
|
||||
:: Use winget tesseract 5.5.0 (conda tesseract crashes with access violation)
|
||||
:: Use winget tesseract 5.5.0 (conda tesseract crashes with access violation).
|
||||
:: Only export the path if it actually exists -- on machines where Tesseract was
|
||||
:: installed per-user (no admin), it lives under %LOCALAPPDATA%\Programs instead,
|
||||
:: and src\d2r_image\ocr.py resolves that itself.
|
||||
set "TESSDATA_PREFIX=%_ENV%\Library\share"
|
||||
set "PYTESSERACT_TESSERACT_CMD=C:\Program Files\Tesseract-OCR\tesseract.exe"
|
||||
if exist "C:\Program Files\Tesseract-OCR\tesseract.exe" (
|
||||
set "PYTESSERACT_TESSERACT_CMD=C:\Program Files\Tesseract-OCR\tesseract.exe"
|
||||
) else if exist "%LOCALAPPDATA%\Programs\Tesseract-OCR\tesseract.exe" (
|
||||
set "PYTESSERACT_TESSERACT_CMD=%LOCALAPPDATA%\Programs\Tesseract-OCR\tesseract.exe"
|
||||
)
|
||||
|
||||
echo Launching Botty ...
|
||||
"%PYTHON%" "%BOTTY_DIR%src\main.py"
|
||||
|
||||
@@ -46,6 +46,11 @@ try:
|
||||
os.path.join(_APP_BASE, "tesseract", "tesseract.exe"), # bundled in release
|
||||
shutil.which("tesseract"),
|
||||
r"C:\Program Files\Tesseract-OCR\tesseract.exe",
|
||||
r"C:\Program Files (x86)\Tesseract-OCR\tesseract.exe",
|
||||
# Per-user installs (winget --scope user, or install.bat's direct NSIS
|
||||
# fallback) land here and are not on PATH -- needed on machines where
|
||||
# the user has no admin rights.
|
||||
os.path.join(os.environ.get("LOCALAPPDATA", ""), "Programs", "Tesseract-OCR", "tesseract.exe"),
|
||||
]
|
||||
_cmd = next((c for c in _candidates if c and os.path.isfile(c)), None)
|
||||
if _cmd:
|
||||
|
||||
Reference in New Issue
Block a user