可视化工作流/PSL(Pop Script Language)脚本

5.5 PSL(Pop Script Language)脚本

在可视化工作流中,大部分需求可以通过 拖拽节点 + 配置参数 来完成。
但在某些场景下,你仍然需要:

  • 对数据做更细粒度的处理(过滤、聚合、映射、重命名字段)
  • 按复杂规则组合多个节点的输出
  • 对全局变量进行灵活控制
  • 写一些“如果……就……”逻辑

为此,Pop 提供了 PSL(Pop Script Language)

一种运行在工作流内部的“脚本化胶水语言”,语法风格接近 TypeScript/JavaScript,
但在运行时注入了 inputnodesglobals 等特殊对象,专门用于操作工作流数据。


一、脚本运行环境概览

在支持脚本的节点中(如「脚本节点」「自定义表达式」「条件判断脚本」等),PSL 运行时会注入一组常用对象:

标识符 类型/含义 典型用途
input 当前节点的输入集合(NodeOutputItem 列表) 读取上游输出、聚合多个输入
nodes 整个工作流中其他节点的快照索引 从任意节点取输出、做交叉计算
globals 全局变量对象,可读可写 存储计数器、配置等跨节点共享的数据
output 当前脚本返回值(通过 return 设置) 决定节点的最终输出

你可以把它理解为:

function script({ input, nodes, globals }) {
  // 在这里写 PSL 代码
  return ...; // 作为当前节点输出
}

PSL 并不是完整的浏览器环境

  • 没有 windowdocument 等 DOM 对象
  • 不能直接发起网络请求(请使用 HTTP 节点)
  • 不能直接访问本地文件(请使用文件相关节点)

它的职责:专注于 工作流数据处理与逻辑控制


二、input 对象:访问当前节点输入

input 表示当前节点收到的所有输入端口数据,是 PSL 中最常用的对象之一。

在 PSL 中,你可以像下面这样使用 input

1. 快速访问首个输出项

input.value; // 首个输入项的值
input.type; // 首个输入项的数据类型,如 "text" / "json" 等
input.meta; // 首个输入项的元信息
input.output; // 首个输出项完整对象 { type, value, meta, ... }

适合只有单一输入的简单场景,比如:对上游一个节点的文本结果做二次处理。

2. 访问所有输入项:input[index] / input.all

当当前节点有多个输入时,可以使用数组访问语法:

input[0].value; // 第 1 个输入的值
input[0].type; // 第 1 个输入的类型
input[0].meta; // 第 1 个输入的元信息

input.all[0].output?.value; // 通过 all 访问完整输出结构
input.all[1].meta; // 访问第 2 个输入的元数据

提示:input[index]input.all[index] 返回的元素,都支持 .output / .value / .type / .meta

3. 聚合方法:length / first / byPort / from / flatValues / ofType

input 内置了一组聚合方法,用于快速处理多输入场景:

input.length; // 输入项总数
input.first(); // 返回首个输入项(等价于 input[0])
input.byPort("default"); // 按端口 ID 筛选
input.from("node_12"); // 返回来自指定节点 ID 的输入

input.flatValues(); // 收集所有输入项的 value,组成数组

// 按数据类型筛选
input.ofType("text"); // 只保留文本类型的结果
input.ofType("text").length; // 文本类输入数量
input.ofType("text").map((o) => o.value); // 提取所有文本值

典型用法:

// 将所有文本输入拼成一段话
const text = input
  .ofType("text")
  .map((o) => o.value)
  .join("\n");

return text;

三、nodes 对象:访问任意节点输出

nodes 是一个“节点索引表”,可以在脚本里 随时读取工作流中其他节点的输出

1. 基础用法

nodes[1].output.value; // 第 2 个节点的首个输出值
nodes[8].outputs[0].type; // 第 9 个节点的第 1 个输出类型
nodes.sn(2).output; // 使用 sn(2) 访问第 3 个节点
nodes[3].outputs[1].value; // 第 4 个节点的第 2 个输出值

注意:nodes[n].output 等价于 nodes[n].outputs[0]

典型场景:

  • 在一个“汇总节点”中读取多个前序节点的输出进行合并
  • 在调试脚本中比对不同节点的值

示例:

// 对比两个节点的处理结果是否一致
const a = nodes[2].output.value;
const b = nodes[5].output.value;

return {
  equal: a === b,
  a,
  b,
};

四、globals 对象:全局变量读写

globals 用于存储 工作流级别的状态与配置

  • 计数器(counter)
  • 用户配置(config)
  • 上一步执行结果的缓存

1. 读取全局变量

globals.name; // 如:全局用户名
globals.config; // 任意配置对象

2. 更新全局变量(推荐使用 globals.set

globals.set("name", "lisi");

globals.set("counter", (globals.counter || 0) + 1);

return globals.counter;

建议:始终使用 globals.set(key, value) 更新全局状态,方便未来进行行为跟踪与调试。


五、常用辅助方法与代码片段

除了 input / nodes / globals,PSL 在运行时还配合一系列 常用辅助方法,这些方法大多挂在集合对象上(例如 input.ofTypeinput.flatValues 等)。

1. ofType(type)

按数据类型筛选输出项,返回 NodeOutputItem[]

const texts = input.ofType("text");
const count = input.ofType("number").length;

return {
  textCount: texts.length,
  numberCount: count,
};

2. flatValues()

收集当前集合中所有 outputs[*].value

// 收集所有输入的 value 形成数组
const values = input.flatValues();

// 也可以用于 nodes 某一个节点的 outputs
const nodeValues = nodes[1].outputs.flatValues();

return {
  values,
  nodeValues,
};

六、常用脚本示例

下面的示例与脚本帮助弹窗(ScriptHelpDialog)中的示例保持一致,方便你在界面与文档之间对照查看。

示例 1:拼接所有文本输入

// 文本拼接
return input
  .ofType("text")
  .map((o) => o.value)
  .join(" ");

示例 2:统一返回结构

// 统一返回
return {
  ok: !!input.value,
  values: input.flatValues(),
};

示例 3:多类型结果输出

// 多类型结果
return [
  { type: "boolean", value: input.value === "ok" },
  { type: "text", value: String(nodes[1].type) },
];

示例 4:按条件决定输出内容

// 条件处理
if (input.length > 0) {
  return input.flatValues().join("\n");
} else {
  return "暂无数据";
}

七、编写 PSL 时的注意事项

  1. 尽量保持脚本纯函数化

    • 相同输入 → 相同输出
    • 便于调试和复用
  2. 不要在脚本中做重型计算

    • 如大规模文件处理、网络请求,应该交给专门节点完成
  3. 全局变量只放“状态”与“配置”

    • 避免把大型数组或大量中间结果塞进 globals
  4. 善用 Script 帮助面板

    • 编辑脚本时,点击「脚本帮助」,可以快速查看 input / nodes / globals / funcs 的说明与示例

八、小结

PSL(Pop Script Language)是 Pop 工作流中处理数据与控制细节逻辑的核心能力之一:

  • 通过 input / nodes / globals 访问整个工作流的数据与状态
  • 通过聚合方法(ofTypeflatValues 等)简化数组和多输出处理
  • 通过简洁的脚本实现条件分支、格式转换、结果包装

推荐使用方式:

  1. 优先使用节点组合 完成大部分流程;
  2. 仅在需要细节处理时,引入 PSL 作为“胶水层”;
  3. 将常用脚本整理为片段(Snippets),在多个工作流中复用。

熟练掌握 PSL,可以大幅提升你在 Pop 中构建复杂自动化与 AI 流程的效率。