chore: migrate rust/image-classification to icp-cli#1419
Conversation
919846a to
6209214
Compare
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…e to 1.0.1 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6209214 to
3a5e1ad
Compare
… clean up icp.yaml - Fix download_model.sh: target path was still src/backend/assets/ after source restructure to backend/; the build fails because include_bytes! can't find the model - Remove redundant network definition from icp.yaml (local managed is the default) - Update ic-cdk 0.14 → 0.20, ic-stable-structures 0.6 → 0.7, ic-wasi-polyfill 0.4.1 → 0.13 (0.13 is built for ic-cdk 0.20) - Update edition to 2024; add cdylib comment to Cargo.toml - README: add Node.js v18+, Rust v1.85+ prerequisites Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-toolchain.toml Cargo 1.79 can't parse edition = "2024" in dependency manifests (stabilized in 1.85). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
wasm32-wasi was deprecated in Rust 1.78 and removed in later stable releases. Updated all references in .cargo/config.toml, rust-toolchain.toml, icp.yaml, CI workflow, and README. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… convention (PR 1426) - vite.config.js: use icp network status --json for proxyTarget and rootKey, proper error message when backend not deployed, remove dfx loadEnv/define fallback - actor.js: remove dfx CANISTER_ID_BACKEND fallback, resolve canister ID from ic_env cookie only - package.json: bump @icp-sdk/core 5.0→5.4, @icp-sdk/bindgen 0.2.2→0.4.0, vite 5.4.11→8.1.3 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
media.githubusercontent.com IPv6 connections can hang; --inet4-only / -4 ensures the download completes reliably. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… icp.yaml build Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…DME prerequisites - Fix classify(): was #[ic_cdk::query] but backend.did and README both describe it as an update (replicated execution); change to #[ic_cdk::update] to match - README: remove wasm-opt (auto-installed by icp.yaml), add wasi2ic install command, move candid-extractor to the section where it's actually needed, clarify classify vs classify_query distinction Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add dashed border + subtle background to placeholder image to signal interactivity - Add "Click to upload" hint text below the image, hidden once a file is selected Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ion with updated text After results appear, show "↑ Click image to classify another" so the next action is obvious. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… ratio - Remove forced 300x300 square and object-fit:cover from .image (was cropping uploads) - Keep square dimensions only for .image.placeholder (the logo before any upload) - Remove hardcoded img.width=600; CSS max-width:100% handles sizing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…c in CI wasi2ic has a C++ dependency (link-cplusplus) that requires a C++ compiler; the icp-dev-env-rust container ships without build-essential. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…tial install Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… handle it The binaryen GitHub release download is fragile (504 errors). icp.yaml already has "which wasm-opt || cargo install wasm-opt" and build-essential is present from the wasi2ic step, so wasm-opt installs automatically on first icp deploy. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the rust/image-classification example from dfx + webpack to the icp-cli project layout and workflow, updating the Rust canister toolchain/build pipeline (WASI → ICP WASM) and modernizing the frontend to Vite + @icp-sdk/bindgen.
Changes:
- Replace
dfx.json/Makefile/webpack setup withicp.yaml+test.shand a new GitHub Actions workflow usingicp-dev-env-rust. - Restructure the project into
backend/andfrontend/, introduce a workspaceCargo.toml, and update Rust deps/toolchain/targets (incl.wasm32-wasip1). - Migrate frontend to Vite + bindgen actor wiring and update the UI assets/UX for image upload + classification results.
Reviewed changes
Copilot reviewed 27 out of 39 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| rust/image-classification/icp.yaml | Adds icp-cli canister definitions and a custom backend build pipeline (WASI → wasi2ic → wasm-opt → ic-wasm metadata). |
| rust/image-classification/test.sh | New icp canister call-based smoke test for run(). |
| rust/image-classification/README.md | Updates docs to icp-cli, new prerequisites, deploy/test steps, and candid update instructions. |
| rust/image-classification/package.json | Converts root JS setup to a workspace wrapper for the Vite frontend. |
| rust/image-classification/Cargo.toml | Updates workspace member path to backend/. |
| rust/image-classification/rust-toolchain.toml | Updates targets to include wasm32-wasip1 and removes the old pin. |
| rust/image-classification/.cargo/config.toml | Switches default target config from wasm32-wasi to wasm32-wasip1 and keeps SIMD rustflags. |
| rust/image-classification/.gitignore | Removes dfx-era ignores and ignores new generated bindings + model location. |
| rust/image-classification/download_model.sh | Fixes model download target path and forces IPv4 for wget/curl. |
| rust/image-classification/backend/Cargo.toml | Upgrades edition/deps (incl. ic-cdk) and adjusts crate metadata. |
| rust/image-classification/backend/src/lib.rs | Aligns classify() with the .did by changing it to an update call; keeps query variants and setup. |
| rust/image-classification/backend/src/onnx.rs | Introduces model setup/inference code and ImageNet label table. |
| rust/image-classification/backend/backend.did | Adds the committed Candid interface in the new location. |
| rust/image-classification/frontend/package.json | Adds the Vite frontend package with bindgen + Vite deps/scripts. |
| rust/image-classification/frontend/vite.config.js | New Vite config wiring bindgen + dev server cookie/proxy config for icp-cli. |
| rust/image-classification/frontend/src/actor.js | New canonical actor wiring via ic_env cookie + safeGetCanisterEnv. |
| rust/image-classification/frontend/src/main.js | Switches to new actor import and tweaks UX behavior (hint visibility, image sizing). |
| rust/image-classification/frontend/index.html | Moves assets under assets/, adds module script entry, and adds upload hint UI. |
| rust/image-classification/frontend/assets/main.css | Updates image sizing rules and adds placeholder/hint styling. |
| rust/image-classification/frontend/assets/.ic-assets.json5 | Restores asset-canister headers/CSP configuration in the new frontend layout. |
| rust/image-classification/frontend/assets/logo_transparent.png | Adds/moves the logo asset into the new frontend asset location. |
| rust/image-classification/frontend/assets/loader.svg | Adds/moves loader asset into the new frontend asset location. |
| rust/image-classification/frontend/assets/favicon.ico | Adds/moves favicon asset into the new frontend asset location. |
| .github/workflows/image-classification.yml | Adds new CI workflow using icp-cli in the Rust dev-env container. |
| .github/workflows/rust-image-classification-example.yaml | Removes legacy dfx-based CI workflow. |
| rust/image-classification/dfx.json | Removes dfx project configuration. |
| rust/image-classification/build.sh | Removes legacy build script (replaced by icp.yaml build steps). |
| rust/image-classification/Makefile | Removes legacy make-based build/test flow (replaced by test.sh). |
| rust/image-classification/webpack.config.js | Removes webpack configuration (frontend migrated to Vite). |
| rust/image-classification/src/frontend/src/.ic-assets.json5 | Removes old frontend asset headers config under the legacy src/ tree. |
| rust/image-classification/src/declarations/backend/index.js | Removes legacy dfx-generated declarations. |
| rust/image-classification/src/declarations/backend/index.d.ts | Removes legacy dfx-generated declarations typings. |
| rust/image-classification/src/declarations/backend/backend.did.js | Removes legacy dfx-generated Candid JS binding. |
| rust/image-classification/src/declarations/backend/backend.did.d.ts | Removes legacy dfx-generated Candid TS binding. |
| rust/image-classification/src/declarations/backend/backend.did | Removes legacy .did file under the old declarations tree. |
Comments suppressed due to low confidence (2)
rust/image-classification/frontend/index.html:10
<base href="/" />forces all relative URLs to resolve as absolute paths (e.g./assets/...). This commonly breaks local canister gateway URLs (like.../?canisterId=...) because the query param is dropped on subsequent asset requests. Use a relative base instead.
rust/image-classification/backend/src/lib.rs:41ic_cdk::export_candid!();is missing. This repo’s Rust canisters consistently include it socandid-extractorcan generatebackend.did(and your README’s “Updating the Candid interface” command will fail without the exported candid pointer).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…-extractor Without it the README's "Updating the Candid interface" command fails. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Note that export_candid!() is only needed for re-generation, not for deployment. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 27 out of 39 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (1)
rust/image-classification/backend/src/lib.rs:93
run()is a query method but it callsclassify(), which is intended to be the update/replicated entrypoint. This is confusing (and can change semantics ifclassifylater gains update-only behavior). Prefer calling the query variant (or a shared internal helper) fromrun().
|
Regarding the suppressed comment on |
Summary
dfx.jsonwithicp.yaml; custom build steps:cargo build --target=wasm32-wasip1→wasi2ic→wasm-opt(auto-installed if missing) →ic-wasmmetadata embedsrc/backend/→backend/,src/frontend/→frontend/; add workspaceCargo.tomlic-cdk0.14→0.20,ic-stable-structures0.6→0.7,ic-wasi-polyfill0.4.1→0.13; update edition to"2024"wasm32-wasi→wasm32-wasip1throughout (target removed in Rust stable post-1.78); update.cargo/config.toml,rust-toolchain.toml,icp.yaml, CI, READMEchannel = "1.79"pin fromrust-toolchain.toml(blocked builds with modern stable)download_model.sh: correct path tobackend/assets/(wassrc/backend/assets/); force IPv4 to avoid hanging IPv6 connections tomedia.githubusercontent.comclassify(): was#[ic_cdk::query]butbackend.didand README describe it as an update; changed to#[ic_cdk::update](replicated execution)@icp-sdk/bindgen; updateactor.jsandvite.config.jsto canonical icp-cli pattern (no dfx fallbacks); bump@icp-sdk/core5.0→5.4,@icp-sdk/bindgen0.2.2→0.4.0,vite5.4.11→8.1.3Makefilewithtest.sh; replacerun.shwithtest.shimage-classification.yml(icp-dev-env-rust:1.0.1, installsbuild-essentialforwasi2ic, downloads model); remove legacy workflowdfx.json,build.sh,webpack.config.js,Makefile, oldsrc/tree, old declarations, legacy CITest plan
./download_model.sh && icp network start -d && icp deploy && bash test.shpasses —run()classifiesman_on_ferrari_1975.pngand returnstractoricp deploy; image upload and classification workimage-classificationpasses on push🤖 Generated with Claude Code