diff --git a/.gitignore b/.gitignore index d7e9e6f..7b7c33c 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,17 @@ local-tool/payload/ !local-tool/vendor/ffmpeg/macos/ !local-tool/vendor/ffmpeg/macos/** +# local-agent 對稱規則(build 產物 wheel/python/ffmpeg 不進 git,避免 vendor-sync +# 後 git add -A 撈進大量 build 產物;同 local-tool 保留 macOS LGPL ffmpeg binary 例外) +local-agent/vendor/** +local-agent/dist/ +local-agent/payload/** +!local-agent/payload/.gitkeep +!local-agent/vendor/.gitkeep +!local-agent/vendor/ffmpeg/ +!local-agent/vendor/ffmpeg/macos/ +!local-agent/vendor/ffmpeg/macos/** + # Go server 的 embed 與 build 產物 local-tool/server/web/out/ local-tool/server/visiona-local-server diff --git a/local-agent/Makefile b/local-agent/Makefile index 11eb131..9f08fca 100644 --- a/local-agent/Makefile +++ b/local-agent/Makefile @@ -91,6 +91,14 @@ vendor-python: ## 下載 python-build-standalone tarball → vendor/python/darwi vendor-wheels: ## 同步 wheels → vendor/wheels/darwin/(內部 wheel 從 visiona-agent/wheels 複製,公開相依用 pip download) @mkdir -p vendor/wheels/darwin + @# ⚠️ 先清空舊 wheel:pip download --dest 不會覆蓋/清理舊版本,跨多次 vendor-sync + @# 會累積同一套件的多個版本(如 certifi 2026.2.25 + 2026.4.22 + 2026.6.17)。 + @# 下游 ensureBundledPython 會列舉目錄下「所有」.whl 丟給 pip install,多版本 + @# 並存時 pip resolver 直接 ResolutionImpossible → 整批安裝失敗 → runtime venv + @# 沒有 kp/numpy/cv2 → Kneron scan fallback 回假序號 0x00000000。 + @# 每次都清空重建,確保每個套件恰好單一版本(與 POC 乾淨 vendor 目錄一致)。 + @echo "==> 清空舊 wheels(避免多版本累積導致 pip ResolutionImpossible)..." + @rm -f vendor/wheels/darwin/*.whl @echo "==> 同步內部 wheels(KneronPLUS 等)..." @if [ -d visiona-agent/wheels/macos ]; then \ cp visiona-agent/wheels/macos/*.whl vendor/wheels/darwin/ 2>/dev/null || true; \ @@ -105,7 +113,14 @@ vendor-wheels: ## 同步 wheels → vendor/wheels/darwin/(內部 wheel 從 vis --implementation cp \ --dest vendor/wheels/darwin \ numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)" - @echo "==> wheels 總覽:" + @echo "==> 驗證每個套件恰好單一版本(多版本會讓 runtime pip install 整批失敗)..." + @dup=$$(ls -1 vendor/wheels/darwin/*.whl 2>/dev/null | sed -E 's|.*/||; s/-[0-9].*//' | sort | uniq -d); \ + if [ -n "$$dup" ]; then \ + echo "❌ 偵測到多版本 wheel(清空邏輯失效):$$dup"; \ + ls -1 vendor/wheels/darwin/*.whl | sed 's|.*/| |'; \ + exit 1; \ + fi + @echo "==> wheels 總覽(每套件單版):" @ls -1 vendor/wheels/darwin/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel" @du -sh vendor/wheels/darwin @@ -288,6 +303,10 @@ vendor-python-windows: ## 下載 python-build-standalone Windows x86_64 → vend vendor-wheels-windows: ## 同步 Windows wheels → vendor/wheels/windows/ @mkdir -p vendor/wheels/windows + @# ⚠️ 見 vendor-wheels(macOS)的說明:先清空避免多版本累積,否則 runtime + @# ensureBundledPython 的 pip install 會 ResolutionImpossible → venv 缺 kp。 + @echo "==> 清空舊 wheels (Windows,避免多版本累積)..." + @rm -f vendor/wheels/windows/*.whl @echo "==> 同步內部 wheels (Windows, KneronPLUS 等)..." @if [ -d visiona-agent/wheels/windows ]; then \ cp visiona-agent/wheels/windows/*.whl vendor/wheels/windows/ 2>/dev/null || true; \ @@ -312,7 +331,14 @@ vendor-wheels-windows: ## 同步 Windows wheels → vendor/wheels/windows/ --dest vendor/wheels/windows \ numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)"; \ fi - @echo "==> Windows wheels 總覽:" + @echo "==> 驗證每個套件恰好單一版本(多版本會讓 runtime pip install 整批失敗)..." + @dup=$$(ls -1 vendor/wheels/windows/*.whl 2>/dev/null | sed -E 's|.*/||; s/-[0-9].*//' | sort | uniq -d); \ + if [ -n "$$dup" ]; then \ + echo "❌ 偵測到多版本 wheel(清空邏輯失效):$$dup"; \ + ls -1 vendor/wheels/windows/*.whl | sed 's|.*/| |'; \ + exit 1; \ + fi + @echo "==> Windows wheels 總覽(每套件單版):" @ls -1 vendor/wheels/windows/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel" @du -sh vendor/wheels/windows 2>/dev/null || true @@ -398,10 +424,21 @@ vendor-python-linux: ## 下載 python-build-standalone Linux x86_64 → vendor/p vendor-wheels-linux: ## 同步 Linux wheels → vendor/wheels/linux/ @mkdir -p vendor/wheels/linux + @# ⚠️ 見 vendor-wheels(macOS)的說明:先清空避免多版本累積,否則 runtime + @# ensureBundledPython 的 pip install 會 ResolutionImpossible → venv 缺 kp。 + @echo "==> 清空舊 wheels (Linux,避免多版本累積)..." + @rm -f vendor/wheels/linux/*.whl @echo "==> 同步內部 wheels (Linux, KneronPLUS 等)..." @if [ -d visiona-agent/wheels/linux ]; then \ cp visiona-agent/wheels/linux/*.whl vendor/wheels/linux/ 2>/dev/null || true; \ fi + @# KneronPLUS-*.whl 是 py3-none-any(平台無關)。若上一步沒從 Linux 專屬目錄 + @# 複製到 KneronPLUS wheel,退回複製 macOS 目錄下的,確保 Linux payload 也含 kp。 + @if ! ls vendor/wheels/linux/KneronPLUS-*.whl >/dev/null 2>&1; then \ + cp visiona-agent/wheels/macos/KneronPLUS-*.whl vendor/wheels/linux/ 2>/dev/null && \ + echo "==> (Linux 無專屬 KneronPLUS wheel,改用 macos 目錄的 py3-none-any wheel)" || \ + echo "WARN: 找不到任何 KneronPLUS wheel,Linux payload 將缺 kp"; \ + fi @echo "==> 從 PyPI 下載公開相依 wheels (cp312, manylinux2014_x86_64)..." @pip3 download \ --only-binary=:all: \ @@ -410,7 +447,14 @@ vendor-wheels-linux: ## 同步 Linux wheels → vendor/wheels/linux/ --implementation cp \ --dest vendor/wheels/linux \ numpy opencv-python-headless pyusb requests || echo "WARN: pip download 部分失敗(詳見上方訊息)" - @echo "==> Linux wheels 總覽:" + @echo "==> 驗證每個套件恰好單一版本(多版本會讓 runtime pip install 整批失敗)..." + @dup=$$(ls -1 vendor/wheels/linux/*.whl 2>/dev/null | sed -E 's|.*/||; s/-[0-9].*//' | sort | uniq -d); \ + if [ -n "$$dup" ]; then \ + echo "❌ 偵測到多版本 wheel(清空邏輯失效):$$dup"; \ + ls -1 vendor/wheels/linux/*.whl | sed 's|.*/| |'; \ + exit 1; \ + fi + @echo "==> Linux wheels 總覽(每套件單版):" @ls -1 vendor/wheels/linux/*.whl 2>/dev/null | wc -l | xargs -I{} echo " 共 {} 個 wheel" @du -sh vendor/wheels/linux 2>/dev/null || true