1use crate::{AnnotationSet, Client, Dataset, Error, Sample, client};
5use chrono::{DateTime, Utc};
6use log::trace;
7use reqwest::multipart::{Form, Part};
8use serde::{Deserialize, Deserializer, Serialize};
9use std::{collections::HashMap, fmt::Display, path::PathBuf, str::FromStr};
10
11#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
41#[serde(untagged)]
42pub enum Parameter {
43 Integer(i64),
45 Real(f64),
47 Boolean(bool),
49 String(String),
51 Array(Vec<Parameter>),
53 Object(HashMap<String, Parameter>),
55}
56
57#[derive(Deserialize)]
58pub struct LoginResult {
59 pub(crate) token: String,
60}
61
62#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
82pub struct OrganizationID(u64);
83
84impl Display for OrganizationID {
85 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
86 write!(f, "org-{:x}", self.0)
87 }
88}
89
90impl From<u64> for OrganizationID {
91 fn from(id: u64) -> Self {
92 OrganizationID(id)
93 }
94}
95
96impl From<OrganizationID> for u64 {
97 fn from(val: OrganizationID) -> Self {
98 val.0
99 }
100}
101
102impl OrganizationID {
103 pub fn value(&self) -> u64 {
104 self.0
105 }
106}
107
108impl TryFrom<&str> for OrganizationID {
109 type Error = Error;
110
111 fn try_from(s: &str) -> Result<Self, Self::Error> {
112 let hex_part = s.strip_prefix("org-").ok_or_else(|| {
113 Error::InvalidParameters("Organization ID must start with 'org-' prefix".to_string())
114 })?;
115 let id = u64::from_str_radix(hex_part, 16)?;
116 Ok(OrganizationID(id))
117 }
118}
119
120#[derive(Deserialize, Clone, Debug)]
141pub struct Organization {
142 id: OrganizationID,
143 name: String,
144 #[serde(rename = "latest_credit")]
145 credits: i64,
146}
147
148impl Display for Organization {
149 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
150 write!(f, "{}", self.name())
151 }
152}
153
154impl Organization {
155 pub fn id(&self) -> OrganizationID {
156 self.id
157 }
158
159 pub fn name(&self) -> &str {
160 &self.name
161 }
162
163 pub fn credits(&self) -> i64 {
164 self.credits
165 }
166}
167
168#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
189pub struct ProjectID(u64);
190
191impl Display for ProjectID {
192 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
193 write!(f, "p-{:x}", self.0)
194 }
195}
196
197impl From<u64> for ProjectID {
198 fn from(id: u64) -> Self {
199 ProjectID(id)
200 }
201}
202
203impl From<ProjectID> for u64 {
204 fn from(val: ProjectID) -> Self {
205 val.0
206 }
207}
208
209impl ProjectID {
210 pub fn value(&self) -> u64 {
211 self.0
212 }
213}
214
215impl TryFrom<&str> for ProjectID {
216 type Error = Error;
217
218 fn try_from(s: &str) -> Result<Self, Self::Error> {
219 ProjectID::from_str(s)
220 }
221}
222
223impl TryFrom<String> for ProjectID {
224 type Error = Error;
225
226 fn try_from(s: String) -> Result<Self, Self::Error> {
227 ProjectID::from_str(&s)
228 }
229}
230
231impl FromStr for ProjectID {
232 type Err = Error;
233
234 fn from_str(s: &str) -> Result<Self, Self::Err> {
235 let hex_part = s.strip_prefix("p-").ok_or_else(|| {
236 Error::InvalidParameters("Project ID must start with 'p-' prefix".to_string())
237 })?;
238 let id = u64::from_str_radix(hex_part, 16)?;
239 Ok(ProjectID(id))
240 }
241}
242
243#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
264pub struct ExperimentID(u64);
265
266impl Display for ExperimentID {
267 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
268 write!(f, "exp-{:x}", self.0)
269 }
270}
271
272impl From<u64> for ExperimentID {
273 fn from(id: u64) -> Self {
274 ExperimentID(id)
275 }
276}
277
278impl From<ExperimentID> for u64 {
279 fn from(val: ExperimentID) -> Self {
280 val.0
281 }
282}
283
284impl ExperimentID {
285 pub fn value(&self) -> u64 {
286 self.0
287 }
288}
289
290impl TryFrom<&str> for ExperimentID {
291 type Error = Error;
292
293 fn try_from(s: &str) -> Result<Self, Self::Error> {
294 ExperimentID::from_str(s)
295 }
296}
297
298impl TryFrom<String> for ExperimentID {
299 type Error = Error;
300
301 fn try_from(s: String) -> Result<Self, Self::Error> {
302 ExperimentID::from_str(&s)
303 }
304}
305
306impl FromStr for ExperimentID {
307 type Err = Error;
308
309 fn from_str(s: &str) -> Result<Self, Self::Err> {
310 let hex_part = s.strip_prefix("exp-").ok_or_else(|| {
311 Error::InvalidParameters("Experiment ID must start with 'exp-' prefix".to_string())
312 })?;
313 let id = u64::from_str_radix(hex_part, 16)?;
314 Ok(ExperimentID(id))
315 }
316}
317
318#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
339pub struct TrainingSessionID(u64);
340
341impl Display for TrainingSessionID {
342 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
343 write!(f, "t-{:x}", self.0)
344 }
345}
346
347impl From<u64> for TrainingSessionID {
348 fn from(id: u64) -> Self {
349 TrainingSessionID(id)
350 }
351}
352
353impl From<TrainingSessionID> for u64 {
354 fn from(val: TrainingSessionID) -> Self {
355 val.0
356 }
357}
358
359impl TrainingSessionID {
360 pub fn value(&self) -> u64 {
361 self.0
362 }
363}
364
365impl TryFrom<&str> for TrainingSessionID {
366 type Error = Error;
367
368 fn try_from(s: &str) -> Result<Self, Self::Error> {
369 TrainingSessionID::from_str(s)
370 }
371}
372
373impl TryFrom<String> for TrainingSessionID {
374 type Error = Error;
375
376 fn try_from(s: String) -> Result<Self, Self::Error> {
377 TrainingSessionID::from_str(&s)
378 }
379}
380
381impl FromStr for TrainingSessionID {
382 type Err = Error;
383
384 fn from_str(s: &str) -> Result<Self, Self::Err> {
385 let hex_part = s.strip_prefix("t-").ok_or_else(|| {
386 Error::InvalidParameters("Training Session ID must start with 't-' prefix".to_string())
387 })?;
388 let id = u64::from_str_radix(hex_part, 16)?;
389 Ok(TrainingSessionID(id))
390 }
391}
392
393#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
413pub struct ValidationSessionID(u64);
414
415impl Display for ValidationSessionID {
416 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
417 write!(f, "v-{:x}", self.0)
418 }
419}
420
421impl From<u64> for ValidationSessionID {
422 fn from(id: u64) -> Self {
423 ValidationSessionID(id)
424 }
425}
426
427impl From<ValidationSessionID> for u64 {
428 fn from(val: ValidationSessionID) -> Self {
429 val.0
430 }
431}
432
433impl ValidationSessionID {
434 pub fn value(&self) -> u64 {
435 self.0
436 }
437}
438
439impl TryFrom<&str> for ValidationSessionID {
440 type Error = Error;
441
442 fn try_from(s: &str) -> Result<Self, Self::Error> {
443 let hex_part = s.strip_prefix("v-").ok_or_else(|| {
444 Error::InvalidParameters(
445 "Validation Session ID must start with 'v-' prefix".to_string(),
446 )
447 })?;
448 let id = u64::from_str_radix(hex_part, 16)?;
449 Ok(ValidationSessionID(id))
450 }
451}
452
453impl TryFrom<String> for ValidationSessionID {
454 type Error = Error;
455
456 fn try_from(s: String) -> Result<Self, Self::Error> {
457 ValidationSessionID::try_from(s.as_str())
458 }
459}
460
461#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
462pub struct SnapshotID(u64);
463
464impl Display for SnapshotID {
465 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
466 write!(f, "ss-{:x}", self.0)
467 }
468}
469
470impl From<u64> for SnapshotID {
471 fn from(id: u64) -> Self {
472 SnapshotID(id)
473 }
474}
475
476impl From<SnapshotID> for u64 {
477 fn from(val: SnapshotID) -> Self {
478 val.0
479 }
480}
481
482impl SnapshotID {
483 pub fn value(&self) -> u64 {
484 self.0
485 }
486}
487
488impl TryFrom<&str> for SnapshotID {
489 type Error = Error;
490
491 fn try_from(s: &str) -> Result<Self, Self::Error> {
492 let hex_part = s.strip_prefix("ss-").ok_or_else(|| {
493 Error::InvalidParameters("Snapshot ID must start with 'ss-' prefix".to_string())
494 })?;
495 let id = u64::from_str_radix(hex_part, 16)?;
496 Ok(SnapshotID(id))
497 }
498}
499
500#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
501pub struct TaskID(u64);
502
503impl Display for TaskID {
504 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
505 write!(f, "task-{:x}", self.0)
506 }
507}
508
509impl From<u64> for TaskID {
510 fn from(id: u64) -> Self {
511 TaskID(id)
512 }
513}
514
515impl From<TaskID> for u64 {
516 fn from(val: TaskID) -> Self {
517 val.0
518 }
519}
520
521impl TaskID {
522 pub fn value(&self) -> u64 {
523 self.0
524 }
525}
526
527impl TryFrom<&str> for TaskID {
528 type Error = Error;
529
530 fn try_from(s: &str) -> Result<Self, Self::Error> {
531 TaskID::from_str(s)
532 }
533}
534
535impl TryFrom<String> for TaskID {
536 type Error = Error;
537
538 fn try_from(s: String) -> Result<Self, Self::Error> {
539 TaskID::from_str(&s)
540 }
541}
542
543impl FromStr for TaskID {
544 type Err = Error;
545
546 fn from_str(s: &str) -> Result<Self, Self::Err> {
547 let hex_part = s.strip_prefix("task-").ok_or_else(|| {
548 Error::InvalidParameters("Task ID must start with 'task-' prefix".to_string())
549 })?;
550 let id = u64::from_str_radix(hex_part, 16)?;
551 Ok(TaskID(id))
552 }
553}
554
555#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
576pub struct DatasetID(u64);
577
578impl Display for DatasetID {
579 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
580 write!(f, "ds-{:x}", self.0)
581 }
582}
583
584impl From<u64> for DatasetID {
585 fn from(id: u64) -> Self {
586 DatasetID(id)
587 }
588}
589
590impl From<DatasetID> for u64 {
591 fn from(val: DatasetID) -> Self {
592 val.0
593 }
594}
595
596impl DatasetID {
597 pub fn value(&self) -> u64 {
598 self.0
599 }
600}
601
602impl TryFrom<&str> for DatasetID {
603 type Error = Error;
604
605 fn try_from(s: &str) -> Result<Self, Self::Error> {
606 DatasetID::from_str(s)
607 }
608}
609
610impl TryFrom<String> for DatasetID {
611 type Error = Error;
612
613 fn try_from(s: String) -> Result<Self, Self::Error> {
614 DatasetID::from_str(&s)
615 }
616}
617
618impl FromStr for DatasetID {
619 type Err = Error;
620
621 fn from_str(s: &str) -> Result<Self, Self::Err> {
622 let hex_part = s.strip_prefix("ds-").ok_or_else(|| {
623 Error::InvalidParameters("Dataset ID must start with 'ds-' prefix".to_string())
624 })?;
625 let id = u64::from_str_radix(hex_part, 16)?;
626 Ok(DatasetID(id))
627 }
628}
629
630#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
631pub struct AnnotationSetID(u64);
632
633impl Display for AnnotationSetID {
634 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
635 write!(f, "as-{:x}", self.0)
636 }
637}
638
639impl From<u64> for AnnotationSetID {
640 fn from(id: u64) -> Self {
641 AnnotationSetID(id)
642 }
643}
644
645impl From<AnnotationSetID> for u64 {
646 fn from(val: AnnotationSetID) -> Self {
647 val.0
648 }
649}
650
651impl AnnotationSetID {
652 pub fn value(&self) -> u64 {
653 self.0
654 }
655}
656
657impl TryFrom<&str> for AnnotationSetID {
658 type Error = Error;
659
660 fn try_from(s: &str) -> Result<Self, Self::Error> {
661 AnnotationSetID::from_str(s)
662 }
663}
664
665impl TryFrom<String> for AnnotationSetID {
666 type Error = Error;
667
668 fn try_from(s: String) -> Result<Self, Self::Error> {
669 AnnotationSetID::from_str(&s)
670 }
671}
672
673impl FromStr for AnnotationSetID {
674 type Err = Error;
675
676 fn from_str(s: &str) -> Result<Self, Self::Err> {
677 let hex_part = s.strip_prefix("as-").ok_or_else(|| {
678 Error::InvalidParameters("Annotation Set ID must start with 'as-' prefix".to_string())
679 })?;
680 let id = u64::from_str_radix(hex_part, 16)?;
681 Ok(AnnotationSetID(id))
682 }
683}
684
685#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
686pub struct SampleID(u64);
687
688impl Display for SampleID {
689 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
690 write!(f, "s-{:x}", self.0)
691 }
692}
693
694impl From<u64> for SampleID {
695 fn from(id: u64) -> Self {
696 SampleID(id)
697 }
698}
699
700impl From<SampleID> for u64 {
701 fn from(val: SampleID) -> Self {
702 val.0
703 }
704}
705
706impl SampleID {
707 pub fn value(&self) -> u64 {
708 self.0
709 }
710}
711
712impl TryFrom<&str> for SampleID {
713 type Error = Error;
714
715 fn try_from(s: &str) -> Result<Self, Self::Error> {
716 let hex_part = s.strip_prefix("s-").ok_or_else(|| {
717 Error::InvalidParameters("Sample ID must start with 's-' prefix".to_string())
718 })?;
719 let id = u64::from_str_radix(hex_part, 16)?;
720 Ok(SampleID(id))
721 }
722}
723
724#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
725pub struct AppId(u64);
726
727impl Display for AppId {
728 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
729 write!(f, "app-{:x}", self.0)
730 }
731}
732
733impl From<u64> for AppId {
734 fn from(id: u64) -> Self {
735 AppId(id)
736 }
737}
738
739impl From<AppId> for u64 {
740 fn from(val: AppId) -> Self {
741 val.0
742 }
743}
744
745impl AppId {
746 pub fn value(&self) -> u64 {
747 self.0
748 }
749}
750
751impl TryFrom<&str> for AppId {
752 type Error = Error;
753
754 fn try_from(s: &str) -> Result<Self, Self::Error> {
755 let hex_part = s.strip_prefix("app-").ok_or_else(|| {
756 Error::InvalidParameters("App ID must start with 'app-' prefix".to_string())
757 })?;
758 let id = u64::from_str_radix(hex_part, 16)?;
759 Ok(AppId(id))
760 }
761}
762
763#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
764pub struct ImageId(u64);
765
766impl Display for ImageId {
767 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
768 write!(f, "im-{:x}", self.0)
769 }
770}
771
772impl From<u64> for ImageId {
773 fn from(id: u64) -> Self {
774 ImageId(id)
775 }
776}
777
778impl From<ImageId> for u64 {
779 fn from(val: ImageId) -> Self {
780 val.0
781 }
782}
783
784impl ImageId {
785 pub fn value(&self) -> u64 {
786 self.0
787 }
788}
789
790impl TryFrom<&str> for ImageId {
791 type Error = Error;
792
793 fn try_from(s: &str) -> Result<Self, Self::Error> {
794 let hex_part = s.strip_prefix("im-").ok_or_else(|| {
795 Error::InvalidParameters("Image ID must start with 'im-' prefix".to_string())
796 })?;
797 let id = u64::from_str_radix(hex_part, 16)?;
798 Ok(ImageId(id))
799 }
800}
801
802#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, Hash)]
803pub struct SequenceId(u64);
804
805impl Display for SequenceId {
806 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
807 write!(f, "se-{:x}", self.0)
808 }
809}
810
811impl From<u64> for SequenceId {
812 fn from(id: u64) -> Self {
813 SequenceId(id)
814 }
815}
816
817impl From<SequenceId> for u64 {
818 fn from(val: SequenceId) -> Self {
819 val.0
820 }
821}
822
823impl SequenceId {
824 pub fn value(&self) -> u64 {
825 self.0
826 }
827}
828
829impl TryFrom<&str> for SequenceId {
830 type Error = Error;
831
832 fn try_from(s: &str) -> Result<Self, Self::Error> {
833 let hex_part = s.strip_prefix("se-").ok_or_else(|| {
834 Error::InvalidParameters("Sequence ID must start with 'se-' prefix".to_string())
835 })?;
836 let id = u64::from_str_radix(hex_part, 16)?;
837 Ok(SequenceId(id))
838 }
839}
840
841#[derive(Deserialize, Clone, Debug)]
845pub struct Project {
846 id: ProjectID,
847 name: String,
848 description: String,
849}
850
851impl Display for Project {
852 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
853 write!(f, "{} {}", self.id(), self.name())
854 }
855}
856
857impl Project {
858 pub fn id(&self) -> ProjectID {
859 self.id
860 }
861
862 pub fn name(&self) -> &str {
863 &self.name
864 }
865
866 pub fn description(&self) -> &str {
867 &self.description
868 }
869
870 pub async fn datasets(
871 &self,
872 client: &client::Client,
873 name: Option<&str>,
874 ) -> Result<Vec<Dataset>, Error> {
875 client.datasets(self.id, name).await
876 }
877
878 pub async fn experiments(
879 &self,
880 client: &client::Client,
881 name: Option<&str>,
882 ) -> Result<Vec<Experiment>, Error> {
883 client.experiments(self.id, name).await
884 }
885}
886
887#[derive(Deserialize, Debug)]
888pub struct SamplesCountResult {
889 pub total: u64,
890}
891
892#[derive(Serialize, Clone, Debug)]
893pub struct SamplesListParams {
894 pub dataset_id: DatasetID,
895 #[serde(skip_serializing_if = "Option::is_none")]
896 pub annotation_set_id: Option<AnnotationSetID>,
897 #[serde(skip_serializing_if = "Option::is_none")]
898 pub continue_token: Option<String>,
899 #[serde(skip_serializing_if = "Vec::is_empty")]
900 pub types: Vec<String>,
901 #[serde(skip_serializing_if = "Vec::is_empty")]
902 pub group_names: Vec<String>,
903}
904
905#[derive(Deserialize, Debug)]
906pub struct SamplesListResult {
907 pub samples: Vec<Sample>,
908 pub continue_token: Option<String>,
909}
910
911#[derive(Serialize, Clone, Debug)]
916pub struct SamplesPopulateParams {
917 pub dataset_id: DatasetID,
918 #[serde(skip_serializing_if = "Option::is_none")]
919 pub annotation_set_id: Option<AnnotationSetID>,
920 #[serde(skip_serializing_if = "Option::is_none")]
921 pub presigned_urls: Option<bool>,
922 pub samples: Vec<Sample>,
923}
924
925#[derive(Deserialize, Debug)]
931pub struct SamplesPopulateResult {
932 pub uuid: String,
934 pub urls: Vec<PresignedUrl>,
936}
937
938#[derive(Deserialize, Debug, Clone)]
940pub struct PresignedUrl {
941 pub filename: String,
943 pub key: String,
945 pub url: String,
947}
948
949#[derive(Deserialize)]
950pub struct Snapshot {
951 id: SnapshotID,
952 description: String,
953 status: String,
954 path: String,
955 #[serde(rename = "date")]
956 created: DateTime<Utc>,
957}
958
959impl Display for Snapshot {
960 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
961 write!(f, "{} {}", self.id, self.description)
962 }
963}
964
965impl Snapshot {
966 pub fn id(&self) -> SnapshotID {
967 self.id
968 }
969
970 pub fn description(&self) -> &str {
971 &self.description
972 }
973
974 pub fn status(&self) -> &str {
975 &self.status
976 }
977
978 pub fn path(&self) -> &str {
979 &self.path
980 }
981
982 pub fn created(&self) -> &DateTime<Utc> {
983 &self.created
984 }
985}
986
987#[derive(Serialize, Debug)]
988pub struct SnapshotRestore {
989 pub project_id: ProjectID,
990 pub snapshot_id: SnapshotID,
991 pub fps: u64,
992 #[serde(rename = "enabled_topics", skip_serializing_if = "Vec::is_empty")]
993 pub topics: Vec<String>,
994 #[serde(rename = "label_names", skip_serializing_if = "Vec::is_empty")]
995 pub autolabel: Vec<String>,
996 #[serde(rename = "depth_gen")]
997 pub autodepth: bool,
998 pub agtg_pipeline: bool,
999 #[serde(skip_serializing_if = "Option::is_none")]
1000 pub dataset_name: Option<String>,
1001 #[serde(skip_serializing_if = "Option::is_none")]
1002 pub dataset_description: Option<String>,
1003}
1004
1005#[derive(Deserialize, Debug)]
1006pub struct SnapshotRestoreResult {
1007 pub id: SnapshotID,
1008 pub description: String,
1009 pub dataset_name: String,
1010 pub dataset_id: DatasetID,
1011 pub annotation_set_id: AnnotationSetID,
1012 #[serde(rename = "docker_task_id")]
1013 pub task_id: TaskID,
1014 pub date: DateTime<Utc>,
1015}
1016
1017#[derive(Deserialize)]
1018pub struct Experiment {
1019 id: ExperimentID,
1020 project_id: ProjectID,
1021 name: String,
1022 description: String,
1023}
1024
1025impl Display for Experiment {
1026 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1027 write!(f, "{} {}", self.uid(), self.name)
1028 }
1029}
1030
1031impl Experiment {
1032 pub fn id(&self) -> ExperimentID {
1033 self.id
1034 }
1035
1036 pub fn uid(&self) -> String {
1037 self.id.to_string()
1038 }
1039
1040 pub fn project_id(&self) -> ProjectID {
1041 self.project_id
1042 }
1043
1044 pub fn name(&self) -> &str {
1045 &self.name
1046 }
1047
1048 pub fn description(&self) -> &str {
1049 &self.description
1050 }
1051
1052 pub async fn project(&self, client: &client::Client) -> Result<Project, Error> {
1053 client.project(self.project_id).await
1054 }
1055
1056 pub async fn training_sessions(
1057 &self,
1058 client: &client::Client,
1059 name: Option<&str>,
1060 ) -> Result<Vec<TrainingSession>, Error> {
1061 client.training_sessions(self.id, name).await
1062 }
1063}
1064
1065#[derive(Serialize, Debug)]
1066pub struct PublishMetrics {
1067 #[serde(rename = "trainer_session_id", skip_serializing_if = "Option::is_none")]
1068 pub trainer_session_id: Option<TrainingSessionID>,
1069 #[serde(
1070 rename = "validate_session_id",
1071 skip_serializing_if = "Option::is_none"
1072 )]
1073 pub validate_session_id: Option<ValidationSessionID>,
1074 pub metrics: HashMap<String, Parameter>,
1075}
1076
1077#[derive(Deserialize)]
1078struct TrainingSessionParams {
1079 model_params: HashMap<String, Parameter>,
1080 dataset_params: DatasetParams,
1081}
1082
1083#[derive(Deserialize)]
1084pub struct TrainingSession {
1085 id: TrainingSessionID,
1086 #[serde(rename = "trainer_id")]
1087 experiment_id: ExperimentID,
1088 model: String,
1089 name: String,
1090 description: String,
1091 params: TrainingSessionParams,
1092 #[serde(rename = "docker_task")]
1093 task: Task,
1094}
1095
1096impl Display for TrainingSession {
1097 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1098 write!(f, "{} {}", self.uid(), self.name())
1099 }
1100}
1101
1102impl TrainingSession {
1103 pub fn id(&self) -> TrainingSessionID {
1104 self.id
1105 }
1106
1107 pub fn uid(&self) -> String {
1108 self.id.to_string()
1109 }
1110
1111 pub fn name(&self) -> &str {
1112 &self.name
1113 }
1114
1115 pub fn description(&self) -> &str {
1116 &self.description
1117 }
1118
1119 pub fn model(&self) -> &str {
1120 &self.model
1121 }
1122
1123 pub fn experiment_id(&self) -> ExperimentID {
1124 self.experiment_id
1125 }
1126
1127 pub fn task(&self) -> Task {
1128 self.task.clone()
1129 }
1130
1131 pub fn model_params(&self) -> &HashMap<String, Parameter> {
1132 &self.params.model_params
1133 }
1134
1135 pub fn dataset_params(&self) -> &DatasetParams {
1136 &self.params.dataset_params
1137 }
1138
1139 pub fn train_group(&self) -> &str {
1140 &self.params.dataset_params.train_group
1141 }
1142
1143 pub fn val_group(&self) -> &str {
1144 &self.params.dataset_params.val_group
1145 }
1146
1147 pub async fn experiment(&self, client: &client::Client) -> Result<Experiment, Error> {
1148 client.experiment(self.experiment_id).await
1149 }
1150
1151 pub async fn dataset(&self, client: &client::Client) -> Result<Dataset, Error> {
1152 client.dataset(self.params.dataset_params.dataset_id).await
1153 }
1154
1155 pub async fn annotation_set(&self, client: &client::Client) -> Result<AnnotationSet, Error> {
1156 client
1157 .annotation_set(self.params.dataset_params.annotation_set_id)
1158 .await
1159 }
1160
1161 pub async fn artifacts(&self, client: &client::Client) -> Result<Vec<Artifact>, Error> {
1162 client.artifacts(self.id).await
1163 }
1164
1165 pub async fn metrics(
1166 &self,
1167 client: &client::Client,
1168 ) -> Result<HashMap<String, Parameter>, Error> {
1169 #[derive(Deserialize)]
1170 #[serde(untagged, deny_unknown_fields, expecting = "map, empty map or string")]
1171 enum Response {
1172 Empty {},
1173 Map(HashMap<String, Parameter>),
1174 String(String),
1175 }
1176
1177 let params = HashMap::from([("trainer_session_id", self.id().value())]);
1178 let resp: Response = client
1179 .rpc("trainer.session.metrics".to_owned(), Some(params))
1180 .await?;
1181
1182 Ok(match resp {
1183 Response::String(metrics) => serde_json::from_str(&metrics)?,
1184 Response::Map(metrics) => metrics,
1185 Response::Empty {} => HashMap::new(),
1186 })
1187 }
1188
1189 pub async fn set_metrics(
1190 &self,
1191 client: &client::Client,
1192 metrics: HashMap<String, Parameter>,
1193 ) -> Result<(), Error> {
1194 let metrics = PublishMetrics {
1195 trainer_session_id: Some(self.id()),
1196 validate_session_id: None,
1197 metrics,
1198 };
1199
1200 let _: String = client
1201 .rpc("trainer.session.metrics".to_owned(), Some(metrics))
1202 .await?;
1203
1204 Ok(())
1205 }
1206
1207 pub async fn download_artifact(
1209 &self,
1210 client: &client::Client,
1211 filename: &str,
1212 ) -> Result<Vec<u8>, Error> {
1213 client
1214 .fetch(&format!(
1215 "download_model?training_session_id={}&file={}",
1216 self.id().value(),
1217 filename
1218 ))
1219 .await
1220 }
1221
1222 pub async fn upload_artifact(
1226 &self,
1227 client: &client::Client,
1228 filename: &str,
1229 path: PathBuf,
1230 ) -> Result<(), Error> {
1231 self.upload(client, &[(format!("artifacts/{}", filename), path)])
1232 .await
1233 }
1234
1235 pub async fn download_checkpoint(
1237 &self,
1238 client: &client::Client,
1239 filename: &str,
1240 ) -> Result<Vec<u8>, Error> {
1241 client
1242 .fetch(&format!(
1243 "download_checkpoint?folder=checkpoints&training_session_id={}&file={}",
1244 self.id().value(),
1245 filename
1246 ))
1247 .await
1248 }
1249
1250 pub async fn upload_checkpoint(
1254 &self,
1255 client: &client::Client,
1256 filename: &str,
1257 path: PathBuf,
1258 ) -> Result<(), Error> {
1259 self.upload(client, &[(format!("checkpoints/{}", filename), path)])
1260 .await
1261 }
1262
1263 pub async fn download(&self, client: &client::Client, filename: &str) -> Result<String, Error> {
1267 #[derive(Serialize)]
1268 struct DownloadRequest {
1269 session_id: TrainingSessionID,
1270 file_path: String,
1271 }
1272
1273 let params = DownloadRequest {
1274 session_id: self.id(),
1275 file_path: filename.to_string(),
1276 };
1277
1278 client
1279 .rpc("trainer.download.file".to_owned(), Some(params))
1280 .await
1281 }
1282
1283 pub async fn upload(
1284 &self,
1285 client: &client::Client,
1286 files: &[(String, PathBuf)],
1287 ) -> Result<(), Error> {
1288 let mut parts = Form::new().part(
1289 "params",
1290 Part::text(format!("{{ \"session_id\": {} }}", self.id().value())),
1291 );
1292
1293 for (name, path) in files {
1294 let file_part = Part::file(path).await?.file_name(name.to_owned());
1295 parts = parts.part("file", file_part);
1296 }
1297
1298 let result = client.post_multipart("trainer.upload.files", parts).await?;
1299 trace!("TrainingSession::upload: {:?}", result);
1300 Ok(())
1301 }
1302}
1303
1304#[derive(Deserialize, Clone, Debug)]
1305pub struct ValidationSession {
1306 id: ValidationSessionID,
1307 description: String,
1308 dataset_id: DatasetID,
1309 experiment_id: ExperimentID,
1310 training_session_id: TrainingSessionID,
1311 #[serde(rename = "gt_annotation_set_id")]
1312 annotation_set_id: AnnotationSetID,
1313 #[serde(deserialize_with = "validation_session_params")]
1314 params: HashMap<String, Parameter>,
1315 #[serde(rename = "docker_task")]
1316 task: Task,
1317}
1318
1319fn validation_session_params<'de, D>(
1320 deserializer: D,
1321) -> Result<HashMap<String, Parameter>, D::Error>
1322where
1323 D: Deserializer<'de>,
1324{
1325 #[derive(Deserialize)]
1326 struct ModelParams {
1327 validation: Option<HashMap<String, Parameter>>,
1328 }
1329
1330 #[derive(Deserialize)]
1331 struct ValidateParams {
1332 model: String,
1333 }
1334
1335 #[derive(Deserialize)]
1336 struct Params {
1337 model_params: ModelParams,
1338 validate_params: ValidateParams,
1339 }
1340
1341 let params = Params::deserialize(deserializer)?;
1342 let params = match params.model_params.validation {
1343 Some(mut map) => {
1344 map.insert(
1345 "model".to_string(),
1346 Parameter::String(params.validate_params.model),
1347 );
1348 map
1349 }
1350 None => HashMap::from([(
1351 "model".to_string(),
1352 Parameter::String(params.validate_params.model),
1353 )]),
1354 };
1355
1356 Ok(params)
1357}
1358
1359impl ValidationSession {
1360 pub fn id(&self) -> ValidationSessionID {
1361 self.id
1362 }
1363
1364 pub fn uid(&self) -> String {
1365 self.id.to_string()
1366 }
1367
1368 pub fn name(&self) -> &str {
1369 self.task.name()
1370 }
1371
1372 pub fn description(&self) -> &str {
1373 &self.description
1374 }
1375
1376 pub fn dataset_id(&self) -> DatasetID {
1377 self.dataset_id
1378 }
1379
1380 pub fn experiment_id(&self) -> ExperimentID {
1381 self.experiment_id
1382 }
1383
1384 pub fn training_session_id(&self) -> TrainingSessionID {
1385 self.training_session_id
1386 }
1387
1388 pub fn annotation_set_id(&self) -> AnnotationSetID {
1389 self.annotation_set_id
1390 }
1391
1392 pub fn params(&self) -> &HashMap<String, Parameter> {
1393 &self.params
1394 }
1395
1396 pub fn task(&self) -> &Task {
1397 &self.task
1398 }
1399
1400 pub async fn metrics(
1401 &self,
1402 client: &client::Client,
1403 ) -> Result<HashMap<String, Parameter>, Error> {
1404 #[derive(Deserialize)]
1405 #[serde(untagged, deny_unknown_fields, expecting = "map, empty map or string")]
1406 enum Response {
1407 Empty {},
1408 Map(HashMap<String, Parameter>),
1409 String(String),
1410 }
1411
1412 let params = HashMap::from([("validate_session_id", self.id().value())]);
1413 let resp: Response = client
1414 .rpc("validate.session.metrics".to_owned(), Some(params))
1415 .await?;
1416
1417 Ok(match resp {
1418 Response::String(metrics) => serde_json::from_str(&metrics)?,
1419 Response::Map(metrics) => metrics,
1420 Response::Empty {} => HashMap::new(),
1421 })
1422 }
1423
1424 pub async fn set_metrics(
1425 &self,
1426 client: &client::Client,
1427 metrics: HashMap<String, Parameter>,
1428 ) -> Result<(), Error> {
1429 let metrics = PublishMetrics {
1430 trainer_session_id: None,
1431 validate_session_id: Some(self.id()),
1432 metrics,
1433 };
1434
1435 let _: String = client
1436 .rpc("validate.session.metrics".to_owned(), Some(metrics))
1437 .await?;
1438
1439 Ok(())
1440 }
1441
1442 pub async fn upload(
1443 &self,
1444 client: &client::Client,
1445 files: &[(String, PathBuf)],
1446 ) -> Result<(), Error> {
1447 let mut parts = Form::new().part(
1448 "params",
1449 Part::text(format!("{{ \"session_id\": {} }}", self.id().value())),
1450 );
1451
1452 for (name, path) in files {
1453 let file_part = Part::file(path).await?.file_name(name.to_owned());
1454 parts = parts.part("file", file_part);
1455 }
1456
1457 let result = client
1458 .post_multipart("validate.upload.files", parts)
1459 .await?;
1460 trace!("ValidationSession::upload: {:?}", result);
1461 Ok(())
1462 }
1463}
1464
1465#[derive(Deserialize, Clone, Debug)]
1466pub struct DatasetParams {
1467 dataset_id: DatasetID,
1468 annotation_set_id: AnnotationSetID,
1469 #[serde(rename = "train_group_name")]
1470 train_group: String,
1471 #[serde(rename = "val_group_name")]
1472 val_group: String,
1473}
1474
1475impl DatasetParams {
1476 pub fn dataset_id(&self) -> DatasetID {
1477 self.dataset_id
1478 }
1479
1480 pub fn annotation_set_id(&self) -> AnnotationSetID {
1481 self.annotation_set_id
1482 }
1483
1484 pub fn train_group(&self) -> &str {
1485 &self.train_group
1486 }
1487
1488 pub fn val_group(&self) -> &str {
1489 &self.val_group
1490 }
1491}
1492
1493#[derive(Serialize, Debug, Clone)]
1494pub struct TasksListParams {
1495 #[serde(skip_serializing_if = "Option::is_none")]
1496 pub continue_token: Option<String>,
1497 #[serde(rename = "manage_types", skip_serializing_if = "Option::is_none")]
1498 pub manager: Option<Vec<String>>,
1499 #[serde(skip_serializing_if = "Option::is_none")]
1500 pub status: Option<Vec<String>>,
1501}
1502
1503#[derive(Deserialize, Debug, Clone)]
1504pub struct TasksListResult {
1505 pub tasks: Vec<Task>,
1506 pub continue_token: Option<String>,
1507}
1508
1509#[derive(Deserialize, Debug, Clone)]
1510pub struct Task {
1511 id: TaskID,
1512 name: String,
1513 #[serde(rename = "type")]
1514 workflow: String,
1515 status: String,
1516 #[serde(rename = "manage_type")]
1517 manager: Option<String>,
1518 #[serde(rename = "instance_type")]
1519 instance: String,
1520 #[serde(rename = "date")]
1521 created: DateTime<Utc>,
1522}
1523
1524impl Task {
1525 pub fn id(&self) -> TaskID {
1526 self.id
1527 }
1528
1529 pub fn uid(&self) -> String {
1530 self.id.to_string()
1531 }
1532
1533 pub fn name(&self) -> &str {
1534 &self.name
1535 }
1536
1537 pub fn workflow(&self) -> &str {
1538 &self.workflow
1539 }
1540
1541 pub fn status(&self) -> &str {
1542 &self.status
1543 }
1544
1545 pub fn manager(&self) -> Option<&str> {
1546 self.manager.as_deref()
1547 }
1548
1549 pub fn instance(&self) -> &str {
1550 &self.instance
1551 }
1552
1553 pub fn created(&self) -> &DateTime<Utc> {
1554 &self.created
1555 }
1556}
1557
1558impl Display for Task {
1559 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1560 write!(
1561 f,
1562 "{} [{:?} {}] {}",
1563 self.uid(),
1564 self.manager(),
1565 self.workflow(),
1566 self.name()
1567 )
1568 }
1569}
1570
1571#[derive(Deserialize, Debug)]
1572pub struct TaskInfo {
1573 id: TaskID,
1574 project_id: Option<ProjectID>,
1575 #[serde(rename = "task_description")]
1576 description: String,
1577 #[serde(rename = "type")]
1578 workflow: String,
1579 status: Option<String>,
1580 progress: TaskProgress,
1581 #[serde(rename = "created_date")]
1582 created: DateTime<Utc>,
1583 #[serde(rename = "end_date")]
1584 completed: DateTime<Utc>,
1585}
1586
1587impl Display for TaskInfo {
1588 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
1589 write!(
1590 f,
1591 "{} {}: {}",
1592 self.uid(),
1593 self.workflow(),
1594 self.description()
1595 )
1596 }
1597}
1598
1599impl TaskInfo {
1600 pub fn id(&self) -> TaskID {
1601 self.id
1602 }
1603
1604 pub fn uid(&self) -> String {
1605 self.id.to_string()
1606 }
1607
1608 pub fn project_id(&self) -> Option<ProjectID> {
1609 self.project_id
1610 }
1611
1612 pub fn description(&self) -> &str {
1613 &self.description
1614 }
1615
1616 pub fn workflow(&self) -> &str {
1617 &self.workflow
1618 }
1619
1620 pub fn status(&self) -> &Option<String> {
1621 &self.status
1622 }
1623
1624 pub async fn set_status(&mut self, client: &Client, status: &str) -> Result<(), Error> {
1625 let t = client.task_status(self.id(), status).await?;
1626 self.status = Some(t.status);
1627 Ok(())
1628 }
1629
1630 pub fn stages(&self) -> HashMap<String, Stage> {
1631 match &self.progress.stages {
1632 Some(stages) => stages.clone(),
1633 None => HashMap::new(),
1634 }
1635 }
1636
1637 pub async fn update_stage(
1638 &mut self,
1639 client: &Client,
1640 stage: &str,
1641 status: &str,
1642 message: &str,
1643 percentage: u8,
1644 ) -> Result<(), Error> {
1645 client
1646 .update_stage(self.id(), stage, status, message, percentage)
1647 .await?;
1648 let t = client.task_info(self.id()).await?;
1649 self.progress.stages = Some(t.progress.stages.unwrap_or_default());
1650 Ok(())
1651 }
1652
1653 pub async fn set_stages(
1654 &mut self,
1655 client: &Client,
1656 stages: &[(&str, &str)],
1657 ) -> Result<(), Error> {
1658 client.set_stages(self.id(), stages).await?;
1659 let t = client.task_info(self.id()).await?;
1660 self.progress.stages = Some(t.progress.stages.unwrap_or_default());
1661 Ok(())
1662 }
1663
1664 pub fn created(&self) -> &DateTime<Utc> {
1665 &self.created
1666 }
1667
1668 pub fn completed(&self) -> &DateTime<Utc> {
1669 &self.completed
1670 }
1671}
1672
1673#[derive(Deserialize, Debug)]
1674pub struct TaskProgress {
1675 stages: Option<HashMap<String, Stage>>,
1676}
1677
1678#[derive(Serialize, Debug, Clone)]
1679pub struct TaskStatus {
1680 #[serde(rename = "docker_task_id")]
1681 pub task_id: TaskID,
1682 pub status: String,
1683}
1684
1685#[derive(Serialize, Deserialize, Debug, Clone)]
1686pub struct Stage {
1687 #[serde(rename = "docker_task_id", skip_serializing_if = "Option::is_none")]
1688 task_id: Option<TaskID>,
1689 stage: String,
1690 #[serde(skip_serializing_if = "Option::is_none")]
1691 status: Option<String>,
1692 #[serde(skip_serializing_if = "Option::is_none")]
1693 description: Option<String>,
1694 #[serde(skip_serializing_if = "Option::is_none")]
1695 message: Option<String>,
1696 percentage: u8,
1697}
1698
1699impl Stage {
1700 pub fn new(
1701 task_id: Option<TaskID>,
1702 stage: String,
1703 status: Option<String>,
1704 message: Option<String>,
1705 percentage: u8,
1706 ) -> Self {
1707 Stage {
1708 task_id,
1709 stage,
1710 status,
1711 description: None,
1712 message,
1713 percentage,
1714 }
1715 }
1716
1717 pub fn task_id(&self) -> &Option<TaskID> {
1718 &self.task_id
1719 }
1720
1721 pub fn stage(&self) -> &str {
1722 &self.stage
1723 }
1724
1725 pub fn status(&self) -> &Option<String> {
1726 &self.status
1727 }
1728
1729 pub fn description(&self) -> &Option<String> {
1730 &self.description
1731 }
1732
1733 pub fn message(&self) -> &Option<String> {
1734 &self.message
1735 }
1736
1737 pub fn percentage(&self) -> u8 {
1738 self.percentage
1739 }
1740}
1741
1742#[derive(Serialize, Debug)]
1743pub struct TaskStages {
1744 #[serde(rename = "docker_task_id")]
1745 pub task_id: TaskID,
1746 #[serde(skip_serializing_if = "Vec::is_empty")]
1747 pub stages: Vec<HashMap<String, String>>,
1748}
1749
1750#[derive(Deserialize, Debug)]
1751pub struct Artifact {
1752 name: String,
1753 #[serde(rename = "modelType")]
1754 model_type: String,
1755}
1756
1757impl Artifact {
1758 pub fn name(&self) -> &str {
1759 &self.name
1760 }
1761
1762 pub fn model_type(&self) -> &str {
1763 &self.model_type
1764 }
1765}