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,37 @@
1
+ """Fields for querying sample properties in the dataset query system."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from sqlmodel import col
6
+
7
+ from lightly_studio.core.dataset_query.field import (
8
+ DatetimeField,
9
+ NumericalField,
10
+ StringField,
11
+ )
12
+ from lightly_studio.core.dataset_query.tags_expression import TagsAccessor
13
+ from lightly_studio.models.image import ImageTable
14
+
15
+
16
+ class SampleField:
17
+ """Providing access to predefined sample fields for queries.
18
+
19
+ It is used for the `query.match(...)` and `query.order_by(...)` methods of the
20
+ `DatasetQuery` class.
21
+
22
+ ```python
23
+ from lightly_studio.core.dataset_query import DatasetQuery, SampleField, OrderByField
24
+
25
+ query = dataset.query()
26
+ query.match(SampleField.tags.contains("cat"))
27
+ query.order_by(OrderByField(SampleField.file_path_abs))
28
+ samples = query.to_list()
29
+ ```
30
+ """
31
+
32
+ file_name = StringField(col(ImageTable.file_name))
33
+ width = NumericalField(col(ImageTable.width))
34
+ height = NumericalField(col(ImageTable.height))
35
+ file_path_abs = StringField(col(ImageTable.file_path_abs))
36
+ created_at = DatetimeField(col(ImageTable.created_at))
37
+ tags = TagsAccessor()
@@ -0,0 +1,46 @@
1
+ """Tag field classes for building dataset queries on sample tags."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from sqlalchemy import ColumnElement
8
+ from sqlmodel import col
9
+
10
+ from lightly_studio.core.dataset_query.match_expression import MatchExpression
11
+ from lightly_studio.models.sample import SampleTable
12
+ from lightly_studio.models.tag import TagTable
13
+
14
+
15
+ class TagsAccessor:
16
+ """Provides access to tag operations for query building.
17
+
18
+ This class enables checking tag membership using the contains method:
19
+ SampleField.tags.contains("tag_name") returns a TagsContainsExpression.
20
+ """
21
+
22
+ def contains(self, tag_name: str) -> TagsContainsExpression:
23
+ """Check if a tag name is in the sample's tags.
24
+
25
+ Args:
26
+ tag_name: The name of the tag to check for.
27
+
28
+ Returns:
29
+ A TagsContainsExpression for building queries.
30
+ """
31
+ return TagsContainsExpression(tag_name=tag_name)
32
+
33
+
34
+ @dataclass
35
+ class TagsContainsExpression(MatchExpression):
36
+ """Expression for checking if a sample contains a specific tag."""
37
+
38
+ tag_name: str
39
+
40
+ def get(self) -> ColumnElement[bool]:
41
+ """Get the tag contains expression.
42
+
43
+ Returns:
44
+ The SQLAlchemy expression for this field expression.
45
+ """
46
+ return SampleTable.tags.any(col(TagTable.name) == self.tag_name)
@@ -0,0 +1,36 @@
1
+ """Definition of ImageSample class, representing a dataset image sample."""
2
+
3
+ from sqlmodel import col
4
+
5
+ from lightly_studio.core.sample import DBField, Sample
6
+ from lightly_studio.models.image import ImageTable
7
+
8
+
9
+ class ImageSample(Sample):
10
+ """Interface to a dataset image sample.
11
+
12
+ Many properties of the sample are directly accessible as attributes of this class.
13
+ ```python
14
+ print(f"Sample file name: {sample.file_name}")
15
+ print(f"Sample file path: {sample.file_path_abs}")
16
+ print(f"Sample width: {sample.width}")
17
+ print(f"Sample height: {sample.height}")
18
+ ```
19
+ """
20
+
21
+ file_name = DBField(col(ImageTable.file_name))
22
+ width = DBField(col(ImageTable.width))
23
+ height = DBField(col(ImageTable.height))
24
+ file_path_abs = DBField(col(ImageTable.file_path_abs))
25
+
26
+ created_at = DBField(col(ImageTable.created_at))
27
+ updated_at = DBField(col(ImageTable.updated_at))
28
+
29
+ def __init__(self, inner: ImageTable) -> None:
30
+ """Initialize the Sample.
31
+
32
+ Args:
33
+ inner: The ImageTable SQLAlchemy model instance.
34
+ """
35
+ self.inner = inner
36
+ super().__init__(sample_table=inner.sample)
@@ -0,0 +1,56 @@
1
+ """Functions to add samples and their annotations to a dataset in the database."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from dataclasses import dataclass, field
7
+ from uuid import UUID
8
+
9
+ from sqlmodel import Session
10
+
11
+ from lightly_studio.resolvers import (
12
+ sample_resolver,
13
+ )
14
+
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Constants
18
+ MAX_EXAMPLE_PATHS_TO_SHOW = 5
19
+
20
+
21
+ @dataclass
22
+ class LoadingLoggingContext:
23
+ """Context for the logging while loading data."""
24
+
25
+ n_samples_before_loading: int
26
+ n_samples_to_be_inserted: int = 0
27
+ example_paths_not_inserted: list[str] = field(default_factory=list)
28
+
29
+ def update_example_paths(self, example_paths_not_inserted: list[str]) -> None:
30
+ """Update the list of example paths that were not inserted."""
31
+ if len(self.example_paths_not_inserted) >= MAX_EXAMPLE_PATHS_TO_SHOW:
32
+ return
33
+ upper_limit = MAX_EXAMPLE_PATHS_TO_SHOW - len(self.example_paths_not_inserted)
34
+ self.example_paths_not_inserted.extend(example_paths_not_inserted[:upper_limit])
35
+
36
+
37
+ def log_loading_results(
38
+ session: Session, dataset_id: UUID, logging_context: LoadingLoggingContext
39
+ ) -> None:
40
+ """Log the results of loading samples into a dataset.
41
+
42
+ Calculates how many samples were successfully inserted by comparing the
43
+ current sample count with the count before loading. Prints a summary message
44
+ and, if any paths failed to be inserted, prints examples of those paths.
45
+ """
46
+ n_samples_end = sample_resolver.count_by_dataset_id(session=session, dataset_id=dataset_id)
47
+ n_samples_inserted = n_samples_end - logging_context.n_samples_before_loading
48
+ logger.info(
49
+ f"Added {n_samples_inserted} out of {logging_context.n_samples_to_be_inserted} "
50
+ "new samples to the dataset."
51
+ )
52
+ if logging_context.example_paths_not_inserted:
53
+ logger.warning(
54
+ "Examples of paths that were not added: "
55
+ f"{', '.join(logging_context.example_paths_not_inserted)}"
56
+ )
@@ -0,0 +1,291 @@
1
+ """Interface for Sample objects."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from abc import ABC
6
+ from collections.abc import Iterable
7
+ from typing import Any, Generic, Protocol, TypeVar, cast
8
+ from uuid import UUID
9
+
10
+ from sqlalchemy.orm import Mapped, object_session
11
+ from sqlmodel import Session
12
+
13
+ from lightly_studio.models.caption import CaptionCreate
14
+ from lightly_studio.models.sample import SampleTable
15
+ from lightly_studio.resolvers import caption_resolver, metadata_resolver, tag_resolver
16
+
17
+ T = TypeVar("T")
18
+
19
+
20
+ class _DBFieldOwner(Protocol):
21
+ inner: Any
22
+
23
+ def get_object_session(self) -> Session: ...
24
+
25
+
26
+ class DBField(Generic[T]):
27
+ """Descriptor for a database-backed field.
28
+
29
+ Provides interface to a SQLAlchemy model field. Setting the field
30
+ immediately commits to the database. The owner class must implement
31
+ the inner attribute and the get_object_session() method.
32
+ """
33
+
34
+ __slots__ = ("_sqla_descriptor",)
35
+ """Store the SQLAlchemy descriptor for accessing the field."""
36
+
37
+ def __init__(self, sqla_descriptor: Mapped[T]) -> None:
38
+ """Initialize the DBField with a SQLAlchemy descriptor."""
39
+ self._sqla_descriptor = sqla_descriptor
40
+
41
+ def __get__(self, obj: _DBFieldOwner | None, owner: type | None = None) -> T:
42
+ """Get the value of the field from the database."""
43
+ assert obj is not None, "DBField must be accessed via an instance, not the class"
44
+ # Delegate to SQLAlchemy's descriptor.
45
+ value: T = self._sqla_descriptor.__get__(obj.inner, type(obj.inner))
46
+ return value
47
+
48
+ def __set__(self, obj: _DBFieldOwner, value: T) -> None:
49
+ """Set the value of the field in the database. Commits the session."""
50
+ # Delegate to SQLAlchemy's descriptor.
51
+ self._sqla_descriptor.__set__(obj.inner, value)
52
+ obj.get_object_session().commit()
53
+
54
+
55
+ class Sample(ABC):
56
+ """Interface to a dataset sample.
57
+
58
+ It is usually returned by a query to the dataset.
59
+ ```python
60
+ for sample in dataset:
61
+ ...
62
+ ```
63
+
64
+ Access sample's metadata via the `metadata` property, which
65
+ provides a dictionary-like interface to get and set metadata key-value pairs.
66
+ ```python
67
+ some_value = sample.metadata["some_key"]
68
+ sample.metadata["another_key"] = "new_value"
69
+ ```
70
+
71
+ Access sample's tags via the `tags` property.
72
+ ```python
73
+ sample.tags = ["tag1", "tag2"] # Replace all tags
74
+ print(f"Current tags: {sample.tags}")
75
+ sample.add_tag("tag_3")
76
+ sample.remove_tag("tag_1")
77
+ ```
78
+ """
79
+
80
+ _sample_table: SampleTable
81
+
82
+ @property
83
+ def sample_id(self) -> UUID:
84
+ """Sample ID."""
85
+ return self._sample_table.sample_id
86
+
87
+ def __init__(self, sample_table: SampleTable) -> None:
88
+ """Initialize the Sample.
89
+
90
+ Args:
91
+ sample_table: The SampleTable SQLAlchemy model instance.
92
+ """
93
+ self._sample_table = sample_table
94
+ self._metadata = SampleMetadata(self)
95
+
96
+ @property
97
+ def sample_table(self) -> SampleTable:
98
+ """Returns the SampleTable associated with this Sample."""
99
+ # TODO(lukas 12/2025): This should be later removed, as it exposes private implementation.
100
+ # Remove this once we add a `annotations` property and `embeddings` property.
101
+ return self._sample_table
102
+
103
+ def get_object_session(self) -> Session:
104
+ """Get the database session for this sample.
105
+
106
+ Returns:
107
+ The SQLModel session.
108
+
109
+ Raises:
110
+ RuntimeError: If no active session is found.
111
+ """
112
+ session = object_session(self._sample_table)
113
+ if session is None:
114
+ raise RuntimeError("No active session found for the sample")
115
+ # Cast from SQLAlchemy Session to SQLModel Session for mypy.
116
+ return cast(Session, session)
117
+
118
+ def add_tag(self, name: str) -> None:
119
+ """Add a tag to this sample.
120
+
121
+ If the tag doesn't exist, it will be created first.
122
+
123
+ Args:
124
+ name: The name of the tag to add.
125
+ """
126
+ session = self.get_object_session()
127
+
128
+ # Get or create the tag for this dataset.
129
+ tag = tag_resolver.get_or_create_sample_tag_by_name(
130
+ session=session, dataset_id=self.dataset_id, tag_name=name
131
+ )
132
+
133
+ # Add the tag to the sample if not already associated.
134
+ if tag not in self.sample_table.tags:
135
+ tag_resolver.add_tag_to_sample(
136
+ session=session, tag_id=tag.tag_id, sample=self.sample_table
137
+ )
138
+
139
+ def remove_tag(self, name: str) -> None:
140
+ """Remove a tag from this sample.
141
+
142
+ Args:
143
+ name: The name of the tag to remove.
144
+ """
145
+ session = self.get_object_session()
146
+
147
+ # Find the tag by name for this dataset.
148
+ existing_tag = tag_resolver.get_by_name(
149
+ session=session, tag_name=name, dataset_id=self.dataset_id
150
+ )
151
+
152
+ # Remove the tag from the sample if it exists and is associated
153
+ if existing_tag is not None and existing_tag in self.sample_table.tags:
154
+ tag_resolver.remove_tag_from_sample(
155
+ session=session, tag_id=existing_tag.tag_id, sample=self.sample_table
156
+ )
157
+
158
+ @property
159
+ def tags(self) -> set[str]:
160
+ """Get the tag names associated with this sample.
161
+
162
+ Returns:
163
+ A set of tag names as strings.
164
+ """
165
+ return {tag.name for tag in self.sample_table.tags}
166
+
167
+ @tags.setter
168
+ def tags(self, tags: Iterable[str]) -> None:
169
+ """Set the tags for this sample, replacing any existing tags.
170
+
171
+ Args:
172
+ tags: Iterable of tag names to associate with this sample.
173
+ """
174
+ # Get current tag names
175
+ current_tags = self.tags
176
+ new_tags = set(tags)
177
+
178
+ # Remove tags that are no longer needed
179
+ tags_to_remove = current_tags - new_tags
180
+ for tag_name in tags_to_remove:
181
+ self.remove_tag(tag_name)
182
+
183
+ # Add new tags
184
+ tags_to_add = new_tags - current_tags
185
+ for tag_name in tags_to_add:
186
+ self.add_tag(tag_name)
187
+
188
+ @property
189
+ def metadata(self) -> SampleMetadata:
190
+ """Get dictionary-like access to sample metadata.
191
+
192
+ Returns:
193
+ A dictionary-like object for accessing metadata.
194
+ """
195
+ return self._metadata
196
+
197
+ @property
198
+ def dataset_id(self) -> UUID:
199
+ """Get the dataset ID this sample belongs to.
200
+
201
+ Returns:
202
+ The UUID of the dataset.
203
+ """
204
+ return self.sample_table.dataset_id
205
+
206
+ def add_caption(self, text: str) -> None:
207
+ """Add a caption to this sample.
208
+
209
+ Args:
210
+ text: The text of the caption to add.
211
+ """
212
+ session = self.get_object_session()
213
+ caption_resolver.create_many(
214
+ session=session,
215
+ parent_dataset_id=self.dataset_id,
216
+ captions=[
217
+ CaptionCreate(
218
+ parent_sample_id=self.sample_id,
219
+ text=text,
220
+ ),
221
+ ],
222
+ )
223
+
224
+ @property
225
+ def captions(self) -> list[str]:
226
+ """Returns the text of all captions."""
227
+ return [caption.text for caption in self.sample_table.captions]
228
+
229
+ @captions.setter
230
+ def captions(self, captions: Iterable[str]) -> None:
231
+ """Set the captions for this sample, replacing any existing captions.
232
+
233
+ Args:
234
+ captions: Iterable of caption texts to associate with this sample.
235
+ """
236
+ session = self.get_object_session()
237
+
238
+ # Delete all existing captions for this sample
239
+ caption_sample_ids = [c.sample_id for c in self.sample_table.captions]
240
+ for caption_sample_id in caption_sample_ids:
241
+ caption_resolver.delete_caption(session=session, sample_id=caption_sample_id)
242
+
243
+ # Create new captions from the provided texts
244
+ if captions:
245
+ caption_resolver.create_many(
246
+ session=session,
247
+ parent_dataset_id=self.dataset_id,
248
+ captions=[
249
+ CaptionCreate(parent_sample_id=self.sample_id, text=text) for text in captions
250
+ ],
251
+ )
252
+
253
+
254
+ class SampleMetadata:
255
+ """Dictionary-like interface for sample metadata."""
256
+
257
+ def __init__(self, sample: Sample) -> None:
258
+ """Initialize SampleMetadata.
259
+
260
+ Args:
261
+ sample: The Sample instance this metadata belongs to.
262
+ """
263
+ self._sample = sample
264
+
265
+ def __getitem__(self, key: str) -> Any:
266
+ """Get a metadata value by key.
267
+
268
+ Args:
269
+ key: The metadata key to access.
270
+
271
+ Returns:
272
+ The metadata value for the given key, or None if the key doesn't exist.
273
+ """
274
+ if self._sample.sample_table.metadata_dict is None:
275
+ return None
276
+ return self._sample.sample_table.metadata_dict.get_value(key)
277
+
278
+ def __setitem__(self, key: str, value: Any) -> None:
279
+ """Set a metadata key-value pair.
280
+
281
+ Args:
282
+ key: The metadata key.
283
+ value: The metadata value.
284
+ """
285
+ session = self._sample.get_object_session()
286
+ metadata_resolver.set_value_for_sample(
287
+ session=session,
288
+ sample_id=self._sample.sample_id,
289
+ key=key,
290
+ value=value,
291
+ )
@@ -0,0 +1,54 @@
1
+ """Module to launch the GUI."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+
7
+ from lightly_studio import db_manager
8
+ from lightly_studio.api.server import Server
9
+ from lightly_studio.dataset import env
10
+ from lightly_studio.resolvers import dataset_resolver, sample_resolver
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ def _validate_has_samples() -> None:
16
+ """Validate that there are samples in the database before starting GUI.
17
+
18
+ Raises:
19
+ ValueError: If no datasets are found or if no samples exist in any dataset.
20
+ """
21
+ session = db_manager.persistent_session()
22
+
23
+ # Check if any datasets exist
24
+ datasets = dataset_resolver.get_all(session=session, offset=0, limit=1)
25
+
26
+ if not datasets:
27
+ raise ValueError(
28
+ "No datasets found. Please load a dataset using Dataset class methods "
29
+ "(e.g., add_images_from_path(), add_samples_from_yolo(), etc.) "
30
+ "before starting the GUI."
31
+ )
32
+
33
+ # Check if there are any samples in the first dataset
34
+ first_dataset = datasets[0]
35
+ sample_count = sample_resolver.count_by_dataset_id(
36
+ session=session, dataset_id=first_dataset.dataset_id
37
+ )
38
+
39
+ if sample_count == 0:
40
+ raise ValueError(
41
+ "No images have been indexed for the first dataset. "
42
+ "Please ensure your dataset contains valid images and try loading again."
43
+ )
44
+
45
+
46
+ def start_gui() -> None:
47
+ """Launch the web interface for the loaded dataset."""
48
+ _validate_has_samples()
49
+
50
+ server = Server(host=env.LIGHTLY_STUDIO_HOST, port=env.LIGHTLY_STUDIO_PORT)
51
+
52
+ logger.info(f"Open the LightlyStudio GUI under: {env.APP_URL}")
53
+
54
+ server.start()
@@ -0,0 +1,38 @@
1
+ """Definition of VideoSample class, representing a dataset video sample."""
2
+
3
+ from sqlmodel import col
4
+
5
+ from lightly_studio.core.sample import DBField, Sample
6
+ from lightly_studio.models.video import VideoTable
7
+
8
+
9
+ class VideoSample(Sample):
10
+ """Interface to a dataset video sample.
11
+
12
+ Many properties of the sample are directly accessible as attributes of this class.
13
+ ```python
14
+ print(f"Sample file name: {sample.file_name}")
15
+ print(f"Sample file path: {sample.file_path_abs}")
16
+ print(f"Sample width: {sample.width}")
17
+ print(f"Sample height: {sample.height}")
18
+ print(f"Sample duration (seconds): {sample.duration_s}")
19
+ print(f"Sample FPS: {sample.fps}")
20
+ ```
21
+ """
22
+
23
+ file_name = DBField(col(VideoTable.file_name))
24
+ width = DBField(col(VideoTable.width))
25
+ height = DBField(col(VideoTable.height))
26
+ file_path_abs = DBField(col(VideoTable.file_path_abs))
27
+
28
+ duration_s = DBField(col(VideoTable.duration_s))
29
+ fps = DBField(col(VideoTable.fps))
30
+
31
+ def __init__(self, inner: VideoTable) -> None:
32
+ """Initialize the Sample.
33
+
34
+ Args:
35
+ inner: The VideoTable SQLAlchemy model instance.
36
+ """
37
+ self.inner = inner
38
+ super().__init__(sample_table=inner.sample)
File without changes