jim800121chen c54f16fca0 Initial commit: visionA monorepo with local-tool subproject
local-tool/: visionA-local desktop app
- M1: Wails shell + Go server + Next.js UI + Mock mode (macOS dmg ready)
- M2: i18n (zh-TW/en) + Settings 4-tab refactor
- M3: Embedded Python 3.12 runtime (python-build-standalone) + KneronPLUS wheels
- M4: Windows Inno Setup script (build on Windows runner)
- M5: Linux AppImage script + udev rule (build on Linux runner)
- M6: ffmpeg (GPL, pending legal review) + yt-dlp bundled
- Lifecycle: watchServer health check, fatal native dialog,
            Wails IPC raise endpoint, stale process cleanup

.autoflow/: full PRD / Design Spec / Architecture / Testing docs
            (4 rounds tri-party discussion + cross review)
.github/workflows/: macOS / Windows / Linux build CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 22:10:38 +08:00

11 KiB
Raw Blame History

Code Reuse Plan — visionA-local

/Users/jimchen/Innovedus/edge-ai-platform/edge-ai-platform/ 取用程式碼的完整對照表。 三種策略:直接複製改寫新寫


1. 總體比例(預估)

  • 直接複製~60% LOC
  • 改寫~20%
  • 新寫~20%
  • 刪除:獨立計算,見 removed-code.md

2. 目錄層級策略

Fromedge-ai-platform Tolocal_tool 策略 備註
server/main.go server/main.go 改寫 移除 cluster / tunnel / relay / hwid / gitea 邏輯
server/go.mod server/go.mod 改寫 移除不再需要的 importsmodule name 可改為 visiona-local
server/go.sum server/go.sum 改寫 跟著 go.mod 重新生成
server/internal/api/router.go server/internal/api/router.go 改寫 api-endpoints.md §4
server/internal/api/middleware.go 同路徑 直接複製
server/internal/api/handlers/ 同路徑 部分複製 / 改寫 見下方 §3.1
server/internal/api/ws/ 同路徑 部分複製 / 改寫 見下方 §3.2
server/internal/api/api_e2e_test.go 同路徑 改寫 刪除 cluster / flash / auth test case
server/internal/camera/ 同路徑 直接複製 除了 ffmpeg 路徑查找改為「優先 bundled」見 §3.4
server/internal/config/config.go 同路徑 改寫 見 §3.3
server/internal/deps/ 同路徑 改寫 移除 update / relay 相關檢查
server/internal/device/ 同路徑 直接複製 核心裝置管理
server/internal/driver/ 同路徑 直接複製
server/internal/inference/ 同路徑 直接複製
server/internal/model/ 同路徑 直接複製
server/internal/flash/ 刪除 使用者決策 Q9
server/internal/cluster/ 刪除 使用者決策
server/internal/tunnel/ 刪除 使用者決策
server/internal/update/ 刪除 使用者決策 Q6
server/pkg/logger/ 同路徑 直接複製
server/pkg/hwid/ 刪除 只給 relay 用的
server/cmd/relay-server/ 刪除 不需要 relay
server/tray/ 刪除 使用者決策 Q-A=A3砍掉 tray省跨平台圖資產與 Wails tray 踩坑
server/scripts/kneron_bridge.py server/scripts/kneron_bridge.py 直接複製
server/scripts/requirements.txt 同路徑 直接複製
server/scripts/update_kl720_firmware.py 刪除 flash 已砍
server/scripts/firmware/ 刪除 同上
server/data/models.json 同路徑 直接複製
server/data/nef/kl520/ 同路徑 直接複製 全部預置模型
server/data/nef/kl720/ 同路徑 直接複製
server/web/ 同路徑(空目錄) 直接複製 go:embed 掛載點
frontend/ frontend/ 改寫 M1 就要清乾淨:刪除 cluster / relay / tunnel 相關頁面、元件、store、API clientpnpm build 通過且 UI 乾淨(使用者決策 Q-C=C2
installer/ visiona-local/ 改寫(改名 + 精簡) 見 §3.5
installer/wheels/ vendor/wheels/visiona-local/payload/scripts/wheels/ 直接複製 KneronPLUS wheel
installer/drivers/ vendor/drivers/visiona-local/payload/drivers/ 直接複製 Windows WinUSB
installer/payload/ visiona-local/payload/ 結構沿用,內容重建 由 Makefile payload target 重新 stage
Makefile Makefile 改寫 build-pipeline.md
docker/ 刪除
scripts/deploy-*.sh 刪除
scripts/kneron_detect.py server/scripts/kneron_detect.py 直接複製 installer 裝置偵測用
tools/ 視檔案決定 多數刪除 只保留開發相關的 script
docs/ 刪除(之後重寫)

3. 需要改寫的檔案細節

3.1 server/internal/api/handlers/

檔案 策略 動作
system_handler.go 改寫 移除 CheckUpdategiteaURL 參數;刪除 update-check handler
model_handler.go 直接複製
model_upload_handler.go 直接複製
device_handler.go 改寫 移除 FlashDevice handler 與 flashSvc 注入
camera_handler.go 直接複製 StartFromURL 內部的 yt-dlp 路徑查找改為 bundled見 §3.4
cluster_handler.go 刪除

3.2 server/internal/api/ws/

檔案 策略
hub.go 直接複製
device_events.go 直接複製
server_logs.go 直接複製
inference.go 直接複製
flash_progress.go 刪除
cluster_*.go 刪除

3.3 server/internal/config/config.go 改寫版

package config

import (
    "flag"
    "fmt"
    "os"
    "path/filepath"
)

type Config struct {
    Port            int
    Host            string
    MockMode        bool
    MockCamera      bool
    MockDeviceCount int
    LogLevel        string
    DevMode         bool
    PythonBin       string       // 新增:由 Wails app 傳入
    ScriptsDir      string       // 新增
    DataDir         string       // 新增
    // ❌ 以下全部移除:
    // RelayURL, RelayToken, GUIMode, GiteaURL
}

func Load() *Config {
    cfg := &Config{}
    flag.IntVar(&cfg.Port, "port", 3721, "Server port")
    flag.StringVar(&cfg.Host, "host", "127.0.0.1", "Server host (always localhost)")
    flag.BoolVar(&cfg.MockMode, "mock", false, "Enable mock device driver")
    flag.BoolVar(&cfg.MockCamera, "mock-camera", false, "Enable mock camera")
    flag.IntVar(&cfg.MockDeviceCount, "mock-devices", 1, "Number of mock devices")
    flag.StringVar(&cfg.LogLevel, "log-level", "info", "Log level")
    flag.BoolVar(&cfg.DevMode, "dev", false, "Dev mode")
    flag.StringVar(&cfg.PythonBin, "python", "", "Path to python3 interpreter")
    flag.StringVar(&cfg.ScriptsDir, "scripts-dir", "", "Path to scripts directory")
    flag.StringVar(&cfg.DataDir, "data-dir", "", "Path to data directory")
    flag.Parse()

    // 合理 defaultdev 模式)
    if cfg.ScriptsDir == "" {
        cfg.ScriptsDir = filepath.Join(".", "scripts")
    }
    if cfg.DataDir == "" {
        cfg.DataDir = filepath.Join(".", "data")
    }
    return cfg
}

func (c *Config) Addr() string {
    return fmt.Sprintf("%s:%d", c.Host, c.Port)
}

3.4 ffmpeg / yt-dlp 路徑查找

新增 server/internal/camera/binaries.go

package camera

import (
    "os"
    "path/filepath"
    "runtime"
)

// FfmpegBinary returns the ffmpeg binary to use, preferring bundled over PATH.
func FfmpegBinary() string {
    if p := os.Getenv("VISIONA_FFMPEG"); p != "" {
        return p
    }
    if p := bundled("ffmpeg"); p != "" {
        return p
    }
    return "ffmpeg"  // PATH fallback
}

func YtDlpBinary() string {
    if p := os.Getenv("VISIONA_YTDLP"); p != "" {
        return p
    }
    if p := bundled("yt-dlp"); p != "" {
        return p
    }
    return "yt-dlp"
}

func bundled(name string) string {
    exe, err := os.Executable()
    if err != nil {
        return ""
    }
    dir := filepath.Dir(exe)
    candidate := filepath.Join(dir, name)
    if runtime.GOOS == "windows" {
        candidate += ".exe"
    }
    if _, err := os.Stat(candidate); err == nil {
        return candidate
    }
    return ""
}

3.5 installer/app.govisiona-local/app.go 改寫

原 894 行,改寫要點:

移除的欄位 / 函式

  • relayURL, relayToken, dashboardURL
  • GetDashboardURL, GenerateToken, OpenBrowser 中任何跟 relay 有關的邏輯
  • stepInstallUSBDriver 需要保留,但只給 Windows 用flash driver 已砍但 WinUSB 還需要)
  • stepInstallFfmpeg 改寫:不去系統 PATH 找,而是從 payload/bin 解壓 bundled ffmpeg

新增的欄位 / 函式

  • pythonModebundled / system / auto
  • stepSetupPythonStandalone(解壓內嵌 python-build-standalone
  • stepSetupPythonSystemfallback 到系統 python沿用舊的 setupPythonVenv 邏輯)
  • stepInstallWheelsOffline(用 pip install --no-index --find-links
  • i18n translator 注入
  • launchServer / stopServer / watchServer(見 tray-and-lifecycle.md §4
  • single-instance lock

保留(幾乎不動)

  • GetSystemInfo, BrowseDirectory, ValidatePath
  • stepCreateDir, stepExtractBinary, stepExtractData, stepExtractScripts
  • DetectHardware, parseDetectOutput
  • extractFile, extractDir
  • Platform-specific 檔案(platform_darwin.go / platform_linux.go / platform_windows.go

4. 新寫的程式碼

完全新寫的檔案:

4.1 Wails app 側

visiona-local/
├── python_runtime.go         ← python-build-standalone 解壓 + 版本偵測
├── server_launcher.go        ← spawn / stop / watch Go server
├── lifecycle.go              ← single-instance lock、port picking、cleanup
├── ipc.go                    ← /ipc/raise 小型 HTTP listener
├── i18n.go                   ← Translator + locales embed
└── locales/
    ├── en.json
    └── zh-TW.json

4.2 Build / CI

scripts/
├── vendor-sync.sh            ← 下載 python-build-standalone、ffmpeg、yt-dlp 到 vendor/
├── build-appimage.sh         ← Linux AppImage 打包腳本
├── check-i18n.sh             ← 檢查 i18n key 一致性
└── smoke-test.sh             ← 安裝後 smoke test
visiona-local-installer.iss   ← Inno Setup 腳本
dmg-config.py                 ← macOS dmgbuild 設定
.github/workflows/release.yml ← CI選配

5. 搬家步驟(建議執行順序)

  1. 建立骨架mkdir -p local_tool/{server,frontend,visiona-local,vendor,scripts,dist}
  2. 複製 server corecp -r edge-ai-platform/server/{internal/{api,camera,config,deps,device,driver,inference,model},pkg/logger,scripts,data,web} local_tool/server/
  3. 跳過要刪的 package:不要複製 clustertunnelflashupdatepkg/hwidcmd/relay-servertray(使用者決策 Q-A砍 tray
  4. 改寫 main.go + config.go + router.go(見上方 §3
  5. 改寫 go.modgo mod init visiona-local/servergo mod tidy(會自動清掉 unused imports
  6. 驗證 go build ./... 通過
  7. 複製 frontendcp -r edge-ai-platform/frontend local_tool/frontend
  8. 清理前端 cluster / relay / tunnel UI(使用者決策 Q-C=C2M1 就要清乾淨,不留到 M2刪除 src/app/clusters/src/app/workspace/cluster/src/components/cluster/src/components/relay-token-sync.tsxsrc/lib/api/clusters.tssrc/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. 複製 installercp -r edge-ai-platform/installer local_tool/visiona-local,改 main.go 的 app 名稱與 bundle ID
  10. 先跑 M1-12:全新機器上 installer 能裝起來並跑通 Mock 模式