@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.
- package/CHANGELOG.md +85 -0
- package/EXTERNAL_DATA_SOURCING.md +484 -0
- package/IMPLEMENTATION_GUIDE.md +469 -0
- package/INTEGRATION.md +279 -0
- package/README.md +1014 -0
- package/SETUP_GUIDE.md +577 -0
- package/TEST_GUIDE.md +387 -0
- package/UI_CUSTOMIZATION.md +395 -0
- package/USER_SYNC_GUIDE.md +514 -0
- package/client/bootstrap.ts +1 -0
- package/client/index.ts +1 -0
- package/client/label-studio-label-page.ts +52 -0
- package/client/label-studio-project-create.ts +216 -0
- package/client/label-studio-project-list.ts +214 -0
- package/client/label-studio-wrapper.ts +294 -0
- package/client/route.ts +15 -0
- package/client/tsconfig.json +13 -0
- package/config/config.development.js +124 -0
- package/config/config.production.js +182 -0
- package/dist-client/bootstrap.d.ts +1 -0
- package/dist-client/bootstrap.js +2 -0
- package/dist-client/bootstrap.js.map +1 -0
- package/dist-client/index.d.ts +1 -0
- package/dist-client/index.js +2 -0
- package/dist-client/index.js.map +1 -0
- package/dist-client/label-studio-label-page.d.ts +8 -0
- package/dist-client/label-studio-label-page.js +54 -0
- package/dist-client/label-studio-label-page.js.map +1 -0
- package/dist-client/label-studio-project-create.d.ts +16 -0
- package/dist-client/label-studio-project-create.js +235 -0
- package/dist-client/label-studio-project-create.js.map +1 -0
- package/dist-client/label-studio-project-list.d.ts +16 -0
- package/dist-client/label-studio-project-list.js +222 -0
- package/dist-client/label-studio-project-list.js.map +1 -0
- package/dist-client/label-studio-wrapper.d.ts +57 -0
- package/dist-client/label-studio-wrapper.js +304 -0
- package/dist-client/label-studio-wrapper.js.map +1 -0
- package/dist-client/route.d.ts +1 -0
- package/dist-client/route.js +14 -0
- package/dist-client/route.js.map +1 -0
- package/dist-client/tsconfig.tsbuildinfo +1 -0
- package/dist-server/controller/label-studio-role-mapper.d.ts +35 -0
- package/dist-server/controller/label-studio-role-mapper.js +65 -0
- package/dist-server/controller/label-studio-role-mapper.js.map +1 -0
- package/dist-server/controller/user-provisioning-service.d.ts +66 -0
- package/dist-server/controller/user-provisioning-service.js +264 -0
- package/dist-server/controller/user-provisioning-service.js.map +1 -0
- package/dist-server/index.d.ts +7 -0
- package/dist-server/index.js +19 -0
- package/dist-server/index.js.map +1 -0
- package/dist-server/route/label-studio-sso.d.ts +2 -0
- package/dist-server/route/label-studio-sso.js +156 -0
- package/dist-server/route/label-studio-sso.js.map +1 -0
- package/dist-server/route/webhook.d.ts +65 -0
- package/dist-server/route/webhook.js +248 -0
- package/dist-server/route/webhook.js.map +1 -0
- package/dist-server/route.d.ts +1 -0
- package/dist-server/route.js +21 -0
- package/dist-server/route.js.map +1 -0
- package/dist-server/service/ai-prediction-service.d.ts +27 -0
- package/dist-server/service/ai-prediction-service.js +222 -0
- package/dist-server/service/ai-prediction-service.js.map +1 -0
- package/dist-server/service/dataset-labeling-integration.d.ts +44 -0
- package/dist-server/service/dataset-labeling-integration.js +512 -0
- package/dist-server/service/dataset-labeling-integration.js.map +1 -0
- package/dist-server/service/external-data-source-service.d.ts +78 -0
- package/dist-server/service/external-data-source-service.js +415 -0
- package/dist-server/service/external-data-source-service.js.map +1 -0
- package/dist-server/service/index.d.ts +12 -0
- package/dist-server/service/index.js +27 -0
- package/dist-server/service/index.js.map +1 -0
- package/dist-server/service/label-studio-sso-service.d.ts +38 -0
- package/dist-server/service/label-studio-sso-service.js +98 -0
- package/dist-server/service/label-studio-sso-service.js.map +1 -0
- package/dist-server/service/ml/ml-backend-service.d.ts +23 -0
- package/dist-server/service/ml/ml-backend-service.js +153 -0
- package/dist-server/service/ml/ml-backend-service.js.map +1 -0
- package/dist-server/service/prediction/prediction-management.d.ts +32 -0
- package/dist-server/service/prediction/prediction-management.js +299 -0
- package/dist-server/service/prediction/prediction-management.js.map +1 -0
- package/dist-server/service/project/project-management.d.ts +36 -0
- package/dist-server/service/project/project-management.js +309 -0
- package/dist-server/service/project/project-management.js.map +1 -0
- package/dist-server/service/task/task-management.d.ts +42 -0
- package/dist-server/service/task/task-management.js +372 -0
- package/dist-server/service/task/task-management.js.map +1 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.d.ts +28 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js +111 -0
- package/dist-server/service/user-provisioning/user-sync-mutation.js.map +1 -0
- package/dist-server/service/webhook/webhook-management.d.ts +21 -0
- package/dist-server/service/webhook/webhook-management.js +134 -0
- package/dist-server/service/webhook/webhook-management.js.map +1 -0
- package/dist-server/tsconfig.tsbuildinfo +1 -0
- package/dist-server/types/dataset-labeling-types.d.ts +71 -0
- package/dist-server/types/dataset-labeling-types.js +259 -0
- package/dist-server/types/dataset-labeling-types.js.map +1 -0
- package/dist-server/types/label-studio-types.d.ts +128 -0
- package/dist-server/types/label-studio-types.js +494 -0
- package/dist-server/types/label-studio-types.js.map +1 -0
- package/dist-server/types/prediction-types.d.ts +39 -0
- package/dist-server/types/prediction-types.js +121 -0
- package/dist-server/types/prediction-types.js.map +1 -0
- package/dist-server/utils/annotation-exporter.d.ts +104 -0
- package/dist-server/utils/annotation-exporter.js +261 -0
- package/dist-server/utils/annotation-exporter.js.map +1 -0
- package/dist-server/utils/label-config-builder.d.ts +117 -0
- package/dist-server/utils/label-config-builder.js +286 -0
- package/dist-server/utils/label-config-builder.js.map +1 -0
- package/dist-server/utils/label-studio-api-client.d.ts +180 -0
- package/dist-server/utils/label-studio-api-client.js +401 -0
- package/dist-server/utils/label-studio-api-client.js.map +1 -0
- package/dist-server/utils/media-url-extractor.d.ts +45 -0
- package/dist-server/utils/media-url-extractor.js +152 -0
- package/dist-server/utils/media-url-extractor.js.map +1 -0
- package/dist-server/utils/task-transformer.d.ts +108 -0
- package/dist-server/utils/task-transformer.js +260 -0
- package/dist-server/utils/task-transformer.js.map +1 -0
- package/package.json +47 -0
- package/server/SERVER_STRUCTURE.md +351 -0
- package/server/controller/label-studio-role-mapper.ts +76 -0
- package/server/controller/user-provisioning-service.ts +340 -0
- package/server/index.ts +19 -0
- package/server/route/label-studio-sso.ts +194 -0
- package/server/route/webhook.ts +304 -0
- package/server/route.ts +35 -0
- package/server/service/ai-prediction-service.ts +239 -0
- package/server/service/dataset-labeling-integration.ts +590 -0
- package/server/service/external-data-source-service.ts +438 -0
- package/server/service/index.ts +24 -0
- package/server/service/label-studio-sso-service.ts +108 -0
- package/server/service/labeling-scenario-service.ts.deprecated +566 -0
- package/server/service/ml/ml-backend-service.ts +127 -0
- package/server/service/prediction/prediction-management.ts +281 -0
- package/server/service/project/project-management.ts +284 -0
- package/server/service/task/task-management.ts +363 -0
- package/server/service/user-provisioning/user-sync-mutation.ts +80 -0
- package/server/service/webhook/webhook-management.ts +109 -0
- package/server/tsconfig.json +11 -0
- package/server/types/dataset-labeling-types.ts +181 -0
- package/server/types/global.d.ts +23 -0
- package/server/types/label-studio-types.ts +346 -0
- package/server/types/prediction-types.ts +86 -0
- package/server/types/scenario-types.ts.deprecated +362 -0
- package/server/utils/annotation-exporter.ts +340 -0
- package/server/utils/label-config-builder.ts +340 -0
- package/server/utils/label-studio-api-client.ts +487 -0
- package/server/utils/media-url-extractor.ts +193 -0
- package/server/utils/task-transformer.ts +342 -0
- package/test-ai-prediction.js +268 -0
- package/test-dataset-integration.js +449 -0
- package/test-simple.js +89 -0
- package/things-factory.config.js +12 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|
6
|
+
|
|
7
|
+
### Changed
|
|
8
|
+
|
|
9
|
+
- **[2025-10-07] Fixed hardcoded project ID in `label-studio-label-page.ts`**
|
|
10
|
+
- **Impact**: Critical bug fix - Now supports dynamic project routing
|
|
11
|
+
- **Changes**:
|
|
12
|
+
- Replaced hardcoded `/projects/3` with dynamic project ID extraction from URL route
|
|
13
|
+
- Added `projectId` property to LabelStudioLabelPage component
|
|
14
|
+
- Implemented `_extractProjectIdFromRoute()` method to parse project ID from window.location.pathname
|
|
15
|
+
- Added error handling for missing project ID
|
|
16
|
+
- **Files modified**:
|
|
17
|
+
- `client/label-studio-label-page.ts:28,33-60`
|
|
18
|
+
- **Migration**: No breaking changes - component now accepts optional `projectId` property
|
|
19
|
+
|
|
20
|
+
- **[2025-10-07] Enhanced error handling and loading states**
|
|
21
|
+
- **Impact**: Improved user experience with better feedback
|
|
22
|
+
- **Changes**:
|
|
23
|
+
- Added iframe load timeout detection (15 seconds)
|
|
24
|
+
- Added iframe error event handler
|
|
25
|
+
- Added `iframeLoaded` state tracking
|
|
26
|
+
- Improved error messages for iframe loading failures
|
|
27
|
+
- **Files modified**:
|
|
28
|
+
- `client/label-studio-wrapper.ts:124,127-137,168-178,223`
|
|
29
|
+
- **Benefits**: Users now get clear feedback when Label Studio fails to load
|
|
30
|
+
|
|
31
|
+
- **[2025-10-07] Uncommented webhook exports in server/index.ts**
|
|
32
|
+
- **Impact**: Public API now properly exports webhook-related types and functions
|
|
33
|
+
- **Changes**:
|
|
34
|
+
- Uncommented exports for: `WebhookAction`, `WebhookPayload`, `WebhookHandler`, `registerWebhookHandler`, `unregisterWebhookHandler`, `clearWebhookHandlers`
|
|
35
|
+
- These exports were previously commented out but are fully implemented and functional
|
|
36
|
+
- **Files modified**:
|
|
37
|
+
- `server/index.ts:5-12`
|
|
38
|
+
- **Benefits**: Users can now extend webhook functionality for custom Label Studio event handling
|
|
39
|
+
|
|
40
|
+
### Technical Details
|
|
41
|
+
|
|
42
|
+
#### Dynamic Project ID Implementation
|
|
43
|
+
|
|
44
|
+
```typescript
|
|
45
|
+
// Before
|
|
46
|
+
const path = '/projects/3' // Hardcoded project ID
|
|
47
|
+
|
|
48
|
+
// After
|
|
49
|
+
const projectId = this.projectId || this._extractProjectIdFromRoute()
|
|
50
|
+
const path = `/projects/${projectId}`
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Error Handling Enhancement
|
|
54
|
+
|
|
55
|
+
- Added `@error=${this.handleIframeError}` event listener on iframe element
|
|
56
|
+
- Added timeout detection to catch cases where iframe loads but never fires load event
|
|
57
|
+
- Clear error messages guide users to check server connectivity
|
|
58
|
+
|
|
59
|
+
#### Webhook API Exports
|
|
60
|
+
|
|
61
|
+
Users can now register custom webhook handlers:
|
|
62
|
+
|
|
63
|
+
```typescript
|
|
64
|
+
import { registerWebhookHandler, WebhookAction } from 'integration-label-studio'
|
|
65
|
+
|
|
66
|
+
registerWebhookHandler(WebhookAction.ANNOTATION_CREATED, async (payload, ctx) => {
|
|
67
|
+
// Custom annotation handling logic
|
|
68
|
+
})
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Summary
|
|
72
|
+
|
|
73
|
+
**Total Files Modified**: 3
|
|
74
|
+
|
|
75
|
+
- `client/label-studio-label-page.ts` - Fixed hardcoded project ID
|
|
76
|
+
- `client/label-studio-wrapper.ts` - Enhanced error handling
|
|
77
|
+
- `server/index.ts` - Enabled webhook API exports
|
|
78
|
+
|
|
79
|
+
**Impact**:
|
|
80
|
+
|
|
81
|
+
- β
Fixes critical routing bug
|
|
82
|
+
- β
Improves user experience with loading states
|
|
83
|
+
- β
Enables webhook extensibility
|
|
84
|
+
|
|
85
|
+
**Production Ready**: Yes - All changes are backward compatible
|
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
# π Label Studio μΈλΆ λ°μ΄ν° μμ± κ°μ΄λ
|
|
2
|
+
|
|
3
|
+
Label Studio νλ‘μ νΈμ μΈλΆ λ°μ΄ν°λ₯Ό importνλ λ€μν λ°©λ²μ μ€λͺ
ν©λλ€.
|
|
4
|
+
|
|
5
|
+
## π λͺ©μ°¨
|
|
6
|
+
|
|
7
|
+
1. [Dataset λͺ¨λ νμ©](#1-dataset-λͺ¨λ-νμ©-μΆμ²)
|
|
8
|
+
2. [μΈλΆ REST API μ°λ](#2-μΈλΆ-rest-api-μ°λ)
|
|
9
|
+
3. [JSON/CSV νμΌ Import](#3-jsoncsv-νμΌ-import)
|
|
10
|
+
4. [ν΄λΌμ°λ μ€ν λ¦¬μ§ μ°λ](#4-ν΄λΌμ°λ-μ€ν 리μ§-μ°λ)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 1. Dataset λͺ¨λ νμ© (μΆμ²)
|
|
15
|
+
|
|
16
|
+
Things Factoryμ Dataset λͺ¨λμμ DataSampleμ Label Studioλ‘ μλ exportν©λλ€.
|
|
17
|
+
|
|
18
|
+
### μ₯μ
|
|
19
|
+
- β
λ°μ΄ν° ꡬ쑰 μλ λ³ν
|
|
20
|
+
- β
λ©νλ°μ΄ν° μλ λ§€ν
|
|
21
|
+
- β
AI μμΈ‘ μλ μμ±
|
|
22
|
+
- β
μλ°©ν₯ λκΈ°ν μ§μ
|
|
23
|
+
|
|
24
|
+
### GraphQL API
|
|
25
|
+
|
|
26
|
+
```graphql
|
|
27
|
+
mutation {
|
|
28
|
+
createLabelingTasksFromDataset(input: {
|
|
29
|
+
projectId: 2
|
|
30
|
+
dataSetId: "your-dataset-id"
|
|
31
|
+
imageField: "image"
|
|
32
|
+
autoGeneratePredictions: true
|
|
33
|
+
confidenceThreshold: 0.5
|
|
34
|
+
limit: 100
|
|
35
|
+
}) {
|
|
36
|
+
totalSamples
|
|
37
|
+
tasksCreated
|
|
38
|
+
tasksFailed
|
|
39
|
+
predictionsCreated
|
|
40
|
+
taskIds
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### μ¬μ© λ°©λ²
|
|
46
|
+
|
|
47
|
+
1. **DataSet μμ±**
|
|
48
|
+
```graphql
|
|
49
|
+
mutation {
|
|
50
|
+
createDataSet(dataSet: {
|
|
51
|
+
name: "Product Images"
|
|
52
|
+
description: "Quality inspection images"
|
|
53
|
+
active: true
|
|
54
|
+
}) {
|
|
55
|
+
id
|
|
56
|
+
name
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
2. **DataSample μΆκ°**
|
|
62
|
+
```graphql
|
|
63
|
+
mutation {
|
|
64
|
+
createDataSample(dataSample: {
|
|
65
|
+
dataSetId: "dataset-id"
|
|
66
|
+
name: "Sample-001"
|
|
67
|
+
data: {
|
|
68
|
+
image: "https://example.com/image1.jpg"
|
|
69
|
+
product_id: "P123"
|
|
70
|
+
batch: "B456"
|
|
71
|
+
}
|
|
72
|
+
collectedAt: "2025-01-13T10:00:00Z"
|
|
73
|
+
}) {
|
|
74
|
+
id
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
3. **Label Studioλ‘ Export**
|
|
80
|
+
```graphql
|
|
81
|
+
mutation {
|
|
82
|
+
createLabelingTasksFromDataset(input: {
|
|
83
|
+
projectId: 2
|
|
84
|
+
dataSetId: "dataset-id"
|
|
85
|
+
autoGeneratePredictions: true
|
|
86
|
+
}) {
|
|
87
|
+
tasksCreated
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## 2. μΈλΆ REST API μ°λ
|
|
95
|
+
|
|
96
|
+
REST API μλν¬μΈνΈμμ μ§μ λ°μ΄ν°λ₯Ό κ°μ Έμ Label Studioμ importν©λλ€.
|
|
97
|
+
|
|
98
|
+
### 미리보기 (Preview)
|
|
99
|
+
|
|
100
|
+
λ¨Όμ λ°μ΄ν° ꡬ쑰λ₯Ό νμΈν©λλ€:
|
|
101
|
+
|
|
102
|
+
```graphql
|
|
103
|
+
query {
|
|
104
|
+
previewExternalDataSource(source: {
|
|
105
|
+
sourceType: "api"
|
|
106
|
+
sourceUrl: "https://api.example.com/images"
|
|
107
|
+
authHeader: "Bearer YOUR_TOKEN"
|
|
108
|
+
httpMethod: "GET"
|
|
109
|
+
dataPath: "data.items"
|
|
110
|
+
}) {
|
|
111
|
+
itemCount
|
|
112
|
+
sampleData
|
|
113
|
+
schema
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**μλ΅ μμ:**
|
|
119
|
+
```json
|
|
120
|
+
{
|
|
121
|
+
"itemCount": 1,
|
|
122
|
+
"sampleData": "{\n \"id\": \"123\",\n \"imageUrl\": \"https://...\",\n \"category\": \"defect\"\n}",
|
|
123
|
+
"schema": "{\n \"id\": \"string\",\n \"imageUrl\": \"string\",\n \"category\": \"string\"\n}"
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Import μ€ν
|
|
128
|
+
|
|
129
|
+
```graphql
|
|
130
|
+
mutation {
|
|
131
|
+
importFromExternalSource(input: {
|
|
132
|
+
projectId: 2
|
|
133
|
+
source: {
|
|
134
|
+
sourceType: "api"
|
|
135
|
+
sourceUrl: "https://api.example.com/images"
|
|
136
|
+
authHeader: "Bearer YOUR_TOKEN"
|
|
137
|
+
httpMethod: "GET"
|
|
138
|
+
dataPath: "data.items"
|
|
139
|
+
}
|
|
140
|
+
imageField: "imageUrl"
|
|
141
|
+
fieldMapping: "{\"id\":\"task_id\", \"category\":\"label\"}"
|
|
142
|
+
autoGeneratePredictions: true
|
|
143
|
+
limit: 100
|
|
144
|
+
}) {
|
|
145
|
+
totalFetched
|
|
146
|
+
tasksImported
|
|
147
|
+
tasksFailed
|
|
148
|
+
taskIds
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### API μλ΅ νμ
|
|
154
|
+
|
|
155
|
+
μΈλΆ APIλ λ€μ νμμΌλ‘ μλ΅ν΄μΌ ν©λλ€:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"data": {
|
|
160
|
+
"items": [
|
|
161
|
+
{
|
|
162
|
+
"id": "img-001",
|
|
163
|
+
"imageUrl": "https://storage.example.com/image1.jpg",
|
|
164
|
+
"category": "electronics",
|
|
165
|
+
"metadata": {
|
|
166
|
+
"width": 1920,
|
|
167
|
+
"height": 1080
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
]
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
λλ λ°°μ΄ μ§μ λ°ν:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
[
|
|
179
|
+
{
|
|
180
|
+
"id": "img-001",
|
|
181
|
+
"imageUrl": "https://storage.example.com/image1.jpg"
|
|
182
|
+
}
|
|
183
|
+
]
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## 3. JSON/CSV νμΌ Import
|
|
189
|
+
|
|
190
|
+
νμΌ URLμμ μ§μ λ°μ΄ν°λ₯Ό κ°μ Έμ΅λλ€.
|
|
191
|
+
|
|
192
|
+
### JSON νμΌ
|
|
193
|
+
|
|
194
|
+
```graphql
|
|
195
|
+
mutation {
|
|
196
|
+
importFromExternalSource(input: {
|
|
197
|
+
projectId: 2
|
|
198
|
+
source: {
|
|
199
|
+
sourceType: "json"
|
|
200
|
+
sourceUrl: "https://example.com/data/images.json"
|
|
201
|
+
dataPath: "images"
|
|
202
|
+
}
|
|
203
|
+
imageField: "url"
|
|
204
|
+
limit: 50
|
|
205
|
+
}) {
|
|
206
|
+
totalFetched
|
|
207
|
+
tasksImported
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**images.json μμ:**
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"images": [
|
|
216
|
+
{
|
|
217
|
+
"url": "https://example.com/img1.jpg",
|
|
218
|
+
"label": "cat",
|
|
219
|
+
"confidence": 0.95
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"url": "https://example.com/img2.jpg",
|
|
223
|
+
"label": "dog",
|
|
224
|
+
"confidence": 0.87
|
|
225
|
+
}
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### CSV νμΌ
|
|
231
|
+
|
|
232
|
+
```graphql
|
|
233
|
+
mutation {
|
|
234
|
+
importFromExternalSource(input: {
|
|
235
|
+
projectId: 2
|
|
236
|
+
source: {
|
|
237
|
+
sourceType: "csv"
|
|
238
|
+
sourceUrl: "https://example.com/data/images.csv"
|
|
239
|
+
}
|
|
240
|
+
imageField: "image_url"
|
|
241
|
+
limit: 50
|
|
242
|
+
}) {
|
|
243
|
+
totalFetched
|
|
244
|
+
tasksImported
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
**images.csv μμ:**
|
|
250
|
+
```csv
|
|
251
|
+
id,image_url,category,status
|
|
252
|
+
1,https://example.com/img1.jpg,electronics,new
|
|
253
|
+
2,https://example.com/img2.jpg,furniture,new
|
|
254
|
+
3,https://example.com/img3.jpg,clothing,new
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
## 4. ν΄λΌμ°λ μ€ν λ¦¬μ§ μ°λ
|
|
260
|
+
|
|
261
|
+
### S3/GCS/Azure Blob (Presigned URLs)
|
|
262
|
+
|
|
263
|
+
ν΄λΌμ°λ μ€ν 리μ§μ κ²½μ° presigned URLμ μ¬μ©ν©λλ€:
|
|
264
|
+
|
|
265
|
+
```graphql
|
|
266
|
+
mutation {
|
|
267
|
+
importFromExternalSource(input: {
|
|
268
|
+
projectId: 2
|
|
269
|
+
source: {
|
|
270
|
+
sourceType: "url"
|
|
271
|
+
sourceUrl: "https://my-bucket.s3.amazonaws.com/manifest.json?X-Amz-..."
|
|
272
|
+
}
|
|
273
|
+
imageField: "s3_url"
|
|
274
|
+
}) {
|
|
275
|
+
tasksImported
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**manifest.json μμ:**
|
|
281
|
+
```json
|
|
282
|
+
[
|
|
283
|
+
{
|
|
284
|
+
"s3_url": "https://my-bucket.s3.amazonaws.com/image1.jpg?X-Amz-...",
|
|
285
|
+
"object_key": "images/2025/01/image1.jpg",
|
|
286
|
+
"size": 245678,
|
|
287
|
+
"uploaded_at": "2025-01-13T10:00:00Z"
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
### Label Studio Cloud Storage μ§μ μ°λ
|
|
293
|
+
|
|
294
|
+
Label Studioλ ν΄λΌμ°λ μ€ν λ¦¬μ§ μ§μ μ°λλ μ§μν©λλ€:
|
|
295
|
+
|
|
296
|
+
1. **Label Studio UIμμ Storage μ€μ **
|
|
297
|
+
- Project Settings β Cloud Storage
|
|
298
|
+
- Add Source Storage (S3/GCS/Azure)
|
|
299
|
+
|
|
300
|
+
2. **Sync λ²νΌμΌλ‘ μλ import**
|
|
301
|
+
- Storageμμ μλμΌλ‘ task μμ±
|
|
302
|
+
- Label Studioκ° μ§μ μ€ν λ¦¬μ§ μ κ·Ό
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## π Field Mapping (νλ λ§€ν)
|
|
307
|
+
|
|
308
|
+
μμ€ λ°μ΄ν°μ νλλͺ
κ³Ό Label Studio νλλͺ
μ΄ λ€λ₯Ό λ λ§€νμ μ§μ ν©λλ€.
|
|
309
|
+
|
|
310
|
+
### μμ
|
|
311
|
+
|
|
312
|
+
**μμ€ λ°μ΄ν°:**
|
|
313
|
+
```json
|
|
314
|
+
{
|
|
315
|
+
"product_image": "https://...",
|
|
316
|
+
"sku": "SKU-123",
|
|
317
|
+
"inspection_date": "2025-01-13"
|
|
318
|
+
}
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
**Field Mapping:**
|
|
322
|
+
```json
|
|
323
|
+
{
|
|
324
|
+
"product_image": "image",
|
|
325
|
+
"sku": "product_id",
|
|
326
|
+
"inspection_date": "date"
|
|
327
|
+
}
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
**GraphQL:**
|
|
331
|
+
```graphql
|
|
332
|
+
mutation {
|
|
333
|
+
importFromExternalSource(input: {
|
|
334
|
+
projectId: 2
|
|
335
|
+
source: { ... }
|
|
336
|
+
imageField: "product_image"
|
|
337
|
+
fieldMapping: "{\"product_image\":\"image\",\"sku\":\"product_id\",\"inspection_date\":\"date\"}"
|
|
338
|
+
}) { ... }
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## π λ°μ΄ν° νλ¦ λ€μ΄μ΄κ·Έλ¨
|
|
345
|
+
|
|
346
|
+
```
|
|
347
|
+
βββββββββββββββββββ
|
|
348
|
+
β External API β
|
|
349
|
+
β JSON/CSV File β
|
|
350
|
+
β Cloud Storage β
|
|
351
|
+
ββββββββββ¬βββββββββ
|
|
352
|
+
β HTTP Request
|
|
353
|
+
βΌ
|
|
354
|
+
βββββββββββββββββββββββββββ
|
|
355
|
+
β ExternalDataSourceServiceβ
|
|
356
|
+
β - fetchFromSource() β
|
|
357
|
+
β - transformData() β
|
|
358
|
+
ββββββββββ¬βββββββββββββββββ
|
|
359
|
+
β Label Studio API
|
|
360
|
+
βΌ
|
|
361
|
+
βββββββββββββββββββ
|
|
362
|
+
β Label Studio β
|
|
363
|
+
β Project β
|
|
364
|
+
β (Tasks μμ±) β
|
|
365
|
+
βββββββββββββββββββ
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## π οΈ κ³ κΈ μ¬μ©λ²
|
|
371
|
+
|
|
372
|
+
### 1. μΈμ¦ ν€λ μ¬μ©
|
|
373
|
+
|
|
374
|
+
```graphql
|
|
375
|
+
source: {
|
|
376
|
+
sourceType: "api"
|
|
377
|
+
sourceUrl: "https://api.example.com/data"
|
|
378
|
+
authHeader: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### 2. POST μμ²μΌλ‘ λ°μ΄ν° κ°μ Έμ€κΈ°
|
|
383
|
+
|
|
384
|
+
```graphql
|
|
385
|
+
source: {
|
|
386
|
+
sourceType: "api"
|
|
387
|
+
sourceUrl: "https://api.example.com/search"
|
|
388
|
+
httpMethod: "POST"
|
|
389
|
+
requestBody: "{\"query\":\"defect images\",\"limit\":100}"
|
|
390
|
+
dataPath: "results"
|
|
391
|
+
}
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### 3. μ€μ²©λ λ°μ΄ν° μΆμΆ
|
|
395
|
+
|
|
396
|
+
```graphql
|
|
397
|
+
source: {
|
|
398
|
+
sourceType: "url"
|
|
399
|
+
sourceUrl: "https://example.com/data.json"
|
|
400
|
+
dataPath: "response.data.items" # response.data.items λ°°μ΄ μΆμΆ
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## π Best Practices
|
|
407
|
+
|
|
408
|
+
### 1. 미리보기 λ¨Όμ μ€ν
|
|
409
|
+
νμ `previewExternalDataSource`λ‘ λ°μ΄ν° ꡬ쑰λ₯Ό νμΈν ν importλ₯Ό μ€ννμΈμ.
|
|
410
|
+
|
|
411
|
+
### 2. λ°°μΉ ν¬κΈ° μ‘°μ
|
|
412
|
+
λλ λ°μ΄ν°λ `limit` νλΌλ―Έν°λ‘ λλμ΄ importν©λλ€:
|
|
413
|
+
```graphql
|
|
414
|
+
# 첫 λ²μ§Έ λ°°μΉ
|
|
415
|
+
mutation { importFromExternalSource(input: { limit: 100 }) { ... } }
|
|
416
|
+
|
|
417
|
+
# λ λ²μ§Έ λ°°μΉ (APIμμ offset/page μ§μ νμ)
|
|
418
|
+
mutation { importFromExternalSource(input: { limit: 100 }) { ... } }
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
### 3. μ€λ₯ μ²λ¦¬
|
|
422
|
+
Import κ²°κ³Όλ₯Ό νμΈνκ³ μ€ν¨ν νλͺ©μ μ¬μλν©λλ€:
|
|
423
|
+
```graphql
|
|
424
|
+
mutation {
|
|
425
|
+
importFromExternalSource(input: { ... }) {
|
|
426
|
+
totalFetched
|
|
427
|
+
tasksImported
|
|
428
|
+
tasksFailed # μ΄ κ° νμΈ
|
|
429
|
+
error
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 4. μ΄λ―Έμ§ URL κ²μ¦
|
|
435
|
+
Import μ μ μ΄λ―Έμ§ URLμ΄ μ ν¨νμ§ νμΈνμΈμ:
|
|
436
|
+
- URLμ΄ κ³΅κ° μ κ·Ό κ°λ₯νμ§
|
|
437
|
+
- CORS μ€μ μ΄ μ¬λ°λ₯Έμ§
|
|
438
|
+
- Presigned URLμ λ§λ£ μκ° νμΈ
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## π¨ λ¬Έμ ν΄κ²°
|
|
443
|
+
|
|
444
|
+
### "No image URL found"
|
|
445
|
+
- `imageField` νλΌλ―Έν°λ₯Ό μμ€ λ°μ΄ν°μ μ€μ νλλͺ
μΌλ‘ μ€μ
|
|
446
|
+
- Previewλ‘ λ°μ΄ν° ꡬ쑰 νμΈ
|
|
447
|
+
|
|
448
|
+
### "401 Unauthorized"
|
|
449
|
+
- `authHeader`μ μ ν¨ν μΈμ¦ ν ν° μ€μ
|
|
450
|
+
- API ν€λ Bearer ν ν° νμΈ
|
|
451
|
+
|
|
452
|
+
### "Path not found in data"
|
|
453
|
+
- `dataPath`κ° μ¬λ°λ₯Έμ§ νμΈ
|
|
454
|
+
- Previewλ‘ μ€μ μλ΅ κ΅¬μ‘° νμΈ
|
|
455
|
+
|
|
456
|
+
### Importλ μ±κ³΅νμ§λ§ μ΄λ―Έμ§κ° μ 보μ
|
|
457
|
+
- Label Studioμμ μ΄λ―Έμ§ URL μ κ·Ό κ°λ₯νμ§ νμΈ
|
|
458
|
+
- CORS μ€μ νμΈ
|
|
459
|
+
- Presigned URL λ§λ£ νμΈ
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
## π μ°Έκ³ μλ£
|
|
464
|
+
|
|
465
|
+
- [Label Studio API Documentation](https://labelstud.io/api)
|
|
466
|
+
- [Label Studio Cloud Storage](https://labelstud.io/guide/storage.html)
|
|
467
|
+
- [Things Factory Dataset Module](../dataset/README.md)
|
|
468
|
+
|
|
469
|
+
---
|
|
470
|
+
|
|
471
|
+
## π― μμ½
|
|
472
|
+
|
|
473
|
+
| λ°©λ² | μ©λ | μ₯μ | λ¨μ |
|
|
474
|
+
|------|------|------|------|
|
|
475
|
+
| **Dataset λͺ¨λ** | Things Factory λ΄λΆ λ°μ΄ν° | μλ λ³ν, μλ°©ν₯ λκΈ°ν | Things Factory μ μ© |
|
|
476
|
+
| **REST API** | μΈλΆ μμ€ν
μ°λ | μ€μκ° λ°μ΄ν°, λμ μ‘°ν | API κ°λ° νμ |
|
|
477
|
+
| **JSON/CSV νμΌ** | μ μ λ°μ΄ν°μ
| κ°λ¨ν¨, νμ€ νμ | μλ μ
λ°μ΄νΈ νμ |
|
|
478
|
+
| **Cloud Storage** | λμ©λ μ΄λ―Έμ§ | νμ₯μ±, λΉμ© ν¨μ¨ | μ€μ λ³΅μ‘ |
|
|
479
|
+
|
|
480
|
+
**μΆμ² μμ:**
|
|
481
|
+
1. Things Factory λ΄λΆ λ°μ΄ν° β **Dataset λͺ¨λ**
|
|
482
|
+
2. μΈλΆ API μμ β **REST API μ°λ**
|
|
483
|
+
3. νμΌ νν λ°μ΄ν° β **JSON/CSV Import**
|
|
484
|
+
4. λμ©λ μ΄λ―Έμ§ β **Cloud Storage**
|