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

259 lines
15 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Edge AI Platform Installer</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div id="app">
<!-- Header -->
<header id="wizard-header">
<div class="header-left">
<div class="logo-text" data-i18n="welcome.title">Edge AI Platform</div>
<div class="version-text">Installer v0.2.0</div>
</div>
<div class="header-center">
<div class="step-indicators">
<span class="step-dot active" data-step="0">1</span>
<span class="step-line"></span>
<span class="step-dot" data-step="1">2</span>
<span class="step-line"></span>
<span class="step-dot" data-step="2">3</span>
<span class="step-line"></span>
<span class="step-dot" data-step="3">4</span>
<span class="step-line"></span>
<span class="step-dot" data-step="4">5</span>
<span class="step-line"></span>
<span class="step-dot" data-step="5">6</span>
<span class="step-line"></span>
<span class="step-dot" data-step="6">7</span>
</div>
</div>
<div class="header-right">
<div class="lang-switch">
<button class="lang-btn active" id="lang-en">EN</button>
<span class="lang-sep">|</span>
<button class="lang-btn" id="lang-zh">中文</button>
</div>
</div>
</header>
<main>
<!-- Step 0: Welcome -->
<section id="step-0" class="step active">
<h1 data-i18n="welcome.title">Edge AI Platform Installer</h1>
<p class="subtitle" data-i18n="welcome.subtitle">Set up your edge AI development environment with Kneron hardware support.</p>
<div id="system-info" class="info-card">
<div class="info-row"><span class="info-label" data-i18n="system.platform">Platform</span><span id="info-platform" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="system.python">Python</span><span id="info-python" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="system.libusb">libusb</span><span id="info-libusb" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="system.ffmpeg">FFmpeg</span><span id="info-ffmpeg" class="info-value">-</span></div>
</div>
<div id="existing-install" class="warning-card" style="display:none">
<strong data-i18n="existing.detected">Existing installation detected</strong>
<p data-i18n="existing.desc">An existing installation was found. You can uninstall it or install over it.</p>
<p id="existing-path" class="existing-path"></p>
<button id="btn-uninstall" class="btn btn-danger" data-i18n="existing.uninstall">Uninstall</button>
</div>
<div class="actions">
<button id="btn-next-0" class="btn btn-primary" data-i18n="btn.next">Next</button>
</div>
</section>
<!-- Step 1: Install Path -->
<section id="step-1" class="step">
<h1 data-i18n="path.title">Installation Path</h1>
<p class="subtitle" data-i18n="path.subtitle">Choose where to install Edge AI Platform.</p>
<div class="form-group">
<div class="path-input-group">
<input type="text" id="install-path" class="input-field" readonly>
<button id="btn-browse" class="btn btn-secondary" data-i18n="path.browse">Browse</button>
</div>
<p id="path-status" class="status-text"></p>
</div>
<div class="actions">
<button id="btn-back-1" class="btn btn-ghost" data-i18n="btn.back">Back</button>
<button id="btn-next-1" class="btn btn-primary" data-i18n="btn.next">Next</button>
</div>
</section>
<!-- Step 2: Components -->
<section id="step-2" class="step">
<h1 data-i18n="components.title">Select Components</h1>
<p class="subtitle" data-i18n="components.subtitle">Choose which components to install.</p>
<div class="component-list">
<label class="component-item required">
<div class="component-check">
<input type="checkbox" id="comp-server" checked disabled>
<span class="checkmark"></span>
</div>
<div class="component-info">
<span class="component-name" data-i18n="components.server">Edge AI Server</span>
<span class="component-desc" data-i18n="components.serverDesc">Core server binary for hardware communication (~10 MB)</span>
</div>
</label>
<label class="component-item">
<div class="component-check">
<input type="checkbox" id="comp-models" checked>
<span class="checkmark"></span>
</div>
<div class="component-info">
<span class="component-name" data-i18n="components.models">Kneron Models</span>
<span class="component-desc" data-i18n="components.modelsDesc">Pre-trained NEF model files for KL520/KL720 (~50 MB)</span>
</div>
</label>
<label class="component-item">
<div class="component-check">
<input type="checkbox" id="comp-python" checked>
<span class="checkmark"></span>
</div>
<div class="component-info">
<span class="component-name" data-i18n="components.python">Python Environment</span>
<span class="component-desc" data-i18n="components.pythonDesc">Python venv with Kneron PLUS SDK and dependencies (~200 MB)</span>
</div>
</label>
<label class="component-item">
<div class="component-check">
<input type="checkbox" id="comp-libusb" checked>
<span class="checkmark"></span>
</div>
<div class="component-info">
<span class="component-name" data-i18n="components.libusb">libusb</span>
<span class="component-desc" data-i18n="components.libusbDesc">USB library required for Kneron device communication</span>
</div>
</label>
<label class="component-item" id="comp-symlink-row">
<div class="component-check">
<input type="checkbox" id="comp-symlink" checked>
<span class="checkmark"></span>
</div>
<div class="component-info">
<span class="component-name" data-i18n="components.symlink">CLI Symlink</span>
<span class="component-desc" data-i18n="components.symlinkDesc">Add 'edge-ai' command to /usr/local/bin</span>
</div>
</label>
</div>
<div class="actions">
<button id="btn-back-2" class="btn btn-ghost" data-i18n="btn.back">Back</button>
<button id="btn-install" class="btn btn-primary" data-i18n="btn.install">Install</button>
</div>
</section>
<!-- Step 3: Relay Configuration -->
<section id="step-3" class="step">
<h1 data-i18n="relay.title">Relay Configuration</h1>
<p class="subtitle" data-i18n="relay.subtitle">Configure the relay server for remote access. You can skip this and configure later.</p>
<div class="form-group">
<label class="field-label" data-i18n="relay.url">Relay URL</label>
<input type="text" class="input-field" id="relay-url" value="ws://ec2-13-192-170-7.ap-northeast-1.compute.amazonaws.com/tunnel/connect">
</div>
<div class="form-group">
<label class="field-label" data-i18n="relay.token">Relay Token</label>
<div class="path-input-group">
<input type="text" class="input-field" id="relay-token" placeholder="auto-generated" readonly>
<button id="btn-regen-token" class="btn btn-secondary" title="Regenerate">&#x21BB;</button>
</div>
<p class="field-hint" data-i18n="relay.tokenHint">Auto-generated random token. Both the server and browser use this to authenticate with the relay.</p>
</div>
<div class="form-group">
<label class="field-label" data-i18n="relay.dashboardUrl">Dashboard URL</label>
<input type="text" class="input-field" id="dashboard-url" value="http://ec2-13-192-170-7.ap-northeast-1.compute.amazonaws.com">
<p class="field-hint" data-i18n="relay.dashboardHint">The HTTP URL to access the dashboard via relay. Opened after server launch.</p>
</div>
<div class="form-group">
<label class="field-label" data-i18n="relay.port">Server Port</label>
<input type="number" class="input-field" id="server-port" value="3721" min="1024" max="65535">
</div>
<p class="field-hint" data-i18n="relay.hint">Leave empty to skip relay configuration. You can set this later in the config file.</p>
<div class="actions">
<button id="btn-back-3" class="btn btn-ghost" data-i18n="btn.back">Back</button>
<button id="btn-next-3" class="btn btn-primary" data-i18n="btn.next">Next</button>
</div>
</section>
<!-- Step 4: Progress -->
<section id="step-4" class="step">
<h1 id="progress-title" data-i18n="progress.title">Installing...</h1>
<p class="subtitle" id="progress-subtitle" data-i18n="progress.subtitle">Please wait while components are being installed.</p>
<div class="progress-container">
<div class="progress-bar">
<div id="progress-fill" class="progress-fill" style="width:0%"></div>
</div>
<span id="progress-percent" class="progress-percent">0%</span>
</div>
<p id="progress-message" class="progress-message" data-i18n="progress.preparing">Preparing installation...</p>
<div id="progress-log" class="log-area"></div>
</section>
<!-- Step 5: Hardware Detection -->
<section id="step-5" class="step">
<h1 data-i18n="hardware.title">Hardware Detection</h1>
<p class="subtitle" data-i18n="hardware.subtitle">Connect your Kneron devices and scan for hardware.</p>
<div id="hardware-results" class="hardware-list">
<div class="device-scanning" id="device-scanning">
<div class="spinner"></div>
<p data-i18n="hardware.scanning">Scanning for devices...</p>
</div>
<div class="no-devices" id="no-devices" style="display:none;">
<p data-i18n="hardware.noDevices">No Kneron devices found. Connect a device and try again.</p>
</div>
</div>
<div class="actions">
<button id="btn-rescan" class="btn btn-secondary" data-i18n="hardware.rescan">Rescan</button>
<button id="btn-next-5" class="btn btn-primary" data-i18n="btn.next">Next</button>
</div>
</section>
<!-- Step 6: Complete -->
<section id="step-6" class="step">
<div class="complete-icon">
<svg width="64" height="64" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/>
<polyline points="22 4 12 14.01 9 11.01"/>
</svg>
</div>
<h1 data-i18n="complete.title">Installation Complete</h1>
<p class="subtitle" data-i18n="complete.subtitle">Edge AI Platform has been installed successfully.</p>
<div id="install-summary" class="info-card">
<div class="info-row"><span class="info-label" data-i18n="complete.location">Install Location</span><span id="summary-path" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="complete.server">Edge AI Server</span><span id="summary-server" class="info-value status-ok" data-i18n="complete.installed">Installed</span></div>
<div class="info-row"><span class="info-label" data-i18n="complete.models">Kneron Models</span><span id="summary-models" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="complete.python">Python Environment</span><span id="summary-python" class="info-value">-</span></div>
<div class="info-row"><span class="info-label" data-i18n="complete.libusb">libusb</span><span id="summary-libusb" class="info-value">-</span></div>
</div>
<div class="actions">
<button id="btn-launch" class="btn btn-primary" data-i18n="btn.launch">Launch Server</button>
<button id="btn-open-dashboard" class="btn btn-secondary" style="display:none" data-i18n="btn.openDashboard">Open Dashboard</button>
<button id="btn-close" class="btn btn-ghost" data-i18n="btn.close">Close</button>
</div>
</section>
</main>
</div>
<script src="wailsjs/runtime/runtime.js"></script>
<script src="wailsjs/go/main/App.js"></script>
<script src="app.js"></script>
</body>
</html>