lightly-studio 0.3.1__py3-none-any.whl → 0.3.3__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.

Potentially problematic release.


This version of lightly-studio might be problematic. Click here for more details.

Files changed (169) hide show
  1. lightly_studio/__init__.py +4 -4
  2. lightly_studio/api/app.py +7 -5
  3. lightly_studio/api/db_tables.py +0 -3
  4. lightly_studio/api/routes/api/annotation.py +32 -16
  5. lightly_studio/api/routes/api/annotation_label.py +2 -5
  6. lightly_studio/api/routes/api/annotations/__init__.py +7 -0
  7. lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
  8. lightly_studio/api/routes/api/classifier.py +2 -5
  9. lightly_studio/api/routes/api/dataset.py +5 -8
  10. lightly_studio/api/routes/api/dataset_tag.py +2 -3
  11. lightly_studio/api/routes/api/embeddings2d.py +104 -0
  12. lightly_studio/api/routes/api/export.py +73 -0
  13. lightly_studio/api/routes/api/metadata.py +2 -4
  14. lightly_studio/api/routes/api/sample.py +5 -13
  15. lightly_studio/api/routes/api/selection.py +87 -0
  16. lightly_studio/api/routes/api/settings.py +2 -6
  17. lightly_studio/api/routes/images.py +6 -6
  18. lightly_studio/core/add_samples.py +374 -0
  19. lightly_studio/core/dataset.py +272 -400
  20. lightly_studio/core/dataset_query/boolean_expression.py +67 -0
  21. lightly_studio/core/dataset_query/dataset_query.py +216 -0
  22. lightly_studio/core/dataset_query/field.py +113 -0
  23. lightly_studio/core/dataset_query/field_expression.py +79 -0
  24. lightly_studio/core/dataset_query/match_expression.py +23 -0
  25. lightly_studio/core/dataset_query/order_by.py +79 -0
  26. lightly_studio/core/dataset_query/sample_field.py +28 -0
  27. lightly_studio/core/dataset_query/tags_expression.py +46 -0
  28. lightly_studio/core/sample.py +159 -32
  29. lightly_studio/core/start_gui.py +35 -0
  30. lightly_studio/dataset/edge_embedding_generator.py +13 -8
  31. lightly_studio/dataset/embedding_generator.py +2 -3
  32. lightly_studio/dataset/embedding_manager.py +74 -6
  33. lightly_studio/dataset/env.py +4 -0
  34. lightly_studio/dataset/file_utils.py +13 -2
  35. lightly_studio/dataset/fsspec_lister.py +275 -0
  36. lightly_studio/dataset/loader.py +49 -84
  37. lightly_studio/dataset/mobileclip_embedding_generator.py +9 -6
  38. lightly_studio/db_manager.py +145 -0
  39. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.CA_CXIBb.css +1 -0
  40. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.DS78jgNY.css +1 -0
  41. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/index.BVs_sZj9.css +1 -0
  42. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform.D487hwJk.css +1 -0
  43. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/6t3IJ0vQ.js +1 -0
  44. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{D6su9Aln.js → 8NsknIT2.js} +1 -1
  45. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{x9G_hzyY.js → BND_-4Kp.js} +1 -1
  46. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{BylOuP6i.js → BdfTHw61.js} +1 -1
  47. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{DOlTMNyt.js → BfHVnyNT.js} +1 -1
  48. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BjkP1AHA.js +1 -0
  49. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BuuNVL9G.js +1 -0
  50. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{O-EABkf9.js → BzKGpnl4.js} +1 -1
  51. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CCx7Ho51.js +1 -0
  52. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{l7KrR96u.js → CH6P3X75.js} +1 -1
  53. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{D5-A_Ffd.js → CR2upx_Q.js} +2 -2
  54. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWPZrTTJ.js +1 -0
  55. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{C8I8rFJQ.js → Cs1XmhiF.js} +1 -1
  56. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{CDnpyLsT.js → CwPowJfP.js} +1 -1
  57. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CxFKfZ9T.js +1 -0
  58. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cxevwdid.js +1 -0
  59. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{DjfY96ND.js → D4whDBUi.js} +1 -1
  60. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D6r9vr07.js +1 -0
  61. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DA6bFLPR.js +1 -0
  62. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DEgUu98i.js +3 -0
  63. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DGTPl6Gk.js +1 -0
  64. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DKGxBSlK.js +1 -0
  65. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQXoLcsF.js +1 -0
  66. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQe_kdRt.js +92 -0
  67. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DcY4jgG3.js +1 -0
  68. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Bu7uvVrG.js → RmD8FzRo.js} +1 -1
  69. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/V-MnMC1X.js +1 -0
  70. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Bsi3UGy5.js → keKYsoph.js} +1 -1
  71. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BVr6DYqP.js +2 -0
  72. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.u7zsVvqp.js +1 -0
  73. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.Da2agmdd.js +1 -0
  74. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{1.B4rNYwVp.js → 1.B11tVRJV.js} +1 -1
  75. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.l30Zud4h.js +1 -0
  76. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.CgKPGcAP.js +1 -0
  77. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.C8HLK8mj.js +857 -0
  78. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{3.CWHpKonm.js → 3.CLvg3QcJ.js} +1 -1
  79. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{4.OUWOLQeV.js → 4.BQhDtXUI.js} +1 -1
  80. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.-6XqWX5G.js +1 -0
  81. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.uBV1Lhat.js +1 -0
  82. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.BXsgoQZh.js +1 -0
  83. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.BkbcnUs8.js +1 -0
  84. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{9.CPu3CiBc.js → 9.Bkrv-Vww.js} +1 -1
  85. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
  86. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
  87. lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -1
  88. lightly_studio/dist_lightly_studio_view_app/index.html +14 -14
  89. lightly_studio/examples/example.py +13 -12
  90. lightly_studio/examples/example_coco.py +13 -0
  91. lightly_studio/examples/example_metadata.py +83 -98
  92. lightly_studio/examples/example_selection.py +7 -19
  93. lightly_studio/examples/example_split_work.py +12 -36
  94. lightly_studio/examples/{example_v2.py → example_yolo.py} +3 -4
  95. lightly_studio/export/export_dataset.py +65 -0
  96. lightly_studio/export/lightly_studio_label_input.py +120 -0
  97. lightly_studio/few_shot_classifier/classifier_manager.py +5 -26
  98. lightly_studio/metadata/compute_typicality.py +67 -0
  99. lightly_studio/models/annotation/annotation_base.py +18 -20
  100. lightly_studio/models/annotation/instance_segmentation.py +8 -8
  101. lightly_studio/models/annotation/object_detection.py +4 -4
  102. lightly_studio/models/dataset.py +6 -2
  103. lightly_studio/models/sample.py +10 -3
  104. lightly_studio/resolvers/annotation_label_resolver/__init__.py +2 -1
  105. lightly_studio/resolvers/annotation_label_resolver/get_all.py +15 -0
  106. lightly_studio/resolvers/annotation_resolver/__init__.py +2 -3
  107. lightly_studio/resolvers/annotation_resolver/create_many.py +3 -3
  108. lightly_studio/resolvers/annotation_resolver/delete_annotation.py +1 -1
  109. lightly_studio/resolvers/annotation_resolver/delete_annotations.py +7 -3
  110. lightly_studio/resolvers/annotation_resolver/get_by_id.py +19 -1
  111. lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +0 -1
  112. lightly_studio/resolvers/annotations/annotations_filter.py +1 -11
  113. lightly_studio/resolvers/dataset_resolver.py +10 -0
  114. lightly_studio/resolvers/embedding_model_resolver.py +22 -0
  115. lightly_studio/resolvers/sample_resolver.py +53 -9
  116. lightly_studio/resolvers/tag_resolver.py +23 -0
  117. lightly_studio/selection/mundig.py +7 -10
  118. lightly_studio/selection/select.py +55 -46
  119. lightly_studio/selection/select_via_db.py +23 -19
  120. lightly_studio/selection/selection_config.py +10 -4
  121. lightly_studio/services/annotations_service/__init__.py +12 -0
  122. lightly_studio/services/annotations_service/create_annotation.py +63 -0
  123. lightly_studio/services/annotations_service/delete_annotation.py +22 -0
  124. lightly_studio/services/annotations_service/update_annotation.py +21 -32
  125. lightly_studio/services/annotations_service/update_annotation_bounding_box.py +36 -0
  126. lightly_studio-0.3.3.dist-info/METADATA +814 -0
  127. {lightly_studio-0.3.1.dist-info → lightly_studio-0.3.3.dist-info}/RECORD +130 -113
  128. lightly_studio/api/db.py +0 -133
  129. lightly_studio/api/routes/api/annotation_task.py +0 -38
  130. lightly_studio/api/routes/api/metrics.py +0 -80
  131. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.DenzbfeK.css +0 -1
  132. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.OwPEPQZu.css +0 -1
  133. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.b653GmVf.css +0 -1
  134. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.T-zjSUd3.css +0 -1
  135. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B2FVR0s0.js +0 -1
  136. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B9zumHo5.js +0 -1
  137. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BJXwVxaE.js +0 -1
  138. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bx1xMsFy.js +0 -1
  139. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CcaPhhk3.js +0 -1
  140. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvOmgdoc.js +0 -93
  141. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CxtLVaYz.js +0 -3
  142. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D6RI2Zrd.js +0 -1
  143. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D98V7j6A.js +0 -1
  144. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIRAtgl0.js +0 -1
  145. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DjUWrjOv.js +0 -1
  146. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/XO7A28GO.js +0 -1
  147. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/hQVEETDE.js +0 -1
  148. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/nAHhluT7.js +0 -1
  149. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/r64xT6ao.js +0 -1
  150. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/vC4nQVEB.js +0 -1
  151. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.CjnvpsmS.js +0 -2
  152. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.0o1H7wM9.js +0 -1
  153. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.XRq_TUwu.js +0 -1
  154. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.DfBwOEhN.js +0 -1
  155. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.CwF2_8mP.js +0 -1
  156. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.CS4muRY-.js +0 -6
  157. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.Dm6t9F5W.js +0 -1
  158. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.Bw5ck4gK.js +0 -1
  159. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.CF0EDTR6.js +0 -1
  160. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.Cw30LEcV.js +0 -1
  161. lightly_studio/metrics/detection/__init__.py +0 -0
  162. lightly_studio/metrics/detection/map.py +0 -268
  163. lightly_studio/models/annotation_task.py +0 -28
  164. lightly_studio/resolvers/annotation_resolver/create.py +0 -19
  165. lightly_studio/resolvers/annotation_task_resolver.py +0 -31
  166. lightly_studio-0.3.1.dist-info/METADATA +0 -520
  167. /lightly_studio/{metrics → core/dataset_query}/__init__.py +0 -0
  168. /lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/{OpenSans- → OpenSans-Medium.DVUZMR_6.ttf} +0 -0
  169. {lightly_studio-0.3.1.dist-info → lightly_studio-0.3.3.dist-info}/WHEEL +0 -0
@@ -1 +0,0 @@
1
- import"../chunks/CWj6FrbW.js";import{p as f,u as $,a as h,g as o,d as r}from"../chunks/l7KrR96u.js";import{s as S,a as i}from"../chunks/XO7A28GO.js";import{A as T}from"../chunks/CvOmgdoc.js";import{u as _}from"../chunks/vC4nQVEB.js";import"../chunks/CxtLVaYz.js";import"../chunks/D6su9Aln.js";import"../chunks/Bx1xMsFy.js";import"../chunks/Bsi3UGy5.js";import"../chunks/69_IOA4Y.js";import{u as G}from"../chunks/DIRAtgl0.js";import"../chunks/BJXwVxaE.js";function k(p,t){f(t,!0);const[e,m]=S(),n=()=>i(l,"$lastGridType",e),s=()=>i(d,"$sampleSize",e),{datasetId:a,sampleSize:d,selectedAnnotationFilterIds:c}=t.data,{lastGridType:l}=_(),u=r(()=>G({dataset_id:a})),g=r(()=>o(u).clearTagsSelected);$(()=>{n()!=="annotations"&&o(g)()}),T(p,{get itemHeight(){return s().height},get itemWidth(){return s().width},dataset_id:a,selectedAnnotationFilterIds:c}),h(),m()}export{k as component};
@@ -1 +0,0 @@
1
- import{p as T,f as B,n as Et,a as j,w as bt,l as V,$ as ct,g as a,d,c as f,r as m,s as S,t as F,L as Dt,V as Tt,ax as gt}from"../chunks/l7KrR96u.js";import{c as jt}from"../chunks/BJXwVxaE.js";import"../chunks/CWj6FrbW.js";import{c as Z,a as _,t as k,n as Ht}from"../chunks/Bu7uvVrG.js";import{i as O,a as D,s as q}from"../chunks/XO7A28GO.js";import{e as ut}from"../chunks/DjfY96ND.js";import{I as Rt,s as J,K as Ut,L as at,M as Ft,N as Ot,O as zt,P as Gt,p as xt,F as Kt,e as Wt,l as qt,h as Vt,C as It,z as At,E as wt,u as Zt,d as Jt,S as Qt,Q as Yt,a as Xt}from"../chunks/CvOmgdoc.js";import{g as tt}from"../chunks/CxtLVaYz.js";import{u as St}from"../chunks/vC4nQVEB.js";import{f as ht,S as ta}from"../chunks/D5-A_Ffd.js";import{r as U}from"../chunks/H7C68rOM.js";import"../chunks/D6su9Aln.js";import"../chunks/Bx1xMsFy.js";import{p as z}from"../chunks/Bsi3UGy5.js";import"../chunks/69_IOA4Y.js";import{S as aa}from"../chunks/B2FVR0s0.js";import{S as na,B as ea,a as oa,b as X,c as lt,H as sa,d as dt,D as ra,e as ia,Z as la,g as da,u as ca}from"../chunks/nAHhluT7.js";import{S as ua}from"../chunks/BylOuP6i.js";import{s as va,r as ma,a as fa}from"../chunks/D98V7j6A.js";import{s as W}from"../chunks/D6RI2Zrd.js";import{C as _a}from"../chunks/CDnpyLsT.js";import{s as pa}from"../chunks/DIRAtgl0.js";function ga(v,t){T(t,!0);let r=ma(t,["$$slots","$$events","$$legacy"]);Rt(v,va({name:"square-dashed"},()=>r,{iconNode:[["path",{d:"M5 3a2 2 0 0 0-2 2"}],["path",{d:"M19 3a2 2 0 0 1 2 2"}],["path",{d:"M21 19a2 2 0 0 1-2 2"}],["path",{d:"M5 21a2 2 0 0 1-2-2"}],["path",{d:"M9 3h1"}],["path",{d:"M9 21h1"}],["path",{d:"M14 3h1"}],["path",{d:"M14 21h1"}],["path",{d:"M3 9v1"}],["path",{d:"M21 9v1"}],["path",{d:"M3 14v1"}],["path",{d:"M21 14v1"}]],children:(n,o)=>{var s=Z(),p=B(s);pa(p,()=>t.children??Et),_(n,s)},$$slots:{default:!0}})),j()}const ha=async({dataset_id:v,cursor:t=0,limit:r=10,annotation_label_ids:i,tag_ids:n})=>{const o={data:[],error:void 0};try{const s=await jt.GET("/api/datasets/{dataset_id}/annotations",{params:{path:{dataset_id:v},query:{annotation_label_ids:i,tag_ids:n,cursor:t,limit:r}}});if(s.error)throw new Error(JSON.stringify(s.error,null,2));if(!s.data)throw new Error("No data");o.data=s.data.data}catch(s){o.error="Error loading annotations: "+String(s)}return o},ba=({annotationIndex:v,...t})=>{const r=bt({isLoading:!1});return(async()=>{r.update(n=>({...n,isLoading:!0}));try{const n=await ha({cursor:v>0?v-1:0,limit:3,...t}),o=n.data.findIndex(e=>e.annotation_id===t.currentAnnotationId),s=n.data[o+1],p=n.data[o-1];r.update(e=>({...e,isLoading:!1,error:n.error?String(n.error):void 0,data:n.error?void 0:{annotationNext:s,annotationPrevious:p}}))}catch(n){r.update(o=>({...o,isLoading:!1,error:String(n)}))}})(),r},xa=async({parent:v,params:{dataset_id:t,annotationId:r,annotationIndex:i}})=>{const{annotationsSelectedTagsIds:n,annotationsSelectedAnnotationLabelsIds:o,dataset:s}=await v(),p=parseInt(i,10),e=bt();if(!s)throw new Error("Dataset data not found");return ba({annotationIndex:p,dataset_id:t,currentAnnotationId:r,annotation_label_ids:Array.from(V(o)),tag_ids:Array.from(V(n))}).subscribe(({data:L})=>{e.set(L)}),{annotationAdjacents:e,annotationIndex:p,annotationId:r,dataset:s}},gn=Object.freeze(Object.defineProperty({__proto__:null,load:xa},Symbol.toStringTag,{value:"Module"}));function Ia(v,t){T(t,!0);const[r,i]=q(),n=()=>D(a(s),"$annotationAdjacents",r),o=d(()=>z.data.annotationIndex),s=d(()=>z.data.annotationAdjacents),p=()=>{n().annotationNext&&tt(U.toSampleWithAnnotation({datasetId:n().annotationNext.dataset_id,sampleId:n().annotationNext.sample_id,annotationId:n().annotationNext.annotation_id,annotationIndex:a(o)+1}))},e=()=>{n().annotationPrevious&&tt(U.toSampleWithAnnotation({datasetId:n().annotationPrevious.dataset_id,sampleId:n().annotationPrevious.sample_id,annotationId:n().annotationPrevious.annotation_id,annotationIndex:a(o)-1}))},L=g=>{switch(g.key){case"ArrowRight":p();break;case"ArrowLeft":e();break}};var x=Z();ut("keydown",ct,L);var $=B(x);{var I=g=>{const P=d(()=>!!n().annotationPrevious),y=d(()=>!!n().annotationNext);ua(g,{get hasPrevious(){return a(P)},get hasNext(){return a(y)},onPrevious:e,onNext:p})};O($,g=>{n()&&g(I)})}_(v,x),j(),i()}const Aa={object_detection:"Object Detection",bbox:"Bounding Box",instance_segmentation:"Instance Segmentation",semantic_segmentation:"Semantic Segmentation",classification:"Classification"};var wa=k('<span class="text-sm"> </span> <span class="break-all text-sm"> </span>',1);function Sa(v,t){var r=wa(),i=B(r),n=f(i,!0);m(i);var o=S(i,2),s=f(o,!0);m(o),F(()=>{W(n,t.label),J(o,"data-testid",`annotation-metadata-${t.id}`),W(s,t.value)}),_(v,r)}var $a=k('<span class="break-all text-sm"> </span>'),ya=k('<span class="text-sm"> </span> <!>',1);function ka(v,t){T(t,!0);const[r,i]=q(),n=()=>D(s,"$result",r),o=()=>D(t.isEditingMode,"$isEditingMode",r),s=Ut(),{updateAnnotation:p}=at({datasetId:t.datasetId,annotationId:t.annotationId,onUpdate:t.onUpdate}),e=d(()=>zt(n().data||[])),L=d(()=>{const A=a(e).find(c=>c.value===t.value);return A||{value:t.value,label:t.value}});var x=ya(),$=B(x),I=f($,!0);m($);var g=S($,2);{var P=A=>{Ft(A,{get items(){return a(e)},get value(){return a(L)},name:"annotation-label",placeholder:"Select a label",onSelect:l=>{p({annotation_id:t.annotationId,dataset_id:t.datasetId,label_name:l.value})},notFound:(l,u)=>{let h=()=>u==null?void 0:u().inputValue;Ot(l,{get label(){return h()}})},$$slots:{notFound:!0}})},y=A=>{var c=$a();J(c,"data-testid","annotation-metadata-label");var l=f(c,!0);m(c),F(()=>W(l,t.value)),_(A,c)};O(g,A=>{o()?A(P):A(y,!1)})}F(()=>W(I,t.label)),_(v,x),j(),i()}var Pa=k('<div class="flex flex-col gap-4"><div class="grid grid-cols-[6rem_1fr] gap-y-3 text-diffuse-foreground"></div></div>');function Ma(v,t){T(t,!0);const[r,i]=q(),n=()=>D(a(p),"$annotationResp",r),{datasetId:o}=z.data,s=d(()=>at({datasetId:o,annotationId:t.annotationId})),p=d(()=>a(s).annotation);let e=d(()=>n().data);const L=d(qt),x=d(()=>a(L).taskMap),$=d(()=>a(e)&&a(e).annotation_task_id&&V(a(x)).has(a(e).annotation_task_id)?V(a(x)).get(a(e).annotation_task_id).is_prediction:!1),I=d(()=>{var l,u;if(!a(e))return[];let c=[{id:"label",label:"Label:",value:(u=(l=a(e))==null?void 0:l.annotation_label)==null?void 0:u.annotation_label_name},{id:"type",label:"Type:",value:Aa[a(e).annotation_type]||"Unknown"},{id:"status",label:"Status:",value:a($)?"Prediction":"Ground Truth"}];if(a(e)&&!Gt(a(e))){const{height:h,width:M}=xt(a(e));c=[{id:"height",label:"Height:",value:ht(Math.round(h))+"px"},{id:"width",label:"Width:",value:ht(Math.round(M))+"px"},...c]}return c}),{isEditingMode:g}=z.data.globalStorage;var P=Z(),y=B(P);{var A=c=>{Kt(c,{title:"Annotation details",children:(l,u)=>{var h=Pa(),M=f(h);Wt(M,21,()=>a(I),({label:N,value:b,id:C})=>N,(N,b)=>{let C=()=>a(b).label,E=()=>a(b).value,H=()=>a(b).id;var G=Z(),nt=B(G);{var Q=w=>{ka(w,{get onUpdate(){return t.onUpdate},get annotationId(){return t.annotationId},datasetId:o,get label(){return C()},get value(){return E()},isEditingMode:g})},et=w=>{Sa(w,{get label(){return C()},get id(){return H()},get value(){return E()}})};O(nt,w=>{H()==="label"&&g?w(Q):w(et,!1)})}_(N,G)}),m(M),m(h),_(l,h)}})};O(y,c=>{a(I).length>0&&c(A)})}_(v,P),j(),i()}var Na=k('<!> <h2 class="py-2 text-lg font-semibold"><a>Check all sample annotations</a></h2>',1),Ca=k('<div class="flex h-full w-full items-center justify-center"><!></div>'),Ba=k('<div class="flex h-full min-h-0 flex-col space-y-4 overflow-hidden dark:[color-scheme:dark]"><!> <!></div>');function La(v,t){T(t,!0);const{datasetId:r}=z.data;let i=Tt(void 0);at({datasetId:r,annotationId:t.annotationId}).annotation.subscribe(e=>{e.isSuccess&&Dt(i,fa(e.data.sample))});const o=Vt(),[s,p]=o;It(v,{className:"h-full",children:(e,L)=>{At(e,{className:"h-full flex flex-col",children:(x,$)=>{var I=Ba(),g=f(I);Ma(g,{get annotationId(){return t.annotationId},get onUpdate(){return t.onUpdate}});var P=S(g,2);{var y=c=>{var l=Na(),u=B(l);na(u,{get sample(){return a(i)},showCustomMetadata:!1});var h=S(u,2),M=f(h);m(h),F(N=>J(M,"href",N),[()=>s(U.toSample({sampleId:a(i).sample_id,datasetId:a(i).dataset_id}),void 0)]),_(c,l)},A=c=>{var l=Ca(),u=f(l);wt(u,{size:"large",align:"center"}),m(l),_(c,l)};O(P,c=>{a(i)?c(y):c(A,!1)})}m(I),_(x,I)},$$slots:{default:!0}})},$$slots:{default:!0}}),j()}var Ea=k('<!> <span class="hidden sm:inline">Home</span>',1),Da=k('<!> <span class="max-w-[150px] truncate"> </span>',1),Ta=k('<!> <span class="hidden sm:inline">Annotations</span>',1),ja=k('<!> <span class="max-w-[200px] truncate"> </span>',1),Ha=k("<!> <!> <!> <!> <!> <!> <!>",1);function Ra(v,t){T(t,!0);const[r,i]=q(),n=()=>D(o,"$annotationsTotalCount",r),{annotationsTotalCount:o}=St();ea(v,{class:"mb-2",children:(s,p)=>{oa(s,{children:(e,L)=>{var x=Ha(),$=B(x);X($,{children:(l,u)=>{const h=d(()=>U.toHome());lt(l,{get href(){return a(h)},class:"flex items-center gap-2",children:(M,N)=>{var b=Ea(),C=B(b);sa(C,{class:"h-4 w-4"}),gt(2),_(M,b)},$$slots:{default:!0}})},$$slots:{default:!0}});var I=S($,2);dt(I,{});var g=S(I,2);X(g,{children:(l,u)=>{const h=d(()=>U.toAnnotations(t.dataset.dataset_id));lt(l,{get href(){return a(h)},class:"flex items-center gap-2",get title(){return t.dataset.directory},children:(M,N)=>{var b=Da(),C=B(b);ra(C,{class:"h-4 w-4"});var E=S(C,2),H=f(E,!0);m(E),F(()=>{J(E,"title",t.dataset.directory),W(H,t.dataset.name)}),_(M,b)},$$slots:{default:!0}})},$$slots:{default:!0}});var P=S(g,2);dt(P,{});var y=S(P,2);X(y,{children:(l,u)=>{const h=d(()=>U.toAnnotations(t.dataset.dataset_id));lt(l,{get href(){return a(h)},class:"flex items-center gap-2",children:(M,N)=>{var b=Ta(),C=B(b);_a(C,{class:"h-4 w-4"}),gt(2),_(M,b)},$$slots:{default:!0}})},$$slots:{default:!0}});var A=S(y,2);dt(A,{});var c=S(A,2);X(c,{children:(l,u)=>{ia(l,{class:"flex items-center gap-2",children:(h,M)=>{var N=ja(),b=B(N);ga(b,{class:"h-4 w-4"});var C=S(b,2),E=f(C);m(C),F(()=>W(E,`Annotation ${t.annotationIndex+1} of ${n()??""}`)),_(h,N)},$$slots:{default:!0}})},$$slots:{default:!0}}),_(e,x)},$$slots:{default:!0}})},$$slots:{default:!0}}),j(),i()}var Ua=Ht("<image></image><g><!></g>",1),Fa=k('<div class="h-full w-full overflow-hidden"><div class="sample relative h-full w-full"><div class="absolute right-4 top-2 z-30"><!></div> <!> <!></div></div>'),Oa=k('<div class="flex h-full w-full items-center justify-center"><!></div>'),za=k('<div class="flex h-full w-full flex-col space-y-4"><div class="flex w-full items-center"><!></div> <!> <div class="flex min-h-0 flex-1 gap-4"><div class="flex-1"><!></div> <div class="relative w-[375px]"><!></div></div></div>');function Ga(v,t){T(t,!0);const[r,i]=q(),n=()=>D(a(l),"$annotationResp",r),o=()=>D(e,"$selectedSampleAnnotationCropIds",r),s=()=>D(L,"$isHidden",r),{toggleSampleAnnotationCropSelection:p,selectedSampleAnnotationCropIds:e}=St(),{isHidden:L,handleKeyEvent:x}=Zt(),{settingsStore:$}=Jt(),I=" ",g=V($).key_go_back,P=()=>{var w;(w=t.sample)!=null&&w.dataset_id?tt(U.toAnnotations(t.sample.dataset_id)):tt("/")},y=w=>{switch(w.key){case g:P();break;case I:w.preventDefault(),p(t.annotationId);break}x(w)},A=z.data.datasetId,c=d(()=>at({datasetId:A,annotationId:t.annotationId})),l=d(()=>a(c).annotation);let u=d(()=>n().data),h=d(()=>{var w,ot;return da(((ot=(w=a(u))==null?void 0:w.sample)==null?void 0:ot.sample_id)||"")}),M=d(()=>a(u)?xt(a(u)):void 0);var N=za();ut("keydown",ct,y),ut("keyup",ct,x);var b=f(N),C=f(b);Ra(C,{get dataset(){return t.dataset},get annotationIndex(){return t.annotationIndex}}),m(b);var E=S(b,2);ta(E,{class:"mb-4 bg-border-hard"});var H=S(E,2),G=f(H),nt=f(G);It(nt,{className:"h-full",children:(w,ot)=>{At(w,{className:"h-full",children:($t,Wa)=>{var vt=Z(),yt=B(vt);{var kt=K=>{var R=Fa(),Y=f(R),st=f(Y),Mt=f(st);const Nt=d(()=>o().has(t.annotationId));Qt(Mt,{onSelect:()=>p(t.annotationId),get isSelected(){return a(Nt)}}),m(st);var mt=S(st,2);Ia(mt,{});var Ct=S(mt,2);la(Ct,{get width(){return a(u).sample.width},get height(){return a(u).sample.height},get boundingBox(){return a(M)},children:(Bt,qa)=>{var ft=Ua(),_t=B(ft),rt=S(_t);let pt;var Lt=f(rt);Yt(Lt,()=>a(u).annotation_id,it=>{aa(it,{get annotation(){return a(u)},showLabel:!0,get imageWidth(){return a(u).sample.width}})}),m(rt),F(it=>{J(_t,"href",a(h)),pt=Xt(rt,0,"",null,pt,it)},[()=>({invisible:s()})]),_(Bt,ft)},$$slots:{default:!0}}),m(Y),m(R),_(K,R)},Pt=K=>{var R=Oa(),Y=f(R);wt(Y,{size:"large",align:"center"}),m(R),_(K,R)};O(yt,K=>{a(u)?K(kt):K(Pt,!1)})}_($t,vt)},$$slots:{default:!0}})},$$slots:{default:!0}}),m(G);var Q=S(G,2),et=f(Q);La(et,{get annotationId(){return t.annotationId}}),m(Q),m(H),m(N),_(v,N),j(),i()}var Ka=k('<div class="flex h-full w-full space-x-4 px-4 pb-4" data-testid="annotation-details"><div class="h-full w-full space-y-6 rounded-[1vw] bg-card p-4"><!></div></div>');function hn(v,t){T(t,!0);const[r,i]=q(),n=()=>D(a(x),"$sample",r),o=d(()=>t.data.annotationId),s=d(()=>t.data.dataset),p=d(()=>t.data.annotationIndex),{sampleId:e}=z.params,L=d(()=>ca({sampleId:e,datasetId:a(s).dataset_id})),x=d(()=>a(L).sample);var $=Ka(),I=f($),g=f(I);{var P=y=>{Ga(y,{get annotationId(){return a(o)},get annotationIndex(){return a(p)},get dataset(){return a(s)},get sample(){return n().data}})};O(g,y=>{n().data&&a(o)&&a(s)&&y(P)})}m(I),m($),_(v,$),j(),i()}export{hn as component,gn as universal};
File without changes
@@ -1,268 +0,0 @@
1
- """Implementation for calculating Mean Average Precision (MAP)."""
2
-
3
- from __future__ import annotations
4
-
5
- import math
6
- from collections import defaultdict
7
- from collections.abc import Sequence
8
- from uuid import UUID
9
-
10
- import torch
11
- from pydantic import BaseModel
12
- from torch import Tensor
13
- from torchmetrics.detection.mean_ap import MeanAveragePrecision
14
-
15
- from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable
16
-
17
-
18
- class DetectionMetricsMAP(BaseModel):
19
- """Response for computing the MAP detection metric."""
20
-
21
- name: str
22
- map: float
23
- map_small: float
24
- map_medium: float
25
- map_large: float
26
- mar_1: float
27
- mar_10: float
28
- mar_100: float
29
- mar_small: float
30
- mar_medium: float
31
- mar_large: float
32
- map_50: float
33
- map_75: float
34
- map_per_class: dict[str, float] | None = None
35
- mar_100_per_class: dict[str, float] | None = None
36
- classes: list[int]
37
-
38
- @property
39
- def value(self) -> float:
40
- """Backwards compatibility alias for map."""
41
- return self.map
42
-
43
- @property
44
- def per_class(self) -> dict[str, float] | None:
45
- """Backwards compatibility alias for map_per_class."""
46
- return self.map_per_class
47
-
48
-
49
- def calculate_map_metric( # noqa: C901
50
- pred_annotations: Sequence[AnnotationBaseTable],
51
- gt_annotations: Sequence[AnnotationBaseTable],
52
- ) -> DetectionMetricsMAP:
53
- """Calculate the Mean Average Precision (MAP) metric."""
54
- if not gt_annotations or not pred_annotations:
55
- return DetectionMetricsMAP(
56
- name="mAP@.5:.95",
57
- map=0.0,
58
- map_small=0.0,
59
- map_medium=0.0,
60
- map_large=0.0,
61
- mar_1=0.0,
62
- mar_10=0.0,
63
- mar_100=0.0,
64
- mar_small=0.0,
65
- mar_medium=0.0,
66
- mar_large=0.0,
67
- map_50=-1.0,
68
- map_75=-1.0,
69
- map_per_class=None,
70
- mar_100_per_class=None,
71
- classes=[],
72
- )
73
- uuid_to_int_label: dict[UUID, int] = {}
74
-
75
- # Map sample_id to annotations.
76
- sample_id_to_annotations = _group_by_sample_id(
77
- pred_annotations=pred_annotations,
78
- gt_annotations=gt_annotations,
79
- )
80
-
81
- # Create the MeanAveragePrecision object.
82
- map_metric = MeanAveragePrecision(
83
- box_format="xywh",
84
- iou_thresholds=None,
85
- class_metrics=True,
86
- average="macro",
87
- backend="faster_coco_eval",
88
- )
89
-
90
- # Compute MAP updating the object sample by sample.
91
- for _sample_id, (
92
- sample_pred_annotations,
93
- sample_gt_annotations,
94
- ) in sample_id_to_annotations.items():
95
- # Convert to torchmetrics format.
96
- prediction_tm = _convert_to_torchmetrics(
97
- annotations=sample_pred_annotations,
98
- is_prediction=True,
99
- uuid_to_int_label_map=uuid_to_int_label,
100
- )
101
- ground_truth_tm = _convert_to_torchmetrics(
102
- annotations=sample_gt_annotations,
103
- is_prediction=False,
104
- uuid_to_int_label_map=uuid_to_int_label,
105
- )
106
-
107
- # Update the metric.
108
- map_metric.update(preds=[prediction_tm], target=[ground_truth_tm])
109
-
110
- # Compute the final results.
111
- results = map_metric.compute()
112
- # Invert label map to recover original UUIDs
113
- int_to_uuid = {v: k for k, v in uuid_to_int_label.items()}
114
-
115
- # Helper to convert Tensor to Python list
116
- def to_list(t: Tensor) -> list[float]:
117
- if t.dim() == 0:
118
- return [t.item()]
119
- return t.tolist()
120
-
121
- # Scalar metrics
122
- map_val = results["map"].item()
123
- map_small = results["map_small"].item()
124
- map_medium = results["map_medium"].item()
125
- map_large = results["map_large"].item()
126
- mar_1 = results["mar_1"].item()
127
- mar_10 = results["mar_10"].item()
128
- mar_100 = results["mar_100"].item()
129
- mar_small = results["mar_small"].item()
130
- mar_medium = results["mar_medium"].item()
131
- mar_large = results["mar_large"].item()
132
-
133
- # IoU-specific metrics
134
- map_50 = results.get("map_50")
135
- map_50 = map_50.item() if isinstance(map_50, Tensor) and map_50.dim() == 0 else -1.0
136
- map_75 = results.get("map_75")
137
- map_75 = map_75.item() if isinstance(map_75, Tensor) and map_75.dim() == 0 else -1.0
138
-
139
- # Per-class metrics
140
- raw_map_pc = results.get("map_per_class")
141
- per_class_dict: dict[str, float] | None = None
142
- if raw_map_pc is not None:
143
- pc_list = to_list(raw_map_pc)
144
- per_class_dict = {}
145
- for idx, val in enumerate(pc_list):
146
- if not math.isnan(val):
147
- per_class_dict[str(int_to_uuid[idx])] = val
148
-
149
- # Per-class recall at 100 detections
150
- raw_mar100_pc = results.get("mar_100_per_class")
151
- mar_100_pc_dict: dict[str, float] | None = None
152
- if raw_mar100_pc is not None:
153
- m100_list = to_list(raw_mar100_pc)
154
- mar_100_pc_dict = {}
155
- for idx, val in enumerate(m100_list):
156
- if not math.isnan(val):
157
- mar_100_pc_dict[str(int_to_uuid[idx])] = val
158
-
159
- # Observed classes
160
- raw_classes = results.get("classes")
161
- classes_list_output: list[int] = []
162
- if raw_classes is not None:
163
- classes_list_output = [int(x) for x in to_list(raw_classes)]
164
-
165
- return DetectionMetricsMAP(
166
- name="mAP@.5:.95",
167
- map=map_val,
168
- map_small=map_small,
169
- map_medium=map_medium,
170
- map_large=map_large,
171
- mar_1=mar_1,
172
- mar_10=mar_10,
173
- mar_100=mar_100,
174
- mar_small=mar_small,
175
- mar_medium=mar_medium,
176
- mar_large=mar_large,
177
- map_50=map_50,
178
- map_75=map_75,
179
- map_per_class=per_class_dict,
180
- mar_100_per_class=mar_100_pc_dict,
181
- classes=classes_list_output,
182
- )
183
-
184
-
185
- def _group_by_sample_id(
186
- pred_annotations: Sequence[AnnotationBaseTable],
187
- gt_annotations: Sequence[AnnotationBaseTable],
188
- ) -> dict[
189
- UUID,
190
- tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
191
- ]:
192
- """Group prediction and ground truth annotations by sample_id.
193
-
194
- Returns a dictionary with sample_id as key and a tuple of
195
- (list of prediction annotations, list of ground truth annotations) as value.
196
- """
197
- sample_id_to_annotations: defaultdict[
198
- UUID,
199
- tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
200
- ] = defaultdict(lambda: ([], []))
201
- for ann in pred_annotations:
202
- sample_id_to_annotations[ann.sample_id][0].append(ann)
203
- for ann in gt_annotations:
204
- sample_id_to_annotations[ann.sample_id][1].append(ann)
205
- return sample_id_to_annotations
206
-
207
-
208
- def _convert_to_torchmetrics(
209
- annotations: Sequence[AnnotationBaseTable],
210
- is_prediction: bool,
211
- uuid_to_int_label_map: dict[UUID, int],
212
- ) -> dict[str, Tensor]:
213
- """Convert annotations to torchmetrics format.
214
-
215
- Args:
216
- annotations: List of bounding box annotations.
217
- is_prediction: Whether the annotations are predictions.
218
- uuid_to_int_label_map: Map from UUID to integer label.
219
-
220
- Returns:
221
- Dictionary in torchmetrics format. For predictions the keys are
222
- `boxes`, `scores`, `labels`. For ground truth they are `boxes`,
223
- `labels`.
224
-
225
- """
226
- if not annotations:
227
- empty_boxes = torch.empty((0, 4), dtype=torch.float32)
228
- empty_labels = torch.empty((0,), dtype=torch.int64)
229
- if is_prediction:
230
- return {
231
- "boxes": empty_boxes,
232
- "scores": torch.empty((0,), dtype=torch.float32),
233
- "labels": empty_labels,
234
- }
235
- return {"boxes": empty_boxes, "labels": empty_labels}
236
-
237
- boxes = torch.tensor(
238
- [
239
- [
240
- a.object_detection_details.x,
241
- a.object_detection_details.y,
242
- a.object_detection_details.width,
243
- a.object_detection_details.height,
244
- ]
245
- for a in annotations
246
- if a.object_detection_details is not None
247
- ],
248
- dtype=torch.float32,
249
- )
250
-
251
- mapped_labels = []
252
- # Use the passed-in map instead of a global one
253
- for uuid_label in (a.annotation_label_id for a in annotations):
254
- if uuid_label not in uuid_to_int_label_map:
255
- # Assign the next available integer ID based on the current map size
256
- uuid_to_int_label_map[uuid_label] = len(uuid_to_int_label_map)
257
- mapped_labels.append(uuid_to_int_label_map[uuid_label])
258
-
259
- labels = torch.tensor(mapped_labels, dtype=torch.int64)
260
-
261
- if is_prediction:
262
- scores = torch.tensor([a.confidence for a in annotations], dtype=torch.float32)
263
- return {
264
- "boxes": boxes,
265
- "scores": scores,
266
- "labels": labels,
267
- }
268
- return {"boxes": boxes, "labels": labels}
@@ -1,28 +0,0 @@
1
- """This module defines the AnnotationTask model."""
2
-
3
- from datetime import datetime
4
- from enum import Enum
5
- from uuid import UUID, uuid4
6
-
7
- from sqlmodel import Field, SQLModel
8
-
9
-
10
- class AnnotationType(str, Enum):
11
- """The type of annotation task."""
12
-
13
- BBOX = "bbox"
14
- CLASSIFICATION = "classification"
15
- SEMANTIC_SEGMENTATION = "semantic_segmentation"
16
- INSTANCE_SEGMENTATION = "instance_segmentation"
17
- OBJECT_DETECTION = "object_detection"
18
-
19
-
20
- class AnnotationTaskTable(SQLModel, table=True):
21
- """The annotation task model."""
22
-
23
- __tablename__ = "annotation_tasks"
24
- annotation_task_id: UUID = Field(default_factory=uuid4, primary_key=True)
25
- name: str
26
- created_at: datetime = Field(default_factory=datetime.utcnow)
27
- annotation_type: AnnotationType
28
- is_prediction: bool
@@ -1,19 +0,0 @@
1
- """Handler for database operations related to annotations."""
2
-
3
- from __future__ import annotations
4
-
5
- from sqlmodel import Session
6
-
7
- from lightly_studio.models.annotation.annotation_base import (
8
- AnnotationBaseTable,
9
- AnnotationCreate,
10
- )
11
-
12
-
13
- def create(session: Session, annotation: AnnotationCreate) -> AnnotationBaseTable:
14
- """Create a new annotation in the database."""
15
- db_annotation = AnnotationBaseTable.model_validate(annotation)
16
- session.add(db_annotation)
17
- session.commit()
18
- session.refresh(db_annotation)
19
- return db_annotation
@@ -1,31 +0,0 @@
1
- """Resolver for annotation tasks."""
2
-
3
- from typing import List, Optional, Sequence
4
- from uuid import UUID
5
-
6
- from sqlmodel import Session, col, select
7
-
8
- from lightly_studio.models.annotation_task import AnnotationTaskTable
9
-
10
-
11
- def create(session: Session, annotation_task: AnnotationTaskTable) -> AnnotationTaskTable:
12
- """Create a new annotation task."""
13
- session.add(annotation_task)
14
- session.commit()
15
- session.refresh(annotation_task)
16
- return annotation_task
17
-
18
-
19
- def get_by_id(session: Session, annotation_task_id: UUID) -> Optional[AnnotationTaskTable]:
20
- """Get an annotation task by ID."""
21
- statement = select(AnnotationTaskTable).where(
22
- AnnotationTaskTable.annotation_task_id == annotation_task_id
23
- )
24
- return session.exec(statement).first()
25
-
26
-
27
- def get_all(session: Session) -> List[AnnotationTaskTable]:
28
- """Get all annotation tasks."""
29
- statement = select(AnnotationTaskTable).order_by(col(AnnotationTaskTable.created_at).asc())
30
- results: Sequence[AnnotationTaskTable] = session.exec(statement).all()
31
- return list(results)