UI控件 (UI Schema)

本章节系统介绍 GdiSDK 中用于描述模块参数 UI 交互的 UI Schema / AttributeSchema 体系, 以及它与 GDIM 平台之间的关系。对应代码主要位于 gdisdk.pipeline.pipeDatagdisdk.pipeline.pipeline 中的若干 Pydantic 模型, 例如 gdisdk.pipeline.pipeData.UIAttributeSchema 及其子类。

总体来看:

  • ui schema 的直接作用:让 Pipeline / 模块的「Python 参数」映射成一组结构化的 UI 控件;

  • ui schema 与 GDIM 的关系:GDIM 在加载 .pipe 文件时,会读取这些 ui schema,自动生成参数表单, 让最终用户可以在 Web 端安全地配置模块参数,而无需理解底层代码;

  • 额外能力:在上传 Pipeline 后,GDIM 还支持通过可视化拖拽控件的方式设计参数区和结果区的布局, ui schema 提供「字段和控件的语义」,GDIM 则负责「编排和排版」。

什么是 UI Schema?

gdisdk.pipeline.pipeline.PipeModule 中,可以选择性地重写 update_ui_schema, 返回一个以「参数名」为键、以 UIAttributeSchema 派生类为值的字典,用来描述 「这个参数应该如何在 UI 中展示和编辑」:

from gdisdk.pipeline.pipeData import UIAttributeSchema, FloatAttributeSchema


def update_ui_schema(self, reset: bool = False) -> dict[str, UIAttributeSchema]:
    return {
        "threshold": FloatAttributeSchema(
            title="阈值",
            default=self.threshold,
            minimum=None,
            maximum=None,
        ),
    }

当 Pipeline 被保存为 .pipe 并上传到 GDIM 后:

  • GDIM 会读取通过 PipeLine.add_attribute 注册到 Pipeline 属性中的 ui schema,基于这些属性生成参数控件(输入框、下拉、多选、文件选择等); 模块内部的 update_ui_schema 只是提供了一份「默认定义」,真正生效的是 Pipeline 属性上的 ui schema,且可以在 add_attribute(..., ui_schema_overrides=...) 中被重写;

  • 应用配置者还可以在 GDIM 管理端使用可视化拖拽方式,调整这些控件和结果展示组件的布局, 例如把某些参数放在同一分组、将主结果图表放在首屏等。

因此可以理解为: ui schema 是为了让 Pipeline 能够在 GDIM / 其他前端上「可视化运行」而生的, 它把模块的内部参数暴露为结构化表单字段,方便非开发者安全地修改参数。

常用 UIAttributeSchema 类型概览

CustomAttributeSchema 外,其他具体控件类型均继承自 gdisdk.pipeline.pipeData.BaseAttributeSchema。 该基类中包含了一组通用字段,例如:

  • title:在 UI 中显示的标题;

  • default:默认值;

  • required:是否必填;

  • visible / readonly:是否在 UI 中可见、是否只读;

  • units:物理量单位(通常来自 gdisdk.dataclass.terminologies 中的 Units);

  • selections / selections_name:枚举 / 下拉值列表及其显示名;

  • depends_on:依赖的模块参数或端口名(如 "InputToken"),用于动态更新选项;

  • widget:建议使用的前端控件类型(如 "select""textarea" 等);

  • widget_attributes:补充的控件配置(例如「下拉启用搜索」「多选」等)。

在此基础上,常见的子类包括(均定义在 gdisdk.pipeline.pipeData 中):

  • StringAttributeSchema 文本输入;可通过 selections / selections_name 配置为下拉框 / 单选框等。

  • IntegerAttributeSchema / FloatAttributeSchema 整数 / 浮点数输入;支持 minimum / maximum / exclude_minimum / exclude_maximum 等数值约束。

  • BooleanAttributeSchema 布尔开关,一般在 UI 中表现为滑动开关。

  • ArrayAttributeSchema 列表 / 多选类控件,常见场景包括「多选表名」「多选列名」等; 通过 items 指定单个元素的 Schema(通常是 StringAttributeSchema), 并可使用 min_items / max_items 控制长度。

  • ObjectAttributeSchema 复杂嵌套对象;通过 properties 定义子字段,用于「结构化配置」场景,例如多字段组合参数。

  • FileAttributeSchema 文件或 GDIM 文件对象配置;通常对应「文件选择 / 上传 / 下载」类控件, 常见于需要用户选择报告模板、上传 Excel、下载生成文件等场景。

  • CustomAttributeSchema``(``vtype="general") 自定义 UI,不由 GDIM 自动生成控件。用于地图选点、专用编辑器等需要前后端单独约定的场景。 仅可作为顶层 Pipeline 属性使用,不能嵌套在 object / array / table 中。 通过 titledescription``default``(示例值)等字段与前端开发者对齐数据结构; 实际取值校验由模块代码负责。

与 PipeLine 属性及 GDIM UI 的协同

在模块内部定义好 update_ui_schema 之后,通常会通过 PipeLine.add_attribute 把关键参数提升为 Pipeline 属性,供 GDIM 或其他前端统一配置,例如:

pipeline.add_attribute(
    attr_name="tpl_number",
    module_name="QueryTable",
    param_name="tpl_number",
    attr_title="沉降点编号",
)

这里:

  • 模块 QueryTableupdate_ui_schema 定义了 tpl_number 字段的 ui schema (值类型、下拉选项、是否多选等);

  • add_attribute 则把它映射为 Pipeline 层的一个属性 tpl_number, 让 GDIM 可以在「应用配置界面」中展示为一个可编辑控件;

  • 运行时,GDIM 会把用户在表单里填写的值写回 Pipeline,再由 Pipeline 写回对应模块参数。

add_attribute 还支持 ui_schema_overrides 参数,可以在 不改动模块源码 的前提下, 对字段的 ui schema 做二次定制,例如:

from gdisdk.llm.promptTemplates import SystemDomainPrompt

pipeline.add_attribute(
    attr_name="system_prompt",
    module_name="TableAnalyzer",
    param_name="system_prompt",
    attr_title="智能助手角色",
    ui_schema_overrides={
        "default": SystemDomainPrompt.GEOLOGICAL.value,
        "selections": [
            SystemDomainPrompt.GEOLOGICAL.value,
            SystemDomainPrompt.GEOTECHNICAL_ENGINEERING.value,
            SystemDomainPrompt.HYDROGEOLOGY.value,
            SystemDomainPrompt.GROUNDWATER_CONTAMINATION.value,
        ],
        "selections_name": [
            "地质专家",
            "岩土工程专家",
            "水文地质专家",
            "地下水污染专家",
        ],
    },
)

当需要 完全自定义 某个 Pipeline 属性的 UI schema 时(而不是在模块已有 schema 上做字段级微调),应使用 add_attribute(..., ui_schema_function_name=...)。 此时模块预设的 ui schema 与 ui_schema_overrides 都会被忽略,由本地函数直接返回 一个完整的 UIAttributeSchema

典型场景包括:

  • 需要换成另一种控件类型 / vtype``(例如模块内置是 ``StringAttributeSchema, 当前应用要用 FloatAttributeSchema)。ui_schema_overrides 无法 修改 vtype,因为它只会在 原有 schema 类型 上更新字段,不会换成另一类 schema;

  • 选项、默认值等依赖上游模块输出或其他 Pipeline 上下文,需要运行时动态生成;

  • 模块本身没有可用的 ui_schema,必须自行提供完整定义。

注意:写在 add_attribute 上的本地函数约定,与 PythonCoder 模块上的 ui_schema_function_name 不同,请勿混用。

方式一:写在 add_attribute 上(Pipeline 级,按属性)

适用于非 PythonCoder 模块,或需要在 Pipeline 层 整体替换 某参数 UI schema 的场景。

  • 函数由 PipeLine.add_attribute / get_attribute_info 调用;

  • 第一个参数是 pipeline``(``PipeLine 实例),不是模块;

  • 返回值是单个 UIAttributeSchema``(不是 ``dict);

  • 文件方式下函数须用 @local_function 装饰,并通过 pipeline.local_functions_path 加载;也可直接传入 inline callable。

from gdisdk.pipeline.nameSpace import local_function
from gdisdk.pipeline.pipeData import StringAttributeSchema


@local_function
def dynamic_soil_schema(pipeline, **kwargs) -> StringAttributeSchema:
    """按上游模块输出动态生成下拉选项。"""
    data_module = pipeline.get_module("DataReader")
    # 输出端口:使用 module["OutputXxx"] 公开写法
    soil_types = data_module["OutputSoilTypes"] if data_module else []
    return StringAttributeSchema(
        title="土层类型",
        selections=soil_types or [],
        # 依赖输入端口时,GDIM 会在上游数据就绪后刷新该属性的 schema
        depends_on=["InputSoilData"],
    )


pipeline.add_attribute(
    attr_name="soil_type",
    module_name="SoilModule",
    param_name="type",
    attr_title="土层类型",
    ui_schema_function_name="dynamic_soil_schema",
)

需要读取目标模块的 输入端口 数据时,请使用 module._ports_in["InputXxx"].datamodule.InputXxx.data / module["InputXxx"] 走的是输出端口 API,对输入端口不适用)。 例如从 LineChartInputData 生成 y_columns 选项:

@local_function
def factor_ui_schema(pipeline, **kwargs) -> StringAttributeSchema:
    line_chart = pipeline.get_module("LineChart")
    table = None
    if line_chart is not None:
        in_port = line_chart._ports_in.get("InputData")
        table = in_port.data if in_port is not None else None

    factor_names: list[str] = []
    factor_titles: list[str] = []
    if table is not None:
        factor_names = [
            col
            for col in table.columns
            if table.get_field_metadata(col).data_format == "pollutantConcentration"
        ]
        factor_titles = [
            table.get_field_metadata(col).title for col in factor_names
        ]

    schema = StringAttributeSchema(
        title="检测因子名称",
        default="硫酸盐",
        selections=factor_names,
        selections_name=factor_titles,
        depends_on=["InputData"],
    )
    schema.widget = "select"
    return schema

方式二:写在 PythonCoder 模块上(模块级,一次覆盖全部自定义属性)

适用于 PythonCoder.add_attributes(...) 声明的自定义参数:把 coder.ui_schema_function_name = "my_ui_schema" 设在模块上,再对每个参数调用 pipeline.add_attribute(...)不要 再传 ui_schema_function_name

  • 函数由模块的 update_ui_schema 调用;

  • 第一个参数是 ``module``(该 PythonCoder 实例);

  • 返回值是 dict[str, UIAttributeSchema],键为全部自定义属性名;

  • 建议签名:def my_ui_schema(module, reset: bool = False, **kwargs): ...

from gdisdk.pipeline.nameSpace import local_function
from gdisdk.pipeline.pipeData import FloatAttributeSchema, IntegerAttributeSchema


@local_function
def terrain_ui_schema(module, reset: bool = False, **kwargs):
    return {
        "vertical_exaggeration": FloatAttributeSchema(
            title="竖向放大系数",
            default=getattr(module, "vertical_exaggeration", 1.0),
            minimum=0.1,
            maximum=10.0,
        ),
        "contour_count": IntegerAttributeSchema(
            title="等值线数量",
            default=getattr(module, "contour_count", 12),
            minimum=1,
            maximum=100,
        ),
    }


coder.ui_schema_function_name = "terrain_ui_schema"
pipeline.add_attribute(
    attr_name="vertical_exaggeration",
    module_name="TerrainBuilder",
    param_name="vertical_exaggeration",
    attr_title="竖向放大系数",
)

两种方式的对比:

场景

设置位置

函数约定

完全自定义 schema(含更换 vtype、动态选项、模块无预设 schema 等)

add_attribute(..., ui_schema_function_name=...)

(pipeline, **kwargs) -> UIAttributeSchema

PythonCoder 自定义属性的静态/模块内 UI

模块 ui_schema_function_name

(module, reset=False, **kwargs) -> dict

仅在 同一 schema 类型上改默认值、选项、可见性等

ui_schema_overrides

无需本地函数(不能改 vtype

Note

上传 GDIM 时,ui_schema_function_name 应优先使用 **字符串函数名**(配合 pipeline.local_functions_path),避免 inline callable 无法随 .pipe 序列化。 PythonCoder 侧更完整的说明见 modules.widgets 模块帮助

这套机制的配合效果是:

  • 模块作者 只需在 update_ui_schema 中声明字段类型和基本 UI 行为;

  • Pipeline 作者 / 应用配置者 可以在不改源码的情况下,针对具体应用场景调整默认值、选项、可见性等, 或通过 ui_schema_function_name 按上游数据动态生成控件;

  • GDIM 平台 则基于这些结构化信息,把参数和结果以表单 + 组件的形式「编排」成应用界面, 包括通过拖拽来调整布局、分组、标签页等。

若属性配置了 auto_bind,前端不再按该属性的 ui_schema 渲染控件, ui_schema_overrides / ui_schema_function_name 会被忽略;attr_schema 仍会随 get_attribute_info() 返回。两种取值:

  • auto_bind="poi_field":GDIM 地图类应用 兴趣点弹窗二次开发。前端隐藏控件, 从当前兴趣点数据行按 ``bind_field``(字段名或标题;缺省为 POI 标签)取值并写入该属性。

  • auto_bind="pk_field":数字模型 「自定义数据更新」 中的子表按主表主键更新。 子表场景下前端用自有的「更新范围」下拉框注入主键; 运行时值始终是 list[主键数据类型]``(例如 ``["ZK1"][]),不会是标量。 不要设置 bind_field。主表上该机制会被忽略,属性按普通控件渲染。

详见 用户指南 (User Guide) 中「自动绑定属性(auto_bind)」一节。

更多示例与推荐阅读

  • 用户指南 (User Guide) 中的「如何定义Pipeline的UI交互」「如何定义模块的UI交互」两节, 展示了 ui schema 与 Pipeline 属性、GDIM 前端之间的完整闭环流程;

  • modules.widgets 模块帮助PythonCoder 的 UI Schema 本地函数与 reset 参数说明;

  • gdisdk.modules.readers 中的 GdimTableReadergdisdk.modules.widgets 中的 PythonCoder 等模块,包含了更多动态控件、复杂对象配置的实际写法;

  • gdisdk.pipeline.pipelinePipeLine.add_attribute 方法。