label-studio-converter 1.0.0

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.
@@ -0,0 +1,1296 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __esm = (fn, res) => function __init() {
10
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
11
+ };
12
+ var __export = (target, all) => {
13
+ for (var name in all)
14
+ __defProp(target, name, { get: all[name], enumerable: true });
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // node_modules/.pnpm/tsup@8.5.1_jiti@2.4.2_postcss@8.5.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js
34
+ var init_cjs_shims = __esm({
35
+ "node_modules/.pnpm/tsup@8.5.1_jiti@2.4.2_postcss@8.5.6_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/cjs_shims.js"() {
36
+ "use strict";
37
+ }
38
+ });
39
+
40
+ // src/constants.ts
41
+ var OUTPUT_BASE_DIR, DEFAULT_LABEL_NAME, DEFAULT_LABEL_STUDIO_FULL_JSON, DEFAULT_CREATE_FILE_PER_IMAGE, DEFAULT_CREATE_FILE_LIST_FOR_SERVING, DEFAULT_FILE_LIST_NAME, DEFAULT_BASE_SERVER_URL, DEFAULT_PPOCR_FILE_NAME, SORT_VERTICAL_NONE, SORT_VERTICAL_TOP_BOTTOM, SORT_VERTICAL_BOTTOM_TOP, DEFAULT_SORT_VERTICAL, SORT_HORIZONTAL_NONE, SORT_HORIZONTAL_LTR, SORT_HORIZONTAL_RTL, DEFAULT_SORT_HORIZONTAL;
42
+ var init_constants = __esm({
43
+ "src/constants.ts"() {
44
+ "use strict";
45
+ init_cjs_shims();
46
+ OUTPUT_BASE_DIR = "./output";
47
+ DEFAULT_LABEL_NAME = "Text";
48
+ DEFAULT_LABEL_STUDIO_FULL_JSON = true;
49
+ DEFAULT_CREATE_FILE_PER_IMAGE = false;
50
+ DEFAULT_CREATE_FILE_LIST_FOR_SERVING = true;
51
+ DEFAULT_FILE_LIST_NAME = "files.txt";
52
+ DEFAULT_BASE_SERVER_URL = "http://localhost:8081";
53
+ DEFAULT_PPOCR_FILE_NAME = "Label.txt";
54
+ SORT_VERTICAL_NONE = "none";
55
+ SORT_VERTICAL_TOP_BOTTOM = "top-bottom";
56
+ SORT_VERTICAL_BOTTOM_TOP = "bottom-top";
57
+ DEFAULT_SORT_VERTICAL = SORT_VERTICAL_NONE;
58
+ SORT_HORIZONTAL_NONE = "none";
59
+ SORT_HORIZONTAL_LTR = "ltr";
60
+ SORT_HORIZONTAL_RTL = "rtl";
61
+ DEFAULT_SORT_HORIZONTAL = SORT_HORIZONTAL_NONE;
62
+ }
63
+ });
64
+
65
+ // src/lib/ppocr-label.ts
66
+ var import_node_crypto, import_node_fs, import_node_path, import_image_size, ppocrToLabelStudio, ppocrToFullLabelStudio, ppocrToMinLabelStudio;
67
+ var init_ppocr_label = __esm({
68
+ "src/lib/ppocr-label.ts"() {
69
+ "use strict";
70
+ init_cjs_shims();
71
+ import_node_crypto = require("crypto");
72
+ import_node_fs = require("fs");
73
+ import_node_path = require("path");
74
+ import_image_size = __toESM(require("image-size"), 1);
75
+ init_constants();
76
+ ppocrToLabelStudio = async (data, options) => {
77
+ const {
78
+ imagePath,
79
+ baseServerUrl,
80
+ inputDir,
81
+ toFullJson = true,
82
+ taskId = 1,
83
+ labelName = DEFAULT_LABEL_NAME
84
+ } = options || {};
85
+ if (toFullJson) {
86
+ return ppocrToFullLabelStudio(
87
+ data,
88
+ imagePath,
89
+ baseServerUrl,
90
+ inputDir,
91
+ taskId,
92
+ labelName
93
+ );
94
+ } else {
95
+ return ppocrToMinLabelStudio(
96
+ data,
97
+ imagePath,
98
+ baseServerUrl,
99
+ inputDir,
100
+ labelName
101
+ );
102
+ }
103
+ };
104
+ ppocrToFullLabelStudio = (data, imagePath, baseServerUrl, inputDir, taskId = 1, labelName = DEFAULT_LABEL_NAME) => {
105
+ const newBaseServerUrl = baseServerUrl.replace(/\/+$/, "") + (baseServerUrl === "" ? "" : "/");
106
+ const now = (/* @__PURE__ */ new Date()).toISOString();
107
+ let original_width = 1920;
108
+ let original_height = 1080;
109
+ const resolvedImagePath = inputDir ? (0, import_node_path.join)(inputDir, imagePath) : imagePath;
110
+ if (!(0, import_node_fs.existsSync)(resolvedImagePath)) {
111
+ throw new Error(`Image file not found: ${resolvedImagePath}`);
112
+ }
113
+ const buffer = (0, import_node_fs.readFileSync)(resolvedImagePath);
114
+ const dimensions = (0, import_image_size.default)(buffer);
115
+ if (!dimensions.width || !dimensions.height) {
116
+ throw new Error(
117
+ `Failed to read image dimensions from: ${resolvedImagePath}`
118
+ );
119
+ }
120
+ original_width = dimensions.width;
121
+ original_height = dimensions.height;
122
+ const fileName = imagePath.split("/").pop() || imagePath;
123
+ const result = [
124
+ {
125
+ id: taskId,
126
+ annotations: [
127
+ {
128
+ id: taskId,
129
+ completed_by: 1,
130
+ result: data.map((item) => {
131
+ const { points } = item;
132
+ const annotationId = (0, import_node_crypto.randomUUID)().slice(0, 10);
133
+ const polygonPoints = points.map(([x, y]) => [
134
+ (x ?? 0) / original_width * 100,
135
+ (y ?? 0) / original_height * 100
136
+ ]);
137
+ return [
138
+ // 1. Polygon geometry only
139
+ {
140
+ original_width,
141
+ original_height,
142
+ image_rotation: 0,
143
+ value: {
144
+ points: polygonPoints,
145
+ closed: true
146
+ },
147
+ id: annotationId,
148
+ from_name: "poly",
149
+ to_name: "image",
150
+ type: "polygon",
151
+ origin: "manual"
152
+ },
153
+ // 2. Labels with polygon geometry
154
+ {
155
+ original_width,
156
+ original_height,
157
+ image_rotation: 0,
158
+ value: {
159
+ points: polygonPoints,
160
+ closed: true,
161
+ labels: [labelName]
162
+ },
163
+ id: annotationId,
164
+ from_name: "label",
165
+ to_name: "image",
166
+ type: "labels",
167
+ origin: "manual"
168
+ },
169
+ // 3. Textarea with polygon geometry and text
170
+ {
171
+ original_width,
172
+ original_height,
173
+ image_rotation: 0,
174
+ value: {
175
+ points: polygonPoints,
176
+ closed: true,
177
+ text: [item.transcription]
178
+ },
179
+ id: annotationId,
180
+ from_name: "transcription",
181
+ to_name: "image",
182
+ type: "textarea",
183
+ origin: "manual"
184
+ }
185
+ ];
186
+ }).flat(),
187
+ was_cancelled: false,
188
+ ground_truth: false,
189
+ created_at: now,
190
+ updated_at: now,
191
+ draft_created_at: now,
192
+ lead_time: 0,
193
+ prediction: {},
194
+ result_count: data.length * 3,
195
+ unique_id: (0, import_node_crypto.randomUUID)(),
196
+ import_id: null,
197
+ last_action: null,
198
+ bulk_created: false,
199
+ task: taskId,
200
+ project: 1,
201
+ updated_by: 1,
202
+ parent_prediction: null,
203
+ parent_annotation: null,
204
+ last_created_by: null
205
+ }
206
+ ],
207
+ file_upload: fileName,
208
+ drafts: [],
209
+ predictions: [],
210
+ data: { ocr: `${newBaseServerUrl}${imagePath}` },
211
+ meta: {},
212
+ created_at: now,
213
+ updated_at: now,
214
+ allow_skip: false,
215
+ inner_id: taskId,
216
+ total_annotations: 1,
217
+ cancelled_annotations: 0,
218
+ total_predictions: 0,
219
+ comment_count: 0,
220
+ unresolved_comment_count: 0,
221
+ last_comment_updated_at: null,
222
+ project: 1,
223
+ updated_by: 1,
224
+ comment_authors: []
225
+ }
226
+ ];
227
+ return result;
228
+ };
229
+ ppocrToMinLabelStudio = (data, imagePath, baseServerUrl, inputDir, labelName = "text") => {
230
+ const newBaseServerUrl = baseServerUrl.replace(/\/+$/, "") + (baseServerUrl === "" ? "" : "/");
231
+ const now = (/* @__PURE__ */ new Date()).toISOString();
232
+ let original_width = 1920;
233
+ let original_height = 1080;
234
+ const resolvedImagePath = inputDir ? (0, import_node_path.join)(inputDir, imagePath) : imagePath;
235
+ if (!(0, import_node_fs.existsSync)(resolvedImagePath)) {
236
+ throw new Error(`Image file not found: ${resolvedImagePath}`);
237
+ }
238
+ const buffer = (0, import_node_fs.readFileSync)(resolvedImagePath);
239
+ const dimensions = (0, import_image_size.default)(buffer);
240
+ if (!dimensions.width || !dimensions.height) {
241
+ throw new Error(
242
+ `Failed to read image dimensions from: ${resolvedImagePath}`
243
+ );
244
+ }
245
+ original_width = dimensions.width;
246
+ original_height = dimensions.height;
247
+ return data.map((item, index) => {
248
+ const { points } = item;
249
+ let minX = Infinity;
250
+ let minY = Infinity;
251
+ let maxX = -Infinity;
252
+ let maxY = -Infinity;
253
+ for (const point of points) {
254
+ const [x, y] = point;
255
+ if (x !== void 0 && y !== void 0) {
256
+ minX = Math.min(minX, x);
257
+ minY = Math.min(minY, y);
258
+ maxX = Math.max(maxX, x);
259
+ maxY = Math.max(maxY, y);
260
+ }
261
+ }
262
+ const width = maxX - minX;
263
+ const height = maxY - minY;
264
+ return {
265
+ ocr: encodeURI(`${newBaseServerUrl}${imagePath}`),
266
+ id: index + 1,
267
+ bbox: [
268
+ {
269
+ x: minX,
270
+ y: minY,
271
+ width,
272
+ height,
273
+ rotation: 0,
274
+ original_width,
275
+ original_height
276
+ }
277
+ ],
278
+ label: [
279
+ {
280
+ points,
281
+ closed: true,
282
+ labels: [labelName],
283
+ original_width,
284
+ original_height
285
+ }
286
+ ],
287
+ transcription: [item.transcription],
288
+ poly: [
289
+ {
290
+ points,
291
+ closed: true,
292
+ original_width,
293
+ original_height
294
+ }
295
+ ],
296
+ annotator: 1,
297
+ annotation_id: index + 1,
298
+ created_at: now,
299
+ updated_at: now,
300
+ lead_time: 0
301
+ };
302
+ });
303
+ };
304
+ }
305
+ });
306
+
307
+ // src/lib/schema.ts
308
+ var import_zod, FullOCRLabelStudioSchema, MinOCRLabelStudioSchema, PPOCRLabelSchema;
309
+ var init_schema = __esm({
310
+ "src/lib/schema.ts"() {
311
+ "use strict";
312
+ init_cjs_shims();
313
+ import_zod = __toESM(require("zod"), 1);
314
+ FullOCRLabelStudioSchema = import_zod.default.array(
315
+ import_zod.default.object({
316
+ id: import_zod.default.number(),
317
+ annotations: import_zod.default.array(
318
+ import_zod.default.object({
319
+ id: import_zod.default.number(),
320
+ completed_by: import_zod.default.number(),
321
+ result: import_zod.default.array(
322
+ import_zod.default.union([
323
+ import_zod.default.object({
324
+ original_width: import_zod.default.number(),
325
+ original_height: import_zod.default.number(),
326
+ image_rotation: import_zod.default.number(),
327
+ value: import_zod.default.object({
328
+ x: import_zod.default.number(),
329
+ y: import_zod.default.number(),
330
+ width: import_zod.default.number(),
331
+ height: import_zod.default.number(),
332
+ rotation: import_zod.default.number()
333
+ }),
334
+ id: import_zod.default.string(),
335
+ from_name: import_zod.default.string(),
336
+ to_name: import_zod.default.string(),
337
+ type: import_zod.default.string(),
338
+ origin: import_zod.default.string()
339
+ }),
340
+ import_zod.default.object({
341
+ original_width: import_zod.default.number(),
342
+ original_height: import_zod.default.number(),
343
+ image_rotation: import_zod.default.number(),
344
+ value: import_zod.default.object({
345
+ x: import_zod.default.number(),
346
+ y: import_zod.default.number(),
347
+ width: import_zod.default.number(),
348
+ height: import_zod.default.number(),
349
+ rotation: import_zod.default.number(),
350
+ labels: import_zod.default.array(import_zod.default.string())
351
+ }),
352
+ id: import_zod.default.string(),
353
+ from_name: import_zod.default.string(),
354
+ to_name: import_zod.default.string(),
355
+ type: import_zod.default.string(),
356
+ origin: import_zod.default.string()
357
+ }),
358
+ import_zod.default.object({
359
+ original_width: import_zod.default.number(),
360
+ original_height: import_zod.default.number(),
361
+ image_rotation: import_zod.default.number(),
362
+ value: import_zod.default.object({
363
+ x: import_zod.default.number(),
364
+ y: import_zod.default.number(),
365
+ width: import_zod.default.number(),
366
+ height: import_zod.default.number(),
367
+ rotation: import_zod.default.number(),
368
+ text: import_zod.default.array(import_zod.default.string())
369
+ }),
370
+ id: import_zod.default.string(),
371
+ from_name: import_zod.default.string(),
372
+ to_name: import_zod.default.string(),
373
+ type: import_zod.default.string(),
374
+ origin: import_zod.default.string()
375
+ }),
376
+ import_zod.default.object({
377
+ original_width: import_zod.default.number(),
378
+ original_height: import_zod.default.number(),
379
+ image_rotation: import_zod.default.number(),
380
+ value: import_zod.default.object({
381
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
382
+ closed: import_zod.default.boolean()
383
+ }),
384
+ id: import_zod.default.string(),
385
+ from_name: import_zod.default.string(),
386
+ to_name: import_zod.default.string(),
387
+ type: import_zod.default.string(),
388
+ origin: import_zod.default.string()
389
+ }),
390
+ import_zod.default.object({
391
+ original_width: import_zod.default.number(),
392
+ original_height: import_zod.default.number(),
393
+ image_rotation: import_zod.default.number(),
394
+ value: import_zod.default.object({
395
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
396
+ closed: import_zod.default.boolean(),
397
+ labels: import_zod.default.array(import_zod.default.string())
398
+ }),
399
+ id: import_zod.default.string(),
400
+ from_name: import_zod.default.string(),
401
+ to_name: import_zod.default.string(),
402
+ type: import_zod.default.string(),
403
+ origin: import_zod.default.string()
404
+ }),
405
+ import_zod.default.object({
406
+ original_width: import_zod.default.number(),
407
+ original_height: import_zod.default.number(),
408
+ image_rotation: import_zod.default.number(),
409
+ value: import_zod.default.object({
410
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
411
+ closed: import_zod.default.boolean(),
412
+ text: import_zod.default.array(import_zod.default.string())
413
+ }),
414
+ id: import_zod.default.string(),
415
+ from_name: import_zod.default.string(),
416
+ to_name: import_zod.default.string(),
417
+ type: import_zod.default.string(),
418
+ origin: import_zod.default.string()
419
+ })
420
+ ])
421
+ ),
422
+ was_cancelled: import_zod.default.boolean(),
423
+ ground_truth: import_zod.default.boolean(),
424
+ created_at: import_zod.default.string(),
425
+ updated_at: import_zod.default.string(),
426
+ draft_created_at: import_zod.default.string(),
427
+ lead_time: import_zod.default.number(),
428
+ prediction: import_zod.default.object({}),
429
+ result_count: import_zod.default.number(),
430
+ unique_id: import_zod.default.string(),
431
+ import_id: import_zod.default.null(),
432
+ last_action: import_zod.default.null(),
433
+ bulk_created: import_zod.default.boolean(),
434
+ task: import_zod.default.number(),
435
+ project: import_zod.default.number(),
436
+ updated_by: import_zod.default.number(),
437
+ parent_prediction: import_zod.default.null(),
438
+ parent_annotation: import_zod.default.null(),
439
+ last_created_by: import_zod.default.null()
440
+ })
441
+ ),
442
+ file_upload: import_zod.default.string(),
443
+ drafts: import_zod.default.array(
444
+ import_zod.default.object({
445
+ id: import_zod.default.number(),
446
+ user: import_zod.default.string(),
447
+ created_username: import_zod.default.string(),
448
+ created_ago: import_zod.default.string(),
449
+ result: import_zod.default.array(
450
+ import_zod.default.union([
451
+ import_zod.default.object({
452
+ original_width: import_zod.default.number(),
453
+ original_height: import_zod.default.number(),
454
+ image_rotation: import_zod.default.number(),
455
+ value: import_zod.default.object({
456
+ x: import_zod.default.number(),
457
+ y: import_zod.default.number(),
458
+ width: import_zod.default.number(),
459
+ height: import_zod.default.number(),
460
+ rotation: import_zod.default.number()
461
+ }),
462
+ id: import_zod.default.string(),
463
+ from_name: import_zod.default.string(),
464
+ to_name: import_zod.default.string(),
465
+ type: import_zod.default.string(),
466
+ origin: import_zod.default.string()
467
+ }),
468
+ import_zod.default.object({
469
+ original_width: import_zod.default.number(),
470
+ original_height: import_zod.default.number(),
471
+ image_rotation: import_zod.default.number(),
472
+ value: import_zod.default.object({
473
+ x: import_zod.default.number(),
474
+ y: import_zod.default.number(),
475
+ width: import_zod.default.number(),
476
+ height: import_zod.default.number(),
477
+ rotation: import_zod.default.number(),
478
+ labels: import_zod.default.array(import_zod.default.string())
479
+ }),
480
+ id: import_zod.default.string(),
481
+ from_name: import_zod.default.string(),
482
+ to_name: import_zod.default.string(),
483
+ type: import_zod.default.string(),
484
+ origin: import_zod.default.string()
485
+ }),
486
+ import_zod.default.object({
487
+ original_width: import_zod.default.number(),
488
+ original_height: import_zod.default.number(),
489
+ image_rotation: import_zod.default.number(),
490
+ value: import_zod.default.object({
491
+ x: import_zod.default.number(),
492
+ y: import_zod.default.number(),
493
+ width: import_zod.default.number(),
494
+ height: import_zod.default.number(),
495
+ rotation: import_zod.default.number(),
496
+ text: import_zod.default.array(import_zod.default.string())
497
+ }),
498
+ id: import_zod.default.string(),
499
+ from_name: import_zod.default.string(),
500
+ to_name: import_zod.default.string(),
501
+ type: import_zod.default.string(),
502
+ origin: import_zod.default.string()
503
+ }),
504
+ import_zod.default.object({
505
+ original_width: import_zod.default.number(),
506
+ original_height: import_zod.default.number(),
507
+ image_rotation: import_zod.default.number(),
508
+ value: import_zod.default.object({
509
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
510
+ closed: import_zod.default.boolean()
511
+ }),
512
+ id: import_zod.default.string(),
513
+ from_name: import_zod.default.string(),
514
+ to_name: import_zod.default.string(),
515
+ type: import_zod.default.string(),
516
+ origin: import_zod.default.string()
517
+ }),
518
+ import_zod.default.object({
519
+ original_width: import_zod.default.number(),
520
+ original_height: import_zod.default.number(),
521
+ image_rotation: import_zod.default.number(),
522
+ value: import_zod.default.object({
523
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
524
+ closed: import_zod.default.boolean(),
525
+ labels: import_zod.default.array(import_zod.default.string())
526
+ }),
527
+ id: import_zod.default.string(),
528
+ from_name: import_zod.default.string(),
529
+ to_name: import_zod.default.string(),
530
+ type: import_zod.default.string(),
531
+ origin: import_zod.default.string()
532
+ }),
533
+ import_zod.default.object({
534
+ original_width: import_zod.default.number(),
535
+ original_height: import_zod.default.number(),
536
+ image_rotation: import_zod.default.number(),
537
+ value: import_zod.default.object({
538
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
539
+ closed: import_zod.default.boolean(),
540
+ text: import_zod.default.array(import_zod.default.string())
541
+ }),
542
+ id: import_zod.default.string(),
543
+ from_name: import_zod.default.string(),
544
+ to_name: import_zod.default.string(),
545
+ type: import_zod.default.string(),
546
+ origin: import_zod.default.string()
547
+ })
548
+ ])
549
+ ),
550
+ lead_time: import_zod.default.number(),
551
+ was_postponed: import_zod.default.boolean(),
552
+ import_id: import_zod.default.null(),
553
+ created_at: import_zod.default.string(),
554
+ updated_at: import_zod.default.string(),
555
+ task: import_zod.default.number(),
556
+ annotation: import_zod.default.number()
557
+ })
558
+ ),
559
+ predictions: import_zod.default.array(import_zod.default.unknown()),
560
+ data: import_zod.default.object({ ocr: import_zod.default.string() }),
561
+ meta: import_zod.default.object({}),
562
+ created_at: import_zod.default.string(),
563
+ updated_at: import_zod.default.string(),
564
+ allow_skip: import_zod.default.boolean(),
565
+ inner_id: import_zod.default.number(),
566
+ total_annotations: import_zod.default.number(),
567
+ cancelled_annotations: import_zod.default.number(),
568
+ total_predictions: import_zod.default.number(),
569
+ comment_count: import_zod.default.number(),
570
+ unresolved_comment_count: import_zod.default.number(),
571
+ last_comment_updated_at: import_zod.default.null(),
572
+ project: import_zod.default.number(),
573
+ updated_by: import_zod.default.number(),
574
+ comment_authors: import_zod.default.array(import_zod.default.unknown())
575
+ })
576
+ );
577
+ MinOCRLabelStudioSchema = import_zod.default.array(
578
+ import_zod.default.object({
579
+ ocr: import_zod.default.string(),
580
+ id: import_zod.default.number(),
581
+ bbox: import_zod.default.array(
582
+ import_zod.default.object({
583
+ x: import_zod.default.number(),
584
+ y: import_zod.default.number(),
585
+ width: import_zod.default.number(),
586
+ height: import_zod.default.number(),
587
+ rotation: import_zod.default.number(),
588
+ original_width: import_zod.default.number(),
589
+ original_height: import_zod.default.number()
590
+ })
591
+ ),
592
+ label: import_zod.default.array(
593
+ import_zod.default.union([
594
+ import_zod.default.object({
595
+ x: import_zod.default.number(),
596
+ y: import_zod.default.number(),
597
+ width: import_zod.default.number(),
598
+ height: import_zod.default.number(),
599
+ rotation: import_zod.default.number(),
600
+ labels: import_zod.default.array(import_zod.default.string()),
601
+ original_width: import_zod.default.number(),
602
+ original_height: import_zod.default.number()
603
+ }),
604
+ import_zod.default.object({
605
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
606
+ closed: import_zod.default.boolean(),
607
+ labels: import_zod.default.array(import_zod.default.string()),
608
+ original_width: import_zod.default.number(),
609
+ original_height: import_zod.default.number()
610
+ })
611
+ ])
612
+ ),
613
+ transcription: import_zod.default.array(import_zod.default.string()),
614
+ poly: import_zod.default.array(
615
+ import_zod.default.object({
616
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
617
+ closed: import_zod.default.boolean(),
618
+ original_width: import_zod.default.number(),
619
+ original_height: import_zod.default.number()
620
+ })
621
+ ),
622
+ annotator: import_zod.default.number(),
623
+ annotation_id: import_zod.default.number(),
624
+ created_at: import_zod.default.string(),
625
+ updated_at: import_zod.default.string(),
626
+ lead_time: import_zod.default.number()
627
+ })
628
+ );
629
+ PPOCRLabelSchema = import_zod.default.array(
630
+ import_zod.default.object({
631
+ transcription: import_zod.default.string(),
632
+ points: import_zod.default.array(import_zod.default.array(import_zod.default.number())),
633
+ dt_score: import_zod.default.number()
634
+ })
635
+ );
636
+ }
637
+ });
638
+
639
+ // src/lib/sort.ts
640
+ function getBoundingBoxCenter(points) {
641
+ let minX = Infinity;
642
+ let minY = Infinity;
643
+ let maxX = -Infinity;
644
+ let maxY = -Infinity;
645
+ for (const [x, y] of points) {
646
+ if (x !== void 0 && y !== void 0) {
647
+ minX = Math.min(minX, x);
648
+ minY = Math.min(minY, y);
649
+ maxX = Math.max(maxX, x);
650
+ maxY = Math.max(maxY, y);
651
+ }
652
+ }
653
+ return {
654
+ x: (minX + maxX) / 2,
655
+ y: (minY + maxY) / 2,
656
+ width: maxX - minX,
657
+ height: maxY - minY
658
+ };
659
+ }
660
+ function sortBoundingBoxes(annotations, verticalSort, horizontalSort) {
661
+ if (verticalSort === SORT_VERTICAL_NONE && horizontalSort === SORT_HORIZONTAL_NONE) {
662
+ return annotations;
663
+ }
664
+ const sorted = [...annotations];
665
+ const isVerticalText = sorted.length > 0 && (() => {
666
+ const verticalCount = sorted.filter((ann) => {
667
+ const center = getBoundingBoxCenter(ann.points);
668
+ return center.height > center.width * 1.5;
669
+ }).length;
670
+ return verticalCount > sorted.length / 2;
671
+ })();
672
+ if (horizontalSort === SORT_HORIZONTAL_RTL && verticalSort !== SORT_VERTICAL_NONE && isVerticalText) {
673
+ const annotationsWithCenters = sorted.map((ann) => ({
674
+ annotation: ann,
675
+ center: getBoundingBoxCenter(ann.points)
676
+ }));
677
+ const columns = [];
678
+ for (const item of annotationsWithCenters) {
679
+ let addedToColumn = false;
680
+ for (const column of columns) {
681
+ const avgX = column.reduce((sum, c) => sum + c.center.x, 0) / column.length;
682
+ if (Math.abs(item.center.x - avgX) < GROUPING_TOLERANCE) {
683
+ column.push(item);
684
+ addedToColumn = true;
685
+ break;
686
+ }
687
+ }
688
+ if (!addedToColumn) {
689
+ columns.push([item]);
690
+ }
691
+ }
692
+ columns.sort((colA, colB) => {
693
+ const avgXA = colA.reduce((sum, c) => sum + c.center.x, 0) / colA.length;
694
+ const avgXB = colB.reduce((sum, c) => sum + c.center.x, 0) / colB.length;
695
+ return avgXB - avgXA;
696
+ });
697
+ for (const column of columns) {
698
+ column.sort((a, b) => {
699
+ return verticalSort === SORT_VERTICAL_TOP_BOTTOM ? a.center.y - b.center.y : b.center.y - a.center.y;
700
+ });
701
+ }
702
+ return columns.flat().map((item) => item.annotation);
703
+ }
704
+ sorted.sort((a, b) => {
705
+ const centerA = getBoundingBoxCenter(a.points);
706
+ const centerB = getBoundingBoxCenter(b.points);
707
+ if (verticalSort !== SORT_VERTICAL_NONE) {
708
+ const yDiff = verticalSort === SORT_VERTICAL_TOP_BOTTOM ? centerA.y - centerB.y : centerB.y - centerA.y;
709
+ if (Math.abs(yDiff) > GROUPING_TOLERANCE) {
710
+ return yDiff;
711
+ }
712
+ }
713
+ if (horizontalSort !== SORT_HORIZONTAL_NONE) {
714
+ return horizontalSort === SORT_HORIZONTAL_LTR ? centerA.x - centerB.x : centerB.x - centerA.x;
715
+ }
716
+ return 0;
717
+ });
718
+ return sorted;
719
+ }
720
+ var GROUPING_TOLERANCE;
721
+ var init_sort = __esm({
722
+ "src/lib/sort.ts"() {
723
+ "use strict";
724
+ init_cjs_shims();
725
+ init_constants();
726
+ GROUPING_TOLERANCE = 50;
727
+ }
728
+ });
729
+
730
+ // src/commands/toLabelStudio/impl.ts
731
+ var impl_exports = {};
732
+ __export(impl_exports, {
733
+ convertToLabelStudio: () => convertToLabelStudio
734
+ });
735
+ async function convertToLabelStudio(flags, ...inputDirs) {
736
+ const {
737
+ outDir = OUTPUT_BASE_DIR,
738
+ defaultLabelName = DEFAULT_LABEL_NAME,
739
+ toFullJson = DEFAULT_LABEL_STUDIO_FULL_JSON,
740
+ createFilePerImage = DEFAULT_CREATE_FILE_PER_IMAGE,
741
+ createFileListForServing = DEFAULT_CREATE_FILE_LIST_FOR_SERVING,
742
+ fileListName = DEFAULT_FILE_LIST_NAME,
743
+ baseServerUrl = DEFAULT_BASE_SERVER_URL,
744
+ sortVertical = DEFAULT_SORT_VERTICAL,
745
+ sortHorizontal = DEFAULT_SORT_HORIZONTAL
746
+ } = flags;
747
+ const newBaseServerUrl = baseServerUrl.replace(/\/+$/, "") + (baseServerUrl === "" ? "" : "/");
748
+ await (0, import_promises.mkdir)(outDir, { recursive: true });
749
+ for (const inputDir of inputDirs) {
750
+ console.log(import_chalk.default.blue(`Processing input directory: ${inputDir}`));
751
+ const files = await (0, import_promises.readdir)(inputDir);
752
+ for (const file of files) {
753
+ if (!file.endsWith(".txt")) {
754
+ continue;
755
+ }
756
+ const filePath = (0, import_path.join)(inputDir, file);
757
+ console.log(import_chalk.default.gray(`Processing file: ${file}`));
758
+ try {
759
+ const fileData = await (0, import_promises.readFile)(filePath, "utf-8");
760
+ const lines = fileData.trim().split("\n");
761
+ const imageDataMap = /* @__PURE__ */ new Map();
762
+ for (const line of lines) {
763
+ const parts = line.split(" ");
764
+ if (parts.length !== 2) {
765
+ throw new Error(`Invalid PPOCRLabelV2 format in line: ${line}`);
766
+ }
767
+ const [imagePath, annotationsStr] = parts;
768
+ const annotations = JSON.parse(annotationsStr);
769
+ PPOCRLabelSchema.parse(annotations);
770
+ imageDataMap.set(imagePath, annotations);
771
+ }
772
+ const allLabelStudioData = [];
773
+ const fileList = [];
774
+ let taskId = 1;
775
+ for (const [imagePath, ppocrData] of imageDataMap.entries()) {
776
+ const sortedPpocrData = sortBoundingBoxes(
777
+ ppocrData,
778
+ sortVertical,
779
+ sortHorizontal
780
+ );
781
+ const finalImagePath = createFileListForServing ? encodeURI(`${newBaseServerUrl}${imagePath}`) : imagePath;
782
+ const labelStudioData = await ppocrToLabelStudio(sortedPpocrData, {
783
+ toFullJson,
784
+ imagePath,
785
+ baseServerUrl: newBaseServerUrl,
786
+ inputDir,
787
+ taskId,
788
+ labelName: defaultLabelName
789
+ });
790
+ if (toFullJson) {
791
+ allLabelStudioData.push(labelStudioData[0]);
792
+ } else {
793
+ allLabelStudioData.push(...labelStudioData);
794
+ }
795
+ if (createFilePerImage) {
796
+ const imageBaseName = imagePath.replace(/\//g, "_").replace(/\.[^.]+$/, "");
797
+ const individualOutputPath = (0, import_path.join)(
798
+ outDir,
799
+ `${imageBaseName}_${toFullJson ? "full" : "min"}.json`
800
+ );
801
+ await (0, import_promises.writeFile)(
802
+ individualOutputPath,
803
+ JSON.stringify(
804
+ toFullJson ? labelStudioData[0] : labelStudioData,
805
+ null,
806
+ 2
807
+ ),
808
+ "utf-8"
809
+ );
810
+ console.log(
811
+ import_chalk.default.gray(
812
+ ` \u2713 Created individual file: ${individualOutputPath}`
813
+ )
814
+ );
815
+ }
816
+ if (createFileListForServing) {
817
+ fileList.push(finalImagePath);
818
+ }
819
+ taskId++;
820
+ }
821
+ const baseName = file.replace(".txt", "");
822
+ const outputPath = (0, import_path.join)(
823
+ outDir,
824
+ `${baseName}_${toFullJson ? "full" : "min"}.json`
825
+ );
826
+ await (0, import_promises.writeFile)(
827
+ outputPath,
828
+ JSON.stringify(allLabelStudioData, null, 2),
829
+ "utf-8"
830
+ );
831
+ console.log(import_chalk.default.green(`\u2713 Converted ${file} -> ${outputPath}`));
832
+ if (createFileListForServing && fileList.length > 0) {
833
+ const fileListPath = (0, import_path.join)(outDir, fileListName);
834
+ await (0, import_promises.writeFile)(fileListPath, fileList.join("\n"), "utf-8");
835
+ console.log(
836
+ import_chalk.default.green(
837
+ `\u2713 Created file list: ${fileListPath} (${fileList.length} files)`
838
+ )
839
+ );
840
+ }
841
+ } catch (error) {
842
+ console.error(
843
+ import_chalk.default.red(`\u2717 Failed to process ${file}:`),
844
+ error instanceof Error ? error.message : error
845
+ );
846
+ }
847
+ }
848
+ }
849
+ console.log(import_chalk.default.green("\n\u2713 Conversion completed!"));
850
+ }
851
+ var import_promises, import_path, import_chalk;
852
+ var init_impl = __esm({
853
+ "src/commands/toLabelStudio/impl.ts"() {
854
+ "use strict";
855
+ init_cjs_shims();
856
+ import_promises = require("fs/promises");
857
+ import_path = require("path");
858
+ import_chalk = __toESM(require("chalk"), 1);
859
+ init_constants();
860
+ init_ppocr_label();
861
+ init_schema();
862
+ init_sort();
863
+ }
864
+ });
865
+
866
+ // src/lib/label-studio.ts
867
+ var turf, labelStudioToPPOCR, minLabelStudioToPPOCR;
868
+ var init_label_studio = __esm({
869
+ "src/lib/label-studio.ts"() {
870
+ "use strict";
871
+ init_cjs_shims();
872
+ turf = __toESM(require("@turf/turf"), 1);
873
+ labelStudioToPPOCR = async (data, baseImageDir) => {
874
+ const resultMap = /* @__PURE__ */ new Map();
875
+ for (const task of data) {
876
+ let imagePath = task.file_upload || "";
877
+ if (task.data.ocr) {
878
+ const urlPath = task.data.ocr.replace(/^https?:\/\/[^/]+\//, "");
879
+ imagePath = decodeURIComponent(urlPath);
880
+ }
881
+ if (baseImageDir) {
882
+ imagePath = `${baseImageDir}/${task.file_upload || imagePath.split("/").pop() || imagePath}`;
883
+ }
884
+ const imageAnnotations = [];
885
+ for (const annotation of task.annotations) {
886
+ const groupedById = /* @__PURE__ */ new Map();
887
+ for (const resultItem of annotation.result) {
888
+ const { id } = resultItem;
889
+ if (!groupedById.has(id)) {
890
+ groupedById.set(id, []);
891
+ }
892
+ groupedById.get(id).push(resultItem);
893
+ }
894
+ for (const [_, resultItems] of groupedById) {
895
+ let points;
896
+ let transcription = "";
897
+ for (const resultItem of resultItems) {
898
+ if ("points" in resultItem.value && resultItem.value.points) {
899
+ const { points: valuePoints } = resultItem.value;
900
+ const { original_width, original_height } = resultItem;
901
+ points = valuePoints.map(([x, y]) => [
902
+ (x ?? 0) * original_width / 100,
903
+ (y ?? 0) * original_height / 100
904
+ ]);
905
+ } else if ("x" in resultItem.value && "y" in resultItem.value && "width" in resultItem.value && "height" in resultItem.value) {
906
+ const { x, y, width, height } = resultItem.value;
907
+ const { original_width, original_height } = resultItem;
908
+ const absX = x * original_width / 100;
909
+ const absY = y * original_height / 100;
910
+ const absWidth = width * original_width / 100;
911
+ const absHeight = height * original_height / 100;
912
+ points = [
913
+ [absX, absY],
914
+ [absX + absWidth, absY],
915
+ [absX + absWidth, absY + absHeight],
916
+ [absX, absY + absHeight]
917
+ ];
918
+ }
919
+ if ("text" in resultItem.value && Array.isArray(resultItem.value.text)) {
920
+ transcription = resultItem.value.text[0] || "";
921
+ }
922
+ }
923
+ if (points && points.length > 0) {
924
+ let dt_score = 1;
925
+ try {
926
+ const firstPoint = points[0];
927
+ if (firstPoint) {
928
+ const polygon2 = turf.polygon([points.concat([firstPoint])]);
929
+ const area2 = turf.area(polygon2);
930
+ dt_score = Math.min(1, Math.max(0.5, area2 / 1e4));
931
+ }
932
+ } catch {
933
+ dt_score = 0.8;
934
+ }
935
+ imageAnnotations.push({
936
+ transcription,
937
+ points,
938
+ dt_score
939
+ });
940
+ }
941
+ }
942
+ }
943
+ if (imageAnnotations.length > 0) {
944
+ resultMap.set(imagePath, imageAnnotations);
945
+ }
946
+ }
947
+ return resultMap;
948
+ };
949
+ minLabelStudioToPPOCR = async (data, baseImageDir) => {
950
+ const resultMap = /* @__PURE__ */ new Map();
951
+ for (const item of data) {
952
+ let imagePath = item.ocr || "";
953
+ if (imagePath) {
954
+ imagePath = decodeURIComponent(
955
+ imagePath.replace(/^https?:\/\/[^/]+\//, "")
956
+ );
957
+ }
958
+ if (baseImageDir) {
959
+ imagePath = `${baseImageDir}/${imagePath.split("/").pop() || imagePath}`;
960
+ }
961
+ let points;
962
+ if (item.poly.length > 0 && item.poly[0]) {
963
+ const { points: polyPoints } = item.poly[0];
964
+ points = polyPoints;
965
+ } else if (item.bbox.length > 0 && item.bbox[0]) {
966
+ const bbox = item.bbox[0];
967
+ const { x, y, width, height } = bbox;
968
+ points = [
969
+ [x, y],
970
+ [x + width, y],
971
+ [x + width, y + height],
972
+ [x, y + height]
973
+ ];
974
+ } else {
975
+ continue;
976
+ }
977
+ const transcription = item.transcription.length > 0 ? item.transcription[0] : "";
978
+ let dt_score = 1;
979
+ try {
980
+ const firstPoint = points[0];
981
+ if (firstPoint) {
982
+ const polygon2 = turf.polygon([points.concat([firstPoint])]);
983
+ const area2 = turf.area(polygon2);
984
+ dt_score = Math.min(1, Math.max(0.5, area2 / 1e4));
985
+ }
986
+ } catch {
987
+ dt_score = 0.8;
988
+ }
989
+ const annotation = {
990
+ transcription: transcription ?? "",
991
+ points,
992
+ dt_score
993
+ };
994
+ if (!resultMap.has(imagePath)) {
995
+ resultMap.set(imagePath, []);
996
+ }
997
+ resultMap.get(imagePath).push(annotation);
998
+ }
999
+ return resultMap;
1000
+ };
1001
+ }
1002
+ });
1003
+
1004
+ // src/commands/toPPOCR/impl.ts
1005
+ var impl_exports2 = {};
1006
+ __export(impl_exports2, {
1007
+ convertToPPOCR: () => convertToPPOCR
1008
+ });
1009
+ async function convertToPPOCR(flags, ...inputDirs) {
1010
+ const {
1011
+ outDir = `${OUTPUT_BASE_DIR}`,
1012
+ fileName = DEFAULT_PPOCR_FILE_NAME,
1013
+ baseImageDir,
1014
+ sortVertical = DEFAULT_SORT_VERTICAL,
1015
+ sortHorizontal = DEFAULT_SORT_HORIZONTAL
1016
+ } = flags;
1017
+ await (0, import_promises2.mkdir)(outDir, { recursive: true });
1018
+ for (const inputDir of inputDirs) {
1019
+ console.log(import_chalk2.default.blue(`Processing input directory: ${inputDir}`));
1020
+ const files = await (0, import_promises2.readdir)(inputDir);
1021
+ for (const file of files) {
1022
+ if (!file.endsWith(".json")) {
1023
+ continue;
1024
+ }
1025
+ const filePath = (0, import_path2.join)(inputDir, file);
1026
+ console.log(import_chalk2.default.gray(`Processing file: ${file}`));
1027
+ try {
1028
+ const fileData = await (0, import_promises2.readFile)(filePath, "utf-8");
1029
+ const labelStudioData = JSON.parse(fileData);
1030
+ const { data, isFull } = isLabelStudioFullJSON(labelStudioData);
1031
+ const ppocrDataMap = isFull ? await labelStudioToPPOCR(data, baseImageDir) : await minLabelStudioToPPOCR(
1032
+ data,
1033
+ baseImageDir
1034
+ );
1035
+ const outputLines = [];
1036
+ for (const [imagePath, annotations] of ppocrDataMap.entries()) {
1037
+ const sortedAnnotations = sortBoundingBoxes(
1038
+ annotations,
1039
+ sortVertical,
1040
+ sortHorizontal
1041
+ );
1042
+ PPOCRLabelSchema.parse(sortedAnnotations);
1043
+ const jsonArray = JSON.stringify(sortedAnnotations);
1044
+ outputLines.push(`${imagePath} ${jsonArray}`);
1045
+ }
1046
+ const baseName = file.replace(".json", "");
1047
+ const outputPath = (0, import_path2.join)(outDir, `${baseName}_${fileName}`);
1048
+ await (0, import_promises2.writeFile)(outputPath, outputLines.join("\n"), "utf-8");
1049
+ console.log(import_chalk2.default.green(`\u2713 Converted ${file} -> ${outputPath}`));
1050
+ } catch (error) {
1051
+ console.error(
1052
+ import_chalk2.default.red(`\u2717 Failed to process ${file}:`),
1053
+ error instanceof Error ? error.message : error
1054
+ );
1055
+ }
1056
+ }
1057
+ }
1058
+ console.log(import_chalk2.default.green("\n\u2713 Conversion completed!"));
1059
+ }
1060
+ var import_promises2, import_path2, import_chalk2, isLabelStudioFullJSON;
1061
+ var init_impl2 = __esm({
1062
+ "src/commands/toPPOCR/impl.ts"() {
1063
+ "use strict";
1064
+ init_cjs_shims();
1065
+ import_promises2 = require("fs/promises");
1066
+ import_path2 = require("path");
1067
+ import_chalk2 = __toESM(require("chalk"), 1);
1068
+ init_constants();
1069
+ init_label_studio();
1070
+ init_schema();
1071
+ init_sort();
1072
+ isLabelStudioFullJSON = (data) => {
1073
+ const parsedFull = FullOCRLabelStudioSchema.safeParse(data);
1074
+ if (parsedFull.success) {
1075
+ return { isFull: true, data: parsedFull.data };
1076
+ }
1077
+ if (!Array.isArray(data) && typeof data === "object" && data !== null) {
1078
+ const parsedSingleFull = FullOCRLabelStudioSchema.safeParse([data]);
1079
+ if (parsedSingleFull.success) {
1080
+ return { isFull: true, data: parsedSingleFull.data };
1081
+ }
1082
+ }
1083
+ const parsedMin = MinOCRLabelStudioSchema.safeParse(data);
1084
+ if (parsedMin.success) {
1085
+ return { isFull: false, data: parsedMin.data };
1086
+ }
1087
+ throw new Error("Input data is not valid Label Studio JSON format.");
1088
+ };
1089
+ }
1090
+ });
1091
+
1092
+ // src/bin/bash-complete.ts
1093
+ init_cjs_shims();
1094
+ var import_core4 = require("@stricli/core");
1095
+
1096
+ // src/app.ts
1097
+ init_cjs_shims();
1098
+ var import_auto_complete = require("@stricli/auto-complete");
1099
+ var import_core3 = require("@stricli/core");
1100
+
1101
+ // package.json
1102
+ var version = "1.0.0";
1103
+ var description = "Convert between Label Studio OCR format and PPOCRLabelv2 format";
1104
+
1105
+ // src/commands/toLabelStudio/command.ts
1106
+ init_cjs_shims();
1107
+ var import_core = require("@stricli/core");
1108
+ init_constants();
1109
+ var toLabelStudioCommand = (0, import_core.buildCommand)({
1110
+ loader: async () => {
1111
+ const { convertToLabelStudio: convertToLabelStudio2 } = await Promise.resolve().then(() => (init_impl(), impl_exports));
1112
+ return convertToLabelStudio2;
1113
+ },
1114
+ parameters: {
1115
+ positional: {
1116
+ kind: "array",
1117
+ parameter: {
1118
+ brief: "Input directories containing PPOCRLabel files",
1119
+ parse: String
1120
+ },
1121
+ minimum: 1
1122
+ },
1123
+ flags: {
1124
+ outDir: {
1125
+ kind: "parsed",
1126
+ brief: `Output directory. Default to "${OUTPUT_BASE_DIR}"`,
1127
+ parse: String,
1128
+ optional: true
1129
+ },
1130
+ defaultLabelName: {
1131
+ kind: "parsed",
1132
+ brief: `Default label name for text annotations. Default to "${DEFAULT_LABEL_NAME}"`,
1133
+ parse: String,
1134
+ optional: true
1135
+ },
1136
+ toFullJson: {
1137
+ kind: "boolean",
1138
+ brief: `Convert to Full OCR Label Studio format. Default to "${DEFAULT_LABEL_STUDIO_FULL_JSON}"`,
1139
+ optional: true
1140
+ },
1141
+ createFilePerImage: {
1142
+ kind: "boolean",
1143
+ brief: `Create a separate Label Studio JSON file for each image. Default to "${DEFAULT_CREATE_FILE_PER_IMAGE}"`,
1144
+ optional: true
1145
+ },
1146
+ createFileListForServing: {
1147
+ kind: "boolean",
1148
+ brief: `Create a file list for serving in Label Studio. Default to "${DEFAULT_CREATE_FILE_LIST_FOR_SERVING}"`,
1149
+ optional: true
1150
+ },
1151
+ fileListName: {
1152
+ kind: "parsed",
1153
+ brief: `Name of the file list for serving. Default to "${DEFAULT_FILE_LIST_NAME}"`,
1154
+ parse: String,
1155
+ optional: true
1156
+ },
1157
+ baseServerUrl: {
1158
+ kind: "parsed",
1159
+ brief: `Base server URL for constructing image URLs in the file list. Default to "${DEFAULT_BASE_SERVER_URL}"`,
1160
+ parse: String,
1161
+ optional: true
1162
+ },
1163
+ sortVertical: {
1164
+ kind: "parsed",
1165
+ brief: `Sort bounding boxes vertically. Options: "${SORT_VERTICAL_NONE}" (default), "${SORT_VERTICAL_TOP_BOTTOM}", "${SORT_VERTICAL_BOTTOM_TOP}"`,
1166
+ parse: String,
1167
+ optional: true
1168
+ },
1169
+ sortHorizontal: {
1170
+ kind: "parsed",
1171
+ brief: `Sort bounding boxes horizontally. Options: "${SORT_HORIZONTAL_NONE}" (default), "${SORT_HORIZONTAL_LTR}", "${SORT_HORIZONTAL_RTL}"`,
1172
+ parse: String,
1173
+ optional: true
1174
+ }
1175
+ }
1176
+ },
1177
+ docs: {
1178
+ brief: "Convert PPOCRLabel files to Label Studio format"
1179
+ }
1180
+ });
1181
+
1182
+ // src/commands/toPPOCR/commands.ts
1183
+ init_cjs_shims();
1184
+ var import_core2 = require("@stricli/core");
1185
+ init_constants();
1186
+ var toPPOCRCommand = (0, import_core2.buildCommand)({
1187
+ loader: async () => {
1188
+ const { convertToPPOCR: convertToPPOCR2 } = await Promise.resolve().then(() => (init_impl2(), impl_exports2));
1189
+ return convertToPPOCR2;
1190
+ },
1191
+ parameters: {
1192
+ positional: {
1193
+ kind: "array",
1194
+ parameter: {
1195
+ brief: "Input directories containing Label Studio files",
1196
+ parse: String
1197
+ },
1198
+ minimum: 1
1199
+ },
1200
+ flags: {
1201
+ outDir: {
1202
+ kind: "parsed",
1203
+ brief: `Output directory. Default to "${OUTPUT_BASE_DIR}"`,
1204
+ parse: String,
1205
+ optional: true
1206
+ },
1207
+ fileName: {
1208
+ kind: "parsed",
1209
+ brief: `Output PPOCR file name. Default to "${DEFAULT_PPOCR_FILE_NAME}"`,
1210
+ parse: String,
1211
+ optional: true
1212
+ },
1213
+ baseImageDir: {
1214
+ kind: "parsed",
1215
+ brief: 'Base directory path to prepend to image filenames in output (e.g., "ch" or "images/ch")',
1216
+ parse: String,
1217
+ optional: true
1218
+ },
1219
+ sortVertical: {
1220
+ kind: "parsed",
1221
+ brief: `Sort bounding boxes vertically. Options: "${SORT_VERTICAL_NONE}" (default), "${SORT_VERTICAL_TOP_BOTTOM}", "${SORT_VERTICAL_BOTTOM_TOP}"`,
1222
+ parse: String,
1223
+ optional: true
1224
+ },
1225
+ sortHorizontal: {
1226
+ kind: "parsed",
1227
+ brief: `Sort bounding boxes horizontally. Options: "${SORT_HORIZONTAL_NONE}" (default), "${SORT_HORIZONTAL_LTR}", "${SORT_HORIZONTAL_RTL}"`,
1228
+ parse: String,
1229
+ optional: true
1230
+ }
1231
+ }
1232
+ },
1233
+ docs: {
1234
+ brief: "Convert Label Studio files to PPOCRLabel format"
1235
+ }
1236
+ });
1237
+
1238
+ // src/app.ts
1239
+ var routes = (0, import_core3.buildRouteMap)({
1240
+ routes: {
1241
+ toLabelStudio: toLabelStudioCommand,
1242
+ toPPOCR: toPPOCRCommand,
1243
+ install: (0, import_auto_complete.buildInstallCommand)("label-studio-converter", {
1244
+ bash: "__label-studio-converter_bash_complete"
1245
+ }),
1246
+ uninstall: (0, import_auto_complete.buildUninstallCommand)("label-studio-converter", { bash: true })
1247
+ },
1248
+ docs: {
1249
+ brief: description,
1250
+ hideRoute: {
1251
+ install: true,
1252
+ uninstall: true
1253
+ }
1254
+ }
1255
+ });
1256
+ var app = (0, import_core3.buildApplication)(routes, {
1257
+ name: "label-studio-converter",
1258
+ versionInfo: {
1259
+ currentVersion: version
1260
+ }
1261
+ });
1262
+
1263
+ // src/context.ts
1264
+ init_cjs_shims();
1265
+ var import_node_fs2 = __toESM(require("fs"), 1);
1266
+ var import_node_os = __toESM(require("os"), 1);
1267
+ var import_node_path2 = __toESM(require("path"), 1);
1268
+ function buildContext(process2) {
1269
+ return {
1270
+ process: process2,
1271
+ os: import_node_os.default,
1272
+ fs: import_node_fs2.default,
1273
+ path: import_node_path2.default
1274
+ };
1275
+ }
1276
+
1277
+ // src/bin/bash-complete.ts
1278
+ (async () => {
1279
+ const inputs = process.argv.slice(3);
1280
+ if (process.env.COMP_LINE?.endsWith(" ")) {
1281
+ inputs.push("");
1282
+ }
1283
+ await (0, import_core4.proposeCompletions)(app, inputs, buildContext(process));
1284
+ try {
1285
+ for (const { completion } of await (0, import_core4.proposeCompletions)(
1286
+ app,
1287
+ inputs,
1288
+ buildContext(process)
1289
+ )) {
1290
+ process.stdout.write(`${completion}
1291
+ `);
1292
+ }
1293
+ } catch {
1294
+ }
1295
+ })();
1296
+ //# sourceMappingURL=bash-complete.cjs.map