Import existing pipeline results#916
Conversation
✅ Deploy Preview for antenna-preview canceled.
|
|
@mihow confirm that sequence_ids are coming through as occurrences. Every occurrence has a single detection in the test data imported, but that could just be the data as well, since they are snapshots. |
Bring the importer branch up to date with main and resolve conflicts in three files. Resolutions: ami/main/models.py - get_or_create_default_deployment: keep the branch's parameterized find-or-create (the importer needs to create named deployments) while adopting main's canonical "Default Station" name and latitude/longitude=0 defaults on the create path. - group_images_into_events: take main's event-tracking loop body and its post-loop occurrence realignment, which subsumes the branch's per-iteration occurrence update. Keep the branch's ungrouped-occurrence warning alongside main's cached-count refresh comment. ami/ml/models/pipeline.py - get_or_create_algorithm_and_category_map: take main's rewrite (has_valid_category_map flow); drop the branch's now-dead upfront category-map block. - save_results: merge both algorithm paths under main's algorithms_known naming. create_new_algorithms keeps the importer's register-from-results behavior; otherwise use main's pre-registered path plus the detection_algorithm extraction and null-detection marking (#1310). Keep the branch's deployments_used tracking and the merged return that carries both algorithms and deployments. - get_or_create_detection: keep the branch's externally-hosted crop-URL check so imports regenerate crops for non-URL paths. - process_images: take main's signature (adds reprocess_all_images, used by the method body). ami/ml/tests.py - Take main's superset imports and its PipelineNotConfigured expectation (a ValueError subclass) for the unknown-algorithm test. Verified: ami.exports.tests.test_imports + ami.ml.tests (67 ok, 2 skipped), ami.main.tests event tests (11 ok), ami.jobs regroup tests (4 ok). Co-Authored-By: Claude <noreply@anthropic.com>
✅ Deploy Preview for antenna-ssec canceled.
|
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for antenna-ssec canceled.
|
Algorithms must be registered with Antenna before a pipeline processes images, but this was only enforced at runtime and never written down. - Add an "Algorithm and Category Map Registration" section to the processing services README explaining that algorithms (and category maps for classifiers) must be declared in the /info endpoint and are picked up when the processing service is registered. The per-result algorithms field is ignored. Registering only through /info avoids the near-duplicate Algorithm records that appear when the same algorithm is reported with slightly different names across responses (algorithms are currently identified by name + version). - Fix the deprecation marker on PipelineResultsResponse.algorithms: the kwarg was misspelled "depreciated" (a no-op that emitted a junk schema key). Using "deprecated=True" now emits the standard OpenAPI "deprecated: true" marker, and the field description explains why the field is ignored. Co-Authored-By: Claude <noreply@anthropic.com>
Surface save_results' create_new_algorithms option on the import_pipeline_results management command. Without it, imports require the pipeline's algorithms to already be registered (via a processing service's /info endpoint) and raise PipelineNotConfigured otherwise. With the flag, the importer registers algorithms and category maps from the results file, which is the common case when importing externally-produced results (e.g. from the AMI Data Companion) into an instance that has never seen that pipeline. Co-Authored-By: Claude <noreply@anthropic.com>
Add a module docstring and expand the command help to explain what the import_pipeline_results command accepts and what it does not, so users do not assume it handles inputs it cannot. - Input is a single PipelineResultsResponse JSON file (the output of the AMI Data Companion's "export api-occurrences" command). - One file at a time: the Data Companion splits large exports into *_batch_NNN.json files; there is no directory/glob/zip input yet. - Results-only: the project must already exist, and deployment configuration (location, device, site) is not imported. - Each detection becomes its own occurrence. The data model supports multi-detection occurrences (tracks) via Detection.occurrence, but the results schema has no field to carry those associations yet, so imported results are not grouped into tracks. Co-Authored-By: Claude <noreply@anthropic.com>
Summary
This PR lets an operator load machine-learning results that were produced outside Antenna back into a project, so the captures, detections, classifications, and occurrences show up in the platform as if Antenna had run the pipeline itself. It is aimed at people who process their images locally with the AMI Data Companion (ADC): ADC can crunch through local images far faster than triggering processing from Antenna today, and until now there was no clean way to get that work back into the web platform. The matching export side is ami-data-companion#82.
The core of the change is a set of new options on
Pipeline.save_results()that let it create the supporting records an external result set needs (deployments, source images), plus a management command that reads a saved results file and feeds it through that path. Importantly,save_results()is the same function the live processing path uses — both the synchronous API flow and the async (PSv2/NATS) flow ingest aPipelineResultsResponsethrough it — so imported data is built exactly like processed data, and the importer is a thin wrapper rather than a parallel code path.This branch has also been brought up to date with
main(it had drifted behind a large batch of pipeline and event-grouping changes); the conflicts insave_results,group_images_into_events, and the algorithm-registration helpers were resolved so the importer sits on top ofmain's current behaviour.How to use
Process images locally with ADC, export the results, then import a results file into an existing Antenna project:
PipelineResultsResponse— the schema processing services already return, and the output of ADC'sexport api-occurrencescommand./infoendpoint), otherwise the import raisesPipelineNotConfigured. Pass--create-new-algorithmsto register them from the results file instead — the common case when importing into an instance that has never seen that pipeline.*_batch_001.json,*_batch_002.json… files; import them one at a time (see follow-ups for multi-file/zip support).List of Changes
import_pipeline_resultsmanagement command parses aPipelineResultsResponseJSON file and callssave_results. Supports--project,--public-base-url,--create-new-algorithms, and--dry-run.save_results()gainscreate_missing_source_images,project_id, andpublic_base_url. New helpersget_or_create_deployments()andcreate_source_images()build the missing records and remap external IDs to internal ones.DeploymentResponseschema;SourceImageResponse.deploymentandPipelineResultsResponse.deploymentsadded to the ML API schema.--create-new-algorithmsflag surfaces the existingcreate_new_algorithmspath onsave_results; default off so the strict, pre-registered flow stays the norm.get_or_create_detection()only reuses a crop URL when it is anhttp(s)URL; relative paths (or none) fall through to local crop generation.get_or_create_default_deployment()takes anameparameter (keepsmain's "Default Station" default andlatitude/longitude = 0).processing_services/README.md; fixed the misspelleddepreciated=TrueonPipelineResultsResponse.algorithmstodeprecated=True(now emits the standard OpenAPI marker) and explained why the field is ignored.main.origin/main; resolved conflicts inami/main/models.py,ami/ml/models/pipeline.py,ami/ml/tests.py. The importer'screate_new_algorithmspath is preserved alongsidemain's pre-registered path and its null-detection marking (#1310).Detailed Description
API contract additions. The processing-service schema now models deployments so a results file can say which station each capture came from.
SourceImageResponsegained an optionaldeployment, andPipelineResultsResponsegained an optionaldeploymentslist, both typed as the newDeploymentResponse(id/name/key).save_resultsimport mode. When called withcreate_missing_source_images=Trueand aproject_id,save_resultsfirst ensures the referenced deployments exist (get_or_create_deployments), then creates any missing source images (create_source_images, usingpublic_base_urlto resolve relative image paths), remaps the external IDs in the results to the new internal IDs, and only then runs the normal detection/classification/occurrence save path. The return value (PipelineSaveResults) now also carries the deployments that were touched, which the command reports and re-saves so sessions and stations are regrouped.Shared ingestion. Both the live async path (
ami/jobs/tasks.py::process_nats_pipeline_result, which parses aPipelineResultsResponseoff NATS) and this importer callPipeline.save_results. The importer issave_resultsplus thecreate_missing_source_images/create_new_algorithmsflags; the live path needs neither because its source images already exist and its algorithms were registered via/info.Follow-ups and Discussion
None of these block the core import path; they are decisions and enhancements worth tracking.
Import track associations (multi-detection occurrences). Antenna's model already supports an occurrence made of several detections across frames (a track) via
Detection.occurrence, and the synthetic generators (create_demo_project,seed_synthetic_occurrences) build them. Antenna does not compute tracks itself, but ADC (or another service) can. The gap is the wire format:DetectionResponsehas no field saying "these detections belong to the same occurrence", so this import gives each detection its own occurrence. Proposed: add an optionalsequence_id/track_idtoDetectionResponse(a pure grouping key, no Antenna concepts, so it respects the ML-backend schema boundary), and havecreate_and_update_occurrences_for_detectionscreate one occurrence per(project, track id)when present, falling back to current behaviour when absent. Pairs with the export change in ami-data-companion#82, which currently flattens occurrences and drops the id.Multi-file / archive import. ADC splits large exports into
*_batch_NNN.jsonfiles plus an optional*_imagesfolder of crops. The command imports one file at a time. Worth adding a directory/glob and/or zip-archive input so a whole export can be imported in one run.Identify algorithms by
key + versioninstead ofname + version. Algorithms are unique onname + version(Algorithm.Meta.unique_together), andget_or_create_algorithm_and_category_mapkeys on the same pair. This is the source of near-duplicate algorithm records when the same algorithm comes back with a slightly different name (e.g. extra whitespace); the stable identifier is thekeyslug. Switching the constraint and the get-or-create tokey + versionis the right fix but touches registration, dedup, and existing data, so it needs its own testing pass and is tracked separately.Two management commands named
import_pipeline_results. One underami/ml/management/commands/(this PR'sPipelineResultsResponseimporter, the one Django actually resolves) and one underami/exports/management/commands/(a legacyoccurrences.jsonparser that builds records directly and does preserve multi-detection occurrences, currently shadowed). They differ by input format and occurrence handling, not by "results vs whole project". Consolidate to one location and rename each to its real purpose (for exampleimport_pipeline_resultsvsimport_legacy_occurrences).Category maps for imported classifiers. Registering a classification algorithm requires a category map; importing a classifier with
--create-new-algorithmswill raisePipelineNotConfiguredif the results file does not include one. The ADC export does not yet emit category maps (include_category_mapsraisesNotImplementedErrorthere). Decide whether the importer should require category maps for classifiers or synthesize a placeholder, and coordinate with the export side.Full project package import. Neither command imports deployment configuration (location, device, research site) or creates the project. If "set up a project from an export" is a goal, that is a separate feature on top of this results importer.
Larger Directions (roadmap, beyond this PR)
These are bigger pieces of work this importer sets up rather than delivers. Recording them here so the design intent is visible.
1. Import from other offline processing tools and from standard datasets
The clean shape for all of these is a small per-source adapter that converts the foreign format into a canonical
PipelineResultsResponse, after which the existingsave_resultspath does the rest. That keeps a single ingestion path (the one this PR shares with live processing) and isolates the format-specific quirks in one converter per source. Candidates, roughly in order of fit:Mothbox offline software (Mothbot_Process, mothbot-classify). A DIY moth-monitoring stack that processes locally and emits its own outputs —
Mothbot_Processexports CSV plus EXIF-embedded images;mothbot-classifykeeps per-project JSON "botdetection" files and patch crops. Supporting these would let Mothbox users land their data in Antenna. Needs a CSV/JSON →PipelineResultsResponseadapter; their taxonomy and algorithm naming will have to be mapped, which makes thekey-based algorithm identity question (follow-up 3 above) more pressing.Standardized / benchmark datasets. Loading published test sets into Antenna would make it a place to evaluate and compare models against known ground truth (this connects to the model-agreement work, antenna#1307).
MachineObservation-vs-human distinction), not just dumped through the prediction path.Both ship as large COCO-style archives, which reinforces follow-ups 2 (multi-file/archive input) and 5 (category maps / ground-truth provenance).
2. A web UI for importing, mirroring the export workflow
Today import is command-line only. The platform already has a data export workflow in the UI; an import counterpart would let a user upload a results file (or point at a stored one), choose the target project, set options (create-missing, register-algorithms, public base URL), and run it as a tracked job with progress — symmetric with export. This is a frontend + endpoint + background-job piece on top of the importer this PR provides, and should reuse the same
save_resultsentry point so the UI and CLI paths cannot diverge.Testing
ami.exports.tests.test_importsandami.ml.tests— 67 passed, 2 skipped.ami.main.testsevent-grouping tests — 11 passed.ami.jobsregroup tests — 4 passed.--create-new-algorithmsflag confirmed in--help; import command exercised bytest_imports.Not yet exercised: an end-to-end import against a clean project with no pre-registered algorithms using
--create-new-algorithms, and a real ADC export run through the command on a live stack.