

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 演示模板：使用 `crowd-classifier` 的标注目的
<a name="sms-custom-templates-step2-demo2"></a>

如果您选择自定义模板，将转到**自定义标注任务面板**。在该面板上，您可以从多个表示一些更常见任务的入门模板中进行选择。这些模板为构建自定义标注任务的模板提供了一个起点。

在此演示中，您将使用**目的检测**模板，该模板使用 `crowd-classifier` 元素和在任务前后处理数据所需的 Amazon Lambda 函数。

**Topics**
+ [入门目的检测自定义模板](#sms-custom-templates-step2-demo2-base-template)
+ [您的目的检测自定义模板](#sms-custom-templates-step2-demo2-your-template)
+ [注释前 Lambda 函数](#sms-custom-templates-step2-demo2-pre-lambda)
+ [注释后 Lambda 函数](#sms-custom-templates-step2-demo2-post-lambda)
+ [您的标注作业输出](#sms-custom-templates-step2-demo2-job-output)

## 入门目的检测自定义模板
<a name="sms-custom-templates-step2-demo2-base-template"></a>

这是作为起点提供的目的检测模板。

此自定义模板使用 [Liquid 模板语言](https://shopify.github.io/liquid/)，双大括号之间的每个项都是一个变量。预注解 Lamb Amazon da 函数应提供一个`taskInput`名为的对象，并且可以像在模板中`{{ task.input.<property name> }}`一样访问该对象的属性。

## 您的目的检测自定义模板
<a name="sms-custom-templates-step2-demo2-your-template"></a>

在入门模板中，有两个变量：`crowd-classifier` 元素开始标签中的 `task.input.labels` 属性和 `classification-target` 区域内容中的 `task.input.utterance`。

除非您需要为不同的语篇提供不同的标签集，否则避免使用变量而只使用文本将节省处理时间，并减少出错的可能性。本演示中使用的模板将删除该变量，但类似 `to_json` 的变量和筛选器将在 [`crowd-bounding-box` 演示]()文章中进行更详细的说明。

### 元素样式设计
<a name="sms-custom-templates-step2-demo2-instructions"></a>

这些自定义元素中有时会被忽略的两个部分是 `<full-instructions>` 和 `<short-instructions>` 区域。好的说明会产生好的结果。

在包含这些区域的元素中，`<short-instructions>` 自动显示在工作人员屏幕左侧的“说明”窗格中。`<full-instructions>` 链接自该窗格顶部附近的“查看完整说明”链接。单击链接可打开一个模式窗格，其中包含更详细的说明。

你不仅可以使用 HTML、CSS，而且 JavaScript 在这些章节中，如果你认为自己能提供一套强有力的说明和示例，帮助工作人员以更快的速度和准确度完成任务，那么我们鼓励你这样做。

**Example 试试样品 JSFiddle**  
[https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)  
 试用 [`<crowd-classifier>` 任务示例](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)。该示例由呈现 JSFiddle，因此所有模板变量都替换为硬编码值。单击“查看完整说明”链接，查看一组具有扩展 CSS 样式的示例。您可以分叉项目，尝试自己对 CSS 的更改、添加示例图像或添加扩展 JavaScript 功能。

**Example ：最终的自定义目的检测模板**  
该模板使用 [`<crowd-classifier>` 任务示例](https://jsfiddle.net/MTGT_Fiddle_Manager/bjc0y1vd/35/)，但为 `<classification-target>` 添加了一个变量。如果您尝试在一系列不同的标注作业中保持一致的 CSS 设计，可以像在任何其他 HTML 文档中一样，使用 `<link rel...>` 元素包含外部样式表。

**Example ：您的清单文件**  
如果您正在手动为这样的文本分类任务准备清单文件，请按以下方式格式化数据。  

```
{"source": "Roses are red"}
{"source": "Violets are Blue"}
{"source": "Ground Truth is the best"}
{"source": "And so are you"}
```

这有别于用于“[演示模板：使用 `crowd-bounding-box` 的映像注释](sms-custom-templates-step2-demo1.md)”演示的清单文件，在后者中，`source-ref` 用作属性名而非 `source`。使用`source-ref`指定 S3 URIs 表示必须转换为 HTTP 的图像或其他文件。否则，应将 `source` 视为含上面的文本字符串来使用。

## 注释前 Lambda 函数
<a name="sms-custom-templates-step2-demo2-pre-lambda"></a>

作为任务设置的一部分，提供的 ARN，可以调用 Amazon Lambda 它来处理您的清单条目并将其传递给模板引擎。

此 Lambda 函数必须包含以下四个字符串之一作为函数名的一部分：`SageMaker`、`Sagemaker`、`sagemaker` 或 `LabelingFunction`。

这同时适用于注释前和注释后 Lambda 函数。

在使用控制台时，如果您的账户拥有 Lambdas，则会提供一个符合命名要求的函数下拉列表，供您选择。

在这个非常基本的示例中，只有一个变量，主要是传递函数。下面是一个使用 Python 3.7 的标注前 Lambda 示例。

```
import json

def lambda_handler(event, context):
    return {
        "taskInput":  event['dataObject']
    }
```

`event` 的 `dataObject` 属性包含来自清单中的数据对象的属性。

本演示只是一个变量的简单传递，您只是将该变量作为 `taskInput` 值直接传递。如果将具有这些值的属性添加到 `event['dataObject']` 对象，则它们可作为格式为 `{{ task.input.<property name> }}` 的 Liquid 变量用于 HTML 模板。

## 注释后 Lambda 函数
<a name="sms-custom-templates-step2-demo2-post-lambda"></a>

作为作业设置的一部分，提供一个 Lambda 函数的 ARN，当工作人员完成任务时，可以调用该函数来处理表单数据。这可以很简单，也可以很复杂。如果您想在收到数据时进行答案合并和评分，您可以应用自己选择的评分或合并算法。如果您想要存储原始数据以进行脱机处理，则这是一个选项。

**设置对注释后 Lambda 函数的权限**  
注释数据将位于一个文件中，该文件由 `payload` 对象中的 `s3Uri` 字符串指定。要处理传入的注释，即使是简单的传递函数，也需要为 Lambda 分配 `S3ReadOnly` 访问权限，以使其能够读取注释文件。  
在创建 Lambda 的控制台页面中，滚动到**执行角色**面板。选择**从一个或多个模板中创建新角色**。指定角色的名称。从**策略模板**下拉列表中，选择 **Amazon S3 对象只读权限**。保存 Lambda，将保存并选择该角色。

以下示例适用于 Python 3.7。

```
import json
import boto3
from urllib.parse import urlparse

def lambda_handler(event, context):
    consolidated_labels = []

    parsed_url = urlparse(event['payload']['s3Uri']);
    s3 = boto3.client('s3')
    textFile = s3.get_object(Bucket = parsed_url.netloc, Key = parsed_url.path[1:])
    filecont = textFile['Body'].read()
    annotations = json.loads(filecont);
    
    for dataset in annotations:
        for annotation in dataset['annotations']:
            new_annotation = json.loads(annotation['annotationData']['content'])
            label = {
                'datasetObjectId': dataset['datasetObjectId'],
                'consolidatedAnnotation' : {
                'content': {
                    event['labelAttributeName']: {
                        'workerId': annotation['workerId'],
                        'result': new_annotation,
                        'labeledContent': dataset['dataObject']
                        }
                    }
                }
            }
            consolidated_labels.append(label)

    return consolidated_labels
```

## 您的标注作业输出
<a name="sms-custom-templates-step2-demo2-job-output"></a>

注释后 Lambda 通常会在事件对象中接收成批的任务结果。该批次将是 Lambda 应该遍历的 `payload` 对象。

您将在指定的目标 S3 存储桶中以标注作业命名的文件夹中找到作业的输出。它将位于名为 `manifests` 的子文件夹中。

对于目的检测任务，输出清单中的输出将有点类似于下面的演示。这个示例已进行清理并加宽间距，以便于阅读。实际输出将经过更多压缩，以便机器读取。

**Example ：输出清单中的 JSON**  

```
[
  {
    "datasetObjectId":"<Number representing item's place in the manifest>",
     "consolidatedAnnotation":
     {
       "content":
       {
         "<name of labeling job>":
         {     
           "workerId":"private.us-east-1.XXXXXXXXXXXXXXXXXXXXXX",
           "result":
           {
             "intent":
             {
                 "label":"<label chosen by worker>"
             }
           },
           "labeledContent":
           {
             "content":"<text content that was labeled>"
           }
         }
       }
     }
   },
  "datasetObjectId":"<Number representing item's place in the manifest>",
     "consolidatedAnnotation":
     {
       "content":
       {
         "<name of labeling job>":
         {     
           "workerId":"private.us-east-1.6UDLPKQZHYWJQSCA4MBJBB7FWE",
           "result":
           {
             "intent":
             {
                 "label": "<label chosen by worker>"
             }
           },
           "labeledContent":
           {
             "content": "<text content that was labeled>"
           }
         }
       }
     }
   },
     ...
     ...
     ...
]
```

这应该有助于您创建和使用自己的自定义模板。