@things-factory/integration-label-studio 9.1.19 → 10.0.0-beta.1
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.
- package/dist-client/tsconfig.tsbuildinfo +1 -1
- package/dist-server/tsconfig.tsbuildinfo +1 -1
- package/package.json +10 -10
- package/client/tsconfig.json +0 -13
- package/server/SERVER_STRUCTURE.md +0 -351
- package/server/controller/label-studio-role-mapper.ts +0 -76
- package/server/controller/user-provisioning-service.ts +0 -340
- package/server/index.ts +0 -19
- package/server/route/label-studio-sso.ts +0 -194
- package/server/route/webhook.ts +0 -304
- package/server/route.ts +0 -35
- package/server/service/ai-prediction-service.ts +0 -239
- package/server/service/dataset-labeling-integration.ts +0 -590
- package/server/service/external-data-source-service.ts +0 -438
- package/server/service/index.ts +0 -24
- package/server/service/label-studio-sso-service.ts +0 -108
- package/server/service/labeling-scenario-service.ts.deprecated +0 -566
- package/server/service/ml/ml-backend-service.ts +0 -127
- package/server/service/prediction/prediction-management.ts +0 -281
- package/server/service/project/project-management.ts +0 -284
- package/server/service/task/task-management.ts +0 -363
- package/server/service/user-provisioning/user-sync-mutation.ts +0 -80
- package/server/service/webhook/webhook-management.ts +0 -109
- package/server/tsconfig.json +0 -11
- package/server/types/dataset-labeling-types.ts +0 -181
- package/server/types/global.d.ts +0 -23
- package/server/types/label-studio-types.ts +0 -346
- package/server/types/prediction-types.ts +0 -86
- package/server/types/scenario-types.ts.deprecated +0 -362
- package/server/utils/annotation-exporter.ts +0 -340
- package/server/utils/label-config-builder.ts +0 -340
- package/server/utils/label-studio-api-client.ts +0 -487
- package/server/utils/media-url-extractor.ts +0 -193
- package/server/utils/task-transformer.ts +0 -342
|
@@ -1,342 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Task Transformer
|
|
3
|
-
*
|
|
4
|
-
* Flexible data transformation from any source format to Label Studio tasks.
|
|
5
|
-
* Supports nested data, predictions, and custom field mapping.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
export interface TaskTransformRule {
|
|
9
|
-
/**
|
|
10
|
-
* Field mapping: Label Studio field name -> source data path
|
|
11
|
-
* Example: { "image": "image_url", "date": "metadata.timestamp" }
|
|
12
|
-
*/
|
|
13
|
-
dataFields: { [lsField: string]: string }
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Prediction configuration (optional)
|
|
17
|
-
*/
|
|
18
|
-
predictions?: PredictionConfig
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Metadata to attach to task (optional)
|
|
22
|
-
*/
|
|
23
|
-
meta?: { [key: string]: string }
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export interface PredictionConfig {
|
|
27
|
-
/**
|
|
28
|
-
* Enable predictions
|
|
29
|
-
*/
|
|
30
|
-
enabled: boolean
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Path to prediction result in source data
|
|
34
|
-
*/
|
|
35
|
-
resultPath: string
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Path to confidence score (optional)
|
|
39
|
-
*/
|
|
40
|
-
scorePath?: string
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Model version identifier (optional)
|
|
44
|
-
*/
|
|
45
|
-
modelVersion?: string
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Transform function for prediction result
|
|
49
|
-
*/
|
|
50
|
-
resultTransform?: (result: any) => any
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
export interface LabelStudioTask {
|
|
54
|
-
data: string // JSON string
|
|
55
|
-
predictions?: Array<{
|
|
56
|
-
result: any
|
|
57
|
-
score?: number
|
|
58
|
-
model_version?: string
|
|
59
|
-
}>
|
|
60
|
-
meta?: any
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
export class TaskTransformer {
|
|
64
|
-
/**
|
|
65
|
-
* Transform source data to Label Studio tasks
|
|
66
|
-
*
|
|
67
|
-
* @param sourceData - Array of source data objects
|
|
68
|
-
* @param rule - Transformation rules
|
|
69
|
-
* @returns Array of Label Studio tasks
|
|
70
|
-
*/
|
|
71
|
-
static transform(sourceData: any[], rule: TaskTransformRule): LabelStudioTask[] {
|
|
72
|
-
return sourceData.map(data => this.transformOne(data, rule)).filter(task => task !== null) as LabelStudioTask[]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Transform a single data object
|
|
77
|
-
*/
|
|
78
|
-
static transformOne(sourceData: any, rule: TaskTransformRule): LabelStudioTask | null {
|
|
79
|
-
try {
|
|
80
|
-
// Build task data
|
|
81
|
-
const taskData: any = {}
|
|
82
|
-
for (const [lsField, sourcePath] of Object.entries(rule.dataFields)) {
|
|
83
|
-
const value = this.getNestedValue(sourceData, sourcePath)
|
|
84
|
-
if (value !== undefined) {
|
|
85
|
-
taskData[lsField] = value
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Skip if no data extracted
|
|
90
|
-
if (Object.keys(taskData).length === 0) {
|
|
91
|
-
return null
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const task: LabelStudioTask = {
|
|
95
|
-
data: JSON.stringify(taskData)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// Add predictions if configured
|
|
99
|
-
if (rule.predictions?.enabled) {
|
|
100
|
-
const prediction = this.buildPrediction(sourceData, rule.predictions)
|
|
101
|
-
if (prediction) {
|
|
102
|
-
task.predictions = [prediction]
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
// Add metadata if configured
|
|
107
|
-
if (rule.meta) {
|
|
108
|
-
const meta: any = {}
|
|
109
|
-
for (const [metaKey, sourcePath] of Object.entries(rule.meta)) {
|
|
110
|
-
const value = this.getNestedValue(sourceData, sourcePath)
|
|
111
|
-
if (value !== undefined) {
|
|
112
|
-
meta[metaKey] = value
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
if (Object.keys(meta).length > 0) {
|
|
116
|
-
task.meta = meta
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
return task
|
|
121
|
-
} catch (error) {
|
|
122
|
-
console.error('Failed to transform task:', error)
|
|
123
|
-
return null
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Build prediction object from source data
|
|
129
|
-
*/
|
|
130
|
-
private static buildPrediction(
|
|
131
|
-
sourceData: any,
|
|
132
|
-
config: PredictionConfig
|
|
133
|
-
): { result: any; score?: number; model_version?: string } | null {
|
|
134
|
-
const result = this.getNestedValue(sourceData, config.resultPath)
|
|
135
|
-
if (!result) {
|
|
136
|
-
return null
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const prediction: any = {
|
|
140
|
-
result: config.resultTransform ? config.resultTransform(result) : result
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
if (config.scorePath) {
|
|
144
|
-
const score = this.getNestedValue(sourceData, config.scorePath)
|
|
145
|
-
if (score !== undefined) {
|
|
146
|
-
prediction.score = score
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (config.modelVersion) {
|
|
151
|
-
prediction.model_version = config.modelVersion
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
return prediction
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Get nested value from object using dot notation path
|
|
159
|
-
* Example: "metadata.user.name" -> obj.metadata.user.name
|
|
160
|
-
*/
|
|
161
|
-
private static getNestedValue(obj: any, path: string): any {
|
|
162
|
-
if (!path || !obj) return undefined
|
|
163
|
-
|
|
164
|
-
const keys = path.split('.')
|
|
165
|
-
let current = obj
|
|
166
|
-
|
|
167
|
-
for (const key of keys) {
|
|
168
|
-
if (current === null || current === undefined) {
|
|
169
|
-
return undefined
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Support array indexing: "items[0].name"
|
|
173
|
-
const arrayMatch = key.match(/^(\w+)\[(\d+)\]$/)
|
|
174
|
-
if (arrayMatch) {
|
|
175
|
-
const [, arrayKey, index] = arrayMatch
|
|
176
|
-
current = current[arrayKey]?.[parseInt(index, 10)]
|
|
177
|
-
} else {
|
|
178
|
-
current = current[key]
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return current
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Transform with multiple rules (useful for heterogeneous data)
|
|
187
|
-
*/
|
|
188
|
-
static transformMultiRule(sourceData: any[], rules: TaskTransformRule[]): LabelStudioTask[] {
|
|
189
|
-
const tasks: LabelStudioTask[] = []
|
|
190
|
-
|
|
191
|
-
for (const rule of rules) {
|
|
192
|
-
tasks.push(...this.transform(sourceData, rule))
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
return tasks
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Pre-built transformation templates for common scenarios
|
|
201
|
-
*/
|
|
202
|
-
export class TaskTransformTemplates {
|
|
203
|
-
/**
|
|
204
|
-
* WBM Image Classification with AI predictions
|
|
205
|
-
*/
|
|
206
|
-
static wbmImageClassification(includeAiPrediction: boolean = true): TaskTransformRule {
|
|
207
|
-
const rule: TaskTransformRule = {
|
|
208
|
-
dataFields: {
|
|
209
|
-
image: 'image_url',
|
|
210
|
-
date: 'timestamp',
|
|
211
|
-
device_id: 'device_id'
|
|
212
|
-
},
|
|
213
|
-
meta: {
|
|
214
|
-
wafer_id: 'wafer_id',
|
|
215
|
-
lot_id: 'lot_id'
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
if (includeAiPrediction) {
|
|
220
|
-
rule.predictions = {
|
|
221
|
-
enabled: true,
|
|
222
|
-
resultPath: 'ai_prediction',
|
|
223
|
-
scorePath: 'confidence',
|
|
224
|
-
modelVersion: 'wbm-classifier-v1',
|
|
225
|
-
resultTransform: result => {
|
|
226
|
-
// Transform AI result to Label Studio format
|
|
227
|
-
return [
|
|
228
|
-
{
|
|
229
|
-
from_name: 'rank1',
|
|
230
|
-
to_name: 'data',
|
|
231
|
-
type: 'choices',
|
|
232
|
-
value: {
|
|
233
|
-
choices: [result.rank1]
|
|
234
|
-
}
|
|
235
|
-
},
|
|
236
|
-
{
|
|
237
|
-
from_name: 'rank2',
|
|
238
|
-
to_name: 'data',
|
|
239
|
-
type: 'choices',
|
|
240
|
-
value: {
|
|
241
|
-
choices: [result.rank2]
|
|
242
|
-
}
|
|
243
|
-
},
|
|
244
|
-
{
|
|
245
|
-
from_name: 'rank3',
|
|
246
|
-
to_name: 'data',
|
|
247
|
-
type: 'choices',
|
|
248
|
-
value: {
|
|
249
|
-
choices: [result.rank3]
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
]
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return rule
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Simple image classification
|
|
262
|
-
*/
|
|
263
|
-
static imageClassification(imageField: string = 'image_url'): TaskTransformRule {
|
|
264
|
-
return {
|
|
265
|
-
dataFields: {
|
|
266
|
-
image: imageField
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
/**
|
|
272
|
-
* Text classification with metadata
|
|
273
|
-
*/
|
|
274
|
-
static textClassification(textField: string = 'text', metaFields: string[] = []): TaskTransformRule {
|
|
275
|
-
const rule: TaskTransformRule = {
|
|
276
|
-
dataFields: {
|
|
277
|
-
text: textField
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
if (metaFields.length > 0) {
|
|
282
|
-
rule.meta = {}
|
|
283
|
-
for (const field of metaFields) {
|
|
284
|
-
rule.meta[field] = field
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return rule
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
/**
|
|
292
|
-
* Time series data
|
|
293
|
-
*/
|
|
294
|
-
static timeSeries(valuesField: string, timestampField?: string): TaskTransformRule {
|
|
295
|
-
const dataFields: any = {
|
|
296
|
-
timeseries: valuesField
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (timestampField) {
|
|
300
|
-
dataFields.timestamp = timestampField
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
return {
|
|
304
|
-
dataFields
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
/**
|
|
309
|
-
* Object detection with bounding box predictions
|
|
310
|
-
*/
|
|
311
|
-
static objectDetection(imageField: string = 'image_url', predictionsField?: string): TaskTransformRule {
|
|
312
|
-
const rule: TaskTransformRule = {
|
|
313
|
-
dataFields: {
|
|
314
|
-
image: imageField
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
if (predictionsField) {
|
|
319
|
-
rule.predictions = {
|
|
320
|
-
enabled: true,
|
|
321
|
-
resultPath: predictionsField,
|
|
322
|
-
resultTransform: bboxes => {
|
|
323
|
-
// Transform bounding boxes to Label Studio format
|
|
324
|
-
return bboxes.map((bbox: any) => ({
|
|
325
|
-
from_name: 'bbox',
|
|
326
|
-
to_name: 'data',
|
|
327
|
-
type: 'rectanglelabels',
|
|
328
|
-
value: {
|
|
329
|
-
x: bbox.x,
|
|
330
|
-
y: bbox.y,
|
|
331
|
-
width: bbox.width,
|
|
332
|
-
height: bbox.height,
|
|
333
|
-
rectanglelabels: [bbox.label]
|
|
334
|
-
}
|
|
335
|
-
}))
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return rule
|
|
341
|
-
}
|
|
342
|
-
}
|