zorya-classifier 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE.md +2 -0
- package/README.md +18 -6
- package/dist/app/cli-arguments.d.ts +40 -0
- package/dist/app/cli-arguments.js +67 -0
- package/dist/app/create-classifier.d.ts +19 -0
- package/dist/app/create-classifier.js +226 -14
- package/dist/app/extraction-files.d.ts +9 -0
- package/dist/app/extraction-files.js +28 -0
- package/dist/cli.js +58 -14
- package/dist/entities/boundary-view.d.ts +29 -0
- package/dist/entities/boundary-view.js +1 -0
- package/dist/entities/contracts.d.ts +77 -1
- package/dist/entities/contracts.js +7 -0
- package/dist/entities/cutout-raster.d.ts +7 -0
- package/dist/entities/cutout-raster.js +1 -0
- package/dist/entities/object-proposals.d.ts +53 -0
- package/dist/entities/object-proposals.js +8 -0
- package/dist/entities/representation.d.ts +225 -0
- package/dist/entities/representation.js +33 -0
- package/dist/entities/segmentation-metadata.d.ts +11 -0
- package/dist/entities/segmentation-metadata.js +1 -0
- package/dist/entities/segmentation-verification.d.ts +30 -0
- package/dist/entities/segmentation-verification.js +1 -0
- package/dist/entities/segmentation.d.ts +159 -0
- package/dist/entities/segmentation.js +5 -0
- package/dist/entities/whole-object.d.ts +128 -0
- package/dist/entities/whole-object.js +7 -0
- package/dist/features/choice.d.ts +1 -1
- package/dist/features/choice.js +2 -2
- package/dist/features/segmentation/box-check.d.ts +10 -0
- package/dist/features/segmentation/box-check.js +299 -0
- package/dist/features/segmentation/mask.d.ts +6 -0
- package/dist/features/segmentation/mask.js +89 -0
- package/dist/features/segmentation/packed-mask.d.ts +5 -0
- package/dist/features/segmentation/packed-mask.js +53 -0
- package/dist/index.d.ts +6 -1
- package/dist/infrastructure/boundary-view.d.ts +2 -0
- package/dist/infrastructure/boundary-view.js +263 -0
- package/dist/infrastructure/openrouter-common.d.ts +8 -8
- package/dist/infrastructure/openrouter-vision.d.ts +3 -0
- package/dist/infrastructure/openrouter-vision.js +5 -0
- package/dist/infrastructure/raster.d.ts +10 -1
- package/dist/infrastructure/raster.js +99 -4
- package/dist/infrastructure/segmentation/box-presentation.d.ts +2 -0
- package/dist/infrastructure/segmentation/box-presentation.js +136 -0
- package/dist/infrastructure/segmentation/cutout-raster.d.ts +3 -0
- package/dist/infrastructure/segmentation/cutout-raster.js +79 -0
- package/dist/infrastructure/segmentation/grabcut/index.d.ts +13 -0
- package/dist/infrastructure/segmentation/grabcut/index.js +118 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.d.ts +47 -0
- package/dist/infrastructure/segmentation/grabcut/worker-inference.js +260 -0
- package/dist/infrastructure/segmentation/index.d.ts +2 -0
- package/dist/infrastructure/segmentation/index.js +2 -0
- package/dist/infrastructure/segmentation/mobile-sam/index.d.ts +58 -0
- package/dist/infrastructure/segmentation/mobile-sam/index.js +472 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.d.ts +149 -0
- package/dist/infrastructure/segmentation/mobile-sam/worker-inference.js +845 -0
- package/dist/infrastructure/segmentation/native-child.d.ts +23 -0
- package/dist/infrastructure/segmentation/native-child.js +297 -0
- package/dist/infrastructure/segmentation/native-protocol.d.ts +923 -0
- package/dist/infrastructure/segmentation/native-protocol.js +242 -0
- package/dist/infrastructure/segmentation/native-worker.d.ts +1 -0
- package/dist/infrastructure/segmentation/native-worker.js +93 -0
- package/dist/infrastructure/segmentation/probe-backend.d.ts +1 -0
- package/dist/infrastructure/segmentation/probe-backend.js +31 -0
- package/dist/infrastructure/segmentation/proposal-presentation.d.ts +3 -0
- package/dist/infrastructure/segmentation/proposal-presentation.js +371 -0
- package/dist/infrastructure/segmentation/verify-asset.d.ts +4 -0
- package/dist/infrastructure/segmentation/verify-asset.js +32 -0
- package/dist/infrastructure/text-representation.d.ts +23 -0
- package/dist/infrastructure/text-representation.js +226 -0
- package/dist/infrastructure/vision-chat.d.ts +1 -1
- package/dist/infrastructure/vision-chat.js +13 -4
- package/dist/openai-compatible.d.ts +3 -0
- package/dist/openai-compatible.js +4 -0
- package/dist/openrouter.d.ts +2 -2
- package/dist/openrouter.js +1 -1
- package/dist/processes/boundary-state.d.ts +12 -0
- package/dist/processes/boundary-state.js +196 -0
- package/dist/processes/classify.d.ts +2 -1
- package/dist/processes/classify.js +21 -3
- package/dist/processes/extract-from-region.d.ts +19 -0
- package/dist/processes/extract-from-region.js +415 -0
- package/dist/processes/extract.d.ts +25 -0
- package/dist/processes/extract.js +223 -0
- package/dist/processes/locate.d.ts +2 -1
- package/dist/processes/locate.js +84 -11
- package/dist/processes/proposal-location.d.ts +19 -0
- package/dist/processes/proposal-location.js +396 -0
- package/dist/processes/whole-object.d.ts +7 -0
- package/dist/processes/whole-object.js +272 -0
- package/dist/segmentation.d.ts +10 -0
- package/dist/segmentation.js +4 -0
- package/dist/shared/input-budget.d.ts +7 -0
- package/dist/shared/input-budget.js +21 -0
- package/docs/0.2.0-plan.md +190 -0
- package/docs/README.ru.md +18 -5
- package/docs/acceptance.md +116 -3
- package/docs/api.md +8 -4
- package/docs/architecture.md +20 -7
- package/docs/benchmarks.md +10 -0
- package/docs/categorical-presence-port.md +26 -0
- package/docs/evidence/v02/baseline.json +1043 -0
- package/docs/evidence/v02/boundary-variants.md +17 -0
- package/docs/evidence/v02/box-confirmation-dev40/README.md +15 -0
- package/docs/evidence/v02/box-confirmation-dev40/component-refinement.json +246 -0
- package/docs/evidence/v02/box-confirmation-dev40/evaluation.json +1663 -0
- package/docs/evidence/v02/box-confirmation-dev40/provenance.json +130 -0
- package/docs/evidence/v02/box-confirmation-dev40/report.json +127 -0
- package/docs/evidence/v02/box-confirmation-dev40-freeze-20261020-v1.json +230 -0
- package/docs/evidence/v02/box-confirmation-method-selection-20261020-v1.json +85 -0
- package/docs/evidence/v02/box-heldout-cancelled-before-dispatch-20261021-v1.json +32 -0
- package/docs/evidence/v02/box-heldout-combined-seal-20261021-v1.json +89 -0
- package/docs/evidence/v02/box-heldout-evaluator-truth-seal-20261021-v1.json +61 -0
- package/docs/evidence/v02/box-heldout-exclusion-audit-20261020-v1.json +81 -0
- package/docs/evidence/v02/box-heldout-map-seal-20261021-v1.json +48 -0
- package/docs/evidence/v02/box-heldout-photo-seal-20261020-v1.json +62 -0
- package/docs/evidence/v02/box-heldout-run-freeze-20261021-v1.json +61 -0
- package/docs/evidence/v02/box-heldout-source-review-20261020-v1.json +134 -0
- package/docs/evidence/v02/box-heldout-ui-seal-20261020-v1.json +44 -0
- package/docs/evidence/v02/calculator-proof-root-review-20261020-v1.json +63 -0
- package/docs/evidence/v02/categorical-dev40-freeze.json +94 -0
- package/docs/evidence/v02/categorical-dev40-preserve.json +460 -0
- package/docs/evidence/v02/categorical-dev40-target-only.json +460 -0
- package/docs/evidence/v02/categorical-heldout-admission-20261020-v3.json +215 -0
- package/docs/evidence/v02/categorical-heldout-admission-20261020-v4.json +270 -0
- package/docs/evidence/v02/categorical-heldout-dispatch-authorization-20261020-v4.json +79 -0
- package/docs/evidence/v02/categorical-heldout-predispatch-20261020-v3.json +57 -0
- package/docs/evidence/v02/categorical-heldout-producer-source-map-v4.json +262 -0
- package/docs/evidence/v02/categorical-heldout-producer-source-map.json +263 -0
- package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v3.json +35 -0
- package/docs/evidence/v02/categorical-heldout-run-freeze-20261020-v4.json +35 -0
- package/docs/evidence/v02/categorical-heldout-v4/README.md +35 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-evaluation.json +2812 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-physical-receipts.json +15261 -0
- package/docs/evidence/v02/categorical-heldout-v4/candidate-provenance.json +131 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-evaluation.json +855 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-physical-receipts.json +4402 -0
- package/docs/evidence/v02/categorical-heldout-v4/control-provenance.json +31 -0
- package/docs/evidence/v02/categorical-heldout-v4/mask-normalized-exploratory.json +682 -0
- package/docs/evidence/v02/categorical-heldout-v4/paired-qualification.json +21 -0
- package/docs/evidence/v02/categorical-heldout-v4/report.json +258 -0
- package/docs/evidence/v02/categorical-presence-dev6.json +144 -0
- package/docs/evidence/v02/categorical-presence-dev6.md +18 -0
- package/docs/evidence/v02/categorical-vision-method-selection.json +90 -0
- package/docs/evidence/v02/checked-region-component-v1/README.md +7 -0
- package/docs/evidence/v02/checked-region-component-v1/evidence.json +311 -0
- package/docs/evidence/v02/checked-region-resource-interrupted-2b0d09f.json +102 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-receipt.json +167 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-4df544c-root-review.json +58 -0
- package/docs/evidence/v02/checked-region-segmentation-resource-987ac32-receipt.json +158 -0
- package/docs/evidence/v02/ci-012b935.json +17 -0
- package/docs/evidence/v02/ci-0c365cb.json +372 -0
- package/docs/evidence/v02/ci-185bde8.json +32 -0
- package/docs/evidence/v02/ci-24f849f.json +95 -0
- package/docs/evidence/v02/ci-25c19cd.json +375 -0
- package/docs/evidence/v02/ci-2922caf.json +375 -0
- package/docs/evidence/v02/ci-29357d7.json +29 -0
- package/docs/evidence/v02/ci-32aa90d.json +24 -0
- package/docs/evidence/v02/ci-35e3064.json +376 -0
- package/docs/evidence/v02/ci-4331b1b.json +384 -0
- package/docs/evidence/v02/ci-43b7426.json +376 -0
- package/docs/evidence/v02/ci-450439c.json +373 -0
- package/docs/evidence/v02/ci-46283fe.json +29 -0
- package/docs/evidence/v02/ci-4c9c09f.json +34 -0
- package/docs/evidence/v02/ci-5579646.json +27 -0
- package/docs/evidence/v02/ci-6f9cc15.json +127 -0
- package/docs/evidence/v02/ci-7c1051f.json +27 -0
- package/docs/evidence/v02/ci-9837888.json +34 -0
- package/docs/evidence/v02/ci-987ac32.json +29 -0
- package/docs/evidence/v02/ci-9d00fe5.json +25 -0
- package/docs/evidence/v02/ci-9f85acc.json +127 -0
- package/docs/evidence/v02/ci-be275a6.json +201 -0
- package/docs/evidence/v02/ci-c107ddf.json +372 -0
- package/docs/evidence/v02/ci-c35f67d.json +127 -0
- package/docs/evidence/v02/ci-c5eddd8.json +32 -0
- package/docs/evidence/v02/ci-d2042e0.json +372 -0
- package/docs/evidence/v02/ci-d684259.json +375 -0
- package/docs/evidence/v02/ci-e0c190b.json +127 -0
- package/docs/evidence/v02/ci-e551253.json +372 -0
- package/docs/evidence/v02/ci-f9d4633.json +29 -0
- package/docs/evidence/v02/dev1-proposal-evaluation.md +13 -0
- package/docs/evidence/v02/dev2-mobile-sam-proposal-oracle.md +21 -0
- package/docs/evidence/v02/dev2-proposal-evaluation.md +21 -0
- package/docs/evidence/v02/fresh-development.md +16 -0
- package/docs/evidence/v02/fresh-native-numeric/artifact-hashes.json +9 -0
- package/docs/evidence/v02/fresh-native-numeric/evaluation-root-v1.json +568 -0
- package/docs/evidence/v02/fresh-native-numeric/run-manifest.json +342 -0
- package/docs/evidence/v02/fresh-native-numeric/summary.json +5654 -0
- package/docs/evidence/v02/fresh-native-outline-axis/artifact-hashes.json +9 -0
- package/docs/evidence/v02/fresh-native-outline-axis/evaluation-root-v1.json +568 -0
- package/docs/evidence/v02/fresh-native-outline-axis/run-manifest.json +378 -0
- package/docs/evidence/v02/fresh-native-outline-axis/summary.json +5605 -0
- package/docs/evidence/v02/fresh-text/README.md +23 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-contours-v1/original-summary.json +4416 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-luma-v1/original-summary.json +4647 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/classify-followup-summary.json +846 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/ascii-svg-layered-v1/original-summary.json +1789 -0
- package/docs/evidence/v02/fresh-text/no-image-control/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/no-image-control/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/no-image-control/original-summary.json +3953 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/palette-grid-v1/original-summary.json +3974 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/classify-followup-summary.json +1646 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/pixel-rle-v1/original-summary.json +4945 -0
- package/docs/evidence/v02/fresh-text/report.json +284 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-run-manifest.json +405 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/classify-followup-summary.json +846 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/evaluation.json +568 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/original-run-manifest.json +404 -0
- package/docs/evidence/v02/fresh-text/svg-contours-v1/original-summary.json +2189 -0
- package/docs/evidence/v02/heldout-evaluation-20261020.md +37 -0
- package/docs/evidence/v02/heldout-input-derivation.md +18 -0
- package/docs/evidence/v02/integration-0c365cb.json +90 -0
- package/docs/evidence/v02/integration-25c19cd.json +52 -0
- package/docs/evidence/v02/integration-35e3064.json +41 -0
- package/docs/evidence/v02/integration-4331b1b.json +42 -0
- package/docs/evidence/v02/integration-4c9c09f.json +46 -0
- package/docs/evidence/v02/integration-8010aad.json +48 -0
- package/docs/evidence/v02/integration-c1aa640.json +41 -0
- package/docs/evidence/v02/integration-eea1790.json +46 -0
- package/docs/evidence/v02/integration-fa82e65.json +42 -0
- package/docs/evidence/v02/jpeg-transport-offline.json +268 -0
- package/docs/evidence/v02/jpeg-transport-offline.md +7 -0
- package/docs/evidence/v02/local-archive-cleanup.json +59 -0
- package/docs/evidence/v02/native-base64-after.json +30 -0
- package/docs/evidence/v02/native-base64-before.json +32 -0
- package/docs/evidence/v02/native-checked-region-windows-46283fe.json +248 -0
- package/docs/evidence/v02/native-checked-region-windows-987ac32.json +141 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3-run2.json +148 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3-run3.json +148 -0
- package/docs/evidence/v02/native-grabcut-windows-4c494a3.json +56 -0
- package/docs/evidence/v02/native-proposal-windows-0c365cb.json +148 -0
- package/docs/evidence/v02/native-proposal-windows-450439c.json +156 -0
- package/docs/evidence/v02/native-proposal-windows-4c9c09f-retry1.json +147 -0
- package/docs/evidence/v02/native-proposal-windows-4c9c09f.json +52 -0
- package/docs/evidence/v02/native-region-windows-efc9318.json +163 -0
- package/docs/evidence/v02/native-windows-eea1790-baseline.json +198 -0
- package/docs/evidence/v02/native-windows-eea1790.json +228 -0
- package/docs/evidence/v02/ordinary-luna-axis/run-manifest.json +99 -0
- package/docs/evidence/v02/ordinary-luna-axis/summary.json +811 -0
- package/docs/evidence/v02/owned-temp-cleanup-20261020-v1.json +28 -0
- package/docs/evidence/v02/presentation-paired-20261020.json +1438 -0
- package/docs/evidence/v02/proposal-resource-soak-261dc23.json +201 -0
- package/docs/evidence/v02/proposal-resource-soak-261dc23.md +15 -0
- package/docs/evidence/v02/proposal-resource-soak-450439c-receipt.md +13 -0
- package/docs/evidence/v02/reconstructed-c03-box.json +41 -0
- package/docs/evidence/v02/region-seeded-dev-v1/README.md +17 -0
- package/docs/evidence/v02/region-seeded-dev-v1/evaluation.json +260 -0
- package/docs/evidence/v02/region-seeded-dev-v2/README.md +15 -0
- package/docs/evidence/v02/region-seeded-dev-v2/evaluation.json +232 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/README.md +9 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/control-identity-failure.json +22 -0
- package/docs/evidence/v02/region-seeded-dev-v3-candidate-only/evaluation.json +160 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/README.md +9 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/attempt-accounting.json +55 -0
- package/docs/evidence/v02/region-seeded-dev-v3-control-r2/evaluation.json +136 -0
- package/docs/evidence/v02/region-seeded-development-control-r2-freeze-20261021.json +132 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v1.json +167 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v2.json +186 -0
- package/docs/evidence/v02/region-seeded-development-freeze-20261021-v3.json +205 -0
- package/docs/evidence/v02/region-seeded-heldout-cancelled-before-dispatch-20261021-v2.json +20 -0
- package/docs/evidence/v02/region-seeded-heldout-dispatch-authorization-20261021-v3.json +47 -0
- package/docs/evidence/v02/region-seeded-heldout-readiness-audit-20261021-v3.json +125 -0
- package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v2.json +234 -0
- package/docs/evidence/v02/region-seeded-heldout-run-freeze-20261021-v3.json +357 -0
- package/docs/evidence/v02/region-seeded-heldout-v3/README.md +19 -0
- package/docs/evidence/v02/region-seeded-heldout-v3/evaluation-summary.json +445 -0
- package/docs/evidence/v02/region-seeded-method-selection-20261021-v2.json +66 -0
- package/docs/evidence/v02/region-seeded-method-selection-20261021-v3.json +120 -0
- package/docs/evidence/v02/region-segmentation-resource-0ba4c87-receipt.json +156 -0
- package/docs/evidence/v02/resource-soak-linux-8010aad.json +125 -0
- package/docs/evidence/v02/screen-v2-terminal-evaluation.md +22 -0
- package/docs/evidence/v02/seed-outline/run-manifest.json +59 -0
- package/docs/evidence/v02/seed-outline/summary.json +487 -0
- package/docs/evidence/v02/seed-unbounded/run-manifest.json +80 -0
- package/docs/evidence/v02/seed-unbounded/summary.json +730 -0
- package/docs/evidence/v02/segmentation/README.md +21 -0
- package/docs/evidence/v02/segmentation/component-comparison-summary.json +240 -0
- package/docs/evidence/v02/segmentation/provenance/MOBILE-SAM-LICENSE.txt +201 -0
- package/docs/evidence/v02/segmentation/provenance/OPENCV-LICENSE.txt +202 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-download-receipt.json +29 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-graph-audit.json +214 -0
- package/docs/evidence/v02/segmentation/provenance/mobile-sam-model-metadata.json +166 -0
- package/docs/evidence/v02/split-choice-noul-dev6.json +72 -0
- package/docs/evidence/v02/split-choice-noul-dev6.md +11 -0
- package/docs/evidence/v02/supported-vision-screen-20261020.md +65 -0
- package/docs/evidence/v02/wesnoth-1.16.11-minimap-projection-source-audit.md +56 -0
- package/docs/evidence/v02/wesnoth-proof-root-review-20261020-v1.json +76 -0
- package/docs/operations.md +6 -0
- package/docs/plan.md +2 -0
- package/docs/publishing.md +10 -1
- package/docs/research/text-transport-audit.md +66 -0
- package/docs/v02-usage.md +162 -0
- package/docs/vision-results.md +29 -2
- package/package.json +30 -5
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { pixelRectSchema } from '../../entities/contracts.js';
|
|
3
|
+
/** Validate canonical RFC 4648 base64 without a large repeated-group RegExp. */
|
|
4
|
+
function isCanonicalBase64(value) {
|
|
5
|
+
if (value.length % 4 !== 0)
|
|
6
|
+
return false;
|
|
7
|
+
if (value.length === 0)
|
|
8
|
+
return true;
|
|
9
|
+
const alphabet = (code) => {
|
|
10
|
+
if (code >= 65 && code <= 90)
|
|
11
|
+
return code - 65;
|
|
12
|
+
if (code >= 97 && code <= 122)
|
|
13
|
+
return code - 97 + 26;
|
|
14
|
+
if (code >= 48 && code <= 57)
|
|
15
|
+
return code - 48 + 52;
|
|
16
|
+
if (code === 43)
|
|
17
|
+
return 62;
|
|
18
|
+
if (code === 47)
|
|
19
|
+
return 63;
|
|
20
|
+
return -1;
|
|
21
|
+
};
|
|
22
|
+
const length = value.length;
|
|
23
|
+
const padding = value.charCodeAt(length - 1) === 61 ? (value.charCodeAt(length - 2) === 61 ? 2 : 1) : 0;
|
|
24
|
+
const contentEnd = length - padding;
|
|
25
|
+
for (let index = 0; index < contentEnd; index++)
|
|
26
|
+
if (alphabet(value.charCodeAt(index)) < 0)
|
|
27
|
+
return false;
|
|
28
|
+
for (let index = contentEnd; index < length; index++)
|
|
29
|
+
if (value.charCodeAt(index) !== 61)
|
|
30
|
+
return false;
|
|
31
|
+
// Padding must encode zero bits so there is exactly one spelling per byte sequence.
|
|
32
|
+
if (padding === 2)
|
|
33
|
+
return (alphabet(value.charCodeAt(length - 3)) & 15) === 0;
|
|
34
|
+
if (padding === 1)
|
|
35
|
+
return (alphabet(value.charCodeAt(length - 2)) & 3) === 0;
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
function base64Schema(maxLength) {
|
|
39
|
+
return z
|
|
40
|
+
.string()
|
|
41
|
+
.max(maxLength)
|
|
42
|
+
.refine((value) => value.length <= maxLength && isCanonicalBase64(value));
|
|
43
|
+
}
|
|
44
|
+
const modelOptionsSchema = z
|
|
45
|
+
.object({
|
|
46
|
+
encoderPath: z.string().min(1).max(4096),
|
|
47
|
+
decoderPath: z.string().min(1).max(4096),
|
|
48
|
+
executionProvider: z.enum(['cpu', 'dml']),
|
|
49
|
+
deviceId: z.number().int().min(0).max(32).optional(),
|
|
50
|
+
threads: z.number().int().min(1).max(8).default(2),
|
|
51
|
+
})
|
|
52
|
+
.strict();
|
|
53
|
+
const mobileSamProbeSchema = z
|
|
54
|
+
.object({
|
|
55
|
+
id: z.string().uuid(),
|
|
56
|
+
kind: z.literal('probe-mobile-sam'),
|
|
57
|
+
options: modelOptionsSchema,
|
|
58
|
+
})
|
|
59
|
+
.strict();
|
|
60
|
+
const grabCutProbeSchema = z
|
|
61
|
+
.object({
|
|
62
|
+
id: z.string().uuid(),
|
|
63
|
+
kind: z.literal('probe-grabcut'),
|
|
64
|
+
assetPath: z.string().min(1).max(4096),
|
|
65
|
+
})
|
|
66
|
+
.strict();
|
|
67
|
+
const mobileSamRequestSchema = z
|
|
68
|
+
.object({
|
|
69
|
+
id: z.string().uuid(),
|
|
70
|
+
kind: z.literal('mobile-sam'),
|
|
71
|
+
width: z.number().int().positive().max(16384),
|
|
72
|
+
height: z.number().int().positive().max(16384),
|
|
73
|
+
rgba: base64Schema(90_000_000),
|
|
74
|
+
seedRegion: pixelRectSchema,
|
|
75
|
+
wholeRegion: pixelRectSchema,
|
|
76
|
+
roi: pixelRectSchema,
|
|
77
|
+
prompt: z.enum(['whole-region', 'seed-region']).default('whole-region'),
|
|
78
|
+
options: modelOptionsSchema,
|
|
79
|
+
})
|
|
80
|
+
.strict()
|
|
81
|
+
.superRefine((value, context) => {
|
|
82
|
+
if (value.width * value.height > 16_777_216)
|
|
83
|
+
context.addIssue({ code: 'custom', message: 'Image exceeds segmentation pixel limit' });
|
|
84
|
+
for (const region of [value.seedRegion, value.wholeRegion, value.roi])
|
|
85
|
+
if (region.left + region.width > value.width || region.top + region.height > value.height)
|
|
86
|
+
context.addIssue({ code: 'custom', message: 'Segmentation region is outside the source' });
|
|
87
|
+
});
|
|
88
|
+
const mobileSamExpandRequestSchema = z
|
|
89
|
+
.object({
|
|
90
|
+
id: z.string().uuid(),
|
|
91
|
+
kind: z.literal('mobile-sam-expand'),
|
|
92
|
+
width: z.number().int().positive().max(16384),
|
|
93
|
+
height: z.number().int().positive().max(16384),
|
|
94
|
+
rgba: base64Schema(90_000_000),
|
|
95
|
+
previousMask: base64Schema(2_796_204),
|
|
96
|
+
seedRegion: pixelRectSchema,
|
|
97
|
+
wholeRegion: pixelRectSchema,
|
|
98
|
+
roi: pixelRectSchema,
|
|
99
|
+
prompt: z.enum(['whole-region', 'seed-region']).default('whole-region'),
|
|
100
|
+
options: modelOptionsSchema,
|
|
101
|
+
})
|
|
102
|
+
.strict()
|
|
103
|
+
.superRefine((value, context) => {
|
|
104
|
+
if (value.width * value.height > 16_777_216)
|
|
105
|
+
context.addIssue({ code: 'custom', message: 'Image exceeds segmentation pixel limit' });
|
|
106
|
+
const expectedMaskBytes = Math.ceil((value.width * value.height) / 8);
|
|
107
|
+
const padding = value.previousMask.endsWith('==') ? 2 : value.previousMask.endsWith('=') ? 1 : 0;
|
|
108
|
+
const decodedMaskBytes = (value.previousMask.length / 4) * 3 - padding;
|
|
109
|
+
if (decodedMaskBytes !== expectedMaskBytes)
|
|
110
|
+
context.addIssue({
|
|
111
|
+
code: 'custom',
|
|
112
|
+
message: 'Previous mask length does not match dimensions',
|
|
113
|
+
});
|
|
114
|
+
for (const region of [value.seedRegion, value.wholeRegion, value.roi])
|
|
115
|
+
if (region.left + region.width > value.width || region.top + region.height > value.height)
|
|
116
|
+
context.addIssue({ code: 'custom', message: 'Segmentation region is outside the source' });
|
|
117
|
+
});
|
|
118
|
+
// Proposal replies are deliberately packed before IPC; 36 full-resolution byte masks
|
|
119
|
+
// would exceed the native child stdout budget by a wide margin.
|
|
120
|
+
const mobileSamProposalsRequestSchema = z
|
|
121
|
+
.object({
|
|
122
|
+
id: z.string().uuid(),
|
|
123
|
+
kind: z.literal('mobile-sam-proposals'),
|
|
124
|
+
width: z.number().int().positive().max(16384),
|
|
125
|
+
height: z.number().int().positive().max(16384),
|
|
126
|
+
rgba: base64Schema(11_200_000),
|
|
127
|
+
seedRegion: pixelRectSchema,
|
|
128
|
+
roi: pixelRectSchema,
|
|
129
|
+
options: modelOptionsSchema.extend({ executionProvider: z.literal('cpu') }),
|
|
130
|
+
})
|
|
131
|
+
.strict()
|
|
132
|
+
.superRefine((value, context) => {
|
|
133
|
+
if (value.width * value.height > 2_097_152)
|
|
134
|
+
context.addIssue({ code: 'custom', message: 'Image exceeds proposal pixel limit' });
|
|
135
|
+
for (const region of [value.seedRegion, value.roi])
|
|
136
|
+
if (region.left + region.width > value.width || region.top + region.height > value.height)
|
|
137
|
+
context.addIssue({ code: 'custom', message: 'Proposal region is outside the source' });
|
|
138
|
+
});
|
|
139
|
+
const grabCutRequestSchema = z
|
|
140
|
+
.object({
|
|
141
|
+
id: z.string().uuid(),
|
|
142
|
+
kind: z.literal('grabcut'),
|
|
143
|
+
width: z.number().int().positive().max(16384),
|
|
144
|
+
height: z.number().int().positive().max(16384),
|
|
145
|
+
rgba: base64Schema(90_000_000),
|
|
146
|
+
seedRegion: pixelRectSchema,
|
|
147
|
+
wholeRegion: pixelRectSchema,
|
|
148
|
+
roi: pixelRectSchema,
|
|
149
|
+
prompt: z.enum(['whole-region', 'seed-region']).default('whole-region'),
|
|
150
|
+
assetPath: z.string().min(1).max(4096),
|
|
151
|
+
})
|
|
152
|
+
.strict()
|
|
153
|
+
.superRefine((value, context) => {
|
|
154
|
+
if (value.width * value.height > 16_777_216)
|
|
155
|
+
context.addIssue({ code: 'custom', message: 'Image exceeds segmentation pixel limit' });
|
|
156
|
+
for (const region of [value.seedRegion, value.wholeRegion, value.roi])
|
|
157
|
+
if (region.left + region.width > value.width || region.top + region.height > value.height)
|
|
158
|
+
context.addIssue({ code: 'custom', message: 'Segmentation region is outside the source' });
|
|
159
|
+
});
|
|
160
|
+
export const nativeSegmentationRequestSchema = z.union([
|
|
161
|
+
mobileSamProbeSchema,
|
|
162
|
+
grabCutProbeSchema,
|
|
163
|
+
mobileSamProposalsRequestSchema,
|
|
164
|
+
mobileSamRequestSchema,
|
|
165
|
+
mobileSamExpandRequestSchema,
|
|
166
|
+
grabCutRequestSchema,
|
|
167
|
+
]);
|
|
168
|
+
export const nativeSegmentationReplySchema = z
|
|
169
|
+
.object({
|
|
170
|
+
id: z.string().uuid(),
|
|
171
|
+
status: z.literal('segmented'),
|
|
172
|
+
width: z.number().int().positive(),
|
|
173
|
+
height: z.number().int().positive(),
|
|
174
|
+
mask: base64Schema(32_000_000),
|
|
175
|
+
method: z.string().min(1).max(128),
|
|
176
|
+
})
|
|
177
|
+
.strict();
|
|
178
|
+
export const nativeMobileSamExpansionReplySchema = z.discriminatedUnion('status', [
|
|
179
|
+
z
|
|
180
|
+
.object({
|
|
181
|
+
id: z.string().uuid(),
|
|
182
|
+
status: z.literal('expanded'),
|
|
183
|
+
width: z.number().int().positive().max(16384),
|
|
184
|
+
height: z.number().int().positive().max(16384),
|
|
185
|
+
mask: base64Schema(2_796_204),
|
|
186
|
+
method: z.literal('mobile-sam-enclosing-mask-v1'),
|
|
187
|
+
qualityScore: z.number().finite(),
|
|
188
|
+
})
|
|
189
|
+
.strict(),
|
|
190
|
+
z
|
|
191
|
+
.object({
|
|
192
|
+
id: z.string().uuid(),
|
|
193
|
+
status: z.literal('unknown'),
|
|
194
|
+
reason: z.literal('no-enclosing-mask'),
|
|
195
|
+
width: z.number().int().positive().max(16384),
|
|
196
|
+
height: z.number().int().positive().max(16384),
|
|
197
|
+
method: z.literal('mobile-sam-enclosing-mask-v1'),
|
|
198
|
+
})
|
|
199
|
+
.strict(),
|
|
200
|
+
]);
|
|
201
|
+
export const nativeObjectProposalReplySchema = z
|
|
202
|
+
.object({
|
|
203
|
+
id: z.string().uuid(),
|
|
204
|
+
status: z.literal('proposals'),
|
|
205
|
+
width: z.number().int().positive().max(16384),
|
|
206
|
+
height: z.number().int().positive().max(16384),
|
|
207
|
+
proposals: z
|
|
208
|
+
.array(z
|
|
209
|
+
.object({
|
|
210
|
+
id: z.string().regex(/^C(?:0[0-9]|1[0-9]|2[0-9]|3[0-5])$/),
|
|
211
|
+
mask: base64Schema(349_528),
|
|
212
|
+
qualityScore: z.number().finite(),
|
|
213
|
+
})
|
|
214
|
+
.strict())
|
|
215
|
+
.length(36),
|
|
216
|
+
})
|
|
217
|
+
.strict();
|
|
218
|
+
export const nativeProbeReplySchema = z
|
|
219
|
+
.object({
|
|
220
|
+
id: z.string().uuid(),
|
|
221
|
+
status: z.literal('ready'),
|
|
222
|
+
backend: z.enum(['mobile-sam', 'grabcut']),
|
|
223
|
+
})
|
|
224
|
+
.strict();
|
|
225
|
+
export const nativeErrorReplySchema = z
|
|
226
|
+
.object({
|
|
227
|
+
id: z.string().uuid(),
|
|
228
|
+
status: z.literal('error'),
|
|
229
|
+
code: z.enum([
|
|
230
|
+
'INVALID_INPUT',
|
|
231
|
+
'INVALID_RESPONSE',
|
|
232
|
+
'TIMEOUT',
|
|
233
|
+
'ABORTED',
|
|
234
|
+
'CAPACITY',
|
|
235
|
+
'DISPOSED',
|
|
236
|
+
'PROVIDER',
|
|
237
|
+
'UNSUPPORTED',
|
|
238
|
+
'RESOURCE_LIMIT',
|
|
239
|
+
]),
|
|
240
|
+
message: z.string().min(1).max(300),
|
|
241
|
+
})
|
|
242
|
+
.strict();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { nativeSegmentationRequestSchema } from './native-protocol.js';
|
|
2
|
+
import { ClassifierError } from '../../entities/errors.js';
|
|
3
|
+
import { probeMobileSam, runMobileSamExpandTask, runMobileSamObjectProposalTask, runMobileSamTask, } from './mobile-sam/worker-inference.js';
|
|
4
|
+
import { probeGrabCut, runGrabCutTask } from './grabcut/worker-inference.js';
|
|
5
|
+
const stopOnParentLoss = () => {
|
|
6
|
+
process.exit(1);
|
|
7
|
+
};
|
|
8
|
+
let telemetryTimer;
|
|
9
|
+
process.on('disconnect', stopOnParentLoss);
|
|
10
|
+
process.on('message', (message) => {
|
|
11
|
+
if (typeof message !== 'object' ||
|
|
12
|
+
message === null ||
|
|
13
|
+
!('type' in message) ||
|
|
14
|
+
message.type !== 'telemetry' ||
|
|
15
|
+
!('enabled' in message))
|
|
16
|
+
return;
|
|
17
|
+
if (message.enabled === true && !telemetryTimer) {
|
|
18
|
+
sendMemory();
|
|
19
|
+
telemetryTimer = setInterval(() => process.send?.({ type: 'memory', memory: process.memoryUsage() }), 1000);
|
|
20
|
+
telemetryTimer.unref();
|
|
21
|
+
}
|
|
22
|
+
else if (message.enabled === false && telemetryTimer) {
|
|
23
|
+
clearInterval(telemetryTimer);
|
|
24
|
+
telemetryTimer = undefined;
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
process.send?.({ type: 'ready' });
|
|
28
|
+
async function main() {
|
|
29
|
+
const chunks = [];
|
|
30
|
+
for await (const chunk of process.stdin)
|
|
31
|
+
chunks.push(Buffer.from(chunk));
|
|
32
|
+
const raw = JSON.parse(Buffer.concat(chunks).toString('utf8'));
|
|
33
|
+
const request = nativeSegmentationRequestSchema.parse(raw);
|
|
34
|
+
activeId = request.id;
|
|
35
|
+
const reply = request.kind === 'mobile-sam-expand'
|
|
36
|
+
? await runMobileSamExpandTask(request)
|
|
37
|
+
: request.kind === 'mobile-sam-proposals'
|
|
38
|
+
? await runMobileSamObjectProposalTask(request)
|
|
39
|
+
: request.kind === 'mobile-sam'
|
|
40
|
+
? await runMobileSamTask(request)
|
|
41
|
+
: request.kind === 'grabcut'
|
|
42
|
+
? await runGrabCutTask(request)
|
|
43
|
+
: request.kind === 'probe-mobile-sam'
|
|
44
|
+
? await probeMobileSam(request.options).then(() => ({
|
|
45
|
+
id: request.id,
|
|
46
|
+
status: 'ready',
|
|
47
|
+
backend: 'mobile-sam',
|
|
48
|
+
}))
|
|
49
|
+
: await probeGrabCut(request.assetPath).then(() => ({
|
|
50
|
+
id: request.id,
|
|
51
|
+
status: 'ready',
|
|
52
|
+
backend: 'grabcut',
|
|
53
|
+
}));
|
|
54
|
+
sendMemory();
|
|
55
|
+
await new Promise((resolve, reject) => {
|
|
56
|
+
process.stdout.write(JSON.stringify(reply), (error) => {
|
|
57
|
+
if (error)
|
|
58
|
+
reject(error);
|
|
59
|
+
else
|
|
60
|
+
resolve();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
if (telemetryTimer)
|
|
64
|
+
clearInterval(telemetryTimer);
|
|
65
|
+
process.off('disconnect', stopOnParentLoss);
|
|
66
|
+
process.disconnect();
|
|
67
|
+
}
|
|
68
|
+
main().catch(async (error) => {
|
|
69
|
+
const safe = classifyFailure(error);
|
|
70
|
+
await new Promise((resolve) => {
|
|
71
|
+
process.stdout.write(JSON.stringify({ id: activeId, status: 'error', ...safe }), () => resolve());
|
|
72
|
+
});
|
|
73
|
+
if (telemetryTimer)
|
|
74
|
+
clearInterval(telemetryTimer);
|
|
75
|
+
process.off('disconnect', stopOnParentLoss);
|
|
76
|
+
process.disconnect();
|
|
77
|
+
});
|
|
78
|
+
let activeId = '';
|
|
79
|
+
function sendMemory() {
|
|
80
|
+
process.send?.({ type: 'memory', memory: process.memoryUsage() });
|
|
81
|
+
}
|
|
82
|
+
function classifyFailure(error) {
|
|
83
|
+
if (error instanceof ClassifierError)
|
|
84
|
+
return { code: error.code, message: error.message.slice(0, 300) };
|
|
85
|
+
const message = error instanceof Error ? error.message : 'Native segmentation failed';
|
|
86
|
+
if (/unavailable|not supported|not found|cannot find|module|pinned|asset|execution provider/i.test(message))
|
|
87
|
+
return { code: 'UNSUPPORTED', message: 'Required native backend or asset is unavailable' };
|
|
88
|
+
if (/limit|too large|queue full/i.test(message))
|
|
89
|
+
return { code: 'RESOURCE_LIMIT', message: 'Native segmentation exceeded a resource limit' };
|
|
90
|
+
if (/invalid|unexpected|mismatch|incompatible|non-finite/i.test(message))
|
|
91
|
+
return { code: 'INVALID_RESPONSE', message: 'Native backend returned invalid data' };
|
|
92
|
+
return { code: 'PROVIDER', message: 'Native segmentation backend failed' };
|
|
93
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function probeBackend(workerUrl: URL, backend: 'mobile-sam' | 'grabcut', payload: Record<string, unknown>): Promise<void>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ClassifierError } from '../../entities/errors.js';
|
|
2
|
+
import { NativeChildPool } from './native-child.js';
|
|
3
|
+
import { nativeErrorReplySchema, nativeProbeReplySchema } from './native-protocol.js';
|
|
4
|
+
export async function probeBackend(workerUrl, backend, payload) {
|
|
5
|
+
const pool = new NativeChildPool({
|
|
6
|
+
workerUrl,
|
|
7
|
+
maxActive: 1,
|
|
8
|
+
maxWaiting: 2,
|
|
9
|
+
jobTimeoutMs: 10_000,
|
|
10
|
+
abortGraceMs: 250,
|
|
11
|
+
encode: (job) => Buffer.from(JSON.stringify({ id: job.id, ...job.payload })),
|
|
12
|
+
decode: (raw, id) => {
|
|
13
|
+
const error = nativeErrorReplySchema.safeParse(raw);
|
|
14
|
+
if (error.success) {
|
|
15
|
+
if (error.data.id !== id)
|
|
16
|
+
throw new ClassifierError('INVALID_RESPONSE', 'Backend probe error ID mismatch');
|
|
17
|
+
throw new ClassifierError(error.data.code, error.data.message);
|
|
18
|
+
}
|
|
19
|
+
const reply = nativeProbeReplySchema.safeParse(raw);
|
|
20
|
+
if (!reply.success || reply.data.id !== id || reply.data.backend !== backend)
|
|
21
|
+
throw new ClassifierError('INVALID_RESPONSE', 'Native backend probe returned an invalid reply');
|
|
22
|
+
return reply.data;
|
|
23
|
+
},
|
|
24
|
+
});
|
|
25
|
+
try {
|
|
26
|
+
await pool.run({ ...payload, kind: `probe-${backend}` }, new AbortController().signal);
|
|
27
|
+
}
|
|
28
|
+
finally {
|
|
29
|
+
await pool.dispose();
|
|
30
|
+
}
|
|
31
|
+
}
|