Skip to content

Repository files navigation

fal-cli

Schema 驱动的 fal.ai CLI。加新 model = 加一份 TypeScript schema 声明,零改 engine。

安装

npm install
npm run build
export FAL_KEY=your_fal_key
node dist/fal-cli.js list

npm link 可把 fal-cli 暴露到 PATH(指向 dist/fal-cli.js)。

用法

fal-cli list                                 # 列出所有 model alias
fal-cli describe <alias>                     # 查看该 alias 的完整 schema(字段/类型/枚举)
fal-cli describe <alias> --json              # 机读 JSON,方便 agent 消费
fal-cli run <alias> --help                   # 查看该 model 的 CLI flag
fal-cli run gpt-image-2 -p "a cozy cabin at dawn"
fal-cli run gpt-image-2-edit -p "neon tokyo" -i ./photo.png
fal-cli run nano-banana-2 -p "..." --aspect 16:9 --resolution 2K
fal-cli fetch gpt-image-2 <request_id>       # 按 request_id 补捞历史结果

通用运行时 flag:

  • -o, --output-dir <dir> 下载目录,默认 ./fal-output
  • --no-download 不下载,仅打印 URL
  • --json 输出原始 JSON
  • --logs 打印队列进度日志

历史

每次调用写入 ~/.fal-cli/history.jsonl(JSONL,一行一条):

{"ts":"...","status":"submitted","alias":"...","endpoint":"...","request_id":"...","input":{...}}
{"ts":"...","status":"ok","...":"...","urls":[...]}
{"ts":"...","status":"error","...":"...","error":"..."}

jq 示例:

# 最近一次失败的 request_id
tac ~/.fal-cli/history.jsonl | jq -r 'select(.status=="error") | .request_id' | head -1

# 所有成功生成的 URL
jq -r 'select(.status=="ok") | .urls[]' ~/.fal-cli/history.jsonl

架构

bin/fal-cli.ts              # 入口:list / run / fetch 分派
src/
  types.ts                  # FieldSpec discriminated union / Schema / ModalityModule
  schema/                   # 每个 model 一份 schema 声明
    _shared.ts              # 跨 model 复用的字段
    <provider>/<model>.ts   # 按 provider 归类(bytedance/openai/google/seedvr 等)
    index.ts                # 注册表
  engine/
    build-command.ts        # schema → commander Command
    validate.ts             # opts → fal input payload(类型 coerce + 范围校验)
    run.ts                  # subscribe / queue.result / 结果派发
  modality/
    image.ts                # 本地图上传 / 产物下载 / zod 解析 fal 返回
    index.ts
  client.ts                 # FAL_KEY → fal.config
  history.ts                # ~/.fal-cli/history.jsonl

设计原则:

  • engine 是 schema 的唯一消费者。bin 不懂字段类型,不 import zod。
  • FieldSpec 的 type 是 discriminated union。engine 里的 switch 被 assertNever 兜底 —— 加一种 type 但忘改 engine 会在 tsc 失败。
  • modality 承担「这个模态的数据长啥样」。zod 解析 fal 返回只出现在 modality 层。

加一个新 image model

  1. src/schema/<provider>/ 新建 <model>.ts(provider 目录不存在就新建):

    import type { Schema } from "../../types.js";
    import { numImagesField, outputFormatField } from "../_shared.js";
    
    const schema: Schema = {
      alias: "flux-pro",
      endpoint: "fal-ai/flux-pro",
      modality: "image",
      summary: "Black Forest Labs FLUX Pro",
      fields: [
        {
          name: "prompt", cliKey: "prompt", type: "string", required: true,
          flag: "-p, --prompt <text>", desc: "描述",
        },
        numImagesField,
        outputFormatField,
        // 新独有字段直接加在这里
      ],
    };
    export default schema;
  2. src/schema/index.ts 里 import 并加入 ALL

  3. npm run buildfal-cli list 能看到。

FieldSpec 支持的 type:string | enum | integer | boolean | size | image | image[]。如果新 model 需要别的 type(如 floaturlaudio),在 src/types.ts 的 discriminated union 里加一个分支,tsc 会指出哪些文件漏处理。

加一个新模态(比如 video)

  1. src/types.tsModality = "image" 改成 "image" | "video",给 ModalityModule 看看是否还需要调整(比如 extractArtifacts 的返回类型是否要扩成 Artifact)。
  2. src/modality/video.ts 实现 ModalityModule 的三个函数。
  3. src/modality/index.ts 注册到 REGISTRY
  4. schema 里写 modality: "video"

开发

npm run typecheck   # 只做类型检查
npm run build       # 编译到 dist/
npm run start       # 运行 dist/fal-cli.js

鉴权

仅读环境变量 FAL_KEY。未设置会直接报错并退出。

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages