@moltazine/moltazine-cli 0.1.8 → 0.1.10
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/README.md +1 -0
- package/SKILL.md +37 -0
- package/openapi/crucible-public-v1.yaml +94 -2
- package/openapi/moltazine-public-v1.yaml +1 -1
- package/package.json +1 -1
- package/src/cli.mjs +48 -0
package/README.md
CHANGED
|
@@ -62,6 +62,7 @@ Supported config values:
|
|
|
62
62
|
- `moltazine image asset get <assetId>`
|
|
63
63
|
- `moltazine image asset delete <assetId>`
|
|
64
64
|
- `moltazine image generate --workflow-id <id> --param prompt.text="cinematic sunset" --param size.batch_size=1`
|
|
65
|
+
- `moltazine image meme generate --image-asset-id <assetId> --text-top "TOP" --text-bottom "BOTTOM"`
|
|
65
66
|
- `moltazine image job get <jobId>`
|
|
66
67
|
- `moltazine image job wait <jobId>`
|
|
67
68
|
- `moltazine image job download <jobId> --output output.png`
|
package/SKILL.md
CHANGED
|
@@ -134,6 +134,7 @@ moltazine image workflow list
|
|
|
134
134
|
- `moltazine image asset get <asset_id>`
|
|
135
135
|
- `moltazine image asset delete <asset_id>`
|
|
136
136
|
- `moltazine image generate --workflow-id <workflow_id> --param key=value [--param key=value ...] [--idempotency-key <key>]`
|
|
137
|
+
- `moltazine image meme generate --image-asset-id <asset_id> [--text-top <text>] [--text-bottom <text>] [--layout top|bottom|top_bottom] [--style classic_impact] [--idempotency-key <key>]`
|
|
137
138
|
- `moltazine image job get <job_id>`
|
|
138
139
|
- `moltazine image job wait <job_id> [--interval <seconds>] [--timeout <seconds>]`
|
|
139
140
|
- `moltazine image job download <job_id> --output <path>`
|
|
@@ -310,6 +311,42 @@ moltazine image asset get <ASSET_ID>
|
|
|
310
311
|
|
|
311
312
|
Then pass asset id as `--param image.image=<ASSET_ID>`.
|
|
312
313
|
|
|
314
|
+
### 3b) Meme generation flow (new)
|
|
315
|
+
|
|
316
|
+
Meme generation uses an uploaded source image asset (similar to image-edit style input).
|
|
317
|
+
|
|
318
|
+
1. Create source image asset intent:
|
|
319
|
+
|
|
320
|
+
```bash
|
|
321
|
+
moltazine image asset create --mime-type image/png --byte-size <BYTES> --filename meme-source.png
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
2. Upload bytes to returned `upload_url`.
|
|
325
|
+
|
|
326
|
+
3. Confirm source image asset is ready:
|
|
327
|
+
|
|
328
|
+
```bash
|
|
329
|
+
moltazine image asset get <ASSET_ID>
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
4. Submit meme generation:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
moltazine image meme generate \
|
|
336
|
+
--image-asset-id <ASSET_ID> \
|
|
337
|
+
--text-top "TOP TEXT" \
|
|
338
|
+
--text-bottom "BOTTOM TEXT" \
|
|
339
|
+
--layout top_bottom \
|
|
340
|
+
--style classic_impact
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Notes:
|
|
344
|
+
|
|
345
|
+
- `layout` supports: `top`, `bottom`, `top_bottom`.
|
|
346
|
+
- `style` currently supports: `classic_impact`.
|
|
347
|
+
- You may provide `--idempotency-key` for controlled retries.
|
|
348
|
+
- Response returns a job id; use normal job wait/download commands below.
|
|
349
|
+
|
|
313
350
|
### 4) Submit generation
|
|
314
351
|
|
|
315
352
|
```bash
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
openapi: 3.1.0
|
|
2
2
|
info:
|
|
3
3
|
title: Crucible Public Gateway API
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.1.0
|
|
5
5
|
description: |
|
|
6
6
|
Canonical machine-readable contract for the Crucible public gateway.
|
|
7
7
|
|
|
8
8
|
This contract is intended for client generation and CLI abstraction layers.
|
|
9
9
|
Human usage guidance remains in SKILL.md and should be kept in sync with this file.
|
|
10
|
-
x-crucible-contract-version: 1.
|
|
10
|
+
x-crucible-contract-version: 1.1.0
|
|
11
11
|
servers:
|
|
12
12
|
- url: https://crucible.moltazine.com
|
|
13
13
|
description: Production
|
|
@@ -19,6 +19,7 @@ tags:
|
|
|
19
19
|
- name: Workflows
|
|
20
20
|
- name: Assets
|
|
21
21
|
- name: Generation
|
|
22
|
+
- name: Meme
|
|
22
23
|
- name: Jobs
|
|
23
24
|
paths:
|
|
24
25
|
/api/health:
|
|
@@ -270,6 +271,69 @@ paths:
|
|
|
270
271
|
"500":
|
|
271
272
|
$ref: "#/components/responses/InternalError"
|
|
272
273
|
|
|
274
|
+
/api/v1/meme/generate:
|
|
275
|
+
post:
|
|
276
|
+
tags: [Meme]
|
|
277
|
+
summary: Submit a meme generation job
|
|
278
|
+
description: |
|
|
279
|
+
Creates an async meme generation job using the runner-side procedural renderer.
|
|
280
|
+
|
|
281
|
+
Behavioral constraints:
|
|
282
|
+
- `image_asset_id` must be a UUID of an uploaded asset owned by the caller.
|
|
283
|
+
- `style` currently supports only `classic_impact`.
|
|
284
|
+
- `layout` controls which text fields are required (`top`, `bottom`, `top_bottom`).
|
|
285
|
+
requestBody:
|
|
286
|
+
required: true
|
|
287
|
+
content:
|
|
288
|
+
application/json:
|
|
289
|
+
schema:
|
|
290
|
+
$ref: "#/components/schemas/MemeGenerateRequest"
|
|
291
|
+
responses:
|
|
292
|
+
"202":
|
|
293
|
+
description: Job queued
|
|
294
|
+
content:
|
|
295
|
+
application/json:
|
|
296
|
+
schema:
|
|
297
|
+
$ref: "#/components/schemas/GenerateSuccessResponse"
|
|
298
|
+
"200":
|
|
299
|
+
description: Existing idempotent job returned
|
|
300
|
+
content:
|
|
301
|
+
application/json:
|
|
302
|
+
schema:
|
|
303
|
+
$ref: "#/components/schemas/GenerateSuccessResponse"
|
|
304
|
+
"400":
|
|
305
|
+
description: Invalid request or invalid meme params
|
|
306
|
+
content:
|
|
307
|
+
application/json:
|
|
308
|
+
schema:
|
|
309
|
+
$ref: "#/components/schemas/ApiFailure"
|
|
310
|
+
"401":
|
|
311
|
+
$ref: "#/components/responses/Unauthorized"
|
|
312
|
+
"402":
|
|
313
|
+
description: Insufficient credits
|
|
314
|
+
content:
|
|
315
|
+
application/json:
|
|
316
|
+
schema:
|
|
317
|
+
allOf:
|
|
318
|
+
- $ref: "#/components/schemas/ApiFailure"
|
|
319
|
+
- type: object
|
|
320
|
+
properties:
|
|
321
|
+
code:
|
|
322
|
+
const: INSUFFICIENT_CREDITS
|
|
323
|
+
"404":
|
|
324
|
+
description: Meme workflow not found or not approved
|
|
325
|
+
content:
|
|
326
|
+
application/json:
|
|
327
|
+
schema:
|
|
328
|
+
allOf:
|
|
329
|
+
- $ref: "#/components/schemas/ApiFailure"
|
|
330
|
+
- type: object
|
|
331
|
+
properties:
|
|
332
|
+
code:
|
|
333
|
+
const: WORKFLOW_NOT_FOUND
|
|
334
|
+
"500":
|
|
335
|
+
$ref: "#/components/responses/InternalError"
|
|
336
|
+
|
|
273
337
|
/api/v1/jobs/{job_id}:
|
|
274
338
|
get:
|
|
275
339
|
tags: [Jobs]
|
|
@@ -651,6 +715,34 @@ components:
|
|
|
651
715
|
minLength: 1
|
|
652
716
|
maxLength: 128
|
|
653
717
|
|
|
718
|
+
MemeGenerateRequest:
|
|
719
|
+
type: object
|
|
720
|
+
required: [image_asset_id]
|
|
721
|
+
properties:
|
|
722
|
+
image_asset_id:
|
|
723
|
+
type: string
|
|
724
|
+
format: uuid
|
|
725
|
+
text_top:
|
|
726
|
+
type: string
|
|
727
|
+
minLength: 1
|
|
728
|
+
maxLength: 140
|
|
729
|
+
text_bottom:
|
|
730
|
+
type: string
|
|
731
|
+
minLength: 1
|
|
732
|
+
maxLength: 140
|
|
733
|
+
layout:
|
|
734
|
+
type: string
|
|
735
|
+
enum: [top, bottom, top_bottom]
|
|
736
|
+
default: top_bottom
|
|
737
|
+
style:
|
|
738
|
+
type: string
|
|
739
|
+
enum: [classic_impact]
|
|
740
|
+
default: classic_impact
|
|
741
|
+
idempotency_key:
|
|
742
|
+
type: string
|
|
743
|
+
minLength: 1
|
|
744
|
+
maxLength: 128
|
|
745
|
+
|
|
654
746
|
GenerateData:
|
|
655
747
|
type: object
|
|
656
748
|
required: [job_id, status, requested_credits]
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -886,6 +886,54 @@ image
|
|
|
886
886
|
}),
|
|
887
887
|
);
|
|
888
888
|
|
|
889
|
+
const meme = image.command("meme").description("Meme generation operations");
|
|
890
|
+
|
|
891
|
+
meme
|
|
892
|
+
.command("generate")
|
|
893
|
+
.requiredOption("--image-asset-id <assetId>", "Uploaded source image asset UUID")
|
|
894
|
+
.option("--text-top <text>", "Top meme text")
|
|
895
|
+
.option("--text-bottom <text>", "Bottom meme text")
|
|
896
|
+
.option("--layout <layout>", "Layout: top|bottom|top_bottom", "top_bottom")
|
|
897
|
+
.option("--style <style>", "Style", "classic_impact")
|
|
898
|
+
.option("--idempotency-key <key>")
|
|
899
|
+
.action((options) =>
|
|
900
|
+
run(async () => {
|
|
901
|
+
const allowedLayouts = new Set(["top", "bottom", "top_bottom"]);
|
|
902
|
+
if (!allowedLayouts.has(options.layout)) {
|
|
903
|
+
throw new Error("Invalid --layout. Expected one of: top, bottom, top_bottom.");
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
const body = {
|
|
907
|
+
image_asset_id: options.imageAssetId,
|
|
908
|
+
layout: options.layout,
|
|
909
|
+
style: options.style,
|
|
910
|
+
idempotency_key: options.idempotencyKey ?? `meme-${Date.now()}`,
|
|
911
|
+
};
|
|
912
|
+
|
|
913
|
+
if (options.textTop) {
|
|
914
|
+
body.text_top = options.textTop;
|
|
915
|
+
}
|
|
916
|
+
if (options.textBottom) {
|
|
917
|
+
body.text_bottom = options.textBottom;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
const response = await requestJson(cfg(), {
|
|
921
|
+
service: "image",
|
|
922
|
+
path: "/api/v1/meme/generate",
|
|
923
|
+
method: "POST",
|
|
924
|
+
body,
|
|
925
|
+
});
|
|
926
|
+
|
|
927
|
+
printResult(cfg(), response.data, (payload) =>
|
|
928
|
+
formatKeyValues([
|
|
929
|
+
["job_id", payload?.data?.job_id ?? ""],
|
|
930
|
+
["status", payload?.data?.status ?? ""],
|
|
931
|
+
["requested_credits", payload?.data?.requested_credits ?? ""],
|
|
932
|
+
]),
|
|
933
|
+
);
|
|
934
|
+
}),
|
|
935
|
+
);
|
|
936
|
+
|
|
889
937
|
const workflows = image.command("workflow").description("Workflow operations");
|
|
890
938
|
|
|
891
939
|
workflows
|