@merpuya/falgen-cli 0.1.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.
Files changed (2) hide show
  1. package/dist/falgen.js +127 -0
  2. package/package.json +23 -0
package/dist/falgen.js ADDED
@@ -0,0 +1,127 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/falgen.ts
4
+ import { pathToFileURL } from "url";
5
+ import { Command } from "commander";
6
+
7
+ // src/commands/auth.ts
8
+ import { setKey } from "@merpuya/falgen";
9
+ async function runAuthSet(key) {
10
+ const path = await setKey(key);
11
+ console.log(`wrote ${path}`);
12
+ }
13
+
14
+ // src/commands/gen.ts
15
+ import { generate } from "@merpuya/falgen";
16
+ function buildGenerateInput(prompt, flags) {
17
+ const input = { prompt };
18
+ if (flags.spec !== void 0) input.spec = flags.spec;
19
+ if (flags.model !== void 0) input.model = flags.model;
20
+ if (flags.width !== void 0) input.width = flags.width;
21
+ if (flags.height !== void 0) input.height = flags.height;
22
+ if (flags.steps !== void 0) input.steps = flags.steps;
23
+ if (flags.guidance !== void 0) input.guidance = flags.guidance;
24
+ if (flags.seed !== void 0) input.seed = flags.seed;
25
+ if (flags.numImages !== void 0) input.numImages = flags.numImages;
26
+ const output = {};
27
+ if (flags.out !== void 0) output.dir = flags.out;
28
+ if (flags.sidecar !== void 0) output.sidecar = flags.sidecar;
29
+ if (Object.keys(output).length > 0) input.output = output;
30
+ return input;
31
+ }
32
+ function printArtifacts(artifacts) {
33
+ for (const a of artifacts) {
34
+ console.log(`${a.path ?? a.url}${a.sidecarPath ? ` (+ ${a.sidecarPath})` : ""}`);
35
+ }
36
+ }
37
+ async function runGen(prompt, flags) {
38
+ const result = await generate(buildGenerateInput(prompt, flags));
39
+ printArtifacts(result.artifacts);
40
+ if (result.seed !== void 0) console.log(`seed: ${result.seed}`);
41
+ }
42
+
43
+ // src/commands/repro.ts
44
+ import { readFile } from "fs/promises";
45
+ import { generate as generate2, ImageRequest } from "@merpuya/falgen";
46
+ async function runRepro(sidecarPath, deps = {}) {
47
+ const gen = deps.generate ?? generate2;
48
+ const raw = JSON.parse(await readFile(sidecarPath, "utf8"));
49
+ const resolved = ImageRequest.parse(raw.resolved);
50
+ return gen(resolved);
51
+ }
52
+
53
+ // src/commands/spec.ts
54
+ import { mkdir, writeFile } from "fs/promises";
55
+ import { homedir } from "os";
56
+ import { join } from "path";
57
+ import { stringify as toYaml } from "yaml";
58
+ import { FileSpecSource, defaultSpecSearchPath, listSpecs } from "@merpuya/falgen";
59
+ async function runSpecList() {
60
+ const specs = await listSpecs();
61
+ console.log(specs.length ? specs.join("\n") : "(no specs found)");
62
+ }
63
+ async function runSpecShow(name) {
64
+ const src = new FileSpecSource(defaultSpecSearchPath());
65
+ console.log(toYaml(await src.load(name)));
66
+ }
67
+ async function runSpecAdd(name, opts) {
68
+ const dir = opts.local ? join(process.cwd(), "falgen", "specs") : join(homedir(), ".config", "falgen", "specs");
69
+ await mkdir(dir, { recursive: true });
70
+ const path = join(dir, `${name}.yaml`);
71
+ const template = toYaml({
72
+ model: "fal-ai/flux/dev",
73
+ width: 1024,
74
+ height: 1024,
75
+ steps: 28,
76
+ guidance: 3.5
77
+ });
78
+ await writeFile(path, template, { flag: "wx" });
79
+ console.log(`created ${path}`);
80
+ }
81
+
82
+ // src/falgen.ts
83
+ var toInt = (v) => Number.parseInt(v, 10);
84
+ var toNum = (v) => Number.parseFloat(v);
85
+ function buildProgram() {
86
+ const program = new Command();
87
+ program.name("falgen").description("Generate images via fal.ai to reusable specs");
88
+ program.command("gen").argument("<prompt>", "image prompt").option("-s, --spec <name>", "preset name").option("-m, --model <id>", "fal model id").option("--width <px>", "width", toInt).option("--height <px>", "height", toInt).option("--steps <n>", "inference steps", toInt).option("--guidance <n>", "guidance scale", toNum).option("--seed <n>", "seed", toInt).option("-n, --num-images <n>", "number of images", toInt).option("-o, --out <dir>", "output dir").option("--no-sidecar", "skip the json sidecar").action(async (prompt, o) => {
89
+ const flags = {
90
+ spec: o.spec,
91
+ model: o.model,
92
+ width: o.width,
93
+ height: o.height,
94
+ steps: o.steps,
95
+ guidance: o.guidance,
96
+ seed: o.seed,
97
+ numImages: o.numImages,
98
+ out: o.out,
99
+ sidecar: o.sidecar
100
+ };
101
+ await runGen(prompt, flags);
102
+ });
103
+ const spec = program.command("spec").description("manage preset specs");
104
+ spec.command("list").action(runSpecList);
105
+ spec.command("show").argument("<name>").action(runSpecShow);
106
+ spec.command("add").argument("<name>").option("--local", "write to ./falgen/specs").action(
107
+ (name, o) => runSpecAdd(name, o)
108
+ );
109
+ const auth = program.command("auth").description("manage the FAL_KEY");
110
+ auth.command("set").argument("<key>").action(runAuthSet);
111
+ program.command("repro").argument("<sidecar>", "path to a sidecar .json").action(
112
+ async (p) => {
113
+ const res = await runRepro(p);
114
+ printArtifacts(res.artifacts);
115
+ }
116
+ );
117
+ return program;
118
+ }
119
+ if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
120
+ buildProgram().parseAsync().catch((err) => {
121
+ console.error(err instanceof Error ? err.message : err);
122
+ process.exitCode = 1;
123
+ });
124
+ }
125
+ export {
126
+ buildProgram
127
+ };
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@merpuya/falgen-cli",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "falgen": "./dist/falgen.js"
7
+ },
8
+ "files": [
9
+ "dist"
10
+ ],
11
+ "engines": {
12
+ "node": ">=20"
13
+ },
14
+ "dependencies": {
15
+ "commander": "^12.1.0",
16
+ "yaml": "^2.5.0",
17
+ "@merpuya/falgen": "0.1.0"
18
+ },
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "typecheck": "tsc --noEmit"
22
+ }
23
+ }