@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,134 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebhookManagement = exports.Webhook = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const type_graphql_1 = require("type-graphql");
6
+ const label_studio_api_client_js_1 = require("../../utils/label-studio-api-client.js");
7
+ let Webhook = class Webhook {
8
+ };
9
+ exports.Webhook = Webhook;
10
+ tslib_1.__decorate([
11
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Webhook ID' }),
12
+ tslib_1.__metadata("design:type", Number)
13
+ ], Webhook.prototype, "id", void 0);
14
+ tslib_1.__decorate([
15
+ (0, type_graphql_1.Field)({ description: 'Webhook URL' }),
16
+ tslib_1.__metadata("design:type", String)
17
+ ], Webhook.prototype, "url", void 0);
18
+ tslib_1.__decorate([
19
+ (0, type_graphql_1.Field)(type => type_graphql_1.Int, { description: 'Project ID' }),
20
+ tslib_1.__metadata("design:type", Number)
21
+ ], Webhook.prototype, "projectId", void 0);
22
+ tslib_1.__decorate([
23
+ (0, type_graphql_1.Field)({ description: 'Is webhook active' }),
24
+ tslib_1.__metadata("design:type", Boolean)
25
+ ], Webhook.prototype, "isActive", void 0);
26
+ tslib_1.__decorate([
27
+ (0, type_graphql_1.Field)({ description: 'Send payload with webhook' }),
28
+ tslib_1.__metadata("design:type", Boolean)
29
+ ], Webhook.prototype, "sendPayload", void 0);
30
+ exports.Webhook = Webhook = tslib_1.__decorate([
31
+ (0, type_graphql_1.ObjectType)({ description: 'Webhook information' })
32
+ ], Webhook);
33
+ let WebhookManagement = class WebhookManagement {
34
+ /**
35
+ * Register webhook for a project
36
+ */
37
+ async registerLabelStudioWebhook(projectId, context) {
38
+ try {
39
+ // Get Things-Factory server URL from environment or request
40
+ const serverUrl = process.env.SERVER_URL || 'http://localhost:3000';
41
+ const webhookUrl = `${serverUrl}/label-studio/webhook`;
42
+ const webhook = await label_studio_api_client_js_1.labelStudioApi.createWebhook({
43
+ project: projectId,
44
+ url: webhookUrl,
45
+ send_payload: true,
46
+ send_for_all_actions: true,
47
+ headers: {
48
+ 'Content-Type': 'application/json'
49
+ }
50
+ });
51
+ return {
52
+ id: webhook.id,
53
+ url: webhook.url,
54
+ projectId: webhook.project,
55
+ isActive: webhook.is_active || true,
56
+ sendPayload: webhook.send_payload || true
57
+ };
58
+ }
59
+ catch (error) {
60
+ console.error(`Failed to register webhook for project ${projectId}:`, error);
61
+ throw new Error(`Failed to register webhook: ${error.message}`);
62
+ }
63
+ }
64
+ /**
65
+ * Get webhooks for a project
66
+ */
67
+ async labelStudioWebhooks(projectId, context) {
68
+ try {
69
+ const webhooks = await label_studio_api_client_js_1.labelStudioApi.getWebhooks(projectId);
70
+ return webhooks.map(webhook => ({
71
+ id: webhook.id,
72
+ url: webhook.url,
73
+ projectId: webhook.project,
74
+ isActive: webhook.is_active || true,
75
+ sendPayload: webhook.send_payload || true
76
+ }));
77
+ }
78
+ catch (error) {
79
+ console.error(`Failed to fetch webhooks for project ${projectId}:`, error);
80
+ throw new Error(`Failed to fetch webhooks: ${error.message}`);
81
+ }
82
+ }
83
+ /**
84
+ * Delete webhook
85
+ */
86
+ async deleteLabelStudioWebhook(webhookId, context) {
87
+ try {
88
+ await label_studio_api_client_js_1.labelStudioApi.deleteWebhook(webhookId);
89
+ return true;
90
+ }
91
+ catch (error) {
92
+ console.error(`Failed to delete webhook ${webhookId}:`, error);
93
+ throw new Error(`Failed to delete webhook: ${error.message}`);
94
+ }
95
+ }
96
+ };
97
+ exports.WebhookManagement = WebhookManagement;
98
+ tslib_1.__decorate([
99
+ (0, type_graphql_1.Mutation)(returns => Webhook, {
100
+ description: 'Register webhook for Label Studio project to receive real-time updates'
101
+ }),
102
+ (0, type_graphql_1.Directive)('@privilege(category: "label-studio", privilege: "mutation")'),
103
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId', type => type_graphql_1.Int)),
104
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
105
+ tslib_1.__metadata("design:type", Function),
106
+ tslib_1.__metadata("design:paramtypes", [Number, Object]),
107
+ tslib_1.__metadata("design:returntype", Promise)
108
+ ], WebhookManagement.prototype, "registerLabelStudioWebhook", null);
109
+ tslib_1.__decorate([
110
+ (0, type_graphql_1.Query)(returns => [Webhook], {
111
+ description: 'Get all webhooks registered for a Label Studio project'
112
+ }),
113
+ (0, type_graphql_1.Directive)('@privilege(category: "label-studio", privilege: "query")'),
114
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('projectId', type => type_graphql_1.Int)),
115
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
116
+ tslib_1.__metadata("design:type", Function),
117
+ tslib_1.__metadata("design:paramtypes", [Number, Object]),
118
+ tslib_1.__metadata("design:returntype", Promise)
119
+ ], WebhookManagement.prototype, "labelStudioWebhooks", null);
120
+ tslib_1.__decorate([
121
+ (0, type_graphql_1.Mutation)(returns => Boolean, {
122
+ description: 'Delete a webhook'
123
+ }),
124
+ (0, type_graphql_1.Directive)('@privilege(category: "label-studio", privilege: "mutation")'),
125
+ tslib_1.__param(0, (0, type_graphql_1.Arg)('webhookId', type => type_graphql_1.Int)),
126
+ tslib_1.__param(1, (0, type_graphql_1.Ctx)()),
127
+ tslib_1.__metadata("design:type", Function),
128
+ tslib_1.__metadata("design:paramtypes", [Number, Object]),
129
+ tslib_1.__metadata("design:returntype", Promise)
130
+ ], WebhookManagement.prototype, "deleteLabelStudioWebhook", null);
131
+ exports.WebhookManagement = WebhookManagement = tslib_1.__decorate([
132
+ (0, type_graphql_1.Resolver)()
133
+ ], WebhookManagement);
134
+ //# sourceMappingURL=webhook-management.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-management.js","sourceRoot":"","sources":["../../../server/service/webhook/webhook-management.ts"],"names":[],"mappings":"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","sourcesContent":["import { Resolver, Mutation, Query, Arg, Ctx, Int, Directive, Field, ObjectType } from 'type-graphql'\nimport { labelStudioApi } from '../../utils/label-studio-api-client.js'\n\n@ObjectType({ description: 'Webhook information' })\nexport class Webhook {\n @Field(type => Int, { description: 'Webhook ID' })\n id: number\n\n @Field({ description: 'Webhook URL' })\n url: string\n\n @Field(type => Int, { description: 'Project ID' })\n projectId: number\n\n @Field({ description: 'Is webhook active' })\n isActive: boolean\n\n @Field({ description: 'Send payload with webhook' })\n sendPayload: boolean\n}\n\n@Resolver()\nexport class WebhookManagement {\n /**\n * Register webhook for a project\n */\n @Mutation(returns => Webhook, {\n description: 'Register webhook for Label Studio project to receive real-time updates'\n })\n @Directive('@privilege(category: \"label-studio\", privilege: \"mutation\")')\n async registerLabelStudioWebhook(\n @Arg('projectId', type => Int) projectId: number,\n @Ctx() context: ResolverContext\n ): Promise<Webhook> {\n try {\n // Get Things-Factory server URL from environment or request\n const serverUrl = process.env.SERVER_URL || 'http://localhost:3000'\n const webhookUrl = `${serverUrl}/label-studio/webhook`\n\n const webhook = await labelStudioApi.createWebhook({\n project: projectId,\n url: webhookUrl,\n send_payload: true,\n send_for_all_actions: true,\n headers: {\n 'Content-Type': 'application/json'\n }\n })\n\n return {\n id: webhook.id,\n url: webhook.url,\n projectId: webhook.project,\n isActive: webhook.is_active || true,\n sendPayload: webhook.send_payload || true\n }\n } catch (error) {\n console.error(`Failed to register webhook for project ${projectId}:`, error)\n throw new Error(`Failed to register webhook: ${error.message}`)\n }\n }\n\n /**\n * Get webhooks for a project\n */\n @Query(returns => [Webhook], {\n description: 'Get all webhooks registered for a Label Studio project'\n })\n @Directive('@privilege(category: \"label-studio\", privilege: \"query\")')\n async labelStudioWebhooks(\n @Arg('projectId', type => Int) projectId: number,\n @Ctx() context: ResolverContext\n ): Promise<Webhook[]> {\n try {\n const webhooks = await labelStudioApi.getWebhooks(projectId)\n\n return webhooks.map(webhook => ({\n id: webhook.id,\n url: webhook.url,\n projectId: webhook.project,\n isActive: webhook.is_active || true,\n sendPayload: webhook.send_payload || true\n }))\n } catch (error) {\n console.error(`Failed to fetch webhooks for project ${projectId}:`, error)\n throw new Error(`Failed to fetch webhooks: ${error.message}`)\n }\n }\n\n /**\n * Delete webhook\n */\n @Mutation(returns => Boolean, {\n description: 'Delete a webhook'\n })\n @Directive('@privilege(category: \"label-studio\", privilege: \"mutation\")')\n async deleteLabelStudioWebhook(\n @Arg('webhookId', type => Int) webhookId: number,\n @Ctx() context: ResolverContext\n ): Promise<boolean> {\n try {\n await labelStudioApi.deleteWebhook(webhookId)\n return true\n } catch (error) {\n console.error(`Failed to delete webhook ${webhookId}:`, error)\n throw new Error(`Failed to delete webhook: ${error.message}`)\n }\n }\n}\n"]}