Files
Meeting_Assistant/scripts/build-client.bat
egg 01d578c67e feat: Add SQLite database support and fixed portable extraction path
- Add SQLite as alternative database for offline/firewall environments
- Add --database-type parameter to build-client.bat (mysql/sqlite)
- Refactor database.py to support both MySQL and SQLite
- Add DB_TYPE and SQLITE_PATH configuration options
- Set fixed unpackDirName for portable exe (Meeting-Assistant)
- Update DEPLOYMENT.md with SQLite mode documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-17 13:57:02 +08:00

578 lines
18 KiB
Batchfile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@echo off
chcp 65001 >nul
REM Meeting Assistant Client - Windows 打包腳本
REM 將 Electron 應用與 Python Sidecar 打包成免安裝 exe
setlocal enabledelayedexpansion
REM 顏色設定 (Windows 10+)
set "GREEN=[92m"
set "YELLOW=[93m"
set "RED=[91m"
set "BLUE=[94m"
set "CYAN=[96m"
set "NC=[0m"
REM 專案路徑
set "SCRIPT_DIR=%~dp0"
set "PROJECT_DIR=%SCRIPT_DIR%.."
set "CLIENT_DIR=%PROJECT_DIR%\client"
set "SIDECAR_DIR=%PROJECT_DIR%\sidecar"
set "BACKEND_DIR=%PROJECT_DIR%\backend"
set "BUILD_DIR=%PROJECT_DIR%\build"
REM 預設配置
set "SKIP_SIDECAR=false"
set "SKIP_BACKEND=true"
set "EMBEDDED_BACKEND=false"
set "CLEAN_BUILD=false"
set "API_URL="
set "DATABASE_TYPE="
REM 解析參數
set "COMMAND=help"
:parse_args
if "%~1"=="" goto :main
if /i "%~1"=="build" (set "COMMAND=build" & shift & goto :parse_args)
if /i "%~1"=="sidecar" (set "COMMAND=sidecar" & shift & goto :parse_args)
if /i "%~1"=="electron" (set "COMMAND=electron" & shift & goto :parse_args)
if /i "%~1"=="clean" (set "COMMAND=clean" & shift & goto :parse_args)
if /i "%~1"=="help" (set "COMMAND=help" & shift & goto :parse_args)
if /i "%~1"=="--skip-sidecar" (set "SKIP_SIDECAR=true" & shift & goto :parse_args)
if /i "%~1"=="--skip-backend" (set "SKIP_BACKEND=true" & shift & goto :parse_args)
if /i "%~1"=="--embedded-backend" (set "EMBEDDED_BACKEND=true" & set "SKIP_BACKEND=false" & shift & goto :parse_args)
if /i "%~1"=="--clean" (set "CLEAN_BUILD=true" & shift & goto :parse_args)
if /i "%~1"=="--api-url" (set "API_URL=%~2" & shift & shift & goto :parse_args)
if /i "%~1"=="--database-type" (set "DATABASE_TYPE=%~2" & shift & shift & goto :parse_args)
echo %RED%[ERROR]%NC% 未知參數: %~1
goto :show_help
:main
if "%COMMAND%"=="help" goto :show_help
if "%COMMAND%"=="build" goto :do_build
if "%COMMAND%"=="sidecar" goto :do_sidecar
if "%COMMAND%"=="electron" goto :do_electron
if "%COMMAND%"=="clean" goto :do_clean
goto :show_help
:show_banner
echo.
echo %CYAN%==========================================
echo Meeting Assistant Client Builder
echo 打包 Electron + Sidecar 為免安裝執行檔
echo ==========================================%NC%
echo.
goto :eof
:check_environment
echo %BLUE%[STEP]%NC% 檢查建置環境...
REM 檢查 Node.js
where node >nul 2>&1
if %errorlevel% equ 0 (
for /f "tokens=*" %%i in ('node --version') do echo %GREEN%[OK]%NC% Node.js: %%i
) else (
echo %RED%[ERROR]%NC% Node.js 未安裝
exit /b 1
)
REM 檢查 npm
where npm >nul 2>&1
if %errorlevel% equ 0 (
for /f "tokens=*" %%i in ('npm --version') do echo %GREEN%[OK]%NC% npm: %%i
) else (
echo %RED%[ERROR]%NC% npm 未安裝
exit /b 1
)
REM 檢查 Python
where python >nul 2>&1
if %errorlevel% equ 0 (
for /f "tokens=*" %%i in ('python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')"') do set "PY_VERSION=%%i"
for /f "tokens=*" %%i in ('python -c "import sys; print(sys.version_info.major)"') do set "PY_MAJOR=%%i"
for /f "tokens=*" %%i in ('python -c "import sys; print(sys.version_info.minor)"') do set "PY_MINOR=%%i"
if !PY_MAJOR! geq 3 if !PY_MINOR! geq 10 (
set "PYTHON_CMD=python"
echo %GREEN%[OK]%NC% Python !PY_VERSION!
goto :eof
)
)
echo %RED%[ERROR]%NC% 需要 Python 3.10 或更高版本
exit /b 1
:update_config
if "%API_URL%"=="" goto :eof
echo %BLUE%[STEP]%NC% 更新 API URL 設定...
set "CONFIG_FILE=%CLIENT_DIR%\config.json"
if not exist "%CONFIG_FILE%" (
echo %YELLOW%[WARN]%NC% 找不到 config.json跳過 API URL 設定
goto :eof
)
REM 使用 PowerShell 更新 JSON
powershell -Command "$config = Get-Content '%CONFIG_FILE%' -Raw | ConvertFrom-Json; $config.apiBaseUrl = '%API_URL%'; $config | ConvertTo-Json -Depth 10 | Set-Content '%CONFIG_FILE%' -Encoding UTF8"
if errorlevel 1 (
echo %RED%[ERROR]%NC% 更新 config.json 失敗
exit /b 1
)
echo %GREEN%[OK]%NC% API URL 已設定為: %API_URL%
goto :eof
:do_clean
echo %BLUE%[STEP]%NC% 清理建置目錄...
if exist "%BUILD_DIR%" rmdir /s /q "%BUILD_DIR%"
if exist "%CLIENT_DIR%\dist" rmdir /s /q "%CLIENT_DIR%\dist"
if exist "%SIDECAR_DIR%\dist" rmdir /s /q "%SIDECAR_DIR%\dist"
if exist "%SIDECAR_DIR%\build" rmdir /s /q "%SIDECAR_DIR%\build"
if exist "%SIDECAR_DIR%\venv" rmdir /s /q "%SIDECAR_DIR%\venv"
if exist "%SIDECAR_DIR%\*.spec" del /q "%SIDECAR_DIR%\*.spec"
if exist "%BACKEND_DIR%\dist" rmdir /s /q "%BACKEND_DIR%\dist"
if exist "%BACKEND_DIR%\build" rmdir /s /q "%BACKEND_DIR%\build"
if exist "%BACKEND_DIR%\venv" rmdir /s /q "%BACKEND_DIR%\venv"
if exist "%BACKEND_DIR%\*.spec" del /q "%BACKEND_DIR%\*.spec"
echo %GREEN%[OK]%NC% 建置目錄已清理
goto :eof
:setup_sidecar_venv
echo %BLUE%[STEP]%NC% 設置 Sidecar 建置環境...
cd /d "%SIDECAR_DIR%"
if not exist "venv" (
echo %BLUE%[INFO]%NC% 創建虛擬環境...
%PYTHON_CMD% -m venv venv
)
echo %BLUE%[INFO]%NC% 安裝 Sidecar 依賴...
call venv\Scripts\activate.bat
python -m pip install --upgrade pip -q
python -m pip install -r requirements.txt -q
echo %BLUE%[INFO]%NC% 安裝 PyInstaller...
python -m pip install pyinstaller -q
echo %GREEN%[OK]%NC% Sidecar 建置環境就緒
goto :eof
:build_sidecar
echo %BLUE%[STEP]%NC% 打包 Sidecar (Python → 獨立執行檔)...
cd /d "%SIDECAR_DIR%"
call venv\Scripts\activate.bat
if not exist "dist" mkdir dist
echo %BLUE%[INFO]%NC% 執行 PyInstaller...
echo %BLUE%[INFO]%NC% 這可能需要幾分鐘...
pyinstaller ^
--onedir ^
--name transcriber ^
--distpath dist ^
--workpath build ^
--specpath . ^
--noconfirm ^
--clean ^
--log-level WARN ^
--console ^
--hidden-import=faster_whisper ^
--hidden-import=ctranslate2 ^
--hidden-import=huggingface_hub ^
--hidden-import=tokenizers ^
--hidden-import=onnxruntime ^
--hidden-import=opencc ^
--hidden-import=pydub ^
--hidden-import=numpy ^
--hidden-import=av ^
--collect-data=onnxruntime ^
--collect-data=faster_whisper ^
transcriber.py
if exist "dist\transcriber" (
echo %GREEN%[OK]%NC% Sidecar 打包完成: %SIDECAR_DIR%\dist\transcriber
) else (
echo %RED%[ERROR]%NC% Sidecar 打包失敗
exit /b 1
)
goto :eof
:setup_backend_venv
echo %BLUE%[STEP]%NC% 設置 Backend 建置環境...
cd /d "%BACKEND_DIR%"
if not exist "venv" (
echo %BLUE%[INFO]%NC% 創建虛擬環境...
%PYTHON_CMD% -m venv venv
)
echo %BLUE%[INFO]%NC% 安裝 Backend 依賴...
call venv\Scripts\activate.bat
python -m pip install --upgrade pip -q
python -m pip install -r requirements.txt -q
echo %BLUE%[INFO]%NC% 安裝 PyInstaller...
python -m pip install pyinstaller -q
echo %GREEN%[OK]%NC% Backend 建置環境就緒
goto :eof
:build_backend
echo %BLUE%[STEP]%NC% 打包 Backend (Python → 獨立執行檔)...
cd /d "%BACKEND_DIR%"
call venv\Scripts\activate.bat
if not exist "dist" mkdir dist
echo %BLUE%[INFO]%NC% 執行 PyInstaller...
echo %BLUE%[INFO]%NC% 這可能需要幾分鐘...
pyinstaller ^
--onedir ^
--name backend ^
--distpath dist ^
--workpath build ^
--specpath . ^
--noconfirm ^
--clean ^
--log-level WARN ^
--console ^
--hidden-import=uvicorn ^
--hidden-import=uvicorn.logging ^
--hidden-import=uvicorn.loops ^
--hidden-import=uvicorn.loops.auto ^
--hidden-import=uvicorn.protocols ^
--hidden-import=uvicorn.protocols.http ^
--hidden-import=uvicorn.protocols.http.auto ^
--hidden-import=uvicorn.protocols.websockets ^
--hidden-import=uvicorn.protocols.websockets.auto ^
--hidden-import=uvicorn.lifespan ^
--hidden-import=uvicorn.lifespan.on ^
--hidden-import=uvicorn.lifespan.off ^
--hidden-import=fastapi ^
--hidden-import=starlette ^
--hidden-import=pydantic ^
--hidden-import=pydantic_core ^
--hidden-import=mysql.connector ^
--hidden-import=mysql.connector.pooling ^
--hidden-import=httpx ^
--hidden-import=httpcore ^
--hidden-import=jose ^
--hidden-import=jose.jwt ^
--hidden-import=cryptography ^
--hidden-import=openpyxl ^
--hidden-import=multipart ^
--hidden-import=python_multipart ^
--hidden-import=dotenv ^
--hidden-import=app ^
--hidden-import=app.main ^
--hidden-import=app.config ^
--hidden-import=app.database ^
--hidden-import=app.auth ^
--hidden-import=app.routers ^
--hidden-import=app.routers.auth ^
--hidden-import=app.routers.meetings ^
--hidden-import=app.routers.dify ^
--hidden-import=app.routers.health ^
--hidden-import=app.routers.excel ^
--collect-data=pydantic ^
--collect-data=uvicorn ^
run_server.py
if exist "dist\backend" (
echo %BLUE%[INFO]%NC% 複製 template 目錄...
if exist "template" (
xcopy /s /e /y "template\*" "dist\backend\template\" >nul 2>&1
)
if not exist "dist\backend\record" mkdir "dist\backend\record"
echo %GREEN%[OK]%NC% Backend 打包完成: %BACKEND_DIR%\dist\backend
) else (
echo %RED%[ERROR]%NC% Backend 打包失敗
exit /b 1
)
goto :eof
:update_config_embedded
REM 更新 config.json 以啟用 embedded backend
if "%EMBEDDED_BACKEND%"=="false" goto :eof
echo %BLUE%[STEP]%NC% 啟用內嵌後端模式...
set "CONFIG_FILE=%CLIENT_DIR%\config.json"
if not exist "%CONFIG_FILE%" (
echo %YELLOW%[WARN]%NC% 找不到 config.json跳過內嵌模式設定
goto :eof
)
REM 使用 PowerShell 更新 backend.embedded = true (使用 UTF8 without BOM)
powershell -Command "$config = Get-Content '%CONFIG_FILE%' -Raw | ConvertFrom-Json; if (-not $config.backend) { $config | Add-Member -NotePropertyName 'backend' -NotePropertyValue @{} }; $config.backend.embedded = $true; $json = $config | ConvertTo-Json -Depth 10; [System.IO.File]::WriteAllText('%CONFIG_FILE%', $json, [System.Text.UTF8Encoding]::new($false))"
if errorlevel 1 (
echo %RED%[ERROR]%NC% 更新 config.json embedded 設定失敗
exit /b 1
)
echo %GREEN%[OK]%NC% 已啟用內嵌後端模式
goto :eof
:update_config_database
REM 更新 config.json 的資料庫類型
if "%DATABASE_TYPE%"=="" goto :eof
echo %BLUE%[STEP]%NC% 設定資料庫類型...
set "CONFIG_FILE=%CLIENT_DIR%\config.json"
if not exist "%CONFIG_FILE%" (
echo %YELLOW%[WARN]%NC% 找不到 config.json跳過資料庫類型設定
goto :eof
)
REM 驗證資料庫類型
if /i not "%DATABASE_TYPE%"=="mysql" if /i not "%DATABASE_TYPE%"=="sqlite" (
echo %RED%[ERROR]%NC% 無效的資料庫類型: %DATABASE_TYPE%
echo %BLUE%[INFO]%NC% 有效選項: mysql, sqlite
exit /b 1
)
REM 使用 PowerShell 更新 database.type (使用 UTF8 without BOM)
if /i "%DATABASE_TYPE%"=="sqlite" (
REM SQLite 模式: 設定 type=sqlite清空 MySQL 連線資訊
powershell -Command "$config = Get-Content '%CONFIG_FILE%' -Raw | ConvertFrom-Json; $config.backend.database.type = 'sqlite'; $config.backend.database.host = ''; $config.backend.database.user = ''; $config.backend.database.password = ''; $config.backend.database.database = ''; $json = $config | ConvertTo-Json -Depth 10; [System.IO.File]::WriteAllText('%CONFIG_FILE%', $json, [System.Text.UTF8Encoding]::new($false))"
echo %GREEN%[OK]%NC% 資料庫類型已設定為: SQLite (本地模式)
) else (
REM MySQL 模式: 僅設定 type=mysql保留連線資訊
powershell -Command "$config = Get-Content '%CONFIG_FILE%' -Raw | ConvertFrom-Json; $config.backend.database.type = 'mysql'; $json = $config | ConvertTo-Json -Depth 10; [System.IO.File]::WriteAllText('%CONFIG_FILE%', $json, [System.Text.UTF8Encoding]::new($false))"
echo %GREEN%[OK]%NC% 資料庫類型已設定為: MySQL (雲端模式)
)
if errorlevel 1 (
echo %RED%[ERROR]%NC% 更新 config.json database.type 失敗
exit /b 1
)
goto :eof
:setup_client
echo %BLUE%[STEP]%NC% 設置前端建置環境...
cd /d "%CLIENT_DIR%"
REM 總是執行 npm install 確保依賴完整
echo %BLUE%[INFO]%NC% 安裝前端依賴...
call npm install
if errorlevel 1 (
echo %RED%[ERROR]%NC% npm install 失敗
exit /b 1
)
REM 確認 electron-builder 已安裝
if not exist "node_modules\electron-builder" (
echo %RED%[ERROR]%NC% electron-builder 未安裝
echo %BLUE%[INFO]%NC% 請檢查 package.json 中的 devDependencies
exit /b 1
)
if not exist ".env" (
if exist ".env.example" (
copy .env.example .env >nul
echo %YELLOW%[WARN]%NC% 已創建 .env 檔案,請確認設定
)
)
echo %GREEN%[OK]%NC% 前端建置環境就緒
goto :eof
:build_electron
echo %BLUE%[STEP]%NC% 打包 Electron 應用...
cd /d "%CLIENT_DIR%"
echo %BLUE%[INFO]%NC% 目標平台: Windows (Portable)
REM 清理可能損壞的 electron-builder 快取(解決 symlink 問題)
set "EB_CACHE=%LOCALAPPDATA%\electron-builder\Cache\winCodeSign"
if exist "%EB_CACHE%" (
echo %BLUE%[INFO]%NC% 清理 electron-builder 快取...
rmdir /s /q "%EB_CACHE%" 2>nul
)
echo %BLUE%[INFO]%NC% 執行 electron-builder...
REM 使用 npm run build 或直接執行 node_modules 中的 electron-builder
if exist "node_modules\.bin\electron-builder.cmd" (
call "node_modules\.bin\electron-builder.cmd" --win
) else (
call npx electron-builder --win
)
if errorlevel 1 (
echo %RED%[ERROR]%NC% electron-builder 執行失敗
echo %YELLOW%[WARN]%NC% 如果出現 symlink 錯誤,請嘗試以下方案:
echo %YELLOW%[WARN]%NC% 1. 以系統管理員身分執行此腳本
echo %YELLOW%[WARN]%NC% 2. 或啟用 Windows 開發人員模式(設定 ^> 更新與安全性 ^> 開發人員專用)
exit /b 1
)
if exist "dist" (
echo %GREEN%[OK]%NC% Electron 打包完成
echo %BLUE%[INFO]%NC% 輸出目錄: %CLIENT_DIR%\dist
) else (
echo %RED%[ERROR]%NC% Electron 打包失敗 - dist 目錄不存在
exit /b 1
)
goto :eof
:finalize_build
echo %BLUE%[STEP]%NC% 整合建置輸出...
if not exist "%BUILD_DIR%" mkdir "%BUILD_DIR%"
REM 複製 Electron 輸出
if exist "%CLIENT_DIR%\dist" (
xcopy /s /e /y "%CLIENT_DIR%\dist\*" "%BUILD_DIR%\" >nul 2>&1
)
echo.
echo %CYAN%==========================================
echo 建置完成
echo ==========================================%NC%
echo.
echo 輸出目錄: %BUILD_DIR%
echo.
dir /b "%BUILD_DIR%"
echo.
echo %GREEN%[OK]%NC% 打包完成!
echo.
echo Windows 使用說明:
echo 1. 找到 build\ 中的 .exe 檔案
echo 2. 直接執行即可,無需安裝
echo.
goto :eof
:do_build
call :show_banner
call :check_environment
if errorlevel 1 exit /b 1
if "%CLEAN_BUILD%"=="true" call :do_clean
REM 更新 API URL如果有指定
call :update_config
REM 更新 embedded backend 設定(如果有指定)
call :update_config_embedded
REM 更新資料庫類型設定(如果有指定)
call :update_config_database
if "%SKIP_SIDECAR%"=="false" (
call :setup_sidecar_venv
call :build_sidecar
)
if "%SKIP_BACKEND%"=="false" (
call :setup_backend_venv
call :build_backend
)
call :setup_client
call :build_electron
call :finalize_build
goto :eof
:do_sidecar
call :show_banner
call :check_environment
if errorlevel 1 exit /b 1
if "%CLEAN_BUILD%"=="true" (
if exist "%SIDECAR_DIR%\dist" rmdir /s /q "%SIDECAR_DIR%\dist"
if exist "%SIDECAR_DIR%\build" rmdir /s /q "%SIDECAR_DIR%\build"
)
call :setup_sidecar_venv
call :build_sidecar
goto :eof
:do_electron
call :show_banner
call :check_environment
if errorlevel 1 exit /b 1
if not exist "%SIDECAR_DIR%\dist\transcriber" (
if "%SKIP_SIDECAR%"=="false" (
echo %YELLOW%[WARN]%NC% Sidecar 尚未打包
echo %BLUE%[INFO]%NC% 請先執行: %~nx0 sidecar
echo %BLUE%[INFO]%NC% 或使用 --skip-sidecar 跳過
exit /b 1
)
)
if "%CLEAN_BUILD%"=="true" (
if exist "%CLIENT_DIR%\dist" rmdir /s /q "%CLIENT_DIR%\dist"
)
call :setup_client
call :build_electron
call :finalize_build
goto :eof
:show_help
echo.
echo Meeting Assistant Client - Windows 打包腳本
echo.
echo 用法: %~nx0 [命令] [選項]
echo.
echo 命令:
echo build 完整建置 (Sidecar + Electron)
echo sidecar 僅打包 Sidecar
echo electron 僅打包 Electron (需先打包 Sidecar)
echo clean 清理建置目錄
echo help 顯示此幫助訊息
echo.
echo 選項:
echo --api-url URL 後端 API URL (預設: http://localhost:8000/api)
echo --skip-sidecar 跳過 Sidecar 打包
echo --skip-backend 跳過 Backend 打包 (預設)
echo --embedded-backend 打包內嵌後端 (全包部署模式)
echo --database-type TYPE 資料庫類型: mysql (雲端) 或 sqlite (本地)
echo --clean 建置前先清理
echo.
echo 範例:
echo %~nx0 build 完整建置 (前端+Sidecar)
echo %~nx0 build --embedded-backend 全包部署 (含內嵌後端)
echo %~nx0 build --embedded-backend --database-type sqlite 全包部署 + SQLite
echo %~nx0 build --api-url "http://192.168.1.100:8000/api" 指定遠端後端
echo %~nx0 sidecar 僅打包 Sidecar
echo %~nx0 electron --skip-sidecar 僅打包 Electron
echo.
echo 部署模式:
echo 分離部署(預設): 前端連接遠端後端,使用 --api-url 指定後端地址
echo 全包部署: 使用 --embedded-backend 將後端打包進 exe雙擊即可運行
echo.
echo 資料庫模式:
echo MySQL預設: 連接雲端資料庫,需要網路存取
echo SQLite: 本地資料庫,適合離線或防火牆環境,使用 --database-type sqlite
echo.
echo 注意:
echo - 首次打包 Sidecar 需下載 Whisper 模型,可能需要較長時間
echo - 全包部署需要額外約 50MB 空間用於後端
echo - 確保有足夠的磁碟空間 (建議 5GB+)
echo.
goto :eof
:end
endlocal