licos-dev-cli 0.2.12__tar.gz → 0.2.14__tar.gz

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.
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: licos-dev-cli
3
- Version: 0.2.12
3
+ Version: 0.2.14
4
4
  Summary: LICOS Dev CLI - generate files and call model capabilities
5
5
  Requires-Python: >=3.10
6
6
  Requires-Dist: click>=8.1
7
- Requires-Dist: licos-dev-sdk>=0.2.13
7
+ Requires-Dist: licos-dev-sdk>=0.2.14
@@ -4,11 +4,11 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "licos-dev-cli"
7
- version = "0.2.12"
7
+ version = "0.2.14"
8
8
  description = "LICOS Dev CLI - generate files and call model capabilities"
9
9
  requires-python = ">=3.10"
10
10
  dependencies = [
11
- "licos-dev-sdk>=0.2.13",
11
+ "licos-dev-sdk>=0.2.14",
12
12
  "click>=8.1",
13
13
  ]
14
14
 
@@ -2,9 +2,11 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- import sys
6
- import json
7
- import click
5
+ import sys
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ import click
8
10
 
9
11
  # ── Helpers ──────────────────────────────────────────────────────────────────
10
12
 
@@ -35,13 +37,57 @@ def _json_option(value: str | None, name: str) -> dict | list | None:
35
37
  raise click.BadParameter(f"{name} must be valid JSON") from exc
36
38
 
37
39
 
38
- def _echo_json(value: object) -> None:
39
- if hasattr(value, "to_dict"):
40
- value = value.to_dict()
41
- click.echo(json.dumps(value, ensure_ascii=False, indent=2))
42
-
43
-
44
- # ── CLI Group ────────────────────────────────────────────────────────────────
40
+ def _echo_json(value: object) -> None:
41
+ if hasattr(value, "to_dict"):
42
+ value = value.to_dict()
43
+ click.echo(json.dumps(value, ensure_ascii=False, indent=2))
44
+
45
+
46
+ def _path_to_cli_output(path: object) -> str:
47
+ raw = str(path)
48
+ if not raw:
49
+ return raw
50
+
51
+ normalized = raw.replace("\\", "/")
52
+ string_roots = [
53
+ os.environ.get("LICOS_PROJECT_PATH"),
54
+ (os.path.join(os.environ["LICOS_WORKSPACE_PATH"], "projects") if os.environ.get("LICOS_WORKSPACE_PATH") else None),
55
+ "/workspace/projects",
56
+ ]
57
+ for root in string_roots:
58
+ if not root:
59
+ continue
60
+ prefix = root.replace("\\", "/").rstrip("/")
61
+ if normalized == prefix:
62
+ return "."
63
+ if normalized.startswith(f"{prefix}/"):
64
+ return normalized[len(prefix) + 1 :]
65
+
66
+ p = Path(raw)
67
+ if not p.is_absolute():
68
+ return normalized
69
+
70
+ path_roots = [
71
+ os.environ.get("LICOS_PROJECT_PATH"),
72
+ (os.path.join(os.environ["LICOS_WORKSPACE_PATH"], "projects") if os.environ.get("LICOS_WORKSPACE_PATH") else None),
73
+ str(Path.cwd()),
74
+ ]
75
+ for root in path_roots:
76
+ if not root:
77
+ continue
78
+ try:
79
+ return p.resolve().relative_to(Path(root).resolve()).as_posix()
80
+ except (OSError, RuntimeError, ValueError):
81
+ continue
82
+
83
+ return normalized
84
+
85
+
86
+ def _echo_path(path: object) -> None:
87
+ click.echo(_path_to_cli_output(path))
88
+
89
+
90
+ # ── CLI Group ────────────────────────────────────────────────────────────────
45
91
 
46
92
  @click.group()
47
93
  def cli():
@@ -60,10 +106,10 @@ def cli():
60
106
  @click.option("--page-size", default="A4", help="Page size: A4|LETTER")
61
107
  def pdf(input_path, content, filename, output_dir, content_type, page_size):
62
108
  """Generate PDF from Markdown or HTML."""
63
- from licos_dev_sdk import create_pdf
64
- text = _read_input(input_path, content)
65
- path = create_pdf(text, filename, content_type=content_type, output_dir=output_dir, page_size=page_size)
66
- click.echo(path)
109
+ from licos_dev_sdk import create_pdf
110
+ text = _read_input(input_path, content)
111
+ path = create_pdf(text, filename, content_type=content_type, output_dir=output_dir, page_size=page_size)
112
+ _echo_path(path)
67
113
 
68
114
 
69
115
  # ── DOCX ─────────────────────────────────────────────────────────────────────
@@ -78,10 +124,10 @@ def pdf(input_path, content, filename, output_dir, content_type, page_size):
78
124
  @click.option("--font-size", default=11, type=int)
79
125
  def docx(input_path, content, filename, output_dir, content_type, font, font_size):
80
126
  """Generate DOCX from Markdown or HTML."""
81
- from licos_dev_sdk import create_docx
82
- text = _read_input(input_path, content)
83
- path = create_docx(text, filename, content_type=content_type, output_dir=output_dir, font_name=font, font_size=font_size)
84
- click.echo(path)
127
+ from licos_dev_sdk import create_docx
128
+ text = _read_input(input_path, content)
129
+ path = create_docx(text, filename, content_type=content_type, output_dir=output_dir, font_name=font, font_size=font_size)
130
+ _echo_path(path)
85
131
 
86
132
 
87
133
  @cli.command("docx-template")
@@ -94,10 +140,10 @@ def docx_template(template_path, input_path, data_content, filename, output_dir)
94
140
  """Generate DOCX by rendering a DOCX template with JSON data."""
95
141
  from licos_dev_sdk import create_docx_from_template
96
142
  data = _read_json(input_path, data_content)
97
- if not isinstance(data, dict):
98
- raise click.BadParameter("template data must be a JSON object")
99
- path = create_docx_from_template(template_path, data, filename, output_dir=output_dir)
100
- click.echo(path)
143
+ if not isinstance(data, dict):
144
+ raise click.BadParameter("template data must be a JSON object")
145
+ path = create_docx_from_template(template_path, data, filename, output_dir=output_dir)
146
+ _echo_path(path)
101
147
 
102
148
 
103
149
  # ── XLSX ─────────────────────────────────────────────────────────────────────
@@ -111,10 +157,10 @@ def docx_template(template_path, input_path, data_content, filename, output_dir)
111
157
  @click.option("--header-color", default="4472C4")
112
158
  def xlsx(input_path, content, filename, output_dir, sheet_name, header_color):
113
159
  """Generate XLSX from JSON data."""
114
- from licos_dev_sdk import create_xlsx
115
- data = _read_json(input_path, content)
116
- path = create_xlsx(data, filename, output_dir=output_dir, sheet_name=sheet_name, header_color=header_color)
117
- click.echo(path)
160
+ from licos_dev_sdk import create_xlsx
161
+ data = _read_json(input_path, content)
162
+ path = create_xlsx(data, filename, output_dir=output_dir, sheet_name=sheet_name, header_color=header_color)
163
+ _echo_path(path)
118
164
 
119
165
 
120
166
  @cli.command("xlsx-workbook")
@@ -134,10 +180,10 @@ def xlsx_workbook(input_path, content, filename, output_dir, header_color, freez
134
180
  filename,
135
181
  output_dir=output_dir,
136
182
  header_color=header_color,
137
- freeze_header=freeze_header,
138
- autofilter=autofilter,
139
- )
140
- click.echo(path)
183
+ freeze_header=freeze_header,
184
+ autofilter=autofilter,
185
+ )
186
+ _echo_path(path)
141
187
 
142
188
 
143
189
  # ── CSV ──────────────────────────────────────────────────────────────────────
@@ -149,10 +195,10 @@ def xlsx_workbook(input_path, content, filename, output_dir, header_color, freez
149
195
  @click.option("-o", "--output-dir", default=None)
150
196
  def csv(input_path, content, filename, output_dir):
151
197
  """Generate CSV from JSON data."""
152
- from licos_dev_sdk import create_csv
153
- data = _read_json(input_path, content)
154
- path = create_csv(data, filename, output_dir=output_dir)
155
- click.echo(path)
198
+ from licos_dev_sdk import create_csv
199
+ data = _read_json(input_path, content)
200
+ path = create_csv(data, filename, output_dir=output_dir)
201
+ _echo_path(path)
156
202
 
157
203
 
158
204
  # ── PPTX ─────────────────────────────────────────────────────────────────────
@@ -165,10 +211,10 @@ def csv(input_path, content, filename, output_dir):
165
211
  @click.option("--format", "content_type", default="markdown")
166
212
  def pptx(input_path, content, filename, output_dir, content_type):
167
213
  """Generate PPTX from Markdown."""
168
- from licos_dev_sdk import create_pptx
169
- text = _read_input(input_path, content)
170
- path = create_pptx(text, filename, content_type=content_type, output_dir=output_dir)
171
- click.echo(path)
214
+ from licos_dev_sdk import create_pptx
215
+ text = _read_input(input_path, content)
216
+ path = create_pptx(text, filename, content_type=content_type, output_dir=output_dir)
217
+ _echo_path(path)
172
218
 
173
219
 
174
220
  # ── Chart ────────────────────────────────────────────────────────────────────
@@ -185,10 +231,10 @@ def pptx(input_path, content, filename, output_dir, content_type):
185
231
  @click.option("--height", default=600, type=int)
186
232
  def chart(input_path, content, filename, output_dir, chart_type, fmt, title, width, height):
187
233
  """Generate chart image from JSON data."""
188
- from licos_dev_sdk import create_chart
189
- data = _read_json(input_path, content)
190
- path = create_chart(chart_type, data, filename, output_dir=output_dir, format=fmt, title=title, width=width, height=height)
191
- click.echo(path)
234
+ from licos_dev_sdk import create_chart
235
+ data = _read_json(input_path, content)
236
+ path = create_chart(chart_type, data, filename, output_dir=output_dir, format=fmt, title=title, width=width, height=height)
237
+ _echo_path(path)
192
238
 
193
239
 
194
240
  # ── Diagram ──────────────────────────────────────────────────────────────────
@@ -201,10 +247,10 @@ def chart(input_path, content, filename, output_dir, chart_type, fmt, title, wid
201
247
  @click.option("--format", "fmt", default="png", help="png|svg|pdf")
202
248
  def diagram(input_path, content, filename, output_dir, fmt):
203
249
  """Generate diagram from Graphviz DOT source."""
204
- from licos_dev_sdk import create_diagram
205
- text = _read_input(input_path, content)
206
- path = create_diagram(text, filename, output_dir=output_dir, format=fmt)
207
- click.echo(path)
250
+ from licos_dev_sdk import create_diagram
251
+ text = _read_input(input_path, content)
252
+ path = create_diagram(text, filename, output_dir=output_dir, format=fmt)
253
+ _echo_path(path)
208
254
 
209
255
 
210
256
  # ── QR Code ──────────────────────────────────────────────────────────────────
@@ -216,9 +262,9 @@ def diagram(input_path, content, filename, output_dir, fmt):
216
262
  @click.option("--size", default=300, type=int)
217
263
  def qrcode(data, filename, output_dir, size):
218
264
  """Generate QR code PNG image."""
219
- from licos_dev_sdk import create_qrcode
220
- path = create_qrcode(data, filename, output_dir=output_dir, size=size)
221
- click.echo(path)
265
+ from licos_dev_sdk import create_qrcode
266
+ path = create_qrcode(data, filename, output_dir=output_dir, size=size)
267
+ _echo_path(path)
222
268
 
223
269
 
224
270
  # ── Barcode ──────────────────────────────────────────────────────────────────
@@ -230,9 +276,9 @@ def qrcode(data, filename, output_dir, size):
230
276
  @click.option("--type", "barcode_type", default="code128", help="code128|ean13|ean8|isbn13|upc")
231
277
  def barcode(data, filename, output_dir, barcode_type):
232
278
  """Generate barcode PNG image."""
233
- from licos_dev_sdk import create_barcode
234
- path = create_barcode(data, filename, output_dir=output_dir, barcode_type=barcode_type)
235
- click.echo(path)
279
+ from licos_dev_sdk import create_barcode
280
+ path = create_barcode(data, filename, output_dir=output_dir, barcode_type=barcode_type)
281
+ _echo_path(path)
236
282
 
237
283
 
238
284
  # ── ZIP ──────────────────────────────────────────────────────────────────────
@@ -243,10 +289,10 @@ def barcode(data, filename, output_dir, barcode_type):
243
289
  @click.option("-o", "--output-dir", default=None)
244
290
  def zip_cmd(paths, filename, output_dir):
245
291
  """Create ZIP archive."""
246
- from licos_dev_sdk import create_zip
247
- source_paths = [p.strip() for p in paths.split(",")]
248
- path = create_zip(source_paths, filename, output_dir=output_dir)
249
- click.echo(path)
292
+ from licos_dev_sdk import create_zip
293
+ source_paths = [p.strip() for p in paths.split(",")]
294
+ path = create_zip(source_paths, filename, output_dir=output_dir)
295
+ _echo_path(path)
250
296
 
251
297
 
252
298
  # ── TAR.GZ ───────────────────────────────────────────────────────────────────
@@ -257,10 +303,10 @@ def zip_cmd(paths, filename, output_dir):
257
303
  @click.option("-o", "--output-dir", default=None)
258
304
  def tar_cmd(paths, filename, output_dir):
259
305
  """Create TAR.GZ archive."""
260
- from licos_dev_sdk import create_tar_gz
261
- source_paths = [p.strip() for p in paths.split(",")]
262
- path = create_tar_gz(source_paths, filename, output_dir=output_dir)
263
- click.echo(path)
306
+ from licos_dev_sdk import create_tar_gz
307
+ source_paths = [p.strip() for p in paths.split(",")]
308
+ path = create_tar_gz(source_paths, filename, output_dir=output_dir)
309
+ _echo_path(path)
264
310
 
265
311
 
266
312
  # ── JSON ─────────────────────────────────────────────────────────────────────
@@ -276,11 +322,11 @@ def json_cmd(input_path, content, filename, output_dir):
276
322
  raw = _read_input(input_path, content)
277
323
  try:
278
324
  data = json.loads(raw)
279
- except json.JSONDecodeError:
280
- import yaml
281
- data = yaml.safe_load(raw)
282
- path = create_json(data, filename, output_dir=output_dir)
283
- click.echo(path)
325
+ except json.JSONDecodeError:
326
+ import yaml
327
+ data = yaml.safe_load(raw)
328
+ path = create_json(data, filename, output_dir=output_dir)
329
+ _echo_path(path)
284
330
 
285
331
 
286
332
  # ── YAML ─────────────────────────────────────────────────────────────────────
@@ -297,10 +343,10 @@ def yaml_cmd(input_path, content, filename, output_dir):
297
343
  raw = _read_input(input_path, content)
298
344
  try:
299
345
  data = json.loads(raw)
300
- except json.JSONDecodeError:
301
- data = yaml_lib.safe_load(raw)
302
- path = create_yaml(data, filename, output_dir=output_dir)
303
- click.echo(path)
346
+ except json.JSONDecodeError:
347
+ data = yaml_lib.safe_load(raw)
348
+ path = create_yaml(data, filename, output_dir=output_dir)
349
+ _echo_path(path)
304
350
 
305
351
 
306
352
  # ── XML ──────────────────────────────────────────────────────────────────────
@@ -313,10 +359,10 @@ def yaml_cmd(input_path, content, filename, output_dir):
313
359
  @click.option("--root-tag", default="root")
314
360
  def xml_cmd(input_path, content, filename, output_dir, root_tag):
315
361
  """Generate XML file from JSON data."""
316
- from licos_dev_sdk import create_xml
317
- data = _read_json(input_path, content)
318
- path = create_xml(data, filename, output_dir=output_dir, root_tag=root_tag)
319
- click.echo(path)
362
+ from licos_dev_sdk import create_xml
363
+ data = _read_json(input_path, content)
364
+ path = create_xml(data, filename, output_dir=output_dir, root_tag=root_tag)
365
+ _echo_path(path)
320
366
 
321
367
 
322
368
  # ── HTML ─────────────────────────────────────────────────────────────────────
@@ -329,10 +375,10 @@ def xml_cmd(input_path, content, filename, output_dir, root_tag):
329
375
  @click.option("--format", "content_type", default="markdown", help="markdown|html")
330
376
  def html_cmd(input_path, content, filename, output_dir, content_type):
331
377
  """Generate HTML file from Markdown or raw HTML."""
332
- from licos_dev_sdk import create_html
333
- text = _read_input(input_path, content)
334
- path = create_html(text, filename, output_dir=output_dir, content_type=content_type)
335
- click.echo(path)
378
+ from licos_dev_sdk import create_html
379
+ text = _read_input(input_path, content)
380
+ path = create_html(text, filename, output_dir=output_dir, content_type=content_type)
381
+ _echo_path(path)
336
382
 
337
383
 
338
384
  # ── Model Catalog ────────────────────────────────────────────────────────────
@@ -432,32 +478,32 @@ def vision_group():
432
478
  pass
433
479
 
434
480
 
435
- @vision_group.command("understand")
436
- @click.option("--image", "image", multiple=True, help="Image URL, Base64 data URI, or plain Base64 image data. Can be repeated.")
437
- @click.option("--image-url", "image_url", multiple=True, help="Alias for --image. Can be repeated.")
438
- @click.option("--file-path", "file_path", multiple=True, help="Local image file path. Can be repeated.")
439
- @click.option("-p", "--prompt", default="Describe this image.")
440
- @click.option("--model", default=None)
441
- @click.option("--mime-type", default=None, help="MIME type for plain Base64 image inputs. Defaults to image/png.")
442
- @click.option("--raw-request", default=None, help="Raw JSON request body")
443
- def vision_understand(image, image_url, file_path, prompt, model, mime_type, raw_request):
444
- """Understand one or more images with the catalog vision model."""
445
- from licos_dev_sdk import VisionClient
446
-
447
- raw_payload = _json_option(raw_request, "--raw-request")
448
- if raw_payload is not None and not isinstance(raw_payload, dict):
449
- raise click.BadParameter("--raw-request must be a JSON object")
450
- if raw_payload is None and not image_url and not image and not file_path:
451
- raise click.UsageError("Provide --image, --image-url, --file-path, or --raw-request.")
452
- result = VisionClient().understand(
453
- images=[*image, *image_url],
454
- file_paths=list(file_path),
455
- prompt=prompt,
456
- model=model,
457
- mime_type=mime_type,
458
- raw_request=raw_payload,
459
- )
460
- _echo_json(result)
481
+ @vision_group.command("understand")
482
+ @click.option("--image", "image", multiple=True, help="Image URL, Base64 data URI, or plain Base64 image data. Can be repeated.")
483
+ @click.option("--image-url", "image_url", multiple=True, help="Alias for --image. Can be repeated.")
484
+ @click.option("--file-path", "file_path", multiple=True, help="Local image file path. Can be repeated.")
485
+ @click.option("-p", "--prompt", default="Describe this image.")
486
+ @click.option("--model", default=None)
487
+ @click.option("--mime-type", default=None, help="MIME type for plain Base64 image inputs. Defaults to image/png.")
488
+ @click.option("--raw-request", default=None, help="Raw JSON request body")
489
+ def vision_understand(image, image_url, file_path, prompt, model, mime_type, raw_request):
490
+ """Understand one or more images with the catalog vision model."""
491
+ from licos_dev_sdk import VisionClient
492
+
493
+ raw_payload = _json_option(raw_request, "--raw-request")
494
+ if raw_payload is not None and not isinstance(raw_payload, dict):
495
+ raise click.BadParameter("--raw-request must be a JSON object")
496
+ if raw_payload is None and not image_url and not image and not file_path:
497
+ raise click.UsageError("Provide --image, --image-url, --file-path, or --raw-request.")
498
+ result = VisionClient().understand(
499
+ images=[*image, *image_url],
500
+ file_paths=list(file_path),
501
+ prompt=prompt,
502
+ model=model,
503
+ mime_type=mime_type,
504
+ raw_request=raw_payload,
505
+ )
506
+ _echo_json(result)
461
507
 
462
508
 
463
509
  # ── Image Generation ─────────────────────────────────────────────────────────
@@ -469,35 +515,35 @@ def image_generation_group():
469
515
 
470
516
 
471
517
  @image_generation_group.command("generate")
472
- @click.option("-p", "--prompt")
473
- @click.option("--image", "image", multiple=True, help="Source/reference image URL or Base64 data URI")
474
- @click.option("--image-url", "image_url", multiple=True, help="Alias for --image")
475
- @click.option("--reference-image", default=None, help="Alias for --image")
476
- @click.option("--file-path", "file_path", multiple=True, help="Local source/reference image path")
477
- @click.option("--input-capabilities", default=None, help="Override image model input filter: text or image")
478
- @click.option("--negative-prompt", default=None)
479
- @click.option("--count", default=1, type=int)
480
- @click.option("--size", default=None)
518
+ @click.option("-p", "--prompt")
519
+ @click.option("--image", "image", multiple=True, help="Source/reference image URL or Base64 data URI")
520
+ @click.option("--image-url", "image_url", multiple=True, help="Alias for --image")
521
+ @click.option("--reference-image", default=None, help="Alias for --image")
522
+ @click.option("--file-path", "file_path", multiple=True, help="Local source/reference image path")
523
+ @click.option("--input-capabilities", default=None, help="Override image model input filter: text or image")
524
+ @click.option("--negative-prompt", default=None)
525
+ @click.option("--count", default=1, type=int)
526
+ @click.option("--size", default=None)
481
527
  @click.option("--model", default=None)
482
- @click.option("--parameters", default=None, help="Parameters JSON object")
483
- @click.option("--raw-request", default=None, help="Raw JSON request body")
484
- @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
485
- def image_generate(
486
- prompt,
487
- image,
488
- image_url,
489
- reference_image,
490
- file_path,
491
- input_capabilities,
492
- negative_prompt,
493
- count,
494
- size,
495
- model,
496
- parameters,
497
- raw_request,
498
- no_wait,
499
- ):
500
- """Generate images from text, image URLs/Base64, or local image files."""
528
+ @click.option("--parameters", default=None, help="Parameters JSON object")
529
+ @click.option("--raw-request", default=None, help="Raw JSON request body")
530
+ @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
531
+ def image_generate(
532
+ prompt,
533
+ image,
534
+ image_url,
535
+ reference_image,
536
+ file_path,
537
+ input_capabilities,
538
+ negative_prompt,
539
+ count,
540
+ size,
541
+ model,
542
+ parameters,
543
+ raw_request,
544
+ no_wait,
545
+ ):
546
+ """Generate images from text, image URLs/Base64, or local image files."""
501
547
  from licos_dev_sdk import ImageGenerationClient
502
548
 
503
549
  parameter_payload = _json_option(parameters, "--parameters") or {}
@@ -510,16 +556,16 @@ def image_generate(
510
556
  raise click.UsageError("Provide --prompt or --raw-request.")
511
557
  result = ImageGenerationClient().generate(
512
558
  prompt or "",
513
- negative_prompt=negative_prompt,
514
- count=count,
515
- size=size,
516
- images=[*image, *image_url],
517
- reference_image=reference_image,
518
- file_paths=list(file_path),
519
- input_capabilities=input_capabilities,
520
- model=model,
521
- parameters=parameter_payload,
522
- raw_request=raw_payload,
559
+ negative_prompt=negative_prompt,
560
+ count=count,
561
+ size=size,
562
+ images=[*image, *image_url],
563
+ reference_image=reference_image,
564
+ file_paths=list(file_path),
565
+ input_capabilities=input_capabilities,
566
+ model=model,
567
+ parameters=parameter_payload,
568
+ raw_request=raw_payload,
523
569
  wait=not no_wait,
524
570
  )
525
571
  _echo_json(result)
@@ -533,36 +579,36 @@ def video_generation_group():
533
579
  pass
534
580
 
535
581
 
536
- @video_generation_group.command("generate")
537
- @click.option("-p", "--prompt")
538
- @click.option("--image", default=None, help="Source/reference image URL, Base64 data URI, or plain Base64 image data")
539
- @click.option("--image-url", default=None, help="Alias for --image")
540
- @click.option("--reference-image", default=None, help="Alias for --image")
541
- @click.option("--first-frame-url", default=None, help="Alias for --image")
542
- @click.option("--file-path", default=None, help="Local source/reference image path")
543
- @click.option("--model", default=None)
544
- @click.option("--input-capabilities", default=None, help="Override video model input filter: text or image")
545
- @click.option("--mime-type", default=None, help="MIME type for plain Base64 image inputs. Defaults to image/png.")
546
- @click.option("--parameters", default=None, help="Parameters JSON object")
547
- @click.option("--raw-request", default=None, help="Raw JSON request body")
548
- @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
549
- def video_generate(
550
- prompt,
551
- image,
552
- image_url,
553
- reference_image,
554
- first_frame_url,
555
- file_path,
556
- model,
557
- input_capabilities,
558
- mime_type,
559
- parameters,
560
- raw_request,
561
- no_wait,
562
- ):
563
- """Generate a video from a text prompt and optional first-frame image."""
564
- from licos_dev_sdk import VideoGenerationClient
565
-
582
+ @video_generation_group.command("generate")
583
+ @click.option("-p", "--prompt")
584
+ @click.option("--image", default=None, help="Source/reference image URL, Base64 data URI, or plain Base64 image data")
585
+ @click.option("--image-url", default=None, help="Alias for --image")
586
+ @click.option("--reference-image", default=None, help="Alias for --image")
587
+ @click.option("--first-frame-url", default=None, help="Alias for --image")
588
+ @click.option("--file-path", default=None, help="Local source/reference image path")
589
+ @click.option("--model", default=None)
590
+ @click.option("--input-capabilities", default=None, help="Override video model input filter: text or image")
591
+ @click.option("--mime-type", default=None, help="MIME type for plain Base64 image inputs. Defaults to image/png.")
592
+ @click.option("--parameters", default=None, help="Parameters JSON object")
593
+ @click.option("--raw-request", default=None, help="Raw JSON request body")
594
+ @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
595
+ def video_generate(
596
+ prompt,
597
+ image,
598
+ image_url,
599
+ reference_image,
600
+ first_frame_url,
601
+ file_path,
602
+ model,
603
+ input_capabilities,
604
+ mime_type,
605
+ parameters,
606
+ raw_request,
607
+ no_wait,
608
+ ):
609
+ """Generate a video from a text prompt and optional first-frame image."""
610
+ from licos_dev_sdk import VideoGenerationClient
611
+
566
612
  parameter_payload = _json_option(parameters, "--parameters") or {}
567
613
  raw_payload = _json_option(raw_request, "--raw-request")
568
614
  if not isinstance(parameter_payload, dict):
@@ -571,19 +617,19 @@ def video_generate(
571
617
  raise click.BadParameter("--raw-request must be a JSON object")
572
618
  if raw_payload is None and not prompt:
573
619
  raise click.UsageError("Provide --prompt or --raw-request.")
574
- result = VideoGenerationClient().generate(
575
- prompt or "",
576
- image=image,
577
- image_url=image_url,
578
- reference_image=reference_image,
579
- first_frame_url=first_frame_url,
580
- file_path=file_path,
581
- model=model,
582
- input_capabilities=input_capabilities,
583
- mime_type=mime_type,
584
- parameters=parameter_payload,
585
- raw_request=raw_payload,
586
- wait=not no_wait,
620
+ result = VideoGenerationClient().generate(
621
+ prompt or "",
622
+ image=image,
623
+ image_url=image_url,
624
+ reference_image=reference_image,
625
+ first_frame_url=first_frame_url,
626
+ file_path=file_path,
627
+ model=model,
628
+ input_capabilities=input_capabilities,
629
+ mime_type=mime_type,
630
+ parameters=parameter_payload,
631
+ raw_request=raw_payload,
632
+ wait=not no_wait,
587
633
  )
588
634
  _echo_json(result)
589
635
 
@@ -596,35 +642,35 @@ def audio_group():
596
642
  pass
597
643
 
598
644
 
599
- @audio_group.command("recognize")
600
- @click.option("--audio", "audio", multiple=True, help="Audio URL, Base64 data URI, or plain Base64 audio data. Can be repeated.")
601
- @click.option("--audio-url", "audio_url", multiple=True, help="Alias for --audio. Can be repeated.")
602
- @click.option("--file-path", "file_path", multiple=True, help="Local audio file path. Can be repeated.")
603
- @click.option("--model", default=None)
604
- @click.option("--mime-type", default=None, help="MIME type for plain Base64 audio inputs. Defaults to audio/wav.")
605
- @click.option("--parameters", default=None, help="Parameters JSON object")
606
- @click.option("--raw-request", default=None, help="Raw JSON request body")
607
- @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
608
- def audio_recognize(audio, audio_url, file_path, model, mime_type, parameters, raw_request, no_wait):
609
- """Recognize speech from one or more audio inputs."""
610
- from licos_dev_sdk import SpeechRecognitionClient
611
-
645
+ @audio_group.command("recognize")
646
+ @click.option("--audio", "audio", multiple=True, help="Audio URL, Base64 data URI, or plain Base64 audio data. Can be repeated.")
647
+ @click.option("--audio-url", "audio_url", multiple=True, help="Alias for --audio. Can be repeated.")
648
+ @click.option("--file-path", "file_path", multiple=True, help="Local audio file path. Can be repeated.")
649
+ @click.option("--model", default=None)
650
+ @click.option("--mime-type", default=None, help="MIME type for plain Base64 audio inputs. Defaults to audio/wav.")
651
+ @click.option("--parameters", default=None, help="Parameters JSON object")
652
+ @click.option("--raw-request", default=None, help="Raw JSON request body")
653
+ @click.option("--no-wait", is_flag=True, help="Return submit response without polling async tasks")
654
+ def audio_recognize(audio, audio_url, file_path, model, mime_type, parameters, raw_request, no_wait):
655
+ """Recognize speech from one or more audio inputs."""
656
+ from licos_dev_sdk import SpeechRecognitionClient
657
+
612
658
  parameter_payload = _json_option(parameters, "--parameters") or {}
613
659
  raw_payload = _json_option(raw_request, "--raw-request")
614
660
  if not isinstance(parameter_payload, dict):
615
661
  raise click.BadParameter("--parameters must be a JSON object")
616
662
  if raw_payload is not None and not isinstance(raw_payload, dict):
617
663
  raise click.BadParameter("--raw-request must be a JSON object")
618
- if raw_payload is None and not audio and not audio_url and not file_path:
619
- raise click.UsageError("Provide --audio, --audio-url, --file-path, or --raw-request.")
620
- result = SpeechRecognitionClient().recognize(
621
- audios=[*audio, *audio_url],
622
- file_paths=list(file_path),
623
- model=model,
624
- mime_type=mime_type,
625
- parameters=parameter_payload,
626
- raw_request=raw_payload,
627
- wait=not no_wait,
664
+ if raw_payload is None and not audio and not audio_url and not file_path:
665
+ raise click.UsageError("Provide --audio, --audio-url, --file-path, or --raw-request.")
666
+ result = SpeechRecognitionClient().recognize(
667
+ audios=[*audio, *audio_url],
668
+ file_paths=list(file_path),
669
+ model=model,
670
+ mime_type=mime_type,
671
+ parameters=parameter_payload,
672
+ raw_request=raw_payload,
673
+ wait=not no_wait,
628
674
  )
629
675
  _echo_json(result)
630
676
 
@@ -0,0 +1,33 @@
1
+ import os
2
+ from pathlib import Path
3
+
4
+ from licos_dev_cli.main import _path_to_cli_output
5
+
6
+
7
+ def test_project_absolute_path_is_printed_relative(tmp_path, monkeypatch):
8
+ project = tmp_path / "projects"
9
+ monkeypatch.setenv("LICOS_PROJECT_PATH", str(project))
10
+
11
+ assert _path_to_cli_output(project / "reports" / "demo.docx") == "reports/demo.docx"
12
+
13
+
14
+ def test_project_root_is_printed_as_dot(tmp_path, monkeypatch):
15
+ project = tmp_path / "projects"
16
+ monkeypatch.setenv("LICOS_PROJECT_PATH", str(project))
17
+
18
+ assert _path_to_cli_output(project) == "."
19
+
20
+
21
+ def test_external_absolute_path_is_not_trimmed(tmp_path, monkeypatch):
22
+ project = tmp_path / "projects"
23
+ external = tmp_path / "other" / "demo.docx"
24
+ monkeypatch.setenv("LICOS_PROJECT_PATH", str(project))
25
+
26
+ assert _path_to_cli_output(external) == external.as_posix()
27
+
28
+
29
+ def test_agent_default_project_path_is_printed_relative(monkeypatch):
30
+ monkeypatch.delenv("LICOS_PROJECT_PATH", raising=False)
31
+ monkeypatch.delenv("LICOS_WORKSPACE_PATH", raising=False)
32
+
33
+ assert _path_to_cli_output("/workspace/projects/output/demo.docx") == "output/demo.docx"