@things-factory/integration-label-studio 9.1.19

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 (152) hide show
  1. package/CHANGELOG.md +85 -0
  2. package/EXTERNAL_DATA_SOURCING.md +484 -0
  3. package/IMPLEMENTATION_GUIDE.md +469 -0
  4. package/INTEGRATION.md +279 -0
  5. package/README.md +1014 -0
  6. package/SETUP_GUIDE.md +577 -0
  7. package/TEST_GUIDE.md +387 -0
  8. package/UI_CUSTOMIZATION.md +395 -0
  9. package/USER_SYNC_GUIDE.md +514 -0
  10. package/client/bootstrap.ts +1 -0
  11. package/client/index.ts +1 -0
  12. package/client/label-studio-label-page.ts +52 -0
  13. package/client/label-studio-project-create.ts +216 -0
  14. package/client/label-studio-project-list.ts +214 -0
  15. package/client/label-studio-wrapper.ts +294 -0
  16. package/client/route.ts +15 -0
  17. package/client/tsconfig.json +13 -0
  18. package/config/config.development.js +124 -0
  19. package/config/config.production.js +182 -0
  20. package/dist-client/bootstrap.d.ts +1 -0
  21. package/dist-client/bootstrap.js +2 -0
  22. package/dist-client/bootstrap.js.map +1 -0
  23. package/dist-client/index.d.ts +1 -0
  24. package/dist-client/index.js +2 -0
  25. package/dist-client/index.js.map +1 -0
  26. package/dist-client/label-studio-label-page.d.ts +8 -0
  27. package/dist-client/label-studio-label-page.js +54 -0
  28. package/dist-client/label-studio-label-page.js.map +1 -0
  29. package/dist-client/label-studio-project-create.d.ts +16 -0
  30. package/dist-client/label-studio-project-create.js +235 -0
  31. package/dist-client/label-studio-project-create.js.map +1 -0
  32. package/dist-client/label-studio-project-list.d.ts +16 -0
  33. package/dist-client/label-studio-project-list.js +222 -0
  34. package/dist-client/label-studio-project-list.js.map +1 -0
  35. package/dist-client/label-studio-wrapper.d.ts +57 -0
  36. package/dist-client/label-studio-wrapper.js +304 -0
  37. package/dist-client/label-studio-wrapper.js.map +1 -0
  38. package/dist-client/route.d.ts +1 -0
  39. package/dist-client/route.js +14 -0
  40. package/dist-client/route.js.map +1 -0
  41. package/dist-client/tsconfig.tsbuildinfo +1 -0
  42. package/dist-server/controller/label-studio-role-mapper.d.ts +35 -0
  43. package/dist-server/controller/label-studio-role-mapper.js +65 -0
  44. package/dist-server/controller/label-studio-role-mapper.js.map +1 -0
  45. package/dist-server/controller/user-provisioning-service.d.ts +66 -0
  46. package/dist-server/controller/user-provisioning-service.js +264 -0
  47. package/dist-server/controller/user-provisioning-service.js.map +1 -0
  48. package/dist-server/index.d.ts +7 -0
  49. package/dist-server/index.js +19 -0
  50. package/dist-server/index.js.map +1 -0
  51. package/dist-server/route/label-studio-sso.d.ts +2 -0
  52. package/dist-server/route/label-studio-sso.js +156 -0
  53. package/dist-server/route/label-studio-sso.js.map +1 -0
  54. package/dist-server/route/webhook.d.ts +65 -0
  55. package/dist-server/route/webhook.js +248 -0
  56. package/dist-server/route/webhook.js.map +1 -0
  57. package/dist-server/route.d.ts +1 -0
  58. package/dist-server/route.js +21 -0
  59. package/dist-server/route.js.map +1 -0
  60. package/dist-server/service/ai-prediction-service.d.ts +27 -0
  61. package/dist-server/service/ai-prediction-service.js +222 -0
  62. package/dist-server/service/ai-prediction-service.js.map +1 -0
  63. package/dist-server/service/dataset-labeling-integration.d.ts +44 -0
  64. package/dist-server/service/dataset-labeling-integration.js +512 -0
  65. package/dist-server/service/dataset-labeling-integration.js.map +1 -0
  66. package/dist-server/service/external-data-source-service.d.ts +78 -0
  67. package/dist-server/service/external-data-source-service.js +415 -0
  68. package/dist-server/service/external-data-source-service.js.map +1 -0
  69. package/dist-server/service/index.d.ts +12 -0
  70. package/dist-server/service/index.js +27 -0
  71. package/dist-server/service/index.js.map +1 -0
  72. package/dist-server/service/label-studio-sso-service.d.ts +38 -0
  73. package/dist-server/service/label-studio-sso-service.js +98 -0
  74. package/dist-server/service/label-studio-sso-service.js.map +1 -0
  75. package/dist-server/service/ml/ml-backend-service.d.ts +23 -0
  76. package/dist-server/service/ml/ml-backend-service.js +153 -0
  77. package/dist-server/service/ml/ml-backend-service.js.map +1 -0
  78. package/dist-server/service/prediction/prediction-management.d.ts +32 -0
  79. package/dist-server/service/prediction/prediction-management.js +299 -0
  80. package/dist-server/service/prediction/prediction-management.js.map +1 -0
  81. package/dist-server/service/project/project-management.d.ts +36 -0
  82. package/dist-server/service/project/project-management.js +309 -0
  83. package/dist-server/service/project/project-management.js.map +1 -0
  84. package/dist-server/service/task/task-management.d.ts +42 -0
  85. package/dist-server/service/task/task-management.js +372 -0
  86. package/dist-server/service/task/task-management.js.map +1 -0
  87. package/dist-server/service/user-provisioning/user-sync-mutation.d.ts +28 -0
  88. package/dist-server/service/user-provisioning/user-sync-mutation.js +111 -0
  89. package/dist-server/service/user-provisioning/user-sync-mutation.js.map +1 -0
  90. package/dist-server/service/webhook/webhook-management.d.ts +21 -0
  91. package/dist-server/service/webhook/webhook-management.js +134 -0
  92. package/dist-server/service/webhook/webhook-management.js.map +1 -0
  93. package/dist-server/tsconfig.tsbuildinfo +1 -0
  94. package/dist-server/types/dataset-labeling-types.d.ts +71 -0
  95. package/dist-server/types/dataset-labeling-types.js +259 -0
  96. package/dist-server/types/dataset-labeling-types.js.map +1 -0
  97. package/dist-server/types/label-studio-types.d.ts +128 -0
  98. package/dist-server/types/label-studio-types.js +494 -0
  99. package/dist-server/types/label-studio-types.js.map +1 -0
  100. package/dist-server/types/prediction-types.d.ts +39 -0
  101. package/dist-server/types/prediction-types.js +121 -0
  102. package/dist-server/types/prediction-types.js.map +1 -0
  103. package/dist-server/utils/annotation-exporter.d.ts +104 -0
  104. package/dist-server/utils/annotation-exporter.js +261 -0
  105. package/dist-server/utils/annotation-exporter.js.map +1 -0
  106. package/dist-server/utils/label-config-builder.d.ts +117 -0
  107. package/dist-server/utils/label-config-builder.js +286 -0
  108. package/dist-server/utils/label-config-builder.js.map +1 -0
  109. package/dist-server/utils/label-studio-api-client.d.ts +180 -0
  110. package/dist-server/utils/label-studio-api-client.js +401 -0
  111. package/dist-server/utils/label-studio-api-client.js.map +1 -0
  112. package/dist-server/utils/media-url-extractor.d.ts +45 -0
  113. package/dist-server/utils/media-url-extractor.js +152 -0
  114. package/dist-server/utils/media-url-extractor.js.map +1 -0
  115. package/dist-server/utils/task-transformer.d.ts +108 -0
  116. package/dist-server/utils/task-transformer.js +260 -0
  117. package/dist-server/utils/task-transformer.js.map +1 -0
  118. package/package.json +47 -0
  119. package/server/SERVER_STRUCTURE.md +351 -0
  120. package/server/controller/label-studio-role-mapper.ts +76 -0
  121. package/server/controller/user-provisioning-service.ts +340 -0
  122. package/server/index.ts +19 -0
  123. package/server/route/label-studio-sso.ts +194 -0
  124. package/server/route/webhook.ts +304 -0
  125. package/server/route.ts +35 -0
  126. package/server/service/ai-prediction-service.ts +239 -0
  127. package/server/service/dataset-labeling-integration.ts +590 -0
  128. package/server/service/external-data-source-service.ts +438 -0
  129. package/server/service/index.ts +24 -0
  130. package/server/service/label-studio-sso-service.ts +108 -0
  131. package/server/service/labeling-scenario-service.ts.deprecated +566 -0
  132. package/server/service/ml/ml-backend-service.ts +127 -0
  133. package/server/service/prediction/prediction-management.ts +281 -0
  134. package/server/service/project/project-management.ts +284 -0
  135. package/server/service/task/task-management.ts +363 -0
  136. package/server/service/user-provisioning/user-sync-mutation.ts +80 -0
  137. package/server/service/webhook/webhook-management.ts +109 -0
  138. package/server/tsconfig.json +11 -0
  139. package/server/types/dataset-labeling-types.ts +181 -0
  140. package/server/types/global.d.ts +23 -0
  141. package/server/types/label-studio-types.ts +346 -0
  142. package/server/types/prediction-types.ts +86 -0
  143. package/server/types/scenario-types.ts.deprecated +362 -0
  144. package/server/utils/annotation-exporter.ts +340 -0
  145. package/server/utils/label-config-builder.ts +340 -0
  146. package/server/utils/label-studio-api-client.ts +487 -0
  147. package/server/utils/media-url-extractor.ts +193 -0
  148. package/server/utils/task-transformer.ts +342 -0
  149. package/test-ai-prediction.js +268 -0
  150. package/test-dataset-integration.js +449 -0
  151. package/test-simple.js +89 -0
  152. package/things-factory.config.js +12 -0
@@ -0,0 +1,181 @@
1
+ import { Field, InputType, ObjectType, Int, Float } from 'type-graphql'
2
+
3
+ /**
4
+ * Dataset Labeling Integration Types
5
+ *
6
+ * Types for integrating DataSample with Label Studio tasks and AI predictions
7
+ */
8
+
9
+ @InputType({ description: 'Request to create Label Studio tasks from DataSamples' })
10
+ export class CreateLabelingTasksRequest {
11
+ @Field(type => Int, { description: 'Label Studio project ID' })
12
+ projectId: number
13
+
14
+ @Field({ description: 'DataSet ID to sync' })
15
+ dataSetId: string
16
+
17
+ @Field({ nullable: true, description: 'Image field name in DataSample.data or DataSample.rawData' })
18
+ imageField?: string
19
+
20
+ @Field({ nullable: true, defaultValue: true, description: 'Auto-generate AI predictions for created tasks' })
21
+ autoGeneratePredictions?: boolean
22
+
23
+ @Field(type => Float, { nullable: true, description: 'Confidence threshold for AI predictions' })
24
+ confidenceThreshold?: number
25
+
26
+ @Field({ nullable: true, description: 'AI model ID to use for predictions' })
27
+ modelId?: string
28
+
29
+ @Field({ nullable: true, description: 'Only create tasks for samples after this date' })
30
+ sinceDate?: Date
31
+
32
+ @Field({ nullable: true, description: 'Maximum number of tasks to create' })
33
+ limit?: number
34
+ }
35
+
36
+ @ObjectType({ description: 'Result of task creation from dataset' })
37
+ export class TaskCreationResult {
38
+ @Field(type => Int, { description: 'Total DataSamples processed' })
39
+ totalSamples: number
40
+
41
+ @Field(type => Int, { description: 'Number of tasks successfully created' })
42
+ tasksCreated: number
43
+
44
+ @Field(type => Int, { description: 'Number of tasks that failed to create' })
45
+ tasksFailed: number
46
+
47
+ @Field(type => Int, { description: 'Number of samples skipped (no image, already exists, etc.)' })
48
+ tasksSkipped: number
49
+
50
+ @Field(type => [Int], { description: 'Array of created Label Studio task IDs' })
51
+ taskIds: number[]
52
+
53
+ @Field(type => Int, { nullable: true, description: 'Number of AI predictions generated' })
54
+ predictionsCreated?: number
55
+
56
+ @Field({ nullable: true, description: 'Error message if operation partially failed' })
57
+ error?: string
58
+ }
59
+
60
+ @InputType({ description: 'Request to sync Label Studio annotations back to DataSamples' })
61
+ export class SyncAnnotationsRequest {
62
+ @Field(type => Int, { description: 'Label Studio project ID' })
63
+ projectId: number
64
+
65
+ @Field({ description: 'DataSet ID to sync annotations to' })
66
+ dataSetId: string
67
+
68
+ @Field({ nullable: true, defaultValue: false, description: 'Only sync completed annotations' })
69
+ completedOnly?: boolean
70
+
71
+ @Field({ nullable: true, description: 'Only sync annotations updated after this date' })
72
+ sinceDate?: Date
73
+ }
74
+
75
+ @ObjectType({ description: 'Result of syncing annotations to dataset' })
76
+ export class SyncAnnotationsResult {
77
+ @Field(type => Int, { description: 'Total annotations processed' })
78
+ totalAnnotations: number
79
+
80
+ @Field(type => Int, { description: 'Number of DataSamples successfully updated' })
81
+ samplesUpdated: number
82
+
83
+ @Field(type => Int, { description: 'Number of updates that failed' })
84
+ updatesFailed: number
85
+
86
+ @Field(type => Int, { description: 'Number of annotations skipped' })
87
+ skipped: number
88
+
89
+ @Field({ nullable: true, description: 'Error message if operation partially failed' })
90
+ error?: string
91
+ }
92
+
93
+ @ObjectType({ description: 'Labeling status for a dataset' })
94
+ export class DatasetLabelingStatus {
95
+ @Field({ description: 'DataSet ID' })
96
+ dataSetId: string
97
+
98
+ @Field({ description: 'DataSet name' })
99
+ dataSetName: string
100
+
101
+ @Field(type => Int, { description: 'Total number of DataSamples in the dataset' })
102
+ totalSamples: number
103
+
104
+ @Field(type => Int, { description: 'Number of samples with Label Studio tasks' })
105
+ tasksCreated: number
106
+
107
+ @Field(type => Int, { description: 'Number of samples with AI predictions' })
108
+ withPredictions: number
109
+
110
+ @Field(type => Int, { description: 'Number of samples with human annotations' })
111
+ withAnnotations: number
112
+
113
+ @Field(type => Int, { description: 'Number of samples with completed annotations' })
114
+ annotationsCompleted: number
115
+
116
+ @Field(type => Int, { description: 'Number of samples not yet processed' })
117
+ notProcessed: number
118
+
119
+ @Field(type => Float, { description: 'Labeling completion rate (0-1)' })
120
+ completionRate: number
121
+
122
+ @Field({ nullable: true, description: 'Associated Label Studio project ID' })
123
+ projectId?: number
124
+
125
+ @Field({ nullable: true, description: 'Last sync timestamp' })
126
+ lastSyncedAt?: Date
127
+ }
128
+
129
+ @ObjectType({ description: 'Mapping between DataSample and Label Studio task' })
130
+ export class DataSampleTaskMapping {
131
+ @Field({ description: 'DataSample ID' })
132
+ dataSampleId: string
133
+
134
+ @Field({ description: 'DataSample name' })
135
+ dataSampleName: string
136
+
137
+ @Field(type => Int, { description: 'Label Studio task ID' })
138
+ taskId: number
139
+
140
+ @Field({ nullable: true, description: 'Image URL used in the task' })
141
+ imageUrl?: string
142
+
143
+ @Field({ nullable: true, description: 'Task creation timestamp' })
144
+ createdAt?: Date
145
+
146
+ @Field({ nullable: true, description: 'Whether task has AI prediction' })
147
+ hasPrediction?: boolean
148
+
149
+ @Field({ nullable: true, description: 'Whether task has human annotation' })
150
+ hasAnnotation?: boolean
151
+
152
+ @Field({ nullable: true, description: 'Whether annotation is completed' })
153
+ isCompleted?: boolean
154
+ }
155
+
156
+ @InputType({ description: 'Request to query dataset labeling status' })
157
+ export class DatasetLabelingStatusRequest {
158
+ @Field({ description: 'DataSet ID' })
159
+ dataSetId: string
160
+
161
+ @Field(type => Int, { nullable: true, description: 'Associated Label Studio project ID' })
162
+ projectId?: number
163
+ }
164
+
165
+ @InputType({ description: 'Request to generate predictions for existing tasks' })
166
+ export class GeneratePredictionsForDatasetRequest {
167
+ @Field({ description: 'DataSet ID' })
168
+ dataSetId: string
169
+
170
+ @Field(type => Int, { description: 'Label Studio project ID' })
171
+ projectId: number
172
+
173
+ @Field({ nullable: true, description: 'AI model ID to use' })
174
+ modelId?: string
175
+
176
+ @Field(type => Float, { nullable: true, description: 'Confidence threshold' })
177
+ confidenceThreshold?: number
178
+
179
+ @Field({ nullable: true, defaultValue: false, description: 'Regenerate predictions even if they already exist' })
180
+ forceRegenerate?: boolean
181
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Global type definitions for Things-Factory integration
3
+ */
4
+
5
+ import { Domain } from '@things-factory/shell'
6
+ import { User } from '@things-factory/auth-base'
7
+
8
+ declare global {
9
+ /**
10
+ * GraphQL Resolver Context
11
+ * Available in all @Ctx() decorated parameters
12
+ */
13
+ interface ResolverContext {
14
+ state: {
15
+ domain: Domain
16
+ user: User
17
+ [key: string]: any
18
+ }
19
+ [key: string]: any
20
+ }
21
+ }
22
+
23
+ export {}
@@ -0,0 +1,346 @@
1
+ import { Field, ObjectType, InputType, Int, Float } from 'type-graphql'
2
+
3
+ // ============================================================================
4
+ // Project Types
5
+ // ============================================================================
6
+
7
+ @ObjectType({ description: 'Label Studio project information' })
8
+ export class LabelStudioProject {
9
+ @Field(type => Int, { description: 'Project ID' })
10
+ id: number
11
+
12
+ @Field({ description: 'Project title' })
13
+ title: string
14
+
15
+ @Field({ nullable: true, description: 'Project description' })
16
+ description?: string
17
+
18
+ @Field({ description: 'Label configuration XML' })
19
+ labelConfig: string
20
+
21
+ @Field({ nullable: true, description: 'Expert instruction' })
22
+ expertInstruction?: string
23
+
24
+ @Field(type => Int, { description: 'Number of tasks' })
25
+ taskCount: number
26
+
27
+ @Field(type => Int, { description: 'Number of completed tasks' })
28
+ completedTaskCount: number
29
+
30
+ @Field(type => Float, { description: 'Completion rate (0-1)' })
31
+ completionRate: number
32
+
33
+ @Field({ nullable: true, description: 'Created date' })
34
+ createdAt: Date
35
+
36
+ @Field({ nullable: true, description: 'Updated date' })
37
+ updatedAt: Date
38
+ }
39
+
40
+ @InputType({ description: 'Input for creating Label Studio project' })
41
+ export class CreateProjectInput {
42
+ @Field({ description: 'Project title' })
43
+ title: string
44
+
45
+ @Field({ nullable: true, description: 'Project description' })
46
+ description?: string
47
+
48
+ @Field({ description: 'Label configuration XML' })
49
+ labelConfig: string
50
+
51
+ @Field({ nullable: true, description: 'Expert instruction' })
52
+ expertInstruction?: string
53
+ }
54
+
55
+ @InputType({ description: 'Label config specification for flexible project creation' })
56
+ export class LabelConfigSpecInput {
57
+ @Field({ description: 'Data type (image, text, audio, video, timeseries, html, hypertext)' })
58
+ dataType: string
59
+
60
+ @Field({ nullable: true, description: 'Data name (default: data)' })
61
+ dataName?: string
62
+
63
+ @Field({ description: 'Control specifications as JSON array' })
64
+ controls: string
65
+ }
66
+
67
+ @InputType({ description: 'Input for creating project with flexible config builder' })
68
+ export class CreateProjectWithSpecInput {
69
+ @Field({ description: 'Project title' })
70
+ title: string
71
+
72
+ @Field({ nullable: true, description: 'Project description' })
73
+ description?: string
74
+
75
+ @Field({ description: 'Label config specification' })
76
+ labelConfigSpec: LabelConfigSpecInput
77
+
78
+ @Field({ nullable: true, description: 'Expert instruction' })
79
+ expertInstruction?: string
80
+ }
81
+
82
+ @InputType({ description: 'Export annotations input' })
83
+ export class ExportAnnotationsInput {
84
+ @Field({ description: 'Export format (json, jsonl, csv, rank-csv, coco, yolo, ner-json)' })
85
+ format: string
86
+
87
+ @Field({ nullable: true, description: 'Filter by task IDs' })
88
+ taskIds?: string
89
+ }
90
+
91
+ @ObjectType({ description: 'Annotation export result' })
92
+ export class AnnotationExportResult {
93
+ @Field({ description: 'Exported data as JSON string' })
94
+ data: string
95
+
96
+ @Field(type => Int, { description: 'Number of annotations exported' })
97
+ count: number
98
+
99
+ @Field({ description: 'Export format used' })
100
+ format: string
101
+ }
102
+
103
+ // ============================================================================
104
+ // Task Types
105
+ // ============================================================================
106
+
107
+ @ObjectType({ description: 'Label Studio task' })
108
+ export class LabelStudioTask {
109
+ @Field(type => Int, { description: 'Task ID' })
110
+ id: number
111
+
112
+ @Field({ description: 'Task data (JSON)' })
113
+ data: string
114
+
115
+ @Field(type => Int, { description: 'Number of annotations' })
116
+ annotationCount: number
117
+
118
+ @Field({ description: 'Is task completed' })
119
+ isCompleted: boolean
120
+
121
+ @Field({ nullable: true, description: 'Task created date' })
122
+ createdAt?: Date
123
+ }
124
+
125
+ @InputType({ description: 'Input for creating tasks' })
126
+ export class TaskDataInput {
127
+ @Field({ description: 'Task data as JSON string' })
128
+ data: string
129
+ }
130
+
131
+ @InputType({ description: 'Task transformation rule for flexible data import' })
132
+ export class TaskTransformRuleInput {
133
+ @Field({ description: 'Field mapping as JSON (Label Studio field -> source path)' })
134
+ dataFields: string
135
+
136
+ @Field({ nullable: true, description: 'Prediction configuration as JSON' })
137
+ predictions?: string
138
+
139
+ @Field({ nullable: true, description: 'Metadata mapping as JSON' })
140
+ meta?: string
141
+ }
142
+
143
+ @InputType({ description: 'Input for importing tasks with transformation' })
144
+ export class ImportTasksWithTransformInput {
145
+ @Field({ description: 'Source data as JSON array string' })
146
+ sourceData: string
147
+
148
+ @Field({ description: 'Transformation rule' })
149
+ transformRule: TaskTransformRuleInput
150
+ }
151
+
152
+ @ObjectType({ description: 'Result of task import operation' })
153
+ export class TaskImportResult {
154
+ @Field(type => Int, { description: 'Number of tasks imported' })
155
+ imported: number
156
+
157
+ @Field(type => Int, { description: 'Number of tasks failed' })
158
+ failed: number
159
+
160
+ @Field(type => [Int], { description: 'IDs of imported tasks' })
161
+ taskIds: number[]
162
+
163
+ @Field(type => [String], { nullable: true, description: 'Error messages' })
164
+ errors?: string[]
165
+ }
166
+
167
+ // ============================================================================
168
+ // Annotation Types
169
+ // ============================================================================
170
+
171
+ @ObjectType({ description: 'Label Studio annotation' })
172
+ export class LabelStudioAnnotation {
173
+ @Field(type => Int, { description: 'Annotation ID' })
174
+ id: number
175
+
176
+ @Field(type => Int, { description: 'Task ID' })
177
+ taskId: number
178
+
179
+ @Field({ description: 'Annotation result (JSON)' })
180
+ result: string
181
+
182
+ @Field({ description: 'Completed by user email' })
183
+ completedBy: string
184
+
185
+ @Field({ description: 'Created date' })
186
+ createdAt: Date
187
+
188
+ @Field({ nullable: true, description: 'Lead time in seconds' })
189
+ leadTime?: number
190
+ }
191
+
192
+ // ============================================================================
193
+ // Prediction Types
194
+ // ============================================================================
195
+
196
+ @ObjectType({ description: 'Label Studio prediction (AI pre-annotation)' })
197
+ export class LabelStudioPrediction {
198
+ @Field(type => Int, { description: 'Prediction ID' })
199
+ id: number
200
+
201
+ @Field(type => Int, { description: 'Task ID' })
202
+ taskId: number
203
+
204
+ @Field({ description: 'Prediction result (JSON)' })
205
+ result: string
206
+
207
+ @Field(type => Float, { nullable: true, description: 'Prediction confidence score (0-1)' })
208
+ score?: number
209
+
210
+ @Field({ nullable: true, description: 'Model version that generated this prediction' })
211
+ modelVersion?: string
212
+
213
+ @Field({ nullable: true, description: 'Created date' })
214
+ createdAt?: Date
215
+ }
216
+
217
+ @InputType({ description: 'Input for creating a prediction' })
218
+ export class PredictionInput {
219
+ @Field(type => Int, { description: 'Task ID to create prediction for' })
220
+ taskId: number
221
+
222
+ @Field({ description: 'Prediction result as JSON string' })
223
+ result: string
224
+
225
+ @Field(type => Float, { nullable: true, description: 'Prediction confidence score (0-1)' })
226
+ score?: number
227
+
228
+ @Field({ nullable: true, description: 'Model version' })
229
+ modelVersion?: string
230
+ }
231
+
232
+ @InputType({ description: 'Input for bulk prediction creation' })
233
+ export class BulkPredictionInput {
234
+ @Field(type => Int, { description: 'Task ID' })
235
+ taskId: number
236
+
237
+ @Field({ description: 'Prediction result as JSON string' })
238
+ result: string
239
+
240
+ @Field(type => Float, { nullable: true, description: 'Prediction confidence score (0-1)' })
241
+ score?: number
242
+
243
+ @Field({ nullable: true, description: 'Model version' })
244
+ modelVersion?: string
245
+ }
246
+
247
+ @ObjectType({ description: 'Result of prediction import operation' })
248
+ export class PredictionImportResult {
249
+ @Field(type => Int, { description: 'Number of predictions created' })
250
+ created: number
251
+
252
+ @Field(type => Int, { description: 'Number of predictions failed' })
253
+ failed: number
254
+
255
+ @Field(type => [String], { nullable: true, description: 'Error messages' })
256
+ errors?: string[]
257
+ }
258
+
259
+ @ObjectType({ description: 'Export result' })
260
+ export class ExportResult {
261
+ @Field({ description: 'Export file path or URL' })
262
+ exportPath: string
263
+
264
+ @Field(type => Int, { description: 'Number of annotations exported' })
265
+ annotationCount: number
266
+
267
+ @Field({ description: 'Export format (JSON, CSV, YOLO, etc.)' })
268
+ format: string
269
+ }
270
+
271
+ // ============================================================================
272
+ // Analytics Types
273
+ // ============================================================================
274
+
275
+ @ObjectType({ description: 'Project metrics and statistics' })
276
+ export class ProjectMetrics {
277
+ @Field(type => Int, { description: 'Total number of tasks' })
278
+ totalTasks: number
279
+
280
+ @Field(type => Int, { description: 'Number of completed tasks' })
281
+ completedTasks: number
282
+
283
+ @Field(type => Int, { description: 'Total annotations' })
284
+ totalAnnotations: number
285
+
286
+ @Field(type => Float, { description: 'Average annotations per task' })
287
+ avgAnnotationsPerTask: number
288
+
289
+ @Field(type => Float, { description: 'Completion rate (0-1)' })
290
+ completionRate: number
291
+
292
+ @Field(type => Float, { nullable: true, description: 'Average time per task in seconds' })
293
+ avgTimePerTask?: number
294
+
295
+ @Field(type => [AnnotatorStats], { description: 'Statistics per annotator' })
296
+ annotatorStats: AnnotatorStats[]
297
+ }
298
+
299
+ @ObjectType({ description: 'Annotator statistics' })
300
+ export class AnnotatorStats {
301
+ @Field({ description: 'User email' })
302
+ email: string
303
+
304
+ @Field(type => Int, { description: 'Number of annotations' })
305
+ annotationCount: number
306
+
307
+ @Field(type => Float, { description: 'Average time per annotation in seconds' })
308
+ avgTime: number
309
+
310
+ @Field({ description: 'Last annotation date' })
311
+ lastAnnotationDate: Date
312
+ }
313
+
314
+ // ============================================================================
315
+ // ML Backend Types
316
+ // ============================================================================
317
+
318
+ @ObjectType({ description: 'ML Backend information' })
319
+ export class MLBackend {
320
+ @Field(type => Int, { description: 'ML Backend ID' })
321
+ id: number
322
+
323
+ @Field({ description: 'ML Backend URL' })
324
+ url: string
325
+
326
+ @Field({ description: 'ML Backend title' })
327
+ title: string
328
+
329
+ @Field({ description: 'Is interactive preannotation enabled' })
330
+ isInteractive: boolean
331
+
332
+ @Field({ description: 'Model version' })
333
+ modelVersion: string
334
+ }
335
+
336
+ @InputType({ description: 'Input for adding ML Backend' })
337
+ export class AddMLBackendInput {
338
+ @Field({ description: 'ML Backend URL' })
339
+ url: string
340
+
341
+ @Field({ description: 'ML Backend title' })
342
+ title: string
343
+
344
+ @Field({ nullable: true, description: 'Is interactive preannotation enabled' })
345
+ isInteractive?: boolean
346
+ }
@@ -0,0 +1,86 @@
1
+ import { Field, ObjectType, InputType, Int, Float } from 'type-graphql'
2
+
3
+ // ============================================================================
4
+ // Label Studio Prediction Generation Types
5
+ // ============================================================================
6
+
7
+ /**
8
+ * Label Studio prediction generation request
9
+ */
10
+ @InputType({ description: 'Request to generate Label Studio predictions' })
11
+ export class GeneratePredictionRequest {
12
+ @Field(type => Int, { description: 'Label Studio task ID' })
13
+ taskId: number
14
+
15
+ @Field({ description: 'Image URL from task data' })
16
+ imageUrl: string
17
+
18
+ @Field({ nullable: true, description: 'AI model ID to use' })
19
+ modelId?: string
20
+
21
+ @Field(type => Float, { nullable: true, description: 'Confidence threshold (0-1)' })
22
+ confidenceThreshold?: number
23
+ }
24
+
25
+ /**
26
+ * Batch prediction generation request
27
+ */
28
+ @InputType({ description: 'Request to generate predictions for multiple tasks' })
29
+ export class BatchGeneratePredictionRequest {
30
+ @Field(type => Int, { description: 'Label Studio project ID' })
31
+ projectId: number
32
+
33
+ @Field(type => [Int], { description: 'Array of task IDs' })
34
+ taskIds: number[]
35
+
36
+ @Field({ nullable: true, description: 'AI model ID to use' })
37
+ modelId?: string
38
+
39
+ @Field(type => Float, { nullable: true, description: 'Confidence threshold (0-1)' })
40
+ confidenceThreshold?: number
41
+ }
42
+
43
+ /**
44
+ * Prediction generation result
45
+ */
46
+ @ObjectType({ description: 'Prediction generation result' })
47
+ export class PredictionGenerationResult {
48
+ @Field(type => Int, { description: 'Task ID' })
49
+ taskId: number
50
+
51
+ @Field(type => Int, { nullable: true, description: 'Created prediction ID' })
52
+ predictionId?: number
53
+
54
+ @Field({ description: 'Success status' })
55
+ success: boolean
56
+
57
+ @Field({ nullable: true, description: 'Error message if failed' })
58
+ error?: string
59
+
60
+ @Field(type => Int, { description: 'Number of detected objects' })
61
+ objectCount: number
62
+
63
+ @Field(type => Float, { nullable: true, description: 'Average confidence score' })
64
+ avgConfidence?: number
65
+ }
66
+
67
+ /**
68
+ * Batch prediction generation result
69
+ */
70
+ @ObjectType({ description: 'Batch prediction generation result' })
71
+ export class BatchPredictionResult {
72
+ @Field(type => Int, { description: 'Total tasks processed' })
73
+ total: number
74
+
75
+ @Field(type => Int, { description: 'Number of successful predictions' })
76
+ succeeded: number
77
+
78
+ @Field(type => Int, { description: 'Number of failed predictions' })
79
+ failed: number
80
+
81
+ @Field(type => [PredictionGenerationResult], { description: 'Individual results' })
82
+ results: PredictionGenerationResult[]
83
+
84
+ @Field({ description: 'Model version used' })
85
+ modelVersion: string
86
+ }