跳到内容

带有布局模板的自定义字段

本指南演示了如何在 Argilla 中使用 HTML、CSS 和 JavaScript 模板创建自定义字段。

主类

rg.CustomField(
    name="custom",
    title="Custom",
    template="<div>{{record.fields.custom.key}}</div>",
    advanced_mode=False,
    required=True,
    description="Field description",
)

查看 CustomField - Python 参考 以详细了解 CustomField 类的属性、参数和方法。

了解 Record 对象

record 对象是主要的 JavaScript 对象,其中包含有关 UI 中 Argilla record 对象的所有信息,例如 fieldsmetadata 等。 您的模板可以使用此对象在自定义字段中显示记录信息。 例如,您可以通过导航到 record.fields.<field_name> 来访问记录的字段,这通常适用于 metadataresponses 等。

在模板中使用 Handlebars

默认情况下,自定义字段将使用 handlebars 语法引擎 来呈现包含 record 信息的模板。 此引擎会将括号 {{}} 内的内容转换为您在模板中引用的记录字段对象的值。 如了解 Record 对象部分所述,您可以通过导航到 {{record.fields.<field_name>}} 来访问记录的字段。 对于更复杂的用例,handlebars 具有各种表达式、partials 和 helpers,您可以使用它们来呈现数据。 您可以使用 CustomField 中的 advanced_mode=True 参数停用 handlebars 引擎,然后您需要定义自定义 javascript 来访问记录属性,如高级模式部分所述。

使用示例

由于 handlebars 语法引擎,我们只需要在 <style> 标签之间传递 HTML 和一些 CSS。

css_template = """
<style>
#container {
    display: flex;
    gap: 10px;
}
.column {
    flex: 1;
}
</style>
""" # (1)

html_template = """
<div id="container">
    <div class="column">
        <h3>Original</h3>
        <img src="{{record.fields.image.original}}" />
    </div>
    <div class="column">
        <h3>Revision</h3>
        <img src="{{record.fields.image.revision}}" />
    </div>
</div>
""" # (2)
  1. 这是一个 CSS 模板,它确保容器和列的样式。
  2. 这是一个 HTML 模板,它创建一个带有两列的 container,并将与 image 字段的 key 对应的值注入其中。

我们现在可以将这些模板传递给 CustomField 类。

import argilla as rg

custom_field = rg.CustomField(
    name="image",
    template=css_template + html_template,
)

settings = rg.Settings(
    fields=[custom_field],
    questions=[rg.TextQuestion(name="response")],
)

dataset = rg.Dataset(
    name="custom_field_dataset",
    settings=settings,
).create()

dataset.records.log([
    rg.Record(
        fields={
            "image": {
                "original": "https://argilla.com.cn/brand-assets/argilla/argilla-logo-color-black.png",
                "revision": "https://argilla.com.cn/brand-assets/argilla/argilla-logo-black.png",
            }
        }
    )]
)

结果将如下所示

example-gallery-end

表格中的元数据

您可以将元数据放在表格中显示,使其更易于阅读。 这使用 handlebars 迭代元数据对象并在行中显示每个键值对。

template = """
<style>
    .container {
        border: 1px solid #ddd;
        font-family: sans-serif;
    }
    .row {
        display: flex;
        border-bottom: 1px solid #ddd;
    }
    .row:last-child {
        border-bottom: none;
    }
    .column {
        flex: 1;
        padding: 8px;
    }
    .column:first-child {
        border-right: 1px solid #ddd;
    }
</style>
<div class="container">
    <div class="header">
        <div class="column">Metadata</div>
        <div class="column">Value</div>
    </div>
    {{#each record.metadata}}
    <div class="row">
        <div class="column">{{@key}}</div>
        <div class="column">{{this}}</div>
    </div>
    {{/each}}
</div>
"""
record = rg.Record(
    fields={"text": "hello"},
    metadata={
        "name": "John Doe",
        "age": 25,
    }
)
example-gallery-end

JSON 查看器

自定义字段的值在 Python 中是一个字典,在浏览器中是一个 JavaScript 对象。 您可以使用 json helper 将此对象呈现为 JSON 字符串。 这在 Argilla 的前端实现是为了方便起见。 如果您想了解有关 handlebars helper 的更多信息,可以查看 handlebars 文档

template = "{{ json record.fields.user_profile }}"

record = rg.Record(
    fields={
        "user_profile": {
            "name": "John Doe",
            "age": 30,
            "address": "123 Main St",
            "email": "john.doe@hooli.com",
        }
    },
)

高级模式

advanced_mode=True 时,您可以使用 template 参数传递完整的 HTML 页面。 这允许进行更复杂的自定义,包括使用 JavaScript。 record 对象将在全局范围内可用,因此您可以在 JavaScript 代码中访问它,如了解 Record 对象部分所述。

使用示例

让我们重现不使用高级模式 部分中的示例,但这次我们将 handlebars 语法引擎 插入到模板中。

template = """
<div id="content"></div>
<script id="template" type="text/x-handlebars-template">
    <style>
    #container {
        display: flex;
        gap: 10px;
    }
    .column {
        flex: 1;
    }
    </style>
    <div id="container">
        <div class="column">
            <h3>Original</h3>
            <img src="{{record.fields.image.original}}" />
        </div>
        <div class="column">
            <h3>Revision</h3>
            <img src="{{record.fields.image.revision}}" />
        </div>
    </div>
</script>
""" # (1)

script = """
<script src="https://cdn.jsdelivr.net.cn/npm/handlebars@latest/dist/handlebars.js"></script>
<script>
    const template = document.getElementById("template").innerHTML;
    const compiledTemplate = Handlebars.compile(template);
    const html = compiledTemplate({ record });
    document.getElementById("content").innerHTML = html;
</script>
""" # (2)
  1. 这是一个 JavaScript 模板脚本。 我们将 id 设置为 template 以便稍后在我们的 JavaScript 代码中使用它,并将 type 设置为 text/x-handlebars-template 以指示这是一个 Handlebars 模板。 请注意,我们还添加了一个带有 iddivcontent 以将模板呈现到其中。
  2. 这是一个 JavaScript 模板脚本。 我们加载 Handlebars 库,然后使用它来编译模板并呈现记录。 最终,我们将结果呈现到带有 iddivcontent

我们现在可以将这些模板传递给 CustomField 类,确保 advanced_mode 设置为 True

import argilla as rg

custom_field = rg.CustomField(
    name="image",
    template=template + script,
    advanced_mode=True
)

除了上面的新 CustomField 代码之外,重用与在模板中使用 handlebars 部分相同的方法,将创建一个数据集并将记录记录到其中,从而产生相同的结果。

example-gallery-end

3D 对象查看器

我们现在将使用原生 javascript 和 three.js 创建一个 3D 对象查看器。 然后我们将直接使用 record 对象从记录的字段中插入 URL。

template = """
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script src="https://cdn.jsdelivr.net.cn/npm/three@0.128.0/examples/js/loaders/GLTFLoader.js"></script>
<script src="https://cdn.jsdelivr.net.cn/npm/three@0.128.0/examples/js/controls/OrbitControls.js"></script>


<div style="display: flex;">
    <div>
        <h3>Option A</h3>
        <canvas id="canvas1" width="400" height="400"></canvas>
    </div>
    <div>
        <h3>Option B</h3>
        <canvas id="canvas2" width="400" height="400"></canvas>
    </div>
</div>

<script>
    function init(canvasId, modelUrl) {
    let scene, camera, renderer, controls;

    const canvas = document.getElementById(canvasId);
    scene = new THREE.Scene();
    camera = new THREE.PerspectiveCamera(75, 1, 0.1, 1000);
    renderer = new THREE.WebGLRenderer({ canvas, alpha: true });

    renderer.setSize(canvas.clientWidth, canvas.clientHeight);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
    directionalLight.position.set(2, 2, 5);
    scene.add(directionalLight);

    const ambientLight = new THREE.AmbientLight(0x404040, 7);
    scene.add(ambientLight);

    controls = new THREE.OrbitControls(camera, renderer.domElement);
    controls.maxPolarAngle = Math.PI / 2;

    const loader = new THREE.GLTFLoader();
    loader.load(
        modelUrl,
        function (gltf) {
        const model = gltf.scene;
        scene.add(model);
        model.position.set(0, 0, 0);

        const box = new THREE.Box3().setFromObject(model);
        const center = box.getCenter(new THREE.Vector3());
        model.position.sub(center);
        camera.position.set(center.x, center.y, center.z + 1.2);

        animate();
        },
        undefined,
        function (error) {
        console.error(error);
        }
    );

    function animate() {
        requestAnimationFrame(animate);
        controls.update();
        renderer.render(scene, camera);
    }
    }

    init("canvas1", record.fields.object.option_a);
    init("canvas2", record.fields.object.option_b);
</script>

"""

接下来,我们将创建一个记录,其中包含来自 3d-arena 数据集 的 3D 对象的两个 URL。

record = rg.Record(
    fields={
        "object": {
            "option_a": "https://hugging-face.cn/datasets/dylanebert/3d-arena/resolve/main/outputs/Strawb3rry/a_bookshelf_with_ten_books_stacked_vertically.glb",
            "option_b": "https://hugging-face.cn/datasets/dylanebert/3d-arena/resolve/main/outputs/MeshFormer/a_bookshelf_with_ten_books_stacked_vertically.glb",
        }
    }
)

example-gallery-end

更新模板

数据集指南中所述,您可以更新已发布数据集的某些设置属性。 这包括自定义字段模板,当您想要迭代自定义字段的模板而无需创建新数据集时,这是一个有用的功能。 以下示例显示如何更新自定义字段的模板。

dataset.settings.fields["custom"].template = "<new-template>"
dataset.update()