Skip to content

feat(pixel-perfect): expose standalone native tool API - #496

Open
huyanxius wants to merge 21 commits into
1024XEngineer:mainfrom
huyanxius:feat/492-pixel-perfect-api
Open

feat(pixel-perfect): expose standalone native tool API#496
huyanxius wants to merge 21 commits into
1024XEngineer:mainfrom
huyanxius:feat/492-pixel-perfect-api

Conversation

@huyanxius

@huyanxius huyanxius commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

将独立完美像素工具的 Python 调用边界改为 PyO3 原生扩展,并完成 binding、后端适配与容器 wheel 构建接线;工具仍保持在生成管线之外。

Why

每次请求启动 Rust 子进程会增加进程创建、管道传输和生命周期管理成本,也会把 Rust 二进制路径扩散进 Python 后端配置。后端只需要依赖稳定的原生模块接口,同时不能让该工具耦合现有生成或工作流系统。

Changes

  • 新增 windup_pixel_perfect_native PyO3 binding,直接组合 feat(pixel-grid): add independent native grid detector #493 检测器与 feat(pixel-grid): add independent native grid reconstructor #495 重建器。
  • Python 适配层延迟加载原生模块,直接调用 detect / reconstruct,删除子进程与二进制路径配置。
  • Rust 运算期间释放 GIL;输入复制为 Rust-owned bytes,原生输入错误映射为 ValueError
  • 新增 binding 契约测试,并保留现有六字段检测结果、PNG 输出与工具不可用错误校验。
  • Docker 多阶段构建锁定的 abi3 wheel;运行镜像不包含 Rust 工具链或算法源码。
  • backend 与 worker 共用仓库根构建上下文和同一原生扩展。

Implementation

Verification

  • cargo fmt --check --manifest-path native/pixel-perfect/bindings/python/Cargo.toml:通过。
  • cargo check --release --locked --manifest-path native/pixel-perfect/bindings/python/Cargo.toml:通过。
  • pytest -q native/pixel-perfect/bindings/python/tests/test_binding.py:3 项通过。
  • pytest -q backend/tests/test_pixel_perfect_api.py:20 项通过。
  • pytest -q backend/tests/test_env_example_keys_are_live.py:2 项通过。
  • lint-imports:4 条架构契约通过。
  • 定向 ruff checkruff format --check:通过。
  • docker build -f backend/Dockerfile -t windup-pixel-perfect-pyo3:final .:在 feat(pixel-grid): add independent native grid detector #493 + feat(pixel-grid): add independent native grid reconstructor #495 + feat(pixel-perfect): expose standalone native tool API #496 组合树通过。
  • 运行镜像导入 windup_pixel_perfect_native:通过。
  • 运行镜像不含 cargorustc、算法源码目录,并保留两份许可证:通过。
  • git diff --check:通过。

Scope

  • 本 PR 不修改检测器或重建器算法。
  • 本 PR 不包含:前端、默认生成管线集成、数据库、对象存储或媒体资产写入。
  • <3px 自动检测边界保持现状,后续另行处理。

Related Issues

Closes #492

Refs #489
Refs #493
Refs #495

The application needs a minimal boundary for local grid detection and reconstruction.

Add immutable result types and stable input, busy, and unavailable error classes.

Later adapters can compose the native modules without importing business services.
The tool API must invoke fixed local binaries without unbounded subprocess resources.

Add six-field detector parsing, explicit reconstructor arguments, output limits, timeouts, and exit classification.

Native failures now map to controlled tool errors instead of leaking process behavior.
Automatic and manual modes need one application boundary that remains outside generation.

Compose detection and explicit reconstruction with finite parameters, bounded concurrency, and PNG validation.

The tool can run independently while rejecting unsupported sub-three-pixel auto results.
Browsers need an explicit endpoint that never touches storage or generation workflows.

Add streamed request limits, local-tool error mapping, PNG metadata headers, and composition-root registration.

The authenticated endpoint now returns the rebuilt image directly with bounded upload concurrency.
The app package inspects upload and reconstruction dimensions at its own boundary.

Declare Pillow directly and update only the corresponding workspace lock metadata.

Runtime dependency ownership no longer relies on the unrelated AI engine package.
The new tool must remain separate from existing generation and infrastructure modules.

Add bidirectional forbidden-import contracts for the tool, orchestrator, generation API, and worker.

Future coupling attempts now fail the existing architecture gate.
Production needs both standalone Rust modules without shipping a Rust runtime or source tree.

Build each locked crate in a separate stage and copy only binaries plus MIT licenses into the image.

The Python runtime can invoke fixed local tools through explicit environment paths.
The explicit API needs regression evidence for composition, resources, and failure mapping.

Cover uploads, manual bypass, sub-three-pixel rejection, native limits, concurrency, CORS, and OpenAPI.

Tool regressions now fail without exercising storage, generation, databases, or external services.
The repository OpenAPI artifact must match the newly registered multipart endpoint.

Export the PNG success response, business-error JSON, form parameters, and validation schema.

Clients and CI now see the same explicit tool contract as the running application.
@vercel

vercel Bot commented Aug 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
windup Ignored Ignored Preview Aug 21, 2026 8:32am

@codecov

codecov Bot commented Aug 20, 2026

Copy link
Copy Markdown

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review conclusion

The standalone API boundary, subprocess adapter, packaging changes, OpenAPI export, and architecture contracts were reviewed against the fixed SHA range. The targeted 20-test suite, Ruff checks, formatting check, and all four import-linter contracts pass. One integration-level upload-limit path does not preserve the API's documented business-error envelope, as detailed inline.

View job run

Comment thread backend/packages/app/src/windup_app/server/pixel_perfect/factory.py Outdated
Comment thread backend/packages/app/src/windup_app/server/pixel_perfect/factory.py Outdated
Comment thread backend/packages/app/src/windup_app/server/pixel_perfect/errors.py
Comment thread backend/Dockerfile
The backend adapter should not spawn Rust binaries for each request.

Load the PyO3 module lazily and map its typed results into existing tool contracts.

Missing native code affects only this explicit endpoint, not application startup.
The backend needs a stable boundary for detector and reconstructor extension calls.

Replace process-protocol cases with direct-call, input-error, and lazy-load coverage.

Tests now exercise the selected native-extension integration shape.
@huyanxius huyanxius changed the title feat(pixel-perfect): expose standalone local tool API feat(pixel-perfect): expose standalone native tool API Aug 21, 2026
The backend adapter needs a native module that can link both independent Rust crates.

Add the locked Cargo and maturin package metadata for an abi3 Python 3.12 extension.

This gives the binding a reproducible package boundary without changing either algorithm.
The Python adapter should call the independent detector and reconstructor without subprocess overhead.

Expose byte-oriented detect and reconstruct functions while releasing the interpreter during Rust work.

The extension preserves the existing algorithm inputs and maps invalid native input to ValueError.
The extension boundary needs direct coverage apart from the FastAPI adapter tests.

Exercise detector metadata, explicit-grid reconstruction, and invalid-input error mapping.

This protects the Python-facing ABI without changing detector or reconstructor behavior.
Backend contributors need a short reference for building and calling the extension locally.

Document the two byte-oriented functions, the maturin command, and error ownership.

This keeps the native boundary discoverable without adding generation-pipeline guidance.
Local maturin and Cargo verification creates target artifacts beside the binding crate.

Exclude the crate target directory from version control.

This keeps local native builds from polluting the adapter branch.
The backend and worker images need the PyO3 module while keeping Rust tooling out of runtime.

Build a locked wheel in a dedicated stage and install it through the repository-root build context.

Both services now share the packaged extension and retain only required native licenses at runtime.
Comment thread native/pixel-perfect/bindings/python/README.md
Starlette converts multipart receive failures into its own HTTP 400 response.

Suppress that parser response after the byte limit trips and emit the existing business envelope.

Oversized uploads now retain the endpoint contract without weakening the pre-spool limit.
The direct middleware test did not exercise Starlette multipart error handling.

Send an upload above the ASGI limit through the authenticated TestClient endpoint.

The regression now guards the HTTP 200 business-error envelope at the real API boundary.
The same environment variable was parsed independently by the tool factory and middleware wiring.

Define one framework settings object and inject its validated value from the composition root.

The feature module stays framework-independent while both resource guards share one setting.
Deployers need to discover the resource limit without reading application wiring.

Add the validated PIXEL_PERFECT_CONCURRENCY key to the environment template.

Local and container deployments can now tune the explicit tool from the documented config surface.
@huyanxius
huyanxius requested review from minorcell and nighca August 21, 2026 09:08
xyh202131
xyh202131 previously approved these changes Aug 21, 2026

@xyh202131 xyh202131 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

按请求批量审批当前提交。

@xyh202131
xyh202131 dismissed their stale review August 21, 2026 09:16

按请求撤销此前审批。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(pixel-perfect): expose an independent tool API

3 participants