diff --git a/local-tool/.autoflow/03-design/spec/02-pages-diff.md b/local-tool/.autoflow/03-design/spec/02-pages-diff.md index 2660bdb..468aaa0 100644 --- a/local-tool/.autoflow/03-design/spec/02-pages-diff.md +++ b/local-tool/.autoflow/03-design/spec/02-pages-diff.md @@ -95,7 +95,7 @@ ## 2.5 被移除元件回收清單 -以下程式碼可以從原專案直接刪除(不需要轉移到 local_tool): +以下程式碼可以從原專案直接刪除(不需要轉移到 local-tool): ``` components/cluster/**/* diff --git a/local-tool/.autoflow/04-architecture/code-reuse-plan.md b/local-tool/.autoflow/04-architecture/code-reuse-plan.md index a063466..dec2650 100644 --- a/local-tool/.autoflow/04-architecture/code-reuse-plan.md +++ b/local-tool/.autoflow/04-architecture/code-reuse-plan.md @@ -14,7 +14,7 @@ ## 2. 目錄層級策略 -| From(edge-ai-platform) | To(local_tool) | 策略 | 備註 | +| From(edge-ai-platform) | To(local-tool) | 策略 | 備註 | |------------------------|----------------|------|------| | `server/main.go` | `server/main.go` | **改寫** | 移除 cluster / tunnel / relay / hwid / gitea 邏輯 | | `server/go.mod` | `server/go.mod` | **改寫** | 移除不再需要的 imports;module name 可改為 `visiona-local` | @@ -249,13 +249,13 @@ dmg-config.py ← macOS dmgbuild 設定 ## 5. 搬家步驟(建議執行順序) -1. **建立骨架**:`mkdir -p local_tool/{server,frontend,visiona-local,vendor,scripts,dist}` -2. **複製 server core**:`cp -r edge-ai-platform/server/{internal/{api,camera,config,deps,device,driver,inference,model},pkg/logger,scripts,data,web} local_tool/server/` +1. **建立骨架**:`mkdir -p local-tool/{server,frontend,visiona-local,vendor,scripts,dist}` +2. **複製 server core**:`cp -r edge-ai-platform/server/{internal/{api,camera,config,deps,device,driver,inference,model},pkg/logger,scripts,data,web} local-tool/server/` 3. **跳過要刪的 package**:不要複製 `cluster`、`tunnel`、`flash`、`update`、`pkg/hwid`、`cmd/relay-server`、`tray`(使用者決策 Q-A:砍 tray) 4. **改寫 `main.go` + `config.go` + `router.go`**(見上方 §3) 5. **改寫 go.mod**:`go mod init visiona-local/server` → `go mod tidy`(會自動清掉 unused imports) 6. **驗證 `go build ./...` 通過** -7. **複製 frontend**:`cp -r edge-ai-platform/frontend local_tool/frontend` +7. **複製 frontend**:`cp -r edge-ai-platform/frontend local-tool/frontend` 8. **清理前端 cluster / relay / tunnel UI**(使用者決策 Q-C=C2:M1 就要清乾淨,不留到 M2):刪除 `src/app/clusters/`、`src/app/workspace/cluster/`、`src/components/cluster/`、`src/components/relay-token-sync.tsx`、`src/lib/api/clusters.ts`、`src/lib/api/tunnel.ts`(若有)、`src/lib/api/update.ts`(若有),修改 `sidebar.tsx` 移除 Clusters 導航項、`page.tsx` 移除 cluster stat、`settings/page.tsx` 移除 relay / cluster 區塊。最後驗證 `pnpm build` 通過且 UI 乾淨。 -9. **複製 installer**:`cp -r edge-ai-platform/installer local_tool/visiona-local`,改 `main.go` 的 app 名稱與 bundle ID +9. **複製 installer**:`cp -r edge-ai-platform/installer local-tool/visiona-local`,改 `main.go` 的 app 名稱與 bundle ID 10. **先跑 M1-12**:全新機器上 installer 能裝起來並跑通 Mock 模式 diff --git a/local-tool/.autoflow/04-architecture/design-doc.md b/local-tool/.autoflow/04-architecture/design-doc.md index a7606c9..e57890e 100644 --- a/local-tool/.autoflow/04-architecture/design-doc.md +++ b/local-tool/.autoflow/04-architecture/design-doc.md @@ -85,7 +85,7 @@ visionA-local 是 `edge-ai-platform` 的**單機桌面版**,把原本需要 EC ## 4. 程式碼來源策略(摘要) -新專案 `local_tool/` 從零建立,但可以自由從 `edge-ai-platform/` 取用程式碼: +新專案 `local-tool/` 從零建立,但可以自由從 `edge-ai-platform/` 取用程式碼: - **直接複製(~60% 程式碼)**:`installer/`、`server/internal/{api,camera,config,deps,device,driver,inference,model}`、`server/scripts/kneron_bridge.py`、`server/data/`、`server/pkg/logger` - **改寫(~20%)**:`server/main.go`(移除 cluster / tunnel / relay)、`server/internal/api/router.go`(刪 cluster routes)、`server/internal/config/config.go`(刪 relay / gitea flags)、`installer/app.go`(改名 + 加入 Python runtime 雙策略)、`frontend/`(刪 cluster / relay UI) @@ -102,12 +102,12 @@ visionA-local 是 `edge-ai-platform` 的**單機桌面版**,把原本需要 EC | # | 任務 | 說明 | 預估大小 | |---|------|------|---------| -| M1-1 | 建立 repo 骨架 | `local_tool/` 目錄結構 + go.mod + Makefile 骨架 | S | +| M1-1 | 建立 repo 骨架 | `local-tool/` 目錄結構 + go.mod + Makefile 骨架 | S | | M1-2 | 複製 server core | 從 edge-ai-platform 複製 `server/internal/{api,camera,config,deps,device,model,inference}` + `pkg/logger` | S | | M1-3 | 清理 main.go | 改寫 `server/main.go`:移除 cluster / tunnel / relay / hwid / GiteaURL | M | | M1-4 | 清理 config.go | 砍 relay / tunnel / gitea / GUIMode 相關 flags | S | | M1-5 | 清理 router.go | 刪除 `/api/clusters/*`、`/ws/clusters/*`、`/auth/token` | S | -| M1-6 | 複製 frontend | 複製 `frontend/` 進 local_tool | S | +| M1-6 | 複製 frontend | 複製 `frontend/` 進 local-tool | S | | M1-7 | **清理前端 UI**(Q-C=C2) | **M1 必做**:刪除 `src/app/clusters/`、`src/app/workspace/cluster/`、`src/components/cluster/`、`relay-token-sync.tsx`、`lib/api/{clusters,tunnel,update}.ts`;修改 sidebar(移除 Clusters 導航項)、Dashboard(移除 cluster 卡片)、Settings(移除 relay / cluster 區塊);最終 `pnpm build` 通過且 UI 乾淨、沒有殘留的 cluster / relay / tunnel 入口 | M | | M1-8 | Go server 本地 build | `make build` 產出 `visiona-local-server`(含 embedded Next.js),可直接 `./visiona-local-server` 跑起來 | S | | M1-9 | 複製 installer shell | 從 `installer/` 複製 `app.go` + `main.go` + `embed.go` + platform_*.go,改名為 `visiona-local` | M | diff --git a/local-tool/.autoflow/04-architecture/removed-code.md b/local-tool/.autoflow/04-architecture/removed-code.md index 0295bbb..e1c674a 100644 --- a/local-tool/.autoflow/04-architecture/removed-code.md +++ b/local-tool/.autoflow/04-architecture/removed-code.md @@ -1,6 +1,6 @@ # Removed Code — visionA-local -> 要從 edge-ai-platform 砍掉、不搬進 local_tool 的目錄 / 檔案 / import 清單。 +> 要從 edge-ai-platform 砍掉、不搬進 local-tool 的目錄 / 檔案 / import 清單。 --- diff --git a/local-tool/.autoflow/progress.md b/local-tool/.autoflow/progress.md index a3a9958..00ca6f3 100644 --- a/local-tool/.autoflow/progress.md +++ b/local-tool/.autoflow/progress.md @@ -141,7 +141,7 @@ visionA-local 是 `/Users/jimchen/Innovedus/edge-ai-platform` 的 local 版本 ### 來源與策略 - **參考原專案**:`/Users/jimchen/Innovedus/edge-ai-platform` -- **程式碼策略**:重新建立 local_tool,可從 edge-ai-platform 自由取用任何程式碼(不做 fork、不做 submodule) +- **程式碼策略**:重新建立 local-tool,可從 edge-ai-platform 自由取用任何程式碼(不做 fork、不做 submodule) - **產品名稱**:visionA-local - **Bundle ID**(暫定):`com.innovedus.visiona-local` diff --git a/local-tool/README.md b/local-tool/README.md index 303535b..28f3554 100644 --- a/local-tool/README.md +++ b/local-tool/README.md @@ -96,7 +96,7 @@ visionA-local 是 `edge-ai-platform`(原本要部署到 EC2 + Docker 的 Knero ### 專案結構 ``` -local_tool/ +local-tool/ ├── .autoflow/ PRD / 設計 / 架構 / 進度文件 ├── server/ Go 1.26 後端(Gin + go:embed) ├── frontend/ Next.js 16 + React 19 + shadcn diff --git a/local-tool/installer/windows/visiona-local.iss b/local-tool/installer/windows/visiona-local.iss index 7529892..0e5d876 100644 --- a/local-tool/installer/windows/visiona-local.iss +++ b/local-tool/installer/windows/visiona-local.iss @@ -11,7 +11,7 @@ ; 4. make exe — 執行 iscc 編譯本檔 ; ; 所有路徑相對於本 .iss 所在目錄 (installer/windows/) -; 因此 ..\.. 會指回專案根目錄 (local_tool/) +; 因此 ..\.. 會指回專案根目錄 (local-tool/) #define MyAppName "visionA-local" #define MyAppVersion "0.1.0" diff --git a/local-tool/scripts/bootstrap-linux.sh b/local-tool/scripts/bootstrap-linux.sh new file mode 100755 index 0000000..5ae535d --- /dev/null +++ b/local-tool/scripts/bootstrap-linux.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# visionA-local — Ubuntu 22.04/24.04 x86_64 一鍵 build +# +# 使用方式: +# git clone https://github.com/jim800121/visionA.git +# cd visionA/local-tool +# bash scripts/bootstrap-linux.sh +# +# 環境變數: +# VISIONA_TARGET 預設 appimage,可設 wails-linux / payload-linux + +set -euo pipefail + +TARGET="${VISIONA_TARGET:-appimage}" +GO_VERSION="1.22.5" + +log() { printf '\033[1;36m==> %s\033[0m\n' "$*"; } +err() { printf '\033[1;31m!!! %s\033[0m\n' "$*" >&2; exit 1; } + +[[ "$(uname -s)" == "Linux" ]] || err "此腳本只支援 Linux" +[[ "$(uname -m)" == "x86_64" ]] || err "此腳本只支援 x86_64" +[[ -f Makefile && -d visiona-local ]] || err "請先 cd 到 local-tool/ 目錄再執行此腳本" + +log "[1/5] 安裝系統套件(需要 sudo)" +sudo apt update +sudo apt install -y \ + git curl ca-certificates build-essential pkg-config \ + libgtk-3-dev libwebkit2gtk-4.1-dev \ + python3 python3-pip python3-venv \ + file desktop-file-utils fuse libfuse2 + +log "[2/5] 安裝 Go $GO_VERSION" +if ! command -v go >/dev/null || [[ "$(go version 2>/dev/null)" != *"go$GO_VERSION"* ]]; then + curl -fsSL "https://go.dev/dl/go${GO_VERSION}.linux-amd64.tar.gz" -o /tmp/go.tar.gz + sudo rm -rf /usr/local/go + sudo tar -C /usr/local -xzf /tmp/go.tar.gz + rm /tmp/go.tar.gz +fi +export PATH="/usr/local/go/bin:$HOME/go/bin:$PATH" +if ! grep -q '/usr/local/go/bin' "$HOME/.bashrc" 2>/dev/null; then + echo 'export PATH=/usr/local/go/bin:$HOME/go/bin:$PATH' >> "$HOME/.bashrc" +fi + +log "[3/5] 安裝 Node 20 + pnpm" +if ! command -v node >/dev/null || [[ "$(node -v)" != v20.* ]]; then + curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash - + sudo apt install -y nodejs +fi +command -v pnpm >/dev/null || sudo npm i -g pnpm + +log "[4/5] 安裝 Wails CLI" +if ! command -v wails >/dev/null; then + go install github.com/wailsapp/wails/v2/cmd/wails@latest +fi +wails doctor || log "wails doctor 有警告,繼續" + +log "[5/5] 開始 build(target=$TARGET)" +log "⚠️ ffmpeg 使用 GPL build,需設定 VISIONA_ALLOW_GPL_FFMPEG=1" +export VISIONA_ALLOW_GPL_FFMPEG=1 + +make vendor-python-linux vendor-wheels-linux vendor-ffmpeg-linux vendor-ytdlp-linux +make payload-linux +case "$TARGET" in + payload-linux) ;; + wails-linux) make wails-linux ;; + appimage|*) make wails-linux && make appimage ;; +esac + +log "完成 ✅" +log "產出位置:$(pwd)/dist/" +ls -lh dist/ 2>/dev/null || true diff --git a/local-tool/scripts/bootstrap-windows.ps1 b/local-tool/scripts/bootstrap-windows.ps1 new file mode 100644 index 0000000..ae49899 --- /dev/null +++ b/local-tool/scripts/bootstrap-windows.ps1 @@ -0,0 +1,95 @@ +# visionA-local — Windows 10/11 x86_64 一鍵 build +# +# 使用方式(PowerShell 以「系統管理員」開啟): +# git clone https://github.com/jim800121/visionA.git +# cd visionA\local-tool +# powershell -ExecutionPolicy Bypass -File scripts\bootstrap-windows.ps1 +# +# 環境變數: +# $env:VISIONA_TARGET 預設 exe,可設 wails-windows / payload-windows + +$ErrorActionPreference = 'Stop' + +$Target = if ($env:VISIONA_TARGET) { $env:VISIONA_TARGET } else { 'exe' } + +function Log($msg) { Write-Host "==> $msg" -ForegroundColor Cyan } +function Fail($msg) { Write-Host "!!! $msg" -ForegroundColor Red; exit 1 } + +# 必須以系統管理員身份執行(winget 需要) +$isAdmin = ([Security.Principal.WindowsPrincipal] ` + [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( + [Security.Principal.WindowsBuiltInRole] 'Administrator') +if (-not $isAdmin) { Fail '請以系統管理員身份執行 PowerShell 再跑此腳本' } + +if (-not (Test-Path 'Makefile') -or -not (Test-Path 'visiona-local')) { + Fail '請先 cd 到 local-tool\ 目錄再執行此腳本' +} + +if (-not (Get-Command winget -ErrorAction SilentlyContinue)) { + Fail 'winget 未安裝。請先從 Microsoft Store 安裝「App Installer」' +} + +function Ensure-Winget($id) { + $installed = winget list --id $id -e 2>$null | Select-String $id + if (-not $installed) { + Log "安裝 $id" + winget install -e --id $id --accept-source-agreements --accept-package-agreements + } else { + Log "$id 已安裝,跳過" + } +} + +Log '[1/4] 安裝系統套件' +Ensure-Winget 'Git.Git' +Ensure-Winget 'GoLang.Go' +Ensure-Winget 'OpenJS.NodeJS.LTS' +Ensure-Winget 'Python.Python.3.12' +Ensure-Winget 'JRSoftware.InnoSetup' +Ensure-Winget 'MSYS2.MSYS2' + +# 重新載入 PATH(winget 裝完目前 session 拿不到) +$env:Path = [System.Environment]::GetEnvironmentVariable('Path','Machine') + ';' + ` + [System.Environment]::GetEnvironmentVariable('Path','User') +$env:Path += ";$HOME\go\bin;C:\msys64\usr\bin;C:\msys64\mingw64\bin" + +Log '[2/4] 安裝 pnpm' +if (-not (Get-Command pnpm -ErrorAction SilentlyContinue)) { + npm i -g pnpm +} + +Log '[3/4] 安裝 Wails CLI + 確認 MSYS2 make' +if (-not (Get-Command wails -ErrorAction SilentlyContinue)) { + go install github.com/wailsapp/wails/v2/cmd/wails@latest +} +wails doctor +if (-not (Test-Path 'C:\msys64\usr\bin\make.exe')) { + Log '安裝 MSYS2 make' + & 'C:\msys64\usr\bin\bash.exe' -lc 'pacman -Sy --noconfirm make' +} + +Log "[4/4] 開始 build(target=$Target)" +Log '⚠️ ffmpeg 使用 GPL build,需設定 VISIONA_ALLOW_GPL_FFMPEG=1' + +# Makefile 需要 bash + make,透過 MSYS2 MinGW64 shell 執行 +# 將 Windows 路徑 C:\foo\bar 轉成 MSYS2 路徑 /c/foo/bar +$projectPath = (Get-Location).Path +$msysPath = '/' + $projectPath.Substring(0,1).ToLower() + '/' + ` + ($projectPath.Substring(3) -replace '\\','/') + +$bashCmd = "cd '$msysPath' && " + + "export VISIONA_ALLOW_GPL_FFMPEG=1 && " + + "make vendor-python-windows vendor-wheels-windows vendor-ffmpeg-windows vendor-ytdlp-windows && " + + "make payload-windows" + +switch ($Target) { + 'payload-windows' { } + 'wails-windows' { $bashCmd += ' && make wails-windows' } + default { $bashCmd += ' && make wails-windows && make exe' } +} + +& 'C:\msys64\usr\bin\bash.exe' -lc $bashCmd +if ($LASTEXITCODE -ne 0) { Fail "build 失敗,exit code=$LASTEXITCODE" } + +Log '完成 ✅' +Log "產出位置:$(Join-Path (Get-Location) 'dist')" +Get-ChildItem dist -ErrorAction SilentlyContinue | Format-Table Name, Length