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.
Files changed (356) hide show
  1. lightly_studio/__init__.py +12 -0
  2. lightly_studio/api/__init__.py +0 -0
  3. lightly_studio/api/app.py +131 -0
  4. lightly_studio/api/cache.py +77 -0
  5. lightly_studio/api/db_tables.py +35 -0
  6. lightly_studio/api/features.py +5 -0
  7. lightly_studio/api/routes/api/annotation.py +305 -0
  8. lightly_studio/api/routes/api/annotation_label.py +87 -0
  9. lightly_studio/api/routes/api/annotations/__init__.py +7 -0
  10. lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
  11. lightly_studio/api/routes/api/caption.py +100 -0
  12. lightly_studio/api/routes/api/classifier.py +384 -0
  13. lightly_studio/api/routes/api/dataset.py +191 -0
  14. lightly_studio/api/routes/api/dataset_tag.py +266 -0
  15. lightly_studio/api/routes/api/embeddings2d.py +90 -0
  16. lightly_studio/api/routes/api/exceptions.py +114 -0
  17. lightly_studio/api/routes/api/export.py +114 -0
  18. lightly_studio/api/routes/api/features.py +17 -0
  19. lightly_studio/api/routes/api/frame.py +241 -0
  20. lightly_studio/api/routes/api/image.py +155 -0
  21. lightly_studio/api/routes/api/metadata.py +161 -0
  22. lightly_studio/api/routes/api/operator.py +75 -0
  23. lightly_studio/api/routes/api/sample.py +103 -0
  24. lightly_studio/api/routes/api/selection.py +87 -0
  25. lightly_studio/api/routes/api/settings.py +41 -0
  26. lightly_studio/api/routes/api/status.py +19 -0
  27. lightly_studio/api/routes/api/text_embedding.py +50 -0
  28. lightly_studio/api/routes/api/validators.py +17 -0
  29. lightly_studio/api/routes/api/video.py +133 -0
  30. lightly_studio/api/routes/healthz.py +13 -0
  31. lightly_studio/api/routes/images.py +104 -0
  32. lightly_studio/api/routes/video_frames_media.py +116 -0
  33. lightly_studio/api/routes/video_media.py +223 -0
  34. lightly_studio/api/routes/webapp.py +51 -0
  35. lightly_studio/api/server.py +94 -0
  36. lightly_studio/core/__init__.py +0 -0
  37. lightly_studio/core/add_samples.py +533 -0
  38. lightly_studio/core/add_videos.py +294 -0
  39. lightly_studio/core/dataset.py +780 -0
  40. lightly_studio/core/dataset_query/__init__.py +14 -0
  41. lightly_studio/core/dataset_query/boolean_expression.py +67 -0
  42. lightly_studio/core/dataset_query/dataset_query.py +317 -0
  43. lightly_studio/core/dataset_query/field.py +113 -0
  44. lightly_studio/core/dataset_query/field_expression.py +79 -0
  45. lightly_studio/core/dataset_query/match_expression.py +23 -0
  46. lightly_studio/core/dataset_query/order_by.py +79 -0
  47. lightly_studio/core/dataset_query/sample_field.py +37 -0
  48. lightly_studio/core/dataset_query/tags_expression.py +46 -0
  49. lightly_studio/core/image_sample.py +36 -0
  50. lightly_studio/core/loading_log.py +56 -0
  51. lightly_studio/core/sample.py +291 -0
  52. lightly_studio/core/start_gui.py +54 -0
  53. lightly_studio/core/video_sample.py +38 -0
  54. lightly_studio/dataset/__init__.py +0 -0
  55. lightly_studio/dataset/edge_embedding_generator.py +155 -0
  56. lightly_studio/dataset/embedding_generator.py +129 -0
  57. lightly_studio/dataset/embedding_manager.py +349 -0
  58. lightly_studio/dataset/env.py +20 -0
  59. lightly_studio/dataset/file_utils.py +49 -0
  60. lightly_studio/dataset/fsspec_lister.py +275 -0
  61. lightly_studio/dataset/mobileclip_embedding_generator.py +158 -0
  62. lightly_studio/dataset/perception_encoder_embedding_generator.py +260 -0
  63. lightly_studio/db_manager.py +166 -0
  64. lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -0
  65. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.GcXvs2l7.css +1 -0
  66. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/12.Dx6SXgAb.css +1 -0
  67. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/17.9X9_k6TP.css +1 -0
  68. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/18.BxiimdIO.css +1 -0
  69. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
  70. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/ClassifierSamplesGrid.BJbCDlvs.css +1 -0
  71. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/LightlyLogo.BNjCIww-.png +0 -0
  72. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Bold.DGvYQtcs.ttf +0 -0
  73. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf +0 -0
  74. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Medium.DVUZMR_6.ttf +0 -0
  75. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Regular.DxJTClRG.ttf +0 -0
  76. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-SemiBold.D3TTYgdB.ttf +0 -0
  77. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf +0 -0
  78. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.CefECEWA.css +1 -0
  79. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.D5tDcjY-.css +1 -0
  80. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.9X9_k6TP.css +1 -0
  81. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.BxiimdIO.css +1 -0
  82. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_page.Dx6SXgAb.css +1 -0
  83. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform._-1mPSEI.css +1 -0
  84. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/0dDyq72A.js +20 -0
  85. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/69_IOA4Y.js +1 -0
  86. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BK4An2kI.js +1 -0
  87. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRmB-kJ9.js +1 -0
  88. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B_1cpokE.js +1 -0
  89. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BiqpDEr0.js +1 -0
  90. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BpLiSKgx.js +1 -0
  91. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BscxbINH.js +39 -0
  92. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
  93. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C80h3dJx.js +1 -0
  94. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C8mfFM-u.js +2 -0
  95. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CGY1p9L4.js +517 -0
  96. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/COfLknXM.js +1 -0
  97. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWj6FrbW.js +1 -0
  98. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CYgJF_JY.js +1 -0
  99. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CmLg0ys7.js +1 -0
  100. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvGjimpO.js +1 -0
  101. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D3RDXHoj.js +39 -0
  102. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D4y7iiT3.js +1 -0
  103. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D9SC3jBb.js +1 -0
  104. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DCuAdx1Q.js +20 -0
  105. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DDBy-_jD.js +1 -0
  106. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIeogL5L.js +1 -0
  107. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DL9a7v5o.js +1 -0
  108. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DSKECuqX.js +39 -0
  109. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_FFv0Oe.js +1 -0
  110. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DiZ5o5vz.js +1 -0
  111. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkbXUtyG.js +1 -0
  112. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmK2hulV.js +1 -0
  113. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqnHaLTj.js +1 -0
  114. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DtWZc_tl.js +1 -0
  115. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DuUalyFS.js +1 -0
  116. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DwIonDAZ.js +1 -0
  117. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Il-mSPmK.js +1 -0
  118. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KNLP4aJU.js +1 -0
  119. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KjYeVjkE.js +1 -0
  120. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/MErlcOXj.js +1 -0
  121. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VRI4prUD.js +1 -0
  122. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VYb2dkNs.js +1 -0
  123. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/VqWvU2yF.js +1 -0
  124. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/dHC3otuL.js +1 -0
  125. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/da7Oy_lO.js +1 -0
  126. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/eAy8rZzC.js +2 -0
  127. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/erjNR5MX.js +1 -0
  128. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/f1oG3eFE.js +1 -0
  129. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rsLi1iKv.js +20 -0
  130. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/rwuuBP9f.js +1 -0
  131. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/xGHZQ1pe.js +3 -0
  132. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.DrTRUgT3.js +2 -0
  133. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.BK5EOJl2.js +1 -0
  134. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.CIvTuljF.js +4 -0
  135. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.UBvSzxdA.js +1 -0
  136. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.CQ_tiLJa.js +1 -0
  137. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.KqkAcaxW.js +1 -0
  138. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DoYsmxQc.js +1 -0
  139. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/13.571n2LZA.js +1 -0
  140. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/14.DGs689M-.js +1 -0
  141. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/15.CWG1ehzT.js +1 -0
  142. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/16.Dpq6jbSh.js +1 -0
  143. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/17.B5AZbHUU.js +1 -0
  144. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/18.CBga8cnq.js +1 -0
  145. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.D2HXgz-8.js +1090 -0
  146. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/3.f4HAg-y3.js +1 -0
  147. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/4.BKF4xuKQ.js +1 -0
  148. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.BAE0Pm_f.js +39 -0
  149. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.CouWWpzA.js +1 -0
  150. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.UBHT0ktp.js +1 -0
  151. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.FiYNElcc.js +1 -0
  152. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.B3-UaT23.js +1 -0
  153. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
  154. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
  155. lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -0
  156. lightly_studio/dist_lightly_studio_view_app/apple-touch-icon-precomposed.png +0 -0
  157. lightly_studio/dist_lightly_studio_view_app/apple-touch-icon.png +0 -0
  158. lightly_studio/dist_lightly_studio_view_app/favicon.png +0 -0
  159. lightly_studio/dist_lightly_studio_view_app/index.html +45 -0
  160. lightly_studio/errors.py +5 -0
  161. lightly_studio/examples/example.py +25 -0
  162. lightly_studio/examples/example_coco.py +27 -0
  163. lightly_studio/examples/example_coco_caption.py +29 -0
  164. lightly_studio/examples/example_metadata.py +369 -0
  165. lightly_studio/examples/example_operators.py +111 -0
  166. lightly_studio/examples/example_selection.py +28 -0
  167. lightly_studio/examples/example_split_work.py +48 -0
  168. lightly_studio/examples/example_video.py +22 -0
  169. lightly_studio/examples/example_video_annotations.py +157 -0
  170. lightly_studio/examples/example_yolo.py +22 -0
  171. lightly_studio/export/coco_captions.py +69 -0
  172. lightly_studio/export/export_dataset.py +104 -0
  173. lightly_studio/export/lightly_studio_label_input.py +120 -0
  174. lightly_studio/export_schema.py +18 -0
  175. lightly_studio/export_version.py +57 -0
  176. lightly_studio/few_shot_classifier/__init__.py +0 -0
  177. lightly_studio/few_shot_classifier/classifier.py +80 -0
  178. lightly_studio/few_shot_classifier/classifier_manager.py +644 -0
  179. lightly_studio/few_shot_classifier/random_forest_classifier.py +495 -0
  180. lightly_studio/metadata/complex_metadata.py +47 -0
  181. lightly_studio/metadata/compute_similarity.py +84 -0
  182. lightly_studio/metadata/compute_typicality.py +67 -0
  183. lightly_studio/metadata/gps_coordinate.py +41 -0
  184. lightly_studio/metadata/metadata_protocol.py +17 -0
  185. lightly_studio/models/__init__.py +1 -0
  186. lightly_studio/models/annotation/__init__.py +0 -0
  187. lightly_studio/models/annotation/annotation_base.py +303 -0
  188. lightly_studio/models/annotation/instance_segmentation.py +56 -0
  189. lightly_studio/models/annotation/links.py +17 -0
  190. lightly_studio/models/annotation/object_detection.py +47 -0
  191. lightly_studio/models/annotation/semantic_segmentation.py +44 -0
  192. lightly_studio/models/annotation_label.py +47 -0
  193. lightly_studio/models/caption.py +49 -0
  194. lightly_studio/models/classifier.py +20 -0
  195. lightly_studio/models/dataset.py +70 -0
  196. lightly_studio/models/embedding_model.py +30 -0
  197. lightly_studio/models/image.py +96 -0
  198. lightly_studio/models/metadata.py +208 -0
  199. lightly_studio/models/range.py +17 -0
  200. lightly_studio/models/sample.py +154 -0
  201. lightly_studio/models/sample_embedding.py +36 -0
  202. lightly_studio/models/settings.py +69 -0
  203. lightly_studio/models/tag.py +96 -0
  204. lightly_studio/models/two_dim_embedding.py +16 -0
  205. lightly_studio/models/video.py +161 -0
  206. lightly_studio/plugins/__init__.py +0 -0
  207. lightly_studio/plugins/base_operator.py +60 -0
  208. lightly_studio/plugins/operator_registry.py +47 -0
  209. lightly_studio/plugins/parameter.py +70 -0
  210. lightly_studio/py.typed +0 -0
  211. lightly_studio/resolvers/__init__.py +0 -0
  212. lightly_studio/resolvers/annotation_label_resolver/__init__.py +22 -0
  213. lightly_studio/resolvers/annotation_label_resolver/create.py +27 -0
  214. lightly_studio/resolvers/annotation_label_resolver/delete.py +28 -0
  215. lightly_studio/resolvers/annotation_label_resolver/get_all.py +37 -0
  216. lightly_studio/resolvers/annotation_label_resolver/get_by_id.py +24 -0
  217. lightly_studio/resolvers/annotation_label_resolver/get_by_ids.py +25 -0
  218. lightly_studio/resolvers/annotation_label_resolver/get_by_label_name.py +24 -0
  219. lightly_studio/resolvers/annotation_label_resolver/names_by_ids.py +25 -0
  220. lightly_studio/resolvers/annotation_label_resolver/update.py +38 -0
  221. lightly_studio/resolvers/annotation_resolver/__init__.py +40 -0
  222. lightly_studio/resolvers/annotation_resolver/count_annotations_by_dataset.py +129 -0
  223. lightly_studio/resolvers/annotation_resolver/create_many.py +124 -0
  224. lightly_studio/resolvers/annotation_resolver/delete_annotation.py +87 -0
  225. lightly_studio/resolvers/annotation_resolver/delete_annotations.py +60 -0
  226. lightly_studio/resolvers/annotation_resolver/get_all.py +85 -0
  227. lightly_studio/resolvers/annotation_resolver/get_all_with_payload.py +179 -0
  228. lightly_studio/resolvers/annotation_resolver/get_by_id.py +34 -0
  229. lightly_studio/resolvers/annotation_resolver/get_by_id_with_payload.py +130 -0
  230. lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +142 -0
  231. lightly_studio/resolvers/annotation_resolver/update_bounding_box.py +68 -0
  232. lightly_studio/resolvers/annotations/__init__.py +1 -0
  233. lightly_studio/resolvers/annotations/annotations_filter.py +88 -0
  234. lightly_studio/resolvers/caption_resolver.py +129 -0
  235. lightly_studio/resolvers/dataset_resolver/__init__.py +55 -0
  236. lightly_studio/resolvers/dataset_resolver/check_dataset_type.py +29 -0
  237. lightly_studio/resolvers/dataset_resolver/create.py +20 -0
  238. lightly_studio/resolvers/dataset_resolver/delete.py +20 -0
  239. lightly_studio/resolvers/dataset_resolver/export.py +267 -0
  240. lightly_studio/resolvers/dataset_resolver/get_all.py +19 -0
  241. lightly_studio/resolvers/dataset_resolver/get_by_id.py +16 -0
  242. lightly_studio/resolvers/dataset_resolver/get_by_name.py +12 -0
  243. lightly_studio/resolvers/dataset_resolver/get_dataset_details.py +27 -0
  244. lightly_studio/resolvers/dataset_resolver/get_hierarchy.py +31 -0
  245. lightly_studio/resolvers/dataset_resolver/get_or_create_child_dataset.py +58 -0
  246. lightly_studio/resolvers/dataset_resolver/get_parent_dataset_by_sample_id.py +27 -0
  247. lightly_studio/resolvers/dataset_resolver/get_parent_dataset_id.py +22 -0
  248. lightly_studio/resolvers/dataset_resolver/get_root_dataset.py +61 -0
  249. lightly_studio/resolvers/dataset_resolver/get_root_datasets_overview.py +41 -0
  250. lightly_studio/resolvers/dataset_resolver/update.py +25 -0
  251. lightly_studio/resolvers/embedding_model_resolver.py +120 -0
  252. lightly_studio/resolvers/image_filter.py +50 -0
  253. lightly_studio/resolvers/image_resolver/__init__.py +21 -0
  254. lightly_studio/resolvers/image_resolver/create_many.py +52 -0
  255. lightly_studio/resolvers/image_resolver/delete.py +20 -0
  256. lightly_studio/resolvers/image_resolver/filter_new_paths.py +23 -0
  257. lightly_studio/resolvers/image_resolver/get_all_by_dataset_id.py +117 -0
  258. lightly_studio/resolvers/image_resolver/get_by_id.py +14 -0
  259. lightly_studio/resolvers/image_resolver/get_dimension_bounds.py +75 -0
  260. lightly_studio/resolvers/image_resolver/get_many_by_id.py +22 -0
  261. lightly_studio/resolvers/image_resolver/get_samples_excluding.py +43 -0
  262. lightly_studio/resolvers/metadata_resolver/__init__.py +15 -0
  263. lightly_studio/resolvers/metadata_resolver/metadata_filter.py +163 -0
  264. lightly_studio/resolvers/metadata_resolver/sample/__init__.py +21 -0
  265. lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
  266. lightly_studio/resolvers/metadata_resolver/sample/get_by_sample_id.py +24 -0
  267. lightly_studio/resolvers/metadata_resolver/sample/get_metadata_info.py +104 -0
  268. lightly_studio/resolvers/metadata_resolver/sample/get_value_for_sample.py +27 -0
  269. lightly_studio/resolvers/metadata_resolver/sample/set_value_for_sample.py +53 -0
  270. lightly_studio/resolvers/sample_embedding_resolver.py +132 -0
  271. lightly_studio/resolvers/sample_resolver/__init__.py +17 -0
  272. lightly_studio/resolvers/sample_resolver/count_by_dataset_id.py +16 -0
  273. lightly_studio/resolvers/sample_resolver/create.py +16 -0
  274. lightly_studio/resolvers/sample_resolver/create_many.py +25 -0
  275. lightly_studio/resolvers/sample_resolver/get_by_id.py +14 -0
  276. lightly_studio/resolvers/sample_resolver/get_filtered_samples.py +56 -0
  277. lightly_studio/resolvers/sample_resolver/get_many_by_id.py +22 -0
  278. lightly_studio/resolvers/sample_resolver/sample_filter.py +74 -0
  279. lightly_studio/resolvers/settings_resolver.py +62 -0
  280. lightly_studio/resolvers/tag_resolver.py +299 -0
  281. lightly_studio/resolvers/twodim_embedding_resolver.py +119 -0
  282. lightly_studio/resolvers/video_frame_resolver/__init__.py +23 -0
  283. lightly_studio/resolvers/video_frame_resolver/count_video_frames_annotations.py +83 -0
  284. lightly_studio/resolvers/video_frame_resolver/create_many.py +57 -0
  285. lightly_studio/resolvers/video_frame_resolver/get_all_by_dataset_id.py +63 -0
  286. lightly_studio/resolvers/video_frame_resolver/get_by_id.py +13 -0
  287. lightly_studio/resolvers/video_frame_resolver/get_table_fields_bounds.py +44 -0
  288. lightly_studio/resolvers/video_frame_resolver/video_frame_annotations_counter_filter.py +47 -0
  289. lightly_studio/resolvers/video_frame_resolver/video_frame_filter.py +57 -0
  290. lightly_studio/resolvers/video_resolver/__init__.py +27 -0
  291. lightly_studio/resolvers/video_resolver/count_video_frame_annotations_by_video_dataset.py +86 -0
  292. lightly_studio/resolvers/video_resolver/create_many.py +58 -0
  293. lightly_studio/resolvers/video_resolver/filter_new_paths.py +33 -0
  294. lightly_studio/resolvers/video_resolver/get_all_by_dataset_id.py +181 -0
  295. lightly_studio/resolvers/video_resolver/get_by_id.py +22 -0
  296. lightly_studio/resolvers/video_resolver/get_table_fields_bounds.py +72 -0
  297. lightly_studio/resolvers/video_resolver/get_view_by_id.py +52 -0
  298. lightly_studio/resolvers/video_resolver/video_count_annotations_filter.py +50 -0
  299. lightly_studio/resolvers/video_resolver/video_filter.py +98 -0
  300. lightly_studio/selection/__init__.py +1 -0
  301. lightly_studio/selection/mundig.py +143 -0
  302. lightly_studio/selection/select.py +203 -0
  303. lightly_studio/selection/select_via_db.py +273 -0
  304. lightly_studio/selection/selection_config.py +49 -0
  305. lightly_studio/services/annotations_service/__init__.py +33 -0
  306. lightly_studio/services/annotations_service/create_annotation.py +64 -0
  307. lightly_studio/services/annotations_service/delete_annotation.py +22 -0
  308. lightly_studio/services/annotations_service/get_annotation_by_id.py +31 -0
  309. lightly_studio/services/annotations_service/update_annotation.py +54 -0
  310. lightly_studio/services/annotations_service/update_annotation_bounding_box.py +36 -0
  311. lightly_studio/services/annotations_service/update_annotation_label.py +48 -0
  312. lightly_studio/services/annotations_service/update_annotations.py +29 -0
  313. lightly_studio/setup_logging.py +59 -0
  314. lightly_studio/type_definitions.py +31 -0
  315. lightly_studio/utils/__init__.py +3 -0
  316. lightly_studio/utils/download.py +94 -0
  317. lightly_studio/vendor/__init__.py +1 -0
  318. lightly_studio/vendor/mobileclip/ACKNOWLEDGEMENTS +422 -0
  319. lightly_studio/vendor/mobileclip/LICENSE +31 -0
  320. lightly_studio/vendor/mobileclip/LICENSE_weights_data +50 -0
  321. lightly_studio/vendor/mobileclip/README.md +5 -0
  322. lightly_studio/vendor/mobileclip/__init__.py +96 -0
  323. lightly_studio/vendor/mobileclip/clip.py +77 -0
  324. lightly_studio/vendor/mobileclip/configs/mobileclip_b.json +18 -0
  325. lightly_studio/vendor/mobileclip/configs/mobileclip_s0.json +18 -0
  326. lightly_studio/vendor/mobileclip/configs/mobileclip_s1.json +18 -0
  327. lightly_studio/vendor/mobileclip/configs/mobileclip_s2.json +18 -0
  328. lightly_studio/vendor/mobileclip/image_encoder.py +67 -0
  329. lightly_studio/vendor/mobileclip/logger.py +154 -0
  330. lightly_studio/vendor/mobileclip/models/__init__.py +10 -0
  331. lightly_studio/vendor/mobileclip/models/mci.py +933 -0
  332. lightly_studio/vendor/mobileclip/models/vit.py +433 -0
  333. lightly_studio/vendor/mobileclip/modules/__init__.py +4 -0
  334. lightly_studio/vendor/mobileclip/modules/common/__init__.py +4 -0
  335. lightly_studio/vendor/mobileclip/modules/common/mobileone.py +341 -0
  336. lightly_studio/vendor/mobileclip/modules/common/transformer.py +451 -0
  337. lightly_studio/vendor/mobileclip/modules/image/__init__.py +4 -0
  338. lightly_studio/vendor/mobileclip/modules/image/image_projection.py +113 -0
  339. lightly_studio/vendor/mobileclip/modules/image/replknet.py +188 -0
  340. lightly_studio/vendor/mobileclip/modules/text/__init__.py +4 -0
  341. lightly_studio/vendor/mobileclip/modules/text/repmixer.py +281 -0
  342. lightly_studio/vendor/mobileclip/modules/text/tokenizer.py +38 -0
  343. lightly_studio/vendor/mobileclip/text_encoder.py +245 -0
  344. lightly_studio/vendor/perception_encoder/LICENSE.PE +201 -0
  345. lightly_studio/vendor/perception_encoder/README.md +11 -0
  346. lightly_studio/vendor/perception_encoder/vision_encoder/__init__.py +0 -0
  347. lightly_studio/vendor/perception_encoder/vision_encoder/bpe_simple_vocab_16e6.txt.gz +0 -0
  348. lightly_studio/vendor/perception_encoder/vision_encoder/config.py +205 -0
  349. lightly_studio/vendor/perception_encoder/vision_encoder/config_src.py +264 -0
  350. lightly_studio/vendor/perception_encoder/vision_encoder/pe.py +766 -0
  351. lightly_studio/vendor/perception_encoder/vision_encoder/rope.py +352 -0
  352. lightly_studio/vendor/perception_encoder/vision_encoder/tokenizer.py +347 -0
  353. lightly_studio/vendor/perception_encoder/vision_encoder/transforms.py +36 -0
  354. lightly_studio-0.4.6.dist-info/METADATA +88 -0
  355. lightly_studio-0.4.6.dist-info/RECORD +356 -0
  356. lightly_studio-0.4.6.dist-info/WHEEL +4 -0
@@ -0,0 +1,70 @@
1
+ """This module contains the Dataset model and related enumerations."""
2
+
3
+ from datetime import datetime, timezone
4
+ from enum import Enum
5
+ from typing import List, Optional
6
+ from uuid import UUID, uuid4
7
+
8
+ from sqlmodel import Field, Relationship, SQLModel
9
+
10
+
11
+ class SampleType(str, Enum):
12
+ """The type of samples in the dataset."""
13
+
14
+ VIDEO = "video"
15
+ VIDEO_FRAME = "video_frame"
16
+ IMAGE = "image"
17
+ ANNOTATION = "annotation"
18
+ CAPTION = "caption"
19
+
20
+
21
+ class DatasetBase(SQLModel):
22
+ """Base class for the Dataset model."""
23
+
24
+ name: str = Field(unique=True, index=True)
25
+ parent_dataset_id: Optional[UUID] = Field(default=None, foreign_key="dataset.dataset_id")
26
+ sample_type: SampleType
27
+
28
+
29
+ class DatasetCreate(DatasetBase):
30
+ """Dataset class when inserting."""
31
+
32
+
33
+ class DatasetView(DatasetBase):
34
+ """Dataset class when retrieving."""
35
+
36
+ dataset_id: UUID
37
+ created_at: datetime
38
+ updated_at: datetime
39
+ children: List["DatasetView"] = []
40
+
41
+
42
+ class DatasetViewWithCount(DatasetView):
43
+ """Dataset view with total sample count."""
44
+
45
+ total_sample_count: int
46
+
47
+
48
+ class DatasetOverviewView(SQLModel):
49
+ """Dataset view for dashboard display."""
50
+
51
+ dataset_id: UUID
52
+ name: str
53
+ sample_type: SampleType
54
+ created_at: datetime
55
+ total_sample_count: int
56
+
57
+
58
+ class DatasetTable(DatasetBase, table=True):
59
+ """This class defines the Dataset model."""
60
+
61
+ __tablename__ = "dataset"
62
+ dataset_id: UUID = Field(default_factory=uuid4, primary_key=True)
63
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
64
+ updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
65
+
66
+ parent: Optional["DatasetTable"] = Relationship(
67
+ back_populates="children",
68
+ sa_relationship_kwargs={"remote_side": "DatasetTable.dataset_id"},
69
+ )
70
+ children: List["DatasetTable"] = Relationship(back_populates="parent")
@@ -0,0 +1,30 @@
1
+ """This module defines the Embedding_Model model for the application."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from uuid import UUID, uuid4
7
+
8
+ from sqlmodel import CHAR, Column, Field, SQLModel
9
+
10
+
11
+ class EmbeddingModelBase(SQLModel):
12
+ """Base class for the EmbeddingModel."""
13
+
14
+ name: str
15
+ parameter_count_in_mb: int | None = None
16
+ embedding_model_hash: str = Field(default="", sa_column=Column(CHAR(128)))
17
+ embedding_dimension: int
18
+ dataset_id: UUID = Field(default=None, foreign_key="dataset.dataset_id")
19
+
20
+
21
+ class EmbeddingModelCreate(EmbeddingModelBase):
22
+ """Model used for creating an embedding model."""
23
+
24
+
25
+ class EmbeddingModelTable(EmbeddingModelBase, table=True):
26
+ """This class defines the EmbeddingModel model."""
27
+
28
+ __tablename__ = "embedding_model"
29
+ embedding_model_id: UUID = Field(default_factory=uuid4, primary_key=True)
30
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
@@ -0,0 +1,96 @@
1
+ """This module defines the User model for the application."""
2
+
3
+ from datetime import datetime, timezone
4
+ from typing import TYPE_CHECKING, List, Literal, Optional
5
+ from uuid import UUID
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+ from pydantic import Field as PydanticField
9
+ from sqlalchemy.orm import Mapped
10
+ from sqlmodel import Field, Relationship, SQLModel
11
+
12
+ from lightly_studio.models.annotation.annotation_base import AnnotationView
13
+ from lightly_studio.models.caption import CaptionView
14
+ from lightly_studio.models.sample import SampleTable, SampleView
15
+
16
+ if TYPE_CHECKING:
17
+ from lightly_studio.models.metadata import (
18
+ SampleMetadataView,
19
+ )
20
+ else:
21
+ SampleMetadataView = object
22
+
23
+
24
+ class ImageBase(SQLModel):
25
+ """Base class for the Image model."""
26
+
27
+ """The name of the image file."""
28
+ file_name: str
29
+
30
+ """The width of the image in pixels."""
31
+ width: int
32
+
33
+ """The height of the image in pixels."""
34
+ height: int
35
+
36
+ """The dataset image path."""
37
+ file_path_abs: str = Field(default=None)
38
+
39
+
40
+ class ImageCreate(ImageBase):
41
+ """Image class when inserting."""
42
+
43
+
44
+ class ImageTable(ImageBase, table=True):
45
+ """This class defines the Image model."""
46
+
47
+ __tablename__ = "image"
48
+ sample_id: UUID = Field(foreign_key="sample.sample_id", primary_key=True)
49
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
50
+ updated_at: datetime = Field(
51
+ default_factory=lambda: datetime.now(timezone.utc),
52
+ )
53
+ sample: Mapped["SampleTable"] = Relationship()
54
+
55
+
56
+ TagKind = Literal[
57
+ "sample",
58
+ "annotation",
59
+ ]
60
+
61
+
62
+ class ImageView(BaseModel):
63
+ """Image class when retrieving."""
64
+
65
+ class ImageViewTag(BaseModel):
66
+ """Tag view inside Image view."""
67
+
68
+ tag_id: UUID
69
+ name: str
70
+ kind: TagKind
71
+ created_at: datetime
72
+ updated_at: datetime
73
+
74
+ file_name: str
75
+ file_path_abs: str
76
+ sample_id: UUID
77
+ annotations: List["AnnotationView"]
78
+ width: int
79
+ height: int
80
+
81
+ sample: SampleView
82
+
83
+ # TODO(Michal, 10/2025): Add SampleView to ImageView, don't expose these fields directly.
84
+ tags: List[ImageViewTag]
85
+ metadata_dict: Optional["SampleMetadataView"] = None
86
+ captions: List[CaptionView] = []
87
+
88
+
89
+ class ImageViewsWithCount(BaseModel):
90
+ """Response model for counted images."""
91
+
92
+ model_config = ConfigDict(populate_by_name=True)
93
+
94
+ samples: List[ImageView] = PydanticField(..., alias="data")
95
+ total_count: int
96
+ next_cursor: Optional[int] = PydanticField(None, alias="nextCursor")
@@ -0,0 +1,208 @@
1
+ """Metadata models for storing custom metadata."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from typing import TYPE_CHECKING, Any
7
+ from uuid import UUID, uuid4
8
+
9
+ from pydantic import BaseModel
10
+ from sqlalchemy.orm.attributes import flag_modified
11
+ from sqlalchemy.types import JSON
12
+ from sqlmodel import Field, Relationship, SQLModel
13
+
14
+ from lightly_studio.metadata.complex_metadata import (
15
+ COMPLEX_METADATA_TYPES,
16
+ deserialize_complex_metadata,
17
+ serialize_complex_metadata,
18
+ )
19
+
20
+ if TYPE_CHECKING:
21
+ from lightly_studio.models.sample import SampleTable
22
+ else:
23
+ SampleTable = object
24
+
25
+
26
+ TYPE_TO_NAME_MAP = {
27
+ bool: "boolean",
28
+ int: "integer",
29
+ float: "float",
30
+ str: "string",
31
+ list: "list",
32
+ dict: "dict",
33
+ }
34
+
35
+ NAME_TO_TYPE_MAP = {
36
+ "string": str,
37
+ "integer": int,
38
+ "float": float,
39
+ "boolean": bool,
40
+ "list": list,
41
+ "dict": dict,
42
+ }
43
+
44
+
45
+ def get_type_name(value: Any) -> str:
46
+ """Get the type name for a value.
47
+
48
+ Args:
49
+ value: The value to get the type name for.
50
+
51
+ Returns:
52
+ The type name as a string.
53
+ """
54
+ if value is None:
55
+ return "null"
56
+ # Check if it's a complex metadata type.
57
+ for name, cls in COMPLEX_METADATA_TYPES.items():
58
+ if isinstance(value, cls):
59
+ return name
60
+
61
+ # Return mapped type name or fallback to class name.
62
+ return TYPE_TO_NAME_MAP.get(type(value), type(value).__name__.lower())
63
+
64
+
65
+ def validate_type_compatibility(expected_type: str, value: Any) -> bool:
66
+ """Validate that a value is compatible with an expected type.
67
+
68
+ Args:
69
+ expected_type: The expected type name.
70
+ value: The value to validate.
71
+
72
+ Returns:
73
+ True if compatible, False otherwise.
74
+ """
75
+ if value is None:
76
+ return expected_type == "null"
77
+
78
+ # Check complex types.
79
+ if expected_type in COMPLEX_METADATA_TYPES:
80
+ expected_complex_cls = COMPLEX_METADATA_TYPES[expected_type]
81
+ assert expected_complex_cls is not None
82
+ return isinstance(value, expected_complex_cls)
83
+
84
+ # Check simple types
85
+ expected_cls = NAME_TO_TYPE_MAP.get(expected_type)
86
+ if expected_cls is None:
87
+ return False
88
+
89
+ return isinstance(value, expected_cls)
90
+
91
+
92
+ class MetadataBase(SQLModel):
93
+ """Base class for CustomMetadata models."""
94
+
95
+ custom_metadata_id: UUID = Field(default_factory=uuid4, primary_key=True)
96
+ created_at: datetime = Field(
97
+ default_factory=lambda: datetime.now(timezone.utc),
98
+ )
99
+ updated_at: datetime = Field(
100
+ default_factory=lambda: datetime.now(timezone.utc),
101
+ )
102
+ # Dictionary storing the actual metadata values as JSON.
103
+ data: dict[str, Any] = Field(
104
+ default_factory=dict,
105
+ sa_type=JSON,
106
+ description="Custom metadata stored as JSON",
107
+ )
108
+ # Dictionary storing the metadata schema.
109
+ metadata_schema: dict[str, str] = Field(
110
+ default_factory=dict,
111
+ sa_type=JSON,
112
+ description="Schema information for metadata keys",
113
+ )
114
+
115
+ def ensure_schema(self, key: str, value: Any) -> None:
116
+ """Ensure schema exists for a key and validate value type.
117
+
118
+ This method handles schema management for metadata keys:
119
+ If the key doesn't exist in the schema, it creates a new entry
120
+ with the inferred type from the provided value
121
+ If the key exists, it validates that the new value matches
122
+ the expected type from the schema
123
+
124
+ This ensures type consistency across metadata operations and prevents
125
+ accidental type mismatches that could cause issues in applications.
126
+
127
+ Args:
128
+ key: The metadata key to validate/update schema for
129
+ value: The value to validate/use for type inference
130
+
131
+ Raises:
132
+ ValueError: If the value type doesn't match existing schema
133
+ """
134
+ if key not in self.metadata_schema:
135
+ # New key - create schema with actual type name.
136
+ self.metadata_schema[key] = get_type_name(value)
137
+ else:
138
+ # Existing key - validate type.
139
+ existing_type = self.metadata_schema[key]
140
+ if not validate_type_compatibility(existing_type, value):
141
+ raise ValueError(
142
+ f"Value type mismatch for key '{key}'. "
143
+ f"Expected {existing_type}, got {get_type_name(value)}."
144
+ )
145
+
146
+ def set_value(self, key: str, value: Any) -> None:
147
+ """Set a metadata value with schema validation and database tracking.
148
+
149
+ Args:
150
+ key: The metadata key to set
151
+ value: The value to set
152
+
153
+ Raises:
154
+ ValueError: If the value type doesn't match the schema
155
+ """
156
+ self.ensure_schema(key, value)
157
+ # Serialize complex metadata for storage.
158
+ self.data[key] = serialize_complex_metadata(value)
159
+ self.updated_at = datetime.now(timezone.utc)
160
+ # Mark the object as modified so SQLAlchemy knows to update it.
161
+ flag_modified(self, "data")
162
+ flag_modified(self, "metadata_schema")
163
+
164
+ def get_value(self, key: str) -> Any:
165
+ """Get a metadata value with automatic deserialization.
166
+
167
+ Args:
168
+ key: The metadata key.
169
+
170
+ Returns:
171
+ The deserialized value (complex metadata object if applicable)
172
+ or None if the key doesn't exist.
173
+ """
174
+ value = self.data.get(key)
175
+ if value is not None:
176
+ # Get expected type from schema for deserialization.
177
+ expected_type = self.metadata_schema.get(key)
178
+ if expected_type:
179
+ return deserialize_complex_metadata(value, expected_type)
180
+ return value
181
+
182
+
183
+ class MetadataCreate(MetadataBase):
184
+ """Input class for Metadata model."""
185
+
186
+
187
+ class SampleMetadataTable(MetadataBase, table=True):
188
+ """This class defines the SampleMetadataTable model."""
189
+
190
+ __tablename__ = "metadata"
191
+ sample_id: UUID = Field(foreign_key="sample.sample_id", unique=True)
192
+
193
+ sample: SampleTable = Relationship(back_populates="metadata_dict")
194
+
195
+
196
+ class SampleMetadataView(SQLModel):
197
+ """Sample metadata class when retrieving."""
198
+
199
+ data: dict[str, Any]
200
+
201
+
202
+ class MetadataInfoView(BaseModel):
203
+ """Metadata info response model for API endpoints."""
204
+
205
+ name: str = Field(description="The metadata key name")
206
+ type: str = Field(description="The metadata type (e.g., 'string', 'integer', 'float')")
207
+ min: int | float | None = Field(None, description="Minimum value for numerical metadata")
208
+ max: int | float | None = Field(None, description="Maximum value for numerical metadata")
@@ -0,0 +1,17 @@
1
+ """Models representing numeric ranges."""
2
+
3
+ from pydantic import BaseModel
4
+
5
+
6
+ class FloatRange(BaseModel):
7
+ """Defines a range of floating-point values."""
8
+
9
+ min: float
10
+ max: float
11
+
12
+
13
+ class IntRange(BaseModel):
14
+ """Defines a range of integer-point values."""
15
+
16
+ min: int
17
+ max: int
@@ -0,0 +1,154 @@
1
+ """This module defines the Sample model for the application."""
2
+
3
+ from datetime import datetime, timezone
4
+ from typing import TYPE_CHECKING, Any, List, Optional
5
+ from uuid import UUID, uuid4
6
+
7
+ from pydantic import BaseModel, ConfigDict
8
+ from pydantic import Field as PydanticField
9
+ from sqlalchemy.orm import Mapped, Session
10
+ from sqlmodel import Field, Relationship, SQLModel
11
+
12
+ from lightly_studio.resolvers import metadata_resolver
13
+
14
+ if TYPE_CHECKING:
15
+ from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable, AnnotationView
16
+ from lightly_studio.models.caption import CaptionTable, CaptionView
17
+ from lightly_studio.models.metadata import (
18
+ SampleMetadataTable,
19
+ SampleMetadataView,
20
+ )
21
+ from lightly_studio.models.sample_embedding import SampleEmbeddingTable
22
+ from lightly_studio.models.tag import TagTable
23
+
24
+ else:
25
+ AnnotationBaseTable = object
26
+ TagTable = object
27
+ SampleEmbeddingTable = object
28
+ SampleMetadataTable = object
29
+ SampleMetadataView = object
30
+ CaptionTable = object
31
+ CaptionView = object
32
+ AnnotationView = object
33
+
34
+
35
+ class SampleTagLinkTable(SQLModel, table=True):
36
+ """Model to define links between Sample and Tag Many-to-Many."""
37
+
38
+ sample_id: Optional[UUID] = Field(
39
+ default=None, foreign_key="sample.sample_id", primary_key=True
40
+ )
41
+ tag_id: Optional[UUID] = Field(default=None, foreign_key="tag.tag_id", primary_key=True)
42
+
43
+
44
+ class SampleBase(SQLModel):
45
+ """Base class for the Sample model."""
46
+
47
+ """The dataset ID to which the sample belongs."""
48
+ dataset_id: UUID = Field(default=None, foreign_key="dataset.dataset_id")
49
+
50
+
51
+ class SampleCreate(SampleBase):
52
+ """Sample class when inserting."""
53
+
54
+
55
+ class SampleTable(SampleBase, table=True):
56
+ """This class defines the Sample model."""
57
+
58
+ __tablename__ = "sample"
59
+ sample_id: UUID = Field(default_factory=uuid4, primary_key=True)
60
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
61
+ updated_at: datetime = Field(
62
+ default_factory=lambda: datetime.now(timezone.utc),
63
+ )
64
+
65
+ tags: Mapped[List["TagTable"]] = Relationship(
66
+ back_populates="samples", link_model=SampleTagLinkTable
67
+ )
68
+ embeddings: Mapped[List["SampleEmbeddingTable"]] = Relationship(back_populates="sample")
69
+ metadata_dict: "SampleMetadataTable" = Relationship(back_populates="sample")
70
+ annotations: Mapped[List["AnnotationBaseTable"]] = Relationship(
71
+ back_populates="parent_sample",
72
+ sa_relationship_kwargs={
73
+ "lazy": "select",
74
+ "foreign_keys": "[AnnotationBaseTable.parent_sample_id]",
75
+ },
76
+ )
77
+ captions: Mapped[List["CaptionTable"]] = Relationship(
78
+ back_populates="parent_sample",
79
+ sa_relationship_kwargs={
80
+ "foreign_keys": "[CaptionTable.parent_sample_id]",
81
+ },
82
+ )
83
+
84
+ # TODO(Michal, 9/2025): Remove this function in favour of Sample.metadata.
85
+ def __getitem__(self, key: str) -> Any:
86
+ """Provides dict-like access to sample metadata.
87
+
88
+ Args:
89
+ key: The metadata key to access.
90
+
91
+ Returns:
92
+ The metadata value for the given key, or None if the key doesn't
93
+ exist.
94
+ """
95
+ if self.metadata_dict is None:
96
+ return None
97
+ return self.metadata_dict.get_value(key)
98
+
99
+ # TODO(Michal, 9/2025): Remove this function in favour of Sample.metadata.
100
+ def __setitem__(self, key: str, value: Any) -> None:
101
+ """Sets a metadata key-value pair for this sample.
102
+
103
+ Args:
104
+ key: The metadata key.
105
+ value: The metadata value.
106
+
107
+ Note:
108
+ If the sample has no metadata, a new Metadata Table instance
109
+ will be created. Changes are automatically committed to the
110
+ database.
111
+
112
+ Raises:
113
+ RuntimeError: If no database session is found.
114
+ """
115
+ # Get the session from the instance
116
+ session = Session.object_session(self)
117
+ if session is None:
118
+ raise RuntimeError("No database session found for this instance")
119
+
120
+ # Use metadata_resolver to handle the database operations.
121
+ # Added type: ignore to avoid type checking issues. SQLAlchemy and
122
+ # SQLModel sessions are compatible at runtime but have different type
123
+ # annotations.
124
+ metadata_resolver.set_value_for_sample(
125
+ session=session, # type: ignore[arg-type]
126
+ sample_id=self.sample_id,
127
+ key=key,
128
+ value=value,
129
+ )
130
+
131
+
132
+ class SampleView(SampleBase):
133
+ """This class defines the Sample view model."""
134
+
135
+ dataset_id: UUID
136
+
137
+ sample_id: UUID
138
+ created_at: datetime
139
+ updated_at: datetime
140
+
141
+ tags: List["TagTable"] = []
142
+ metadata_dict: Optional["SampleMetadataView"] = None
143
+ captions: List[CaptionView] = []
144
+ annotations: List["AnnotationView"] = []
145
+
146
+
147
+ class SampleViewsWithCount(BaseModel):
148
+ """Result of getting all sample views."""
149
+
150
+ model_config = ConfigDict(populate_by_name=True)
151
+
152
+ samples: List[SampleView] = PydanticField(..., alias="data")
153
+ total_count: int
154
+ next_cursor: Optional[int] = PydanticField(None, alias="nextCursor")
@@ -0,0 +1,36 @@
1
+ """This module defines the SampleEmbedding model for the application."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING
6
+ from uuid import UUID
7
+
8
+ from sqlalchemy import ARRAY, Float
9
+ from sqlmodel import Column, Field, Relationship, SQLModel
10
+
11
+ if TYPE_CHECKING:
12
+ from lightly_studio.models.sample import SampleTable
13
+
14
+ else:
15
+ SampleTable = object
16
+
17
+
18
+ class SampleEmbeddingBase(SQLModel):
19
+ """Base class for the Embeddings used for Samples."""
20
+
21
+ sample_id: UUID = Field(foreign_key="sample.sample_id", primary_key=True)
22
+ embedding_model_id: UUID = Field(
23
+ foreign_key="embedding_model.embedding_model_id", primary_key=True
24
+ )
25
+ embedding: list[float] = Field(sa_column=Column(ARRAY(Float)))
26
+
27
+
28
+ class SampleEmbeddingCreate(SampleEmbeddingBase):
29
+ """Sample embedding class when inserting."""
30
+
31
+
32
+ class SampleEmbeddingTable(SampleEmbeddingBase, table=True):
33
+ """This class defines the SampleEmbedding model."""
34
+
35
+ __tablename__ = "sample_embedding"
36
+ sample: SampleTable = Relationship(back_populates="embeddings")
@@ -0,0 +1,69 @@
1
+ """This module contains settings model for user preferences."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime, timezone
6
+ from enum import Enum
7
+ from uuid import UUID, uuid4
8
+
9
+ from sqlmodel import Field, SQLModel
10
+
11
+
12
+ class GridViewSampleRenderingType(str, Enum):
13
+ """Defines how samples are rendered in the grid view."""
14
+
15
+ COVER = "cover"
16
+ CONTAIN = "contain"
17
+
18
+
19
+ class SettingBase(SQLModel):
20
+ """Base class for Settings model."""
21
+
22
+ grid_view_sample_rendering: GridViewSampleRenderingType = Field(
23
+ default=GridViewSampleRenderingType.CONTAIN,
24
+ description="Controls how samples are rendered in the grid view",
25
+ )
26
+
27
+ # Keyboard shortcuts.
28
+ key_hide_annotations: str = Field(
29
+ default="v",
30
+ description="Key to temporarily hide annotations while pressed",
31
+ )
32
+ key_go_back: str = Field(
33
+ default="Escape",
34
+ description="Key to navigate back from detail view to grid view",
35
+ )
36
+ key_toggle_edit_mode: str = Field(
37
+ default="e",
38
+ description="Key to toggle annotation edit mode",
39
+ )
40
+
41
+ # New setting for annotation text visibility.
42
+ show_annotation_text_labels: bool = Field(
43
+ default=True,
44
+ description="Controls whether to show text labels on annotations",
45
+ )
46
+
47
+ show_sample_filenames: bool = Field(
48
+ default=False,
49
+ description="Controls whether to show sample filenames in the samples grid view",
50
+ )
51
+
52
+
53
+ class SettingView(SettingBase):
54
+ """View class for Settings model."""
55
+
56
+ setting_id: UUID
57
+ created_at: datetime
58
+ updated_at: datetime
59
+
60
+
61
+ class SettingTable(SettingBase, table=True):
62
+ """This class defines the Setting model."""
63
+
64
+ __tablename__ = "setting"
65
+ setting_id: UUID = Field(default_factory=uuid4, primary_key=True)
66
+ created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
67
+ updated_at: datetime = Field(
68
+ default_factory=lambda: datetime.now(timezone.utc),
69
+ )