Skip to content

数据格式

Potato 的输入格式:文本、JSON、JSONL、CSV、图像、音频和视频。输出为 CoNLL、HuggingFace Datasets、COCO、YOLO、Parquet 等格式。

Potato 从 JSON、JSON Lines、CSV 和 TSV 文件读取标注输入。本指南说明如何组织这些数据、Potato 需要每条记录中的哪些字段,以及标注最终落在哪里。

数据在 Potato 中的流动:输入文件变成带 id、文本和元数据的实例,经过标注后导出为多种格式从输入文件到导出的标签

支持的格式

格式扩展名描述
JSON.json对象数组
JSON Lines.jsonl每行一个 JSON 对象
CSV.csv逗号分隔值
TSV.tsv制表符分隔值

JSON 格式

最常用的格式。您的数据应该是一个对象数组:

json
[
  {
    "id": "doc_001",
    "text": "This is the first document to annotate.",
    "source": "twitter",
    "date": "2024-01-15"
  },
  {
    "id": "doc_002",
    "text": "This is the second document.",
    "source": "reddit",
    "date": "2024-01-16"
  }
]

JSON Lines 格式

每行是一个单独的 JSON 对象。适用于大型数据集:

jsonl
{"id": "doc_001", "text": "First document"}
{"id": "doc_002", "text": "Second document"}
{"id": "doc_003", "text": "Third document"}

CSV/TSV 格式

带表头的表格数据:

csv
id,text,source
doc_001,"This is the first document",twitter
doc_002,"This is the second document",reddit

配置

基本设置

在 YAML 中配置数据文件和字段映射:

yaml
data_files:
  - "data/documents.json"
 
item_properties:
  id_key: id      # Field name for unique ID
  text_key: text  # Field name for content to annotate

多个数据文件

组合多个数据源:

yaml
data_files:
  - "data/batch_1.json"
  - "data/batch_2.json"
  - "data/batch_3.jsonl"

文件按顺序处理并合并。

数据类型

纯文本

简单的文本内容:

json
{
  "id": "1",
  "text": "The product arrived quickly and works great!"
}

媒体文件

引用图像、视频或音频:

json
{
  "id": "1",
  "image_path": "images/photo_001.jpg"
}
yaml
item_properties:
  id_key: id
  image_key: image_path

对话/列表

存放 JSON 列表的 text 字段会每行排一项,因为纵向阅读适合对话。要做两两比较时,设置 list_as_text.horizontal 让各项并排:

json
{
  "id": "1",
  "text": ["Option A", "Option B", "Option C"]
}

文本对

存放 JSON 对象的 text 字段由配置声明的显示类型来渲染(conversation_tree、web_agent_trace 之类)。没有声明显示类型时会退回到格式化的 JSON,所以比较任务要声明一个:

json
{
  "id": "pair_001",
  "text": {
    "A": "Response from Model A",
    "B": "Response from Model B"
  }
}

HTML 文件

把 .html 文件放在 task_dir 下的某个文件夹里,再从普通的 text 字段指向它们,因为 Potato 没有单独的 HTML 条目属性。自带的 examples/advanced/html-annotation 任务就是这样嵌入每个文件的:

json
{
  "id": "1",
  "text": "<embed width=\"1020\" height=\"440\" src=\"data/html_data/1.html\" type=\"text/html\">"
}

上下文标注

在主文本旁包含上下文:

json
{
  "id": "1",
  "text": "This is great!",
  "context": "Previous message: How do you like the new feature?"
}

除 id 和 text 之外的字段通过 kwargs 到达页面,它指明每条数据要额外带过来哪些键:

yaml
item_properties:
  id_key: id
  text_key: text
  kwargs:
    - context

显示配置

列表显示选项

控制取值为列表的字段如何排布。这个键有三个子键,而 list_as_text: true 用默认值直接开启:

yaml
list_as_text:
  # Prefix each item so an annotator can refer to one by name.
  text_list_prefix_type: alphabet   # alphabet, number, bullet, or none
 
  # Side-by-side suits a pairwise comparison. The default is vertical.
  horizontal: true
 
  # Shade alternate turns, which keeps a long dialogue readable.
  alternating_shading: true

HTML 内容

text 字段里的标记不需要任何配置键就会渲染。Potato 对它做净化而不是转义,所以允许列表内的标签(<b>、<i>、<span> 之类)会变成格式,而 <script> 以及列表之外的任何东西都会被转义并失效。片段高亮是以标记的形式注入条目的,这正是不能把整个字段都转义的原因。

json
{
  "id": "1",
  "text": "<p>This is <strong>formatted</strong> text.</p>"
}

输出配置

输出目录

指定标注保存在哪里:

yaml
output_annotation_dir: "output/"

输出格式

标注始终以每个用户一份 user_state.json 的形式保存。export_annotation_format 会另外把定期的扁平导出写进 <output_annotation_dir>/exports/<format>/,那才是值得拿来分析的形式。没有哪个导出器叫 json:

yaml
export_annotation_format: "jsonl"   # or csv, tsv, parquet, coco, conll_2003, ...

运行 python -m potato.export --list-formats 查看完整的注册表。

输出结构

每份 user_state.json 按实例为键保存该标注者的标签,片段则单独记录:

json
{
  "user_id": "annotator_1",
  "instance_id_to_label_to_value": {
    "doc_001": {
      "sentiment": {"labels": {"positive": true}}
    }
  },
  "instance_id_to_span_to_value": {
    "doc_001": {
      "ner": [
        {"start": 0, "end": 5, "label": "PERSON", "text": "Alice"}
      ]
    }
  }
}

特殊数据类型

最佳-最差缩放

用于排名任务,使用逗号分隔的项目:

json
{
  "id": "1",
  "text": "Item A,Item B,Item C,Item D"
}

自定义参数

包含额外字段用于显示或筛选:

json
{
  "id": "1",
  "text": "Document content",
  "category": "news",
  "priority": "high",
  "custom_field": "any value"
}

数据库后端

对于大型数据集,使用 MySQL:

yaml
database:
  type: mysql
  host: localhost
  port: 3306
  database: potato_db
  username: ${DB_USER}
  password: ${DB_PASSWORD}

Potato 在首次启动时自动创建所需的表。

数据验证

Potato 在启动时验证您的数据:

  • 缺少 ID 字段 - 所有项目都需要唯一标识符
  • 缺少文本字段 - 项目需要标注内容
  • 重复 ID - 所有 ID 必须唯一
  • 文件未找到 - 验证数据文件路径

完整示例

yaml
annotation_task_name: "Document Classification"
task_dir: "."
port: 8000
 
# Data configuration
data_files:
  - "data/documents.json"
 
item_properties:
  id_key: id
  text_key: text
 
# Display settings
list_as_text:
  text_list_prefix_type: number
  horizontal: false
 
# Output
output_annotation_dir: "output/"
export_annotation_format: "jsonl"
 
# Annotation scheme
annotation_schemes:
  - annotation_type: radio
    name: category
    description: "Select the document category"
    labels:
      - News
      - Opinion
      - Tutorial
      - Other
 
user_config:
  allow_all_users: true
  users: []

最佳实践

1. 使用有意义的 ID

使跟踪和调试更容易:

json
{"id": "twitter_2024_001", "text": "..."}

2. 保持文本简洁

过长的文本会拖慢标注速度。可以考虑:

  • 截取关键部分
  • 提供摘要
  • 使用滚动容器

3. 包含元数据

有助于筛选和分析:

json
{
  "id": "1",
  "text": "Content",
  "source": "twitter",
  "date": "2024-01-15",
  "language": "en"
}

4. 加载前先验证

离线检查您的数据:

python
import json
 
with open('data.json') as f:
    data = json.load(f)
 
# Check for required fields
for item in data:
    assert 'id' in item, f"Missing id: {item}"
    assert 'text' in item, f"Missing text: {item}"
 
# Check for duplicates
ids = [item['id'] for item in data]
assert len(ids) == len(set(ids)), "Duplicate IDs found"
 
print(f"Validated {len(data)} items")

5. 备份原始数据

把原始数据与标注分开保存,以保证可重复性。

6. 大文件使用 JSON Lines

比 JSON 数组更省内存:

bash
# Convert JSON array to JSON Lines
cat data.json | jq -c '.[]' > data.jsonl

延伸阅读

有关实现细节,请参阅源文档。