feat: Add build scripts and runtime config support
Backend: - Add setup-backend.sh/bat for one-click backend setup - Fix test_auth.py mock settings (JWT_EXPIRE_HOURS) - Fix test_excel_export.py TEMPLATE_DIR reference Frontend: - Add config.json for runtime API URL configuration - Add init.js and settings.js for config loading - Update main.js to load config from external file - Update api.js to use dynamic API_BASE_URL - Update all pages to initialize config before API calls - Update package.json with extraResources for config Build: - Add build-client.sh/bat for packaging Electron + Sidecar - Add build-all.ps1 PowerShell script with -ApiUrl parameter - Add GitHub Actions workflow for Windows builds - Add scripts/README.md documentation This allows IT to configure backend URL without rebuilding. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
304
scripts/build-all.ps1
Normal file
304
scripts/build-all.ps1
Normal file
@@ -0,0 +1,304 @@
|
||||
#Requires -Version 5.1
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Meeting Assistant - Windows 一鍵打包腳本
|
||||
.DESCRIPTION
|
||||
在 Windows 環境下一鍵打包 Sidecar + Electron 成免安裝 exe
|
||||
.EXAMPLE
|
||||
.\scripts\build-all.ps1
|
||||
.\scripts\build-all.ps1 -ApiUrl "http://192.168.1.100:8000/api"
|
||||
.\scripts\build-all.ps1 -SkipSidecar
|
||||
.\scripts\build-all.ps1 -Clean
|
||||
#>
|
||||
|
||||
param(
|
||||
[string]$ApiUrl,
|
||||
[switch]$SkipSidecar,
|
||||
[switch]$Clean,
|
||||
[switch]$Help
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# 顏色輸出函數
|
||||
function Write-Step { param($msg) Write-Host "[STEP] $msg" -ForegroundColor Cyan }
|
||||
function Write-OK { param($msg) Write-Host "[OK] $msg" -ForegroundColor Green }
|
||||
function Write-Warn { param($msg) Write-Host "[WARN] $msg" -ForegroundColor Yellow }
|
||||
function Write-Err { param($msg) Write-Host "[ERROR] $msg" -ForegroundColor Red }
|
||||
|
||||
# 路徑設定
|
||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$ProjectDir = Split-Path -Parent $ScriptDir
|
||||
$SidecarDir = Join-Path $ProjectDir "sidecar"
|
||||
$ClientDir = Join-Path $ProjectDir "client"
|
||||
$BuildDir = Join-Path $ProjectDir "build"
|
||||
|
||||
function Show-Banner {
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host " Meeting Assistant - Windows Builder" -ForegroundColor Cyan
|
||||
Write-Host " 一鍵打包 Electron + Sidecar" -ForegroundColor Cyan
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
function Show-Help {
|
||||
Write-Host @"
|
||||
|
||||
Meeting Assistant - Windows 一鍵打包腳本
|
||||
|
||||
用法: .\build-all.ps1 [參數]
|
||||
|
||||
參數:
|
||||
-ApiUrl URL 後端 API URL (預設: http://localhost:8000/api)
|
||||
-SkipSidecar 跳過 Sidecar 打包(如果已經打包過)
|
||||
-Clean 打包前清理所有建置目錄
|
||||
-Help 顯示此幫助訊息
|
||||
|
||||
範例:
|
||||
.\build-all.ps1 # 完整打包 (使用預設 localhost)
|
||||
.\build-all.ps1 -ApiUrl "http://192.168.1.100:8000/api" # 指定後端 URL
|
||||
.\build-all.ps1 -ApiUrl "https://api.example.com/api" # 使用公司伺服器
|
||||
.\build-all.ps1 -Clean # 清理後打包
|
||||
.\build-all.ps1 -SkipSidecar # 僅打包 Electron
|
||||
|
||||
"@
|
||||
}
|
||||
|
||||
function Update-Config {
|
||||
param([string]$NewApiUrl)
|
||||
|
||||
Write-Step "更新設定檔..."
|
||||
|
||||
$configPath = Join-Path $ClientDir "config.json"
|
||||
|
||||
if (Test-Path $configPath) {
|
||||
$config = Get-Content $configPath -Raw | ConvertFrom-Json
|
||||
|
||||
if ($NewApiUrl) {
|
||||
$config.apiBaseUrl = $NewApiUrl
|
||||
Write-Host " API URL: $NewApiUrl" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
$config | ConvertTo-Json -Depth 10 | Set-Content $configPath -Encoding UTF8
|
||||
Write-OK "設定檔已更新"
|
||||
} else {
|
||||
Write-Warn "找不到 config.json,使用預設設定"
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Prerequisites {
|
||||
Write-Step "檢查建置環境..."
|
||||
|
||||
# 檢查 Python
|
||||
try {
|
||||
$pyVersion = python --version 2>&1
|
||||
Write-OK "Python: $pyVersion"
|
||||
} catch {
|
||||
Write-Err "Python 未安裝,請安裝 Python 3.10+"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 檢查 Node.js
|
||||
try {
|
||||
$nodeVersion = node --version 2>&1
|
||||
Write-OK "Node.js: $nodeVersion"
|
||||
} catch {
|
||||
Write-Err "Node.js 未安裝,請安裝 Node.js 18+"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 檢查 npm
|
||||
try {
|
||||
$npmVersion = npm --version 2>&1
|
||||
Write-OK "npm: $npmVersion"
|
||||
} catch {
|
||||
Write-Err "npm 未安裝"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
function Clear-BuildDirs {
|
||||
Write-Step "清理建置目錄..."
|
||||
|
||||
$dirsToClean = @(
|
||||
$BuildDir,
|
||||
(Join-Path $ClientDir "dist"),
|
||||
(Join-Path $SidecarDir "dist"),
|
||||
(Join-Path $SidecarDir "build")
|
||||
)
|
||||
|
||||
foreach ($dir in $dirsToClean) {
|
||||
if (Test-Path $dir) {
|
||||
Remove-Item -Recurse -Force $dir
|
||||
Write-Host " 已刪除: $dir" -ForegroundColor Gray
|
||||
}
|
||||
}
|
||||
|
||||
# 刪除 spec 檔案
|
||||
Get-ChildItem -Path $SidecarDir -Filter "*.spec" | Remove-Item -Force
|
||||
|
||||
Write-OK "清理完成"
|
||||
}
|
||||
|
||||
function Build-Sidecar {
|
||||
Write-Step "打包 Sidecar (Python → exe)..."
|
||||
Write-Host " 這可能需要 5-10 分鐘..." -ForegroundColor Gray
|
||||
|
||||
Push-Location $SidecarDir
|
||||
|
||||
try {
|
||||
# 建立/啟動虛擬環境
|
||||
if (-not (Test-Path "venv")) {
|
||||
Write-Host " 建立虛擬環境..." -ForegroundColor Gray
|
||||
python -m venv venv
|
||||
}
|
||||
|
||||
# 啟動虛擬環境並安裝依賴
|
||||
& ".\venv\Scripts\Activate.ps1"
|
||||
|
||||
Write-Host " 安裝依賴..." -ForegroundColor Gray
|
||||
pip install --upgrade pip -q
|
||||
pip install -r requirements.txt -q
|
||||
pip install pyinstaller -q
|
||||
|
||||
# 建立 dist 目錄
|
||||
if (-not (Test-Path "dist")) {
|
||||
New-Item -ItemType Directory -Path "dist" | Out-Null
|
||||
}
|
||||
|
||||
Write-Host " 執行 PyInstaller..." -ForegroundColor Gray
|
||||
|
||||
# PyInstaller 打包
|
||||
pyinstaller `
|
||||
--onedir `
|
||||
--name transcriber `
|
||||
--distpath dist `
|
||||
--workpath build `
|
||||
--noconfirm `
|
||||
--clean `
|
||||
--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 (Test-Path "dist\transcriber\transcriber.exe") {
|
||||
Write-OK "Sidecar 打包完成"
|
||||
} else {
|
||||
Write-Err "Sidecar 打包失敗"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
function Build-Electron {
|
||||
Write-Step "打包 Electron 應用..."
|
||||
|
||||
Push-Location $ClientDir
|
||||
|
||||
try {
|
||||
# 檢查 Sidecar 是否存在
|
||||
$sidecarExe = Join-Path $SidecarDir "dist\transcriber\transcriber.exe"
|
||||
if (-not (Test-Path $sidecarExe)) {
|
||||
Write-Err "找不到 Sidecar: $sidecarExe"
|
||||
Write-Warn "請先執行完整打包或移除 -SkipSidecar 參數"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 安裝依賴
|
||||
if (-not (Test-Path "node_modules")) {
|
||||
Write-Host " 安裝 npm 依賴..." -ForegroundColor Gray
|
||||
npm install
|
||||
}
|
||||
|
||||
# 建立 .env 如果不存在
|
||||
if (-not (Test-Path ".env") -and (Test-Path ".env.example")) {
|
||||
Copy-Item ".env.example" ".env"
|
||||
Write-Warn "已建立 .env,請確認設定"
|
||||
}
|
||||
|
||||
Write-Host " 執行 electron-builder..." -ForegroundColor Gray
|
||||
npm run build -- --win
|
||||
|
||||
if (Test-Path "dist\*.exe") {
|
||||
Write-OK "Electron 打包完成"
|
||||
} else {
|
||||
Write-Err "Electron 打包失敗"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
finally {
|
||||
Pop-Location
|
||||
}
|
||||
}
|
||||
|
||||
function Copy-Output {
|
||||
Write-Step "整合輸出..."
|
||||
|
||||
if (-not (Test-Path $BuildDir)) {
|
||||
New-Item -ItemType Directory -Path $BuildDir | Out-Null
|
||||
}
|
||||
|
||||
# 複製 exe 檔案
|
||||
$exeFiles = Get-ChildItem -Path (Join-Path $ClientDir "dist") -Filter "*.exe"
|
||||
foreach ($file in $exeFiles) {
|
||||
Copy-Item $file.FullName -Destination $BuildDir
|
||||
Write-Host " 複製: $($file.Name)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host " 打包完成!" -ForegroundColor Green
|
||||
Write-Host "==========================================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
Write-Host " 輸出目錄: $BuildDir" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
# 列出輸出檔案
|
||||
Get-ChildItem -Path $BuildDir | ForEach-Object {
|
||||
$size = [math]::Round($_.Length / 1MB, 2)
|
||||
Write-Host " $($_.Name) ($size MB)" -ForegroundColor Gray
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host " 使用說明:" -ForegroundColor Yellow
|
||||
Write-Host " 直接執行 .exe 檔案即可,無需安裝" -ForegroundColor Gray
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
# 主程式
|
||||
if ($Help) {
|
||||
Show-Help
|
||||
exit 0
|
||||
}
|
||||
|
||||
Show-Banner
|
||||
Test-Prerequisites
|
||||
|
||||
if ($Clean) {
|
||||
Clear-BuildDirs
|
||||
}
|
||||
|
||||
# Update config.json if API URL is specified
|
||||
if ($ApiUrl) {
|
||||
Update-Config -NewApiUrl $ApiUrl
|
||||
}
|
||||
|
||||
if (-not $SkipSidecar) {
|
||||
Build-Sidecar
|
||||
}
|
||||
|
||||
Build-Electron
|
||||
Copy-Output
|
||||
Reference in New Issue
Block a user