Files
Meeting_Assistant/scripts/build-client.bat
egg 0defc829dd fix: Make SQLite default for embedded-backend mode
When --embedded-backend is specified, SQLite is now the default database
type instead of MySQL. This is the expected behavior for all-in-one
deployment where the app should work offline without external database.

Users can still explicitly specify --database-type mysql if needed.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-18 09:10:45 +08:00

623 lines
20 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="
set "BUILD_TARGET=nsis"
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)
if /i "%~1"=="--target" (set "BUILD_TARGET=%~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=sqlite3 ^
--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=tzdata ^
--hidden-import=app ^
--hidden-import=app.main ^
--hidden-import=app.config ^
--hidden-import=app.database ^
--hidden-import=app.models ^
--hidden-import=app.models.schemas ^
--hidden-import=app.routers ^
--hidden-import=app.routers.auth ^
--hidden-import=app.routers.meetings ^
--hidden-import=app.routers.ai ^
--hidden-import=app.routers.export ^
--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%"
REM 驗證 BUILD_TARGET
if /i "%BUILD_TARGET%"=="nsis" goto :valid_target
if /i "%BUILD_TARGET%"=="portable" goto :valid_target
echo %RED%[ERROR]%NC% 無效的打包目標: %BUILD_TARGET%
echo %BLUE%[INFO]%NC% 有效選項: nsis, portable
exit /b 1
:valid_target
if /i "%BUILD_TARGET%"=="nsis" (
echo %BLUE%[INFO]%NC% 目標平台: Windows NSIS 安裝檔 - 推薦
) else (
echo %BLUE%[INFO]%NC% 目標平台: Windows Portable
echo %YELLOW%[WARN]%NC% 注意: Portable 模式的臨時資料夾會在關閉時清空
echo %YELLOW%[WARN]%NC% SQLite 資料庫已自動儲存到 %%APPDATA%%\Meeting-Assistant
)
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 %BUILD_TARGET%
) else (
call npx electron-builder --win %BUILD_TARGET%
)
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.
if /i "%BUILD_TARGET%"=="nsis" goto :show_nsis_help
goto :show_portable_help
:show_nsis_help
echo Windows 使用說明 - NSIS 安裝檔
echo 1. 找到 build\ 中的 *-setup.exe 檔案
echo 2. 執行安裝檔,選擇安裝目錄
echo 3. 安裝後從開始選單或桌面捷徑啟動
echo 4. 資料會持久保存在安裝目錄中
goto :end_help
:show_portable_help
echo Windows 使用說明 - Portable
echo 1. 找到 build\ 中的 *-portable.exe 檔案
echo 2. 直接執行,無需安裝
echo 3. 注意 - 關閉程式後臨時檔案會清空
echo 4. SQLite 資料庫保存在 %%APPDATA%%\Meeting-Assistant
goto :end_help
:end_help
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 內嵌後端模式預設使用 SQLite除非明確指定 mysql
if "%EMBEDDED_BACKEND%"=="true" (
if "%DATABASE_TYPE%"=="" set "DATABASE_TYPE=sqlite"
)
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
echo --skip-sidecar 跳過 Sidecar 打包
echo --skip-backend 跳過 Backend 打包
echo --embedded-backend 打包內嵌後端,預設使用 SQLite
echo --database-type TYPE 資料庫類型: sqlite 或 mysql
echo --target TARGET 打包目標: nsis 或 portable
echo --clean 建置前先清理
echo.
echo 範例:
echo %~nx0 build 完整建置
echo %~nx0 build --embedded-backend 全包部署SQLite 本地資料庫
echo %~nx0 build --embedded-backend --database-type mysql 全包部署MySQL 雲端
echo %~nx0 build --target portable 打包為 Portable
echo %~nx0 sidecar 僅打包 Sidecar
echo %~nx0 electron --skip-sidecar 僅打包 Electron
echo.
echo 部署模式:
echo 分離部署: 前端連接遠端後端,使用 --api-url 指定後端地址
echo 全包部署: 使用 --embedded-backend預設 SQLite 本地資料庫
echo.
echo 打包目標:
echo nsis: 產生安裝檔,推薦正式使用
echo portable: 產生免安裝 exeSQLite 資料庫儲存到 %%APPDATA%%
echo.
echo 資料庫模式 - 全包部署時:
echo SQLite 預設: 本地資料庫,完全離線運作
echo MySQL: 需明確指定 --database-type mysql連接雲端資料庫
echo.
echo 注意:
echo - 首次打包 Sidecar 需下載 Whisper 模型,可能需要較長時間
echo - 全包部署需要額外約 50MB 空間用於後端
echo - 確保有足夠的磁碟空間 (建議 5GB+)
echo.
goto :eof
:end
endlocal