@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,449 @@
1
+ /**
2
+ * Test script for Dataset-Label Studio Integration
3
+ *
4
+ * Tests:
5
+ * 1. Query existing DataSets
6
+ * 2. Query DataSamples from a DataSet
7
+ * 3. Create Label Studio tasks from DataSamples
8
+ * 4. Query labeling status
9
+ * 5. Generate AI predictions for tasks
10
+ * 6. Sync annotations back to DataSamples
11
+ */
12
+
13
+ const axios = require('axios')
14
+
15
+ // Configuration
16
+ // NOTE: With subdomain cookie-sharing approach, services run on separate subdomains
17
+ const THINGS_FACTORY_GRAPHQL = process.env.THINGS_FACTORY_GRAPHQL || 'http://dataset.localhost:3000/graphql'
18
+ const LABEL_STUDIO_URL = process.env.LABEL_STUDIO_URL || 'http://label.dataset.localhost:8080'
19
+ const LABEL_STUDIO_PROJECT_ID = process.env.LABEL_STUDIO_PROJECT_ID || 2 // Change to your project ID
20
+
21
+ async function queryDataSets() {
22
+ console.log('\nšŸ“Š Step 1: Querying DataSets...')
23
+ console.log('='.repeat(60))
24
+
25
+ try {
26
+ const query = `
27
+ query {
28
+ dataSets(params: { pagination: { page: 1, limit: 10 } }) {
29
+ items {
30
+ id
31
+ name
32
+ description
33
+ active
34
+ }
35
+ total
36
+ }
37
+ }
38
+ `
39
+
40
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, { query })
41
+
42
+ if (response.data.errors) {
43
+ console.error('āŒ GraphQL errors:', response.data.errors)
44
+ return null
45
+ }
46
+
47
+ const dataSets = response.data.data.dataSets
48
+ console.log(`āœ… Found ${dataSets.total} DataSet(s)`)
49
+
50
+ if (dataSets.items.length > 0) {
51
+ console.log('\nAvailable DataSets:')
52
+ dataSets.items.forEach((ds, i) => {
53
+ console.log(` ${i + 1}. ${ds.name} (${ds.id})`)
54
+ console.log(` Active: ${ds.active}`)
55
+ if (ds.description) console.log(` Description: ${ds.description}`)
56
+ })
57
+ return dataSets.items[0] // Return first dataset for testing
58
+ } else {
59
+ console.log('āš ļø No DataSets found. Please create a DataSet first.')
60
+ return null
61
+ }
62
+ } catch (error) {
63
+ console.error('āŒ Failed to query DataSets:', error.message)
64
+ return null
65
+ }
66
+ }
67
+
68
+ async function queryDataSamples(dataSetId) {
69
+ console.log(`\nšŸ“¦ Step 2: Querying DataSamples from DataSet ${dataSetId}...`)
70
+ console.log('='.repeat(60))
71
+
72
+ try {
73
+ const query = `
74
+ query DataSamplesByDataSet($dataSetId: String!) {
75
+ dataSamplesByDataSet(
76
+ dataSetId: $dataSetId
77
+ params: { pagination: { page: 1, limit: 10 } }
78
+ ) {
79
+ items {
80
+ id
81
+ name
82
+ data
83
+ rawData
84
+ collectedAt
85
+ }
86
+ total
87
+ }
88
+ }
89
+ `
90
+
91
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
92
+ query,
93
+ variables: { dataSetId }
94
+ })
95
+
96
+ if (response.data.errors) {
97
+ console.error('āŒ GraphQL errors:', response.data.errors)
98
+ return []
99
+ }
100
+
101
+ const samples = response.data.data.dataSamplesByDataSet
102
+ console.log(`āœ… Found ${samples.total} DataSample(s)`)
103
+
104
+ if (samples.items.length > 0) {
105
+ console.log('\nDataSample details:')
106
+ samples.items.forEach((sample, i) => {
107
+ console.log(` ${i + 1}. ${sample.name || sample.id}`)
108
+ console.log(` ID: ${sample.id}`)
109
+ console.log(` Collected: ${sample.collectedAt}`)
110
+
111
+ // Check for image URL
112
+ let imageUrl = null
113
+ if (sample.data && typeof sample.data === 'object' && sample.data.image) {
114
+ imageUrl = sample.data.image
115
+ } else if (sample.rawData) {
116
+ try {
117
+ const rawData = typeof sample.rawData === 'string' ? JSON.parse(sample.rawData) : sample.rawData
118
+ if (rawData.image) imageUrl = rawData.image
119
+ else if (typeof rawData === 'string' && rawData.startsWith('http')) imageUrl = rawData
120
+ } catch (e) {
121
+ if (sample.rawData.startsWith('http')) imageUrl = sample.rawData
122
+ }
123
+ }
124
+
125
+ if (imageUrl) {
126
+ console.log(` Image: ${imageUrl}`)
127
+ } else {
128
+ console.log(` Image: āš ļø No image URL found`)
129
+ }
130
+ })
131
+ return samples.items
132
+ } else {
133
+ console.log('āš ļø No DataSamples found in this DataSet.')
134
+ console.log('šŸ’” Create some DataSamples with image URLs for testing.')
135
+ return []
136
+ }
137
+ } catch (error) {
138
+ console.error('āŒ Failed to query DataSamples:', error.message)
139
+ return []
140
+ }
141
+ }
142
+
143
+ async function createLabelingTasks(dataSetId) {
144
+ console.log(`\nšŸ·ļø Step 3: Creating Label Studio tasks from DataSet ${dataSetId}...`)
145
+ console.log('='.repeat(60))
146
+
147
+ try {
148
+ const mutation = `
149
+ mutation CreateLabelingTasks($input: CreateLabelingTasksRequest!) {
150
+ createLabelingTasksFromDataset(input: $input) {
151
+ totalSamples
152
+ tasksCreated
153
+ tasksFailed
154
+ tasksSkipped
155
+ predictionsCreated
156
+ taskIds
157
+ error
158
+ }
159
+ }
160
+ `
161
+
162
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
163
+ query: mutation,
164
+ variables: {
165
+ input: {
166
+ projectId: LABEL_STUDIO_PROJECT_ID,
167
+ dataSetId: dataSetId,
168
+ imageField: 'image',
169
+ autoGeneratePredictions: true,
170
+ confidenceThreshold: 0.5,
171
+ limit: 10
172
+ }
173
+ }
174
+ })
175
+
176
+ if (response.data.errors) {
177
+ console.error('āŒ GraphQL errors:', response.data.errors)
178
+ return null
179
+ }
180
+
181
+ const result = response.data.data.createLabelingTasksFromDataset
182
+
183
+ console.log('āœ… Task creation completed!')
184
+ console.log(`\nšŸ“Š Results:`)
185
+ console.log(` Total samples processed: ${result.totalSamples}`)
186
+ console.log(` Tasks created: ${result.tasksCreated}`)
187
+ console.log(` Tasks failed: ${result.tasksFailed}`)
188
+ console.log(` Tasks skipped: ${result.tasksSkipped}`)
189
+ if (result.predictionsCreated !== undefined) {
190
+ console.log(` AI predictions created: ${result.predictionsCreated}`)
191
+ }
192
+
193
+ if (result.taskIds && result.taskIds.length > 0) {
194
+ console.log(`\nšŸŽÆ Created task IDs:`)
195
+ result.taskIds.forEach(taskId => {
196
+ console.log(` - Task ${taskId}`)
197
+ })
198
+ }
199
+
200
+ if (result.error) {
201
+ console.log(`\nāš ļø Errors: ${result.error}`)
202
+ }
203
+
204
+ return result
205
+ } catch (error) {
206
+ console.error('āŒ Failed to create labeling tasks:', error.message)
207
+ if (error.response?.data) {
208
+ console.error(' Response:', JSON.stringify(error.response.data, null, 2))
209
+ }
210
+ return null
211
+ }
212
+ }
213
+
214
+ async function queryLabelingStatus(dataSetId) {
215
+ console.log(`\nšŸ“ˆ Step 4: Querying labeling status for DataSet ${dataSetId}...`)
216
+ console.log('='.repeat(60))
217
+
218
+ try {
219
+ const query = `
220
+ query DatasetLabelingStatus($input: DatasetLabelingStatusRequest!) {
221
+ datasetLabelingStatus(input: $input) {
222
+ dataSetId
223
+ dataSetName
224
+ totalSamples
225
+ tasksCreated
226
+ withPredictions
227
+ withAnnotations
228
+ annotationsCompleted
229
+ notProcessed
230
+ completionRate
231
+ projectId
232
+ }
233
+ }
234
+ `
235
+
236
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
237
+ query,
238
+ variables: {
239
+ input: {
240
+ dataSetId: dataSetId,
241
+ projectId: LABEL_STUDIO_PROJECT_ID
242
+ }
243
+ }
244
+ })
245
+
246
+ if (response.data.errors) {
247
+ console.error('āŒ GraphQL errors:', response.data.errors)
248
+ return null
249
+ }
250
+
251
+ const status = response.data.data.datasetLabelingStatus
252
+
253
+ console.log('āœ… Labeling status retrieved!')
254
+ console.log(`\nšŸ“Š Status for "${status.dataSetName}":`)
255
+ console.log(` Total samples: ${status.totalSamples}`)
256
+ console.log(` Tasks created: ${status.tasksCreated}`)
257
+ console.log(` With AI predictions: ${status.withPredictions}`)
258
+ console.log(` With annotations: ${status.withAnnotations}`)
259
+ console.log(` Annotations completed: ${status.annotationsCompleted}`)
260
+ console.log(` Not yet processed: ${status.notProcessed}`)
261
+ console.log(` Completion rate: ${(status.completionRate * 100).toFixed(1)}%`)
262
+
263
+ return status
264
+ } catch (error) {
265
+ console.error('āŒ Failed to query labeling status:', error.message)
266
+ return null
267
+ }
268
+ }
269
+
270
+ async function generatePredictions(dataSetId) {
271
+ console.log(`\nšŸ¤– Step 5: Generating AI predictions for DataSet ${dataSetId}...`)
272
+ console.log('='.repeat(60))
273
+
274
+ try {
275
+ const mutation = `
276
+ mutation GeneratePredictions($input: GeneratePredictionsForDatasetRequest!) {
277
+ generatePredictionsForDataset(input: $input) {
278
+ total
279
+ succeeded
280
+ failed
281
+ modelVersion
282
+ results {
283
+ taskId
284
+ predictionId
285
+ success
286
+ objectCount
287
+ avgConfidence
288
+ error
289
+ }
290
+ }
291
+ }
292
+ `
293
+
294
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
295
+ query: mutation,
296
+ variables: {
297
+ input: {
298
+ dataSetId: dataSetId,
299
+ projectId: LABEL_STUDIO_PROJECT_ID,
300
+ confidenceThreshold: 0.5,
301
+ forceRegenerate: false
302
+ }
303
+ }
304
+ })
305
+
306
+ if (response.data.errors) {
307
+ console.error('āŒ GraphQL errors:', response.data.errors)
308
+ return null
309
+ }
310
+
311
+ const result = response.data.data.generatePredictionsForDataset
312
+
313
+ console.log('āœ… Prediction generation completed!')
314
+ console.log(`\nšŸ“Š Results:`)
315
+ console.log(` Total tasks: ${result.total}`)
316
+ console.log(` Succeeded: ${result.succeeded}`)
317
+ console.log(` Failed: ${result.failed}`)
318
+ console.log(` Model version: ${result.modelVersion}`)
319
+
320
+ if (result.results && result.results.length > 0) {
321
+ console.log(`\nšŸŽÆ Prediction details:`)
322
+ result.results.forEach((res, i) => {
323
+ if (res.success && res.objectCount > 0) {
324
+ console.log(` Task ${res.taskId}: ${res.objectCount} objects (avg conf: ${(res.avgConfidence * 100).toFixed(1)}%)`)
325
+ } else if (res.error) {
326
+ console.log(` Task ${res.taskId}: ${res.error}`)
327
+ }
328
+ })
329
+ }
330
+
331
+ return result
332
+ } catch (error) {
333
+ console.error('āŒ Failed to generate predictions:', error.message)
334
+ return null
335
+ }
336
+ }
337
+
338
+ async function syncAnnotations(dataSetId) {
339
+ console.log(`\nšŸ”„ Step 6: Syncing annotations back to DataSet ${dataSetId}...`)
340
+ console.log('='.repeat(60))
341
+
342
+ try {
343
+ const mutation = `
344
+ mutation SyncAnnotations($input: SyncAnnotationsRequest!) {
345
+ syncAnnotationsToDataset(input: $input) {
346
+ totalAnnotations
347
+ samplesUpdated
348
+ updatesFailed
349
+ skipped
350
+ error
351
+ }
352
+ }
353
+ `
354
+
355
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
356
+ query: mutation,
357
+ variables: {
358
+ input: {
359
+ projectId: LABEL_STUDIO_PROJECT_ID,
360
+ dataSetId: dataSetId,
361
+ completedOnly: false
362
+ }
363
+ }
364
+ })
365
+
366
+ if (response.data.errors) {
367
+ console.error('āŒ GraphQL errors:', response.data.errors)
368
+ return null
369
+ }
370
+
371
+ const result = response.data.data.syncAnnotationsToDataset
372
+
373
+ console.log('āœ… Annotation sync completed!')
374
+ console.log(`\nšŸ“Š Results:`)
375
+ console.log(` Total annotations processed: ${result.totalAnnotations}`)
376
+ console.log(` DataSamples updated: ${result.samplesUpdated}`)
377
+ console.log(` Updates failed: ${result.updatesFailed}`)
378
+ console.log(` Skipped: ${result.skipped}`)
379
+
380
+ if (result.error) {
381
+ console.log(`\nāš ļø Errors: ${result.error}`)
382
+ }
383
+
384
+ return result
385
+ } catch (error) {
386
+ console.error('āŒ Failed to sync annotations:', error.message)
387
+ return null
388
+ }
389
+ }
390
+
391
+ async function main() {
392
+ console.log('šŸš€ Dataset-Label Studio Integration Test\n')
393
+ console.log('='.repeat(60))
394
+ console.log(` Things Factory GraphQL: ${THINGS_FACTORY_GRAPHQL}`)
395
+ console.log(` Label Studio URL: ${LABEL_STUDIO_URL}`)
396
+ console.log(` Label Studio Project ID: ${LABEL_STUDIO_PROJECT_ID}`)
397
+ console.log('='.repeat(60))
398
+
399
+ try {
400
+ // Step 1: Query DataSets
401
+ const dataSet = await queryDataSets()
402
+ if (!dataSet) {
403
+ console.log('\nšŸ’” Please create a DataSet with DataSamples first.')
404
+ process.exit(1)
405
+ }
406
+
407
+ // Step 2: Query DataSamples
408
+ const samples = await queryDataSamples(dataSet.id)
409
+ if (samples.length === 0) {
410
+ console.log('\nšŸ’” Please add DataSamples with image URLs to the DataSet.')
411
+ process.exit(1)
412
+ }
413
+
414
+ // Step 3: Create Label Studio tasks
415
+ const createResult = await createLabelingTasks(dataSet.id)
416
+ if (!createResult || createResult.tasksCreated === 0) {
417
+ console.log('\nāš ļø No tasks were created. Check if images are properly configured.')
418
+ process.exit(1)
419
+ }
420
+
421
+ // Step 4: Query labeling status
422
+ await queryLabelingStatus(dataSet.id)
423
+
424
+ // Step 5: Generate predictions (if not already done)
425
+ await generatePredictions(dataSet.id)
426
+
427
+ // Step 6: Sync annotations (if any exist)
428
+ await syncAnnotations(dataSet.id)
429
+
430
+ console.log('\n' + '='.repeat(60))
431
+ console.log('✨ Integration test completed successfully!')
432
+ console.log('\nšŸ“ Next steps:')
433
+ console.log(` 1. Open Label Studio: ${LABEL_STUDIO_URL}/projects/${LABEL_STUDIO_PROJECT_ID}`)
434
+ console.log(` 2. Review AI-generated predictions`)
435
+ console.log(` 3. Complete annotations`)
436
+ console.log(` 4. Run syncAnnotations again to update DataSamples`)
437
+ console.log('='.repeat(60))
438
+
439
+ } catch (error) {
440
+ console.error('\nšŸ’„ Test failed with error:', error)
441
+ process.exit(1)
442
+ }
443
+ }
444
+
445
+ // Run the test
446
+ main().catch(error => {
447
+ console.error('šŸ’„ Unexpected error:', error)
448
+ process.exit(1)
449
+ })
package/test-simple.js ADDED
@@ -0,0 +1,89 @@
1
+ /**
2
+ * Simple test for AI inference (without Label Studio API token)
3
+ * Tests just the AI detection functionality
4
+ */
5
+
6
+ const axios = require('axios')
7
+
8
+ const THINGS_FACTORY_GRAPHQL = process.env.THINGS_FACTORY_GRAPHQL || 'http://dataset.localhost:3000/graphql'
9
+
10
+ // Sample image URL for testing
11
+ const TEST_IMAGE_URL = 'https://example.com/test.jpg'
12
+
13
+ async function testAIDetection() {
14
+ console.log('šŸ¤– Testing AI Object Detection\n')
15
+ console.log('='.repeat(60))
16
+ console.log(` GraphQL: ${THINGS_FACTORY_GRAPHQL}`)
17
+ console.log(` Test Image: ${TEST_IMAGE_URL}`)
18
+ console.log('='.repeat(60))
19
+
20
+ try {
21
+ const query = `
22
+ query DetectObjects($input: InferenceRequest!) {
23
+ detectObjects(input: $input) {
24
+ className
25
+ confidence
26
+ bbox {
27
+ x
28
+ y
29
+ width
30
+ height
31
+ }
32
+ }
33
+ }
34
+ `
35
+
36
+ console.log('\nšŸ“¤ Sending GraphQL request...')
37
+
38
+ const response = await axios.post(THINGS_FACTORY_GRAPHQL, {
39
+ query,
40
+ variables: {
41
+ input: {
42
+ imageUrl: TEST_IMAGE_URL,
43
+ confidenceThreshold: 0.5
44
+ }
45
+ }
46
+ })
47
+
48
+ if (response.data.errors) {
49
+ console.error('\nāŒ GraphQL errors:')
50
+ response.data.errors.forEach(err => {
51
+ console.error(` - ${err.message}`)
52
+ })
53
+ return false
54
+ }
55
+
56
+ const objects = response.data.data.detectObjects
57
+
58
+ console.log('\nāœ… AI Detection successful!')
59
+ console.log(`\nšŸŽÆ Detected ${objects.length} objects:\n`)
60
+
61
+ objects.forEach((obj, i) => {
62
+ console.log(` ${i + 1}. ${obj.className}`)
63
+ console.log(` Confidence: ${(obj.confidence * 100).toFixed(1)}%`)
64
+ console.log(` BBox: x=${obj.bbox.x}, y=${obj.bbox.y}, w=${obj.bbox.width}, h=${obj.bbox.height}`)
65
+ console.log()
66
+ })
67
+
68
+ console.log('='.repeat(60))
69
+ console.log('✨ Mock AI is working correctly!')
70
+ console.log('\nšŸ“ This confirms:')
71
+ console.log(' āœ“ ai-inference module is loaded')
72
+ console.log(' āœ“ GraphQL API is accessible')
73
+ console.log(' āœ“ Mock AI client is functioning')
74
+ console.log('\nšŸ’” Next step: Configure Label Studio API token to test full integration')
75
+
76
+ return true
77
+ } catch (error) {
78
+ console.error('\nāŒ Test failed:', error.message)
79
+ if (error.response?.data) {
80
+ console.error('\n Response:', JSON.stringify(error.response.data, null, 2))
81
+ }
82
+ return false
83
+ }
84
+ }
85
+
86
+ // Run test
87
+ testAIDetection().then(success => {
88
+ process.exit(success ? 0 : 1)
89
+ })
@@ -0,0 +1,12 @@
1
+ import route from './dist-client/route'
2
+ import bootstrap from './dist-client/bootstrap'
3
+
4
+ export default {
5
+ route,
6
+ routes: [
7
+ { tagname: 'label-studio-project-list', page: 'label-studio-project-list' },
8
+ { tagname: 'label-studio-project-create', page: 'label-studio-project-create' },
9
+ { tagname: 'label-studio-label-page', page: 'label-studio-label' }
10
+ ],
11
+ bootstrap
12
+ }