lightly-studio 0.4.6__py3-none-any.whl
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.
- lightly_studio/__init__.py +12 -0
- lightly_studio/api/__init__.py +0 -0
- lightly_studio/api/app.py +131 -0
- lightly_studio/api/cache.py +77 -0
- lightly_studio/api/db_tables.py +35 -0
- lightly_studio/api/features.py +5 -0
- lightly_studio/api/routes/api/annotation.py +305 -0
- lightly_studio/api/routes/api/annotation_label.py +87 -0
- lightly_studio/api/routes/api/annotations/__init__.py +7 -0
- lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
- lightly_studio/api/routes/api/caption.py +100 -0
- lightly_studio/api/routes/api/classifier.py +384 -0
- lightly_studio/api/routes/api/dataset.py +191 -0
- lightly_studio/api/routes/api/dataset_tag.py +266 -0
- lightly_studio/api/routes/api/embeddings2d.py +90 -0
- lightly_studio/api/routes/api/exceptions.py +114 -0
- lightly_studio/api/routes/api/export.py +114 -0
- lightly_studio/api/routes/api/features.py +17 -0
- lightly_studio/api/routes/api/frame.py +241 -0
- lightly_studio/api/routes/api/image.py +155 -0
- lightly_studio/api/routes/api/metadata.py +161 -0
- lightly_studio/api/routes/api/operator.py +75 -0
- lightly_studio/api/routes/api/sample.py +103 -0
- lightly_studio/api/routes/api/selection.py +87 -0
- lightly_studio/api/routes/api/settings.py +41 -0
- lightly_studio/api/routes/api/status.py +19 -0
- lightly_studio/api/routes/api/text_embedding.py +50 -0
- lightly_studio/api/routes/api/validators.py +17 -0
- lightly_studio/api/routes/api/video.py +133 -0
- lightly_studio/api/routes/healthz.py +13 -0
- lightly_studio/api/routes/images.py +104 -0
- lightly_studio/api/routes/video_frames_media.py +116 -0
- lightly_studio/api/routes/video_media.py +223 -0
- lightly_studio/api/routes/webapp.py +51 -0
- lightly_studio/api/server.py +94 -0
- lightly_studio/core/__init__.py +0 -0
- lightly_studio/core/add_samples.py +533 -0
- lightly_studio/core/add_videos.py +294 -0
- lightly_studio/core/dataset.py +780 -0
- lightly_studio/core/dataset_query/__init__.py +14 -0
- lightly_studio/core/dataset_query/boolean_expression.py +67 -0
- lightly_studio/core/dataset_query/dataset_query.py +317 -0
- lightly_studio/core/dataset_query/field.py +113 -0
- lightly_studio/core/dataset_query/field_expression.py +79 -0
- lightly_studio/core/dataset_query/match_expression.py +23 -0
- lightly_studio/core/dataset_query/order_by.py +79 -0
- lightly_studio/core/dataset_query/sample_field.py +37 -0
- lightly_studio/core/dataset_query/tags_expression.py +46 -0
- lightly_studio/core/image_sample.py +36 -0
- lightly_studio/core/loading_log.py +56 -0
- lightly_studio/core/sample.py +291 -0
- lightly_studio/core/start_gui.py +54 -0
- lightly_studio/core/video_sample.py +38 -0
- lightly_studio/dataset/__init__.py +0 -0
- lightly_studio/dataset/edge_embedding_generator.py +155 -0
- lightly_studio/dataset/embedding_generator.py +129 -0
- lightly_studio/dataset/embedding_manager.py +349 -0
- lightly_studio/dataset/env.py +20 -0
- lightly_studio/dataset/file_utils.py +49 -0
- lightly_studio/dataset/fsspec_lister.py +275 -0
- lightly_studio/dataset/mobileclip_embedding_generator.py +158 -0
- lightly_studio/dataset/perception_encoder_embedding_generator.py +260 -0
- lightly_studio/db_manager.py +166 -0
- lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.GcXvs2l7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/12.Dx6SXgAb.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/17.9X9_k6TP.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/18.BxiimdIO.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/ClassifierSamplesGrid.BJbCDlvs.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/LightlyLogo.BNjCIww-.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Bold.DGvYQtcs.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Medium.DVUZMR_6.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Regular.DxJTClRG.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-SemiBold.D3TTYgdB.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.CefECEWA.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.D5tDcjY-.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.9X9_k6TP.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.BxiimdIO.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.Dx6SXgAb.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform._-1mPSEI.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/0dDyq72A.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/69_IOA4Y.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BK4An2kI.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRmB-kJ9.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B_1cpokE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BiqpDEr0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BpLiSKgx.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BscxbINH.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C80h3dJx.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C8mfFM-u.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CGY1p9L4.js +517 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/COfLknXM.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWj6FrbW.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CYgJF_JY.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CmLg0ys7.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvGjimpO.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D3RDXHoj.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D4y7iiT3.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D9SC3jBb.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DCuAdx1Q.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DDBy-_jD.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIeogL5L.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DL9a7v5o.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DSKECuqX.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_FFv0Oe.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DiZ5o5vz.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkbXUtyG.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmK2hulV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqnHaLTj.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DtWZc_tl.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DuUalyFS.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DwIonDAZ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Il-mSPmK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KNLP4aJU.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KjYeVjkE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/MErlcOXj.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VRI4prUD.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VYb2dkNs.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VqWvU2yF.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/dHC3otuL.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/da7Oy_lO.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/eAy8rZzC.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/erjNR5MX.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/f1oG3eFE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rsLi1iKv.js +20 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rwuuBP9f.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/xGHZQ1pe.js +3 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.DrTRUgT3.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.BK5EOJl2.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.CIvTuljF.js +4 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.UBvSzxdA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.CQ_tiLJa.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.KqkAcaxW.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DoYsmxQc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/13.571n2LZA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/14.DGs689M-.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/15.CWG1ehzT.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/16.Dpq6jbSh.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/17.B5AZbHUU.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/18.CBga8cnq.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.D2HXgz-8.js +1090 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/3.f4HAg-y3.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/4.BKF4xuKQ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.BAE0Pm_f.js +39 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.CouWWpzA.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.UBHT0ktp.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.FiYNElcc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.B3-UaT23.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon-precomposed.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/favicon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/index.html +45 -0
- lightly_studio/errors.py +5 -0
- lightly_studio/examples/example.py +25 -0
- lightly_studio/examples/example_coco.py +27 -0
- lightly_studio/examples/example_coco_caption.py +29 -0
- lightly_studio/examples/example_metadata.py +369 -0
- lightly_studio/examples/example_operators.py +111 -0
- lightly_studio/examples/example_selection.py +28 -0
- lightly_studio/examples/example_split_work.py +48 -0
- lightly_studio/examples/example_video.py +22 -0
- lightly_studio/examples/example_video_annotations.py +157 -0
- lightly_studio/examples/example_yolo.py +22 -0
- lightly_studio/export/coco_captions.py +69 -0
- lightly_studio/export/export_dataset.py +104 -0
- lightly_studio/export/lightly_studio_label_input.py +120 -0
- lightly_studio/export_schema.py +18 -0
- lightly_studio/export_version.py +57 -0
- lightly_studio/few_shot_classifier/__init__.py +0 -0
- lightly_studio/few_shot_classifier/classifier.py +80 -0
- lightly_studio/few_shot_classifier/classifier_manager.py +644 -0
- lightly_studio/few_shot_classifier/random_forest_classifier.py +495 -0
- lightly_studio/metadata/complex_metadata.py +47 -0
- lightly_studio/metadata/compute_similarity.py +84 -0
- lightly_studio/metadata/compute_typicality.py +67 -0
- lightly_studio/metadata/gps_coordinate.py +41 -0
- lightly_studio/metadata/metadata_protocol.py +17 -0
- lightly_studio/models/__init__.py +1 -0
- lightly_studio/models/annotation/__init__.py +0 -0
- lightly_studio/models/annotation/annotation_base.py +303 -0
- lightly_studio/models/annotation/instance_segmentation.py +56 -0
- lightly_studio/models/annotation/links.py +17 -0
- lightly_studio/models/annotation/object_detection.py +47 -0
- lightly_studio/models/annotation/semantic_segmentation.py +44 -0
- lightly_studio/models/annotation_label.py +47 -0
- lightly_studio/models/caption.py +49 -0
- lightly_studio/models/classifier.py +20 -0
- lightly_studio/models/dataset.py +70 -0
- lightly_studio/models/embedding_model.py +30 -0
- lightly_studio/models/image.py +96 -0
- lightly_studio/models/metadata.py +208 -0
- lightly_studio/models/range.py +17 -0
- lightly_studio/models/sample.py +154 -0
- lightly_studio/models/sample_embedding.py +36 -0
- lightly_studio/models/settings.py +69 -0
- lightly_studio/models/tag.py +96 -0
- lightly_studio/models/two_dim_embedding.py +16 -0
- lightly_studio/models/video.py +161 -0
- lightly_studio/plugins/__init__.py +0 -0
- lightly_studio/plugins/base_operator.py +60 -0
- lightly_studio/plugins/operator_registry.py +47 -0
- lightly_studio/plugins/parameter.py +70 -0
- lightly_studio/py.typed +0 -0
- lightly_studio/resolvers/__init__.py +0 -0
- lightly_studio/resolvers/annotation_label_resolver/__init__.py +22 -0
- lightly_studio/resolvers/annotation_label_resolver/create.py +27 -0
- lightly_studio/resolvers/annotation_label_resolver/delete.py +28 -0
- lightly_studio/resolvers/annotation_label_resolver/get_all.py +37 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_id.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_label_name.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/names_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/update.py +38 -0
- lightly_studio/resolvers/annotation_resolver/__init__.py +40 -0
- lightly_studio/resolvers/annotation_resolver/count_annotations_by_dataset.py +129 -0
- lightly_studio/resolvers/annotation_resolver/create_many.py +124 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotation.py +87 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotations.py +60 -0
- lightly_studio/resolvers/annotation_resolver/get_all.py +85 -0
- lightly_studio/resolvers/annotation_resolver/get_all_with_payload.py +179 -0
- lightly_studio/resolvers/annotation_resolver/get_by_id.py +34 -0
- lightly_studio/resolvers/annotation_resolver/get_by_id_with_payload.py +130 -0
- lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +142 -0
- lightly_studio/resolvers/annotation_resolver/update_bounding_box.py +68 -0
- lightly_studio/resolvers/annotations/__init__.py +1 -0
- lightly_studio/resolvers/annotations/annotations_filter.py +88 -0
- lightly_studio/resolvers/caption_resolver.py +129 -0
- lightly_studio/resolvers/dataset_resolver/__init__.py +55 -0
- lightly_studio/resolvers/dataset_resolver/check_dataset_type.py +29 -0
- lightly_studio/resolvers/dataset_resolver/create.py +20 -0
- lightly_studio/resolvers/dataset_resolver/delete.py +20 -0
- lightly_studio/resolvers/dataset_resolver/export.py +267 -0
- lightly_studio/resolvers/dataset_resolver/get_all.py +19 -0
- lightly_studio/resolvers/dataset_resolver/get_by_id.py +16 -0
- lightly_studio/resolvers/dataset_resolver/get_by_name.py +12 -0
- lightly_studio/resolvers/dataset_resolver/get_dataset_details.py +27 -0
- lightly_studio/resolvers/dataset_resolver/get_hierarchy.py +31 -0
- lightly_studio/resolvers/dataset_resolver/get_or_create_child_dataset.py +58 -0
- lightly_studio/resolvers/dataset_resolver/get_parent_dataset_by_sample_id.py +27 -0
- lightly_studio/resolvers/dataset_resolver/get_parent_dataset_id.py +22 -0
- lightly_studio/resolvers/dataset_resolver/get_root_dataset.py +61 -0
- lightly_studio/resolvers/dataset_resolver/get_root_datasets_overview.py +41 -0
- lightly_studio/resolvers/dataset_resolver/update.py +25 -0
- lightly_studio/resolvers/embedding_model_resolver.py +120 -0
- lightly_studio/resolvers/image_filter.py +50 -0
- lightly_studio/resolvers/image_resolver/__init__.py +21 -0
- lightly_studio/resolvers/image_resolver/create_many.py +52 -0
- lightly_studio/resolvers/image_resolver/delete.py +20 -0
- lightly_studio/resolvers/image_resolver/filter_new_paths.py +23 -0
- lightly_studio/resolvers/image_resolver/get_all_by_dataset_id.py +117 -0
- lightly_studio/resolvers/image_resolver/get_by_id.py +14 -0
- lightly_studio/resolvers/image_resolver/get_dimension_bounds.py +75 -0
- lightly_studio/resolvers/image_resolver/get_many_by_id.py +22 -0
- lightly_studio/resolvers/image_resolver/get_samples_excluding.py +43 -0
- lightly_studio/resolvers/metadata_resolver/__init__.py +15 -0
- lightly_studio/resolvers/metadata_resolver/metadata_filter.py +163 -0
- lightly_studio/resolvers/metadata_resolver/sample/__init__.py +21 -0
- lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_by_sample_id.py +24 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_metadata_info.py +104 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_value_for_sample.py +27 -0
- lightly_studio/resolvers/metadata_resolver/sample/set_value_for_sample.py +53 -0
- lightly_studio/resolvers/sample_embedding_resolver.py +132 -0
- lightly_studio/resolvers/sample_resolver/__init__.py +17 -0
- lightly_studio/resolvers/sample_resolver/count_by_dataset_id.py +16 -0
- lightly_studio/resolvers/sample_resolver/create.py +16 -0
- lightly_studio/resolvers/sample_resolver/create_many.py +25 -0
- lightly_studio/resolvers/sample_resolver/get_by_id.py +14 -0
- lightly_studio/resolvers/sample_resolver/get_filtered_samples.py +56 -0
- lightly_studio/resolvers/sample_resolver/get_many_by_id.py +22 -0
- lightly_studio/resolvers/sample_resolver/sample_filter.py +74 -0
- lightly_studio/resolvers/settings_resolver.py +62 -0
- lightly_studio/resolvers/tag_resolver.py +299 -0
- lightly_studio/resolvers/twodim_embedding_resolver.py +119 -0
- lightly_studio/resolvers/video_frame_resolver/__init__.py +23 -0
- lightly_studio/resolvers/video_frame_resolver/count_video_frames_annotations.py +83 -0
- lightly_studio/resolvers/video_frame_resolver/create_many.py +57 -0
- lightly_studio/resolvers/video_frame_resolver/get_all_by_dataset_id.py +63 -0
- lightly_studio/resolvers/video_frame_resolver/get_by_id.py +13 -0
- lightly_studio/resolvers/video_frame_resolver/get_table_fields_bounds.py +44 -0
- lightly_studio/resolvers/video_frame_resolver/video_frame_annotations_counter_filter.py +47 -0
- lightly_studio/resolvers/video_frame_resolver/video_frame_filter.py +57 -0
- lightly_studio/resolvers/video_resolver/__init__.py +27 -0
- lightly_studio/resolvers/video_resolver/count_video_frame_annotations_by_video_dataset.py +86 -0
- lightly_studio/resolvers/video_resolver/create_many.py +58 -0
- lightly_studio/resolvers/video_resolver/filter_new_paths.py +33 -0
- lightly_studio/resolvers/video_resolver/get_all_by_dataset_id.py +181 -0
- lightly_studio/resolvers/video_resolver/get_by_id.py +22 -0
- lightly_studio/resolvers/video_resolver/get_table_fields_bounds.py +72 -0
- lightly_studio/resolvers/video_resolver/get_view_by_id.py +52 -0
- lightly_studio/resolvers/video_resolver/video_count_annotations_filter.py +50 -0
- lightly_studio/resolvers/video_resolver/video_filter.py +98 -0
- lightly_studio/selection/__init__.py +1 -0
- lightly_studio/selection/mundig.py +143 -0
- lightly_studio/selection/select.py +203 -0
- lightly_studio/selection/select_via_db.py +273 -0
- lightly_studio/selection/selection_config.py +49 -0
- lightly_studio/services/annotations_service/__init__.py +33 -0
- lightly_studio/services/annotations_service/create_annotation.py +64 -0
- lightly_studio/services/annotations_service/delete_annotation.py +22 -0
- lightly_studio/services/annotations_service/get_annotation_by_id.py +31 -0
- lightly_studio/services/annotations_service/update_annotation.py +54 -0
- lightly_studio/services/annotations_service/update_annotation_bounding_box.py +36 -0
- lightly_studio/services/annotations_service/update_annotation_label.py +48 -0
- lightly_studio/services/annotations_service/update_annotations.py +29 -0
- lightly_studio/setup_logging.py +59 -0
- lightly_studio/type_definitions.py +31 -0
- lightly_studio/utils/__init__.py +3 -0
- lightly_studio/utils/download.py +94 -0
- lightly_studio/vendor/__init__.py +1 -0
- lightly_studio/vendor/mobileclip/ACKNOWLEDGEMENTS +422 -0
- lightly_studio/vendor/mobileclip/LICENSE +31 -0
- lightly_studio/vendor/mobileclip/LICENSE_weights_data +50 -0
- lightly_studio/vendor/mobileclip/README.md +5 -0
- lightly_studio/vendor/mobileclip/__init__.py +96 -0
- lightly_studio/vendor/mobileclip/clip.py +77 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_b.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s0.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s1.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s2.json +18 -0
- lightly_studio/vendor/mobileclip/image_encoder.py +67 -0
- lightly_studio/vendor/mobileclip/logger.py +154 -0
- lightly_studio/vendor/mobileclip/models/__init__.py +10 -0
- lightly_studio/vendor/mobileclip/models/mci.py +933 -0
- lightly_studio/vendor/mobileclip/models/vit.py +433 -0
- lightly_studio/vendor/mobileclip/modules/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/mobileone.py +341 -0
- lightly_studio/vendor/mobileclip/modules/common/transformer.py +451 -0
- lightly_studio/vendor/mobileclip/modules/image/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/image/image_projection.py +113 -0
- lightly_studio/vendor/mobileclip/modules/image/replknet.py +188 -0
- lightly_studio/vendor/mobileclip/modules/text/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/text/repmixer.py +281 -0
- lightly_studio/vendor/mobileclip/modules/text/tokenizer.py +38 -0
- lightly_studio/vendor/mobileclip/text_encoder.py +245 -0
- lightly_studio/vendor/perception_encoder/LICENSE.PE +201 -0
- lightly_studio/vendor/perception_encoder/README.md +11 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/__init__.py +0 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/bpe_simple_vocab_16e6.txt.gz +0 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/config.py +205 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/config_src.py +264 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/pe.py +766 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/rope.py +352 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/tokenizer.py +347 -0
- lightly_studio/vendor/perception_encoder/vision_encoder/transforms.py +36 -0
- lightly_studio-0.4.6.dist-info/METADATA +88 -0
- lightly_studio-0.4.6.dist-info/RECORD +356 -0
- lightly_studio-0.4.6.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""Create annotation route."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Path
|
|
8
|
+
from fastapi.params import Body
|
|
9
|
+
from pydantic import BaseModel
|
|
10
|
+
from typing_extensions import Annotated
|
|
11
|
+
|
|
12
|
+
from lightly_studio.db_manager import SessionDep
|
|
13
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
14
|
+
AnnotationBaseTable,
|
|
15
|
+
AnnotationType,
|
|
16
|
+
AnnotationView,
|
|
17
|
+
)
|
|
18
|
+
from lightly_studio.services import annotations_service
|
|
19
|
+
from lightly_studio.services.annotations_service.create_annotation import AnnotationCreateParams
|
|
20
|
+
|
|
21
|
+
create_annotation_router = APIRouter()
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AnnotationCreateInput(BaseModel):
|
|
25
|
+
"""API interface to create annotation."""
|
|
26
|
+
|
|
27
|
+
annotation_label_id: UUID
|
|
28
|
+
annotation_type: AnnotationType
|
|
29
|
+
parent_sample_id: UUID
|
|
30
|
+
x: int | None = None
|
|
31
|
+
y: int | None = None
|
|
32
|
+
width: int | None = None
|
|
33
|
+
height: int | None = None
|
|
34
|
+
segmentation_mask: list[int] | None = None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@create_annotation_router.post(
|
|
38
|
+
"/annotations",
|
|
39
|
+
response_model=AnnotationView,
|
|
40
|
+
)
|
|
41
|
+
def create_annotation(
|
|
42
|
+
dataset_id: Annotated[UUID, Path(title="Dataset Id", description="The ID of the dataset")],
|
|
43
|
+
session: SessionDep,
|
|
44
|
+
create_annotation_input: Annotated[AnnotationCreateInput, Body()],
|
|
45
|
+
) -> AnnotationBaseTable:
|
|
46
|
+
"""Create a new annotation."""
|
|
47
|
+
return annotations_service.create_annotation(
|
|
48
|
+
session=session,
|
|
49
|
+
annotation=AnnotationCreateParams(
|
|
50
|
+
dataset_id=dataset_id, **create_annotation_input.model_dump()
|
|
51
|
+
),
|
|
52
|
+
)
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
"""API routes for dataset captions."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from fastapi import APIRouter, Body, HTTPException, Path
|
|
8
|
+
from pydantic import BaseModel
|
|
9
|
+
from typing_extensions import Annotated
|
|
10
|
+
|
|
11
|
+
from lightly_studio.api.routes.api.status import HTTP_STATUS_NOT_FOUND
|
|
12
|
+
from lightly_studio.db_manager import SessionDep
|
|
13
|
+
from lightly_studio.models.caption import CaptionCreate, CaptionTable, CaptionView
|
|
14
|
+
from lightly_studio.resolvers import caption_resolver, sample_resolver
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# TODO(jonas, 11/2025): Use CaptionCreate instead when CaptionTable is linked to SampleTable.
|
|
18
|
+
class CaptionCreateInput(BaseModel):
|
|
19
|
+
"""API interface to create caption."""
|
|
20
|
+
|
|
21
|
+
parent_sample_id: UUID
|
|
22
|
+
text: str = ""
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
captions_router = APIRouter(prefix="/datasets/{dataset_id}", tags=["captions"])
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@captions_router.put("/captions/{sample_id}", response_model=CaptionView)
|
|
29
|
+
def update_caption_text(
|
|
30
|
+
session: SessionDep,
|
|
31
|
+
sample_id: Annotated[
|
|
32
|
+
UUID,
|
|
33
|
+
Path(title="Caption ID", description="ID of the caption to update"),
|
|
34
|
+
],
|
|
35
|
+
text: Annotated[str, Body()],
|
|
36
|
+
) -> CaptionTable:
|
|
37
|
+
"""Update an existing caption in the database."""
|
|
38
|
+
return caption_resolver.update_text(session=session, sample_id=sample_id, text=text)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@captions_router.get("/captions/{sample_id}", response_model=CaptionView)
|
|
42
|
+
def get_caption(
|
|
43
|
+
session: SessionDep,
|
|
44
|
+
sample_id: Annotated[UUID, Path(title="Caption ID")],
|
|
45
|
+
) -> CaptionTable:
|
|
46
|
+
"""Retrieve an existing annotation from the database."""
|
|
47
|
+
captions = caption_resolver.get_by_ids(session, [sample_id])
|
|
48
|
+
if not captions:
|
|
49
|
+
raise ValueError(f"Caption with ID {sample_id} not found.")
|
|
50
|
+
|
|
51
|
+
return captions[0]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@captions_router.post(
|
|
55
|
+
"/captions",
|
|
56
|
+
response_model=CaptionView,
|
|
57
|
+
)
|
|
58
|
+
def create_caption(
|
|
59
|
+
session: SessionDep,
|
|
60
|
+
create_caption_input: Annotated[CaptionCreateInput, Body()],
|
|
61
|
+
) -> CaptionTable:
|
|
62
|
+
"""Create a new caption."""
|
|
63
|
+
# Get the parent sample
|
|
64
|
+
parent_sample = sample_resolver.get_by_id(
|
|
65
|
+
session=session, sample_id=create_caption_input.parent_sample_id
|
|
66
|
+
)
|
|
67
|
+
if parent_sample is None:
|
|
68
|
+
raise ValueError(f"Sample with ID {create_caption_input.parent_sample_id} not found.")
|
|
69
|
+
|
|
70
|
+
# Create the caption
|
|
71
|
+
sample_ids = caption_resolver.create_many(
|
|
72
|
+
session=session,
|
|
73
|
+
parent_dataset_id=parent_sample.dataset_id,
|
|
74
|
+
captions=[
|
|
75
|
+
CaptionCreate(
|
|
76
|
+
parent_sample_id=create_caption_input.parent_sample_id,
|
|
77
|
+
text=create_caption_input.text,
|
|
78
|
+
),
|
|
79
|
+
],
|
|
80
|
+
)
|
|
81
|
+
assert len(sample_ids) == 1, "Expected exactly one caption to be created."
|
|
82
|
+
|
|
83
|
+
# Fetch and return the created caption
|
|
84
|
+
return caption_resolver.get_by_ids(session=session, sample_ids=sample_ids)[0]
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@captions_router.delete("/captions/{sample_id}")
|
|
88
|
+
def delete_caption(
|
|
89
|
+
session: SessionDep,
|
|
90
|
+
sample_id: Annotated[UUID, Path(title="Caption ID", description="ID of the caption to delete")],
|
|
91
|
+
) -> dict[str, str]:
|
|
92
|
+
"""Delete a caption from the database."""
|
|
93
|
+
try:
|
|
94
|
+
caption_resolver.delete_caption(session=session, sample_id=sample_id)
|
|
95
|
+
except ValueError as e:
|
|
96
|
+
raise HTTPException(
|
|
97
|
+
status_code=HTTP_STATUS_NOT_FOUND,
|
|
98
|
+
detail="Caption not found",
|
|
99
|
+
) from e
|
|
100
|
+
return {"status": "deleted"}
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"""This module contains the API routes for managing classifiers."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import io
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from uuid import UUID
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter, UploadFile
|
|
10
|
+
from fastapi.responses import StreamingResponse
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
|
|
13
|
+
from lightly_studio.db_manager import SessionDep
|
|
14
|
+
from lightly_studio.few_shot_classifier.classifier import (
|
|
15
|
+
ExportType,
|
|
16
|
+
)
|
|
17
|
+
from lightly_studio.few_shot_classifier.classifier_manager import (
|
|
18
|
+
ClassifierManagerProvider,
|
|
19
|
+
)
|
|
20
|
+
from lightly_studio.models.classifier import EmbeddingClassifier
|
|
21
|
+
|
|
22
|
+
classifier_router = APIRouter()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class GetNegativeSamplesRequest(BaseModel):
|
|
26
|
+
"""Request for getting negative samples for classifier training."""
|
|
27
|
+
|
|
28
|
+
positive_sample_ids: list[UUID]
|
|
29
|
+
dataset_id: UUID
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class GetNegativeSamplesResponse(BaseModel):
|
|
33
|
+
"""Response for getting negative samples for classifier training."""
|
|
34
|
+
|
|
35
|
+
negative_sample_ids: list[UUID]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
@classifier_router.post("/classifiers/get_negative_samples")
|
|
39
|
+
def get_negative_samples(
|
|
40
|
+
request: GetNegativeSamplesRequest, session: SessionDep
|
|
41
|
+
) -> GetNegativeSamplesResponse:
|
|
42
|
+
"""Get negative samples for classifier training.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
request: The request containing negative sample parameters.
|
|
46
|
+
session: Database session.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
The response containing negative sample IDs.
|
|
50
|
+
"""
|
|
51
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
52
|
+
negative_samples = classifier_manager.provide_negative_samples(
|
|
53
|
+
session=session,
|
|
54
|
+
dataset_id=request.dataset_id,
|
|
55
|
+
selected_samples=request.positive_sample_ids,
|
|
56
|
+
)
|
|
57
|
+
# Extract just the sample IDs from the returned Sample objects
|
|
58
|
+
negative_sample_ids = [sample.sample_id for sample in negative_samples]
|
|
59
|
+
return GetNegativeSamplesResponse(negative_sample_ids=negative_sample_ids)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class SamplesToRefineResponse(BaseModel):
|
|
63
|
+
"""Response for samples for classifier refinement.
|
|
64
|
+
|
|
65
|
+
Maps class names to lists of sample IDs. First class gets high confidence
|
|
66
|
+
samples, second class gets low confidence samples.
|
|
67
|
+
"""
|
|
68
|
+
|
|
69
|
+
samples: dict[str, list[UUID]]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@classifier_router.get("/classifiers/{classifier_id}/samples_to_refine")
|
|
73
|
+
def samples_to_refine(
|
|
74
|
+
classifier_id: UUID,
|
|
75
|
+
dataset_id: UUID,
|
|
76
|
+
session: SessionDep,
|
|
77
|
+
) -> SamplesToRefineResponse:
|
|
78
|
+
"""Get samples for classifier refinement.
|
|
79
|
+
|
|
80
|
+
Args:
|
|
81
|
+
classifier_id: The ID of the classifier.
|
|
82
|
+
dataset_id: The ID of the dataset.
|
|
83
|
+
session: Database session.
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
The response containing sample IDs for refinement.
|
|
87
|
+
"""
|
|
88
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
89
|
+
samples = classifier_manager.get_samples_for_fine_tuning(
|
|
90
|
+
session=session, classifier_id=classifier_id, dataset_id=dataset_id
|
|
91
|
+
)
|
|
92
|
+
return SamplesToRefineResponse(samples=samples)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
@classifier_router.get("/classifiers/{classifier_id}/sample_history")
|
|
96
|
+
def sample_history(
|
|
97
|
+
classifier_id: UUID,
|
|
98
|
+
) -> SamplesToRefineResponse:
|
|
99
|
+
"""Get all samples used in the classifier training.
|
|
100
|
+
|
|
101
|
+
Args:
|
|
102
|
+
classifier_id: The ID of the classifier.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
The response containing sample IDs used in the training.
|
|
106
|
+
"""
|
|
107
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
108
|
+
samples = classifier_manager.get_annotations(classifier_id=classifier_id)
|
|
109
|
+
return SamplesToRefineResponse(samples=samples)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
@classifier_router.post(
|
|
113
|
+
"/classifiers/{classifier_id}/commit_temp_classifier",
|
|
114
|
+
)
|
|
115
|
+
def commit_temp_classifier(
|
|
116
|
+
classifier_id: UUID,
|
|
117
|
+
) -> None:
|
|
118
|
+
"""Commit the classifier.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
classifier_id: The ID of the classifier.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
None
|
|
125
|
+
"""
|
|
126
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
127
|
+
classifier_manager.commit_temp_classifier(classifier_id=classifier_id)
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
@classifier_router.delete(
|
|
131
|
+
"/classifiers/{classifier_id}/drop_temp_classifier",
|
|
132
|
+
)
|
|
133
|
+
def drop_temp_classifier(
|
|
134
|
+
classifier_id: UUID,
|
|
135
|
+
) -> None:
|
|
136
|
+
"""Drop the classifier.
|
|
137
|
+
|
|
138
|
+
Args:
|
|
139
|
+
classifier_id: The ID of the classifier.
|
|
140
|
+
|
|
141
|
+
Returns:
|
|
142
|
+
None
|
|
143
|
+
"""
|
|
144
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
145
|
+
classifier_manager.drop_temp_classifier(classifier_id=classifier_id)
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
class SaveClassifierRequest(BaseModel):
|
|
149
|
+
"""Request for saving classifier to a file."""
|
|
150
|
+
|
|
151
|
+
file_path: str
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@classifier_router.post(
|
|
155
|
+
"/classifiers/{classifier_id}/save_classifier_to_file/{export_type}",
|
|
156
|
+
)
|
|
157
|
+
def save_classifier_to_file(
|
|
158
|
+
classifier_id: UUID,
|
|
159
|
+
export_type: ExportType,
|
|
160
|
+
) -> StreamingResponse:
|
|
161
|
+
"""Save the classifier to a file.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
classifier_id: The ID of the classifier.
|
|
165
|
+
export_type: The type of export (e.g., "sklearn", "lightly").
|
|
166
|
+
|
|
167
|
+
Returns:
|
|
168
|
+
StreamingResponse containing the pickled classifier file.
|
|
169
|
+
"""
|
|
170
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
171
|
+
# Use BytesIO to capture the file content and send it as a response.
|
|
172
|
+
buffer = io.BytesIO()
|
|
173
|
+
classifier_manager.save_classifier_to_buffer(
|
|
174
|
+
classifier_id=classifier_id, buffer=buffer, export_type=export_type
|
|
175
|
+
)
|
|
176
|
+
buffer.seek(0)
|
|
177
|
+
|
|
178
|
+
# Get classifier name for the filename
|
|
179
|
+
classifier = classifier_manager.get_classifier_by_id(classifier_id=classifier_id)
|
|
180
|
+
filename = f"{classifier.classifier_name}.pkl"
|
|
181
|
+
headers = {
|
|
182
|
+
"Content-Disposition": f'attachment; filename="{filename}"',
|
|
183
|
+
"Content-Type": "application/octet-stream",
|
|
184
|
+
"Access-Control-Expose-Headers": "Content-Disposition",
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
return StreamingResponse(buffer, headers=headers, media_type="application/octet-stream")
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
class LoadClassifierRequest(BaseModel):
|
|
191
|
+
"""Request for loading classifier from a file."""
|
|
192
|
+
|
|
193
|
+
file_path: str
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
class LoadClassifierResponse(BaseModel):
|
|
197
|
+
"""Response for loading classifier from a file."""
|
|
198
|
+
|
|
199
|
+
classifier_id: UUID
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@classifier_router.post(
|
|
203
|
+
"/classifiers/load_classifier_from_file",
|
|
204
|
+
)
|
|
205
|
+
def load_classifier_from_file(
|
|
206
|
+
request: LoadClassifierRequest,
|
|
207
|
+
session: SessionDep,
|
|
208
|
+
) -> LoadClassifierResponse:
|
|
209
|
+
"""Load the classifier from a file.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
request: The request containing the file path.
|
|
213
|
+
session: Database session.
|
|
214
|
+
|
|
215
|
+
Returns:
|
|
216
|
+
Response with the ID of the loaded classifier.
|
|
217
|
+
"""
|
|
218
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
219
|
+
classifier = classifier_manager.load_classifier_from_file(
|
|
220
|
+
session=session, file_path=Path(request.file_path)
|
|
221
|
+
)
|
|
222
|
+
return LoadClassifierResponse(classifier_id=classifier.classifier_id)
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
@classifier_router.post(
|
|
226
|
+
"/classifiers/load_classifier_from_buffer",
|
|
227
|
+
)
|
|
228
|
+
def load_classifier_from_buffer(
|
|
229
|
+
file: UploadFile,
|
|
230
|
+
session: SessionDep,
|
|
231
|
+
) -> UUID:
|
|
232
|
+
"""Load a classifier from an uploaded file buffer.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
file: The uploaded classifier file.
|
|
236
|
+
session: Database session.
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
The ID of the loaded classifier.
|
|
240
|
+
"""
|
|
241
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
242
|
+
|
|
243
|
+
# Read file into buffer
|
|
244
|
+
buffer = io.BytesIO(file.file.read())
|
|
245
|
+
|
|
246
|
+
# Load classifier from buffer
|
|
247
|
+
classifier = classifier_manager.load_classifier_from_buffer(session=session, buffer=buffer)
|
|
248
|
+
return classifier.classifier_id
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
@classifier_router.post(
|
|
252
|
+
"/classifiers/{classifier_id}/train_classifier",
|
|
253
|
+
)
|
|
254
|
+
def train_classifier(
|
|
255
|
+
classifier_id: UUID,
|
|
256
|
+
session: SessionDep,
|
|
257
|
+
) -> None:
|
|
258
|
+
"""Train the classifier.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
classifier_id: The ID of the classifier.
|
|
262
|
+
session: Database session.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
None
|
|
266
|
+
"""
|
|
267
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
268
|
+
classifier_manager.train_classifier(session=session, classifier_id=classifier_id)
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
class UpdateAnnotationsRequest(BaseModel):
|
|
272
|
+
"""Request for updating classifier annotations."""
|
|
273
|
+
|
|
274
|
+
annotations: dict[str, list[UUID]]
|
|
275
|
+
|
|
276
|
+
|
|
277
|
+
@classifier_router.post(
|
|
278
|
+
"/classifiers/{classifier_id}/update_annotations",
|
|
279
|
+
)
|
|
280
|
+
def update_classifiers_annotations(
|
|
281
|
+
classifier_id: UUID,
|
|
282
|
+
request: UpdateAnnotationsRequest,
|
|
283
|
+
) -> None:
|
|
284
|
+
"""Update the annotations for a classifier.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
classifier_id: The ID of the classifier.
|
|
288
|
+
request: The request containing the new annotations.
|
|
289
|
+
|
|
290
|
+
Returns:
|
|
291
|
+
None
|
|
292
|
+
|
|
293
|
+
"""
|
|
294
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
295
|
+
classifier_manager.update_classifiers_annotations(
|
|
296
|
+
classifier_id=classifier_id,
|
|
297
|
+
new_annotations=request.annotations,
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
class CreateClassifierRequest(BaseModel):
|
|
302
|
+
"""Request model for creating a classifier."""
|
|
303
|
+
|
|
304
|
+
name: str
|
|
305
|
+
class_list: list[str]
|
|
306
|
+
dataset_id: UUID
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
class CreateClassifierResponse(BaseModel):
|
|
310
|
+
"""Response model for creating a classifier."""
|
|
311
|
+
|
|
312
|
+
name: str
|
|
313
|
+
classifier_id: str
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
@classifier_router.post("/classifiers/create")
|
|
317
|
+
def create_classifier(
|
|
318
|
+
request: CreateClassifierRequest, session: SessionDep
|
|
319
|
+
) -> CreateClassifierResponse:
|
|
320
|
+
"""Create a new classifier.
|
|
321
|
+
|
|
322
|
+
Args:
|
|
323
|
+
request: The request containing classifier creation parameters.
|
|
324
|
+
session: Database session.
|
|
325
|
+
|
|
326
|
+
Returns:
|
|
327
|
+
Response with the name and ID of the classifier.
|
|
328
|
+
|
|
329
|
+
"""
|
|
330
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
331
|
+
classifier = classifier_manager.create_classifier(
|
|
332
|
+
session=session,
|
|
333
|
+
name=request.name,
|
|
334
|
+
class_list=request.class_list,
|
|
335
|
+
dataset_id=request.dataset_id,
|
|
336
|
+
)
|
|
337
|
+
return CreateClassifierResponse(
|
|
338
|
+
name=classifier.few_shot_classifier.name,
|
|
339
|
+
classifier_id=str(classifier.classifier_id),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
class GetAllClassifiersResponse(BaseModel):
|
|
344
|
+
"""Response model for getting all active classifiers."""
|
|
345
|
+
|
|
346
|
+
classifiers: list[EmbeddingClassifier]
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
@classifier_router.get("/classifiers/get_all_classifiers")
|
|
350
|
+
def get_all_classifiers() -> GetAllClassifiersResponse:
|
|
351
|
+
"""Get all active classifiers.
|
|
352
|
+
|
|
353
|
+
Returns:
|
|
354
|
+
Response with list of tuples containing classifier names and IDs.
|
|
355
|
+
"""
|
|
356
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
357
|
+
classifiers = classifier_manager.get_all_classifiers()
|
|
358
|
+
return GetAllClassifiersResponse(classifiers=classifiers)
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
@classifier_router.post(
|
|
362
|
+
"/classifiers/{classifier_id}/run_on_dataset/{dataset_id}",
|
|
363
|
+
)
|
|
364
|
+
def run_classifier_route(
|
|
365
|
+
classifier_id: UUID,
|
|
366
|
+
dataset_id: UUID,
|
|
367
|
+
session: SessionDep,
|
|
368
|
+
) -> None:
|
|
369
|
+
"""Run the classifier on a dataset.
|
|
370
|
+
|
|
371
|
+
Args:
|
|
372
|
+
dataset_id: The ID of the dataset to run the classifier on.
|
|
373
|
+
classifier_id: The ID of the classifier.
|
|
374
|
+
session: Database session.
|
|
375
|
+
|
|
376
|
+
Returns:
|
|
377
|
+
None
|
|
378
|
+
"""
|
|
379
|
+
classifier_manager = ClassifierManagerProvider.get_classifier_manager()
|
|
380
|
+
classifier_manager.run_classifier(
|
|
381
|
+
session=session,
|
|
382
|
+
classifier_id=classifier_id,
|
|
383
|
+
dataset_id=dataset_id,
|
|
384
|
+
)
|