الترحيل من Label Studio إلى Potato
دليل خطوة بخطوة لتحويل مشاريع وقوالب وتوسيمات Label Studio يدوياً إلى صيغة Potato.
الترحيل من Label Studio إلى Potato
يساعدك هذا الدليل في ترحيل مشاريع Label Studio الحالية إلى Potato يدوياً. يتضمن الترحيل تحويل التكوينات يدوياً وكتابة سكريبتات Python لتحويل صيغ البيانات.
لاحظ أنه لا توجد أداة ترحيل رسمية - هذه عملية يدوية تتطلب فهم كلتا المنصتين.
لماذا الترحيل؟
يوفر Potato مزايا لحالات استخدام معينة:
- تركيز بحثي: مصمم لدراسات التوسيم الأكاديمية
- التعهيد الجماعي: تكامل أصلي مع Prolific و MTurk
- البساطة: تكوين قائم على YAML، لا حاجة لقاعدة بيانات
- التخصيص: سهل التمديد باستخدام Python
- خفيف الوزن: تخزين قائم على الملفات، سهل النشر
نظرة عامة على الترحيل
الترحيل عملية يدوية تتضمن هذه الخطوات:
- تحويل قالب XML الخاص بـ Label Studio إلى تكوين YAML الخاص بـ Potato يدوياً
- كتابة سكريبتات Python لتحويل صيغة البيانات (من JSON إلى JSONL)
- كتابة سكريبتات لترحيل التوسيمات الموجودة (إن وجدت)
- الاختبار الشامل والتحقق من البيانات المحولة
تحويل القوالب
تصنيف النصوص
Label Studio XML:
<View>
<Text name="text" value="$text"/>
<Choices name="sentiment" toName="text" choice="single">
<Choice value="Positive"/>
<Choice value="Negative"/>
<Choice value="Neutral"/>
</Choices>
</View>Potato YAML:
annotation_task_name: "Sentiment Classification"
data_files:
- "data/items.jsonl"
item_properties:
id_key: id
text_key: text
annotation_schemes:
- annotation_type: radio
name: sentiment
description: "What is the sentiment?"
labels:
- name: positive
tooltip: "Positive sentiment"
- name: negative
tooltip: "Negative sentiment"
- name: neutral
tooltip: "Neutral sentiment"التصنيف متعدد التسميات
Label Studio XML:
<View>
<Text name="text" value="$text"/>
<Choices name="topics" toName="text" choice="multiple">
<Choice value="Politics"/>
<Choice value="Sports"/>
<Choice value="Technology"/>
<Choice value="Entertainment"/>
</Choices>
</View>Potato YAML:
annotation_schemes:
- annotation_type: multiselect
name: topics
description: "Select all relevant topics"
labels:
- name: politics
tooltip: "Politics content"
- name: sports
tooltip: "Sports content"
- name: technology
tooltip: "Technology content"
- name: entertainment
tooltip: "Entertainment content"التعرف على الكيانات المسماة
Label Studio XML:
<View>
<Labels name="entities" toName="text">
<Label value="PERSON" background="#FFC0CB"/>
<Label value="ORG" background="#90EE90"/>
<Label value="LOCATION" background="#ADD8E6"/>
</Labels>
<Text name="text" value="$text"/>
</View>Potato YAML:
annotation_schemes:
- annotation_type: span
name: entities
description: "Select entity spans in the text"
labels:
- name: PERSON
tooltip: "Person names"
- name: ORG
tooltip: "Organization names"
- name: LOCATION
tooltip: "Location names"ملاحظة: قد يستخدم توسيم النطاق في Potato تمييزاً مختلفاً عن Label Studio. اختبر تكوينك المحول للتحقق من أن العرض يلبي احتياجاتك.
تصنيف الصور
Label Studio XML:
<View>
<Image name="image" value="$image_url"/>
<Choices name="category" toName="image">
<Choice value="Cat"/>
<Choice value="Dog"/>
<Choice value="Other"/>
</Choices>
</View>Potato YAML:
data_files:
- "data/images.jsonl"
item_properties:
id_key: id
text_key: image_url
annotation_schemes:
- annotation_type: radio
name: category
description: "What animal is in the image?"
labels:
- name: cat
tooltip: "Cat"
- name: dog
tooltip: "Dog"
- name: other
tooltip: "Other animal"توسيم مربعات الإحاطة
Label Studio XML:
<View>
<Image name="image" value="$image_url"/>
<RectangleLabels name="objects" toName="image">
<Label value="Car"/>
<Label value="Person"/>
<Label value="Bicycle"/>
</RectangleLabels>
</View>Potato YAML:
annotation_schemes:
- annotation_type: bounding_box
name: objects
description: "Draw boxes around objects"
labels:
- name: car
tooltip: "Car"
- name: person
tooltip: "Person"
- name: bicycle
tooltip: "Bicycle"ملاحظة: قد يختلف دعم مربعات الإحاطة في Potato عن Label Studio. راجع الوثائق للقدرات الحالية.
مقاييس التقييم
Label Studio XML:
<View>
<Text name="text" value="$text"/>
<Rating name="quality" toName="text" maxRating="5"/>
</View>Potato YAML:
annotation_schemes:
- annotation_type: likert
name: quality
description: "Rate the quality"
size: 5
labels:
- name: "1"
tooltip: "Poor"
- name: "2"
tooltip: "Below average"
- name: "3"
tooltip: "Average"
- name: "4"
tooltip: "Good"
- name: "5"
tooltip: "Excellent"تحويل صيغة البيانات
من JSON الخاص بـ Label Studio إلى JSONL الخاص بـ Potato
صيغة Label Studio:
[
{
"id": 1,
"data": {
"text": "This is great!",
"meta_info": "source1"
}
},
{
"id": 2,
"data": {
"text": "This is terrible.",
"meta_info": "source2"
}
}
]صيغة Potato JSONL:
{"id": "1", "text": "This is great!", "metadata": {"source": "source1"}}
{"id": "2", "text": "This is terrible.", "metadata": {"source": "source2"}}سكريبت التحويل
import json
def convert_label_studio_to_potato(ls_file, potato_file):
"""Convert Label Studio JSON to Potato JSONL"""
with open(ls_file, 'r') as f:
ls_data = json.load(f)
with open(potato_file, 'w') as f:
for item in ls_data:
potato_item = {
"id": str(item["id"]),
"text": item["data"].get("text", ""),
}
# Convert nested data fields
if "data" in item:
for key, value in item["data"].items():
if key != "text":
if "metadata" not in potato_item:
potato_item["metadata"] = {}
potato_item["metadata"][key] = value
# Handle image URLs
if "image" in item.get("data", {}):
potato_item["image_url"] = item["data"]["image"]
f.write(json.dumps(potato_item) + "\n")
print(f"Converted {len(ls_data)} items")
# Usage
convert_label_studio_to_potato("label_studio_export.json", "data/items.jsonl")ترحيل التوسيمات
تحويل التوسيمات الموجودة
def convert_annotations(ls_export, potato_output):
"""Convert Label Studio annotations to Potato format"""
with open(ls_export, 'r') as f:
ls_data = json.load(f)
with open(potato_output, 'w') as f:
for item in ls_data:
if "annotations" not in item or not item["annotations"]:
continue
for annotation in item["annotations"]:
potato_ann = {
"id": str(item["id"]),
"text": item["data"].get("text", ""),
"annotations": {},
"annotator": annotation.get("completed_by", {}).get("email", "unknown"),
"timestamp": annotation.get("created_at", "")
}
# Convert results
for result in annotation.get("result", []):
scheme_name = result.get("from_name", "unknown")
if result["type"] == "choices":
# Classification
potato_ann["annotations"][scheme_name] = result["value"]["choices"][0]
elif result["type"] == "labels":
# NER spans
if scheme_name not in potato_ann["annotations"]:
potato_ann["annotations"][scheme_name] = []
potato_ann["annotations"][scheme_name].append({
"start": result["value"]["start"],
"end": result["value"]["end"],
"label": result["value"]["labels"][0],
"text": result["value"]["text"]
})
elif result["type"] == "rating":
potato_ann["annotations"][scheme_name] = result["value"]["rating"]
f.write(json.dumps(potato_ann) + "\n")
# Usage
convert_annotations("ls_annotated_export.json", "annotations/migrated.jsonl")تحويل توسيمات النطاق
يستخدم Label Studio إزاحات الأحرف؛ وكذلك Potato، لذا التحويل مباشر:
def convert_spans(ls_spans):
"""Convert Label Studio span format to Potato format"""
potato_spans = []
for span in ls_spans:
potato_spans.append({
"start": span["value"]["start"],
"end": span["value"]["end"],
"label": span["value"]["labels"][0],
"text": span["value"]["text"]
})
return potato_spansجدول مطابقة الميزات
| Label Studio | Potato |
|---|---|
| Choices (single) | radio |
| Choices (multiple) | multiselect |
| Labels | span |
| Rating | likert |
| TextArea | text |
| RectangleLabels | bounding_box |
| PolygonLabels | polygon |
| Taxonomy | (استخدم multiselect متداخل) |
| Pairwise | comparison |
اعتبارات ضبط الجودة
عند الترحيل من Label Studio، ستحتاج إلى تنفيذ تدابير ضبط الجودة يدوياً. يوفر Potato بعض إمكانيات ضبط الجودة الأساسية، لكن لا يوجد نظام ضبط جودة شامل مدمج.
مناهج ضبط الجودة
فحوصات الانتباه: يمكنك إضافة عناصر فحص الانتباه يدوياً إلى ملف البيانات. هذه عناصر عادية بإجابات صحيحة معروفة تُضمنها للتحقق من يقظة المُوسِّم:
# Add attention check items to your data
attention_items = [
{"id": "attn_1", "text": "ATTENTION CHECK: Please select 'Positive'", "is_attention": True},
{"id": "attn_2", "text": "ATTENTION CHECK: Please select 'Negative'", "is_attention": True},
]
# Intersperse with regular items
import random
all_items = regular_items + attention_items
random.shuffle(all_items)حساب الاتفاق: احسب اتفاق المُوسِّمين دون اتصال باستخدام التوسيمات المجمعة:
from sklearn.metrics import cohen_kappa_score
import numpy as np
def compute_agreement(annotations_file):
"""Compute agreement from collected annotations"""
# Load annotations and compute metrics externally
# Potato does not have built-in agreement calculation
passالتوسيم المتكرر: كوّن عدة مُوسِّمين لكل عنصر عن طريق تعيين العناصر لعدة مستخدمين في عملية إدارة البيانات.
ترحيل المستخدمين
تصدير المستخدمين من Label Studio
# Label Studio API call to get users
import requests
def export_ls_users(ls_url, api_key):
response = requests.get(
f"{ls_url}/api/users",
headers={"Authorization": f"Token {api_key}"}
)
return response.json()إنشاء تكوين مستخدمي Potato
user_config:
# Simple auth for migrated users
auth_type: password
users:
- username: user1@example.com
password_hash: "..." # Generate new passwords
- username: user2@example.com
password_hash: "..."اختبار الترحيل
سكريبت التحقق
def validate_migration(original_ls, converted_potato):
"""Validate converted data matches original"""
with open(original_ls) as f:
ls_data = json.load(f)
with open(converted_potato) as f:
potato_data = [json.loads(line) for line in f]
# Check item count
assert len(ls_data) == len(potato_data), "Item count mismatch"
# Check IDs preserved
ls_ids = {str(item["id"]) for item in ls_data}
potato_ids = {item["id"] for item in potato_data}
assert ls_ids == potato_ids, "ID mismatch"
# Check text content
for ls_item, potato_item in zip(
sorted(ls_data, key=lambda x: x["id"]),
sorted(potato_data, key=lambda x: x["id"])
):
assert ls_item["data"]["text"] == potato_item["text"], \
f"Text mismatch for item {ls_item['id']}"
print("Validation passed!")
validate_migration("label_studio_export.json", "data/items.jsonl")قائمة مراجعة الترحيل
- تصدير البيانات من Label Studio (صيغة JSON)
- تحويل قالب XML إلى YAML الخاص بـ Potato يدوياً
- كتابة وتشغيل سكريبتات Python لتحويل صيغة البيانات (من JSON إلى JSONL)
- كتابة وتشغيل سكريبتات لتحويل التوسيمات الموجودة (إن وجدت)
- إعداد هيكل مشروع Potato
- الاختبار مع بيانات نموذجية
- التحقق من تطابق البيانات المحولة مع الأصلية
- تدريب المُوسِّمين على الواجهة الجديدة
- تشغيل دفعة توسيم تجريبية
مشاكل شائعة
ترميز الأحرف
يستخدم كل من Label Studio و Potato ترميز UTF-8، لكن تحقق من مشاكل الترميز في بياناتك.
مسارات الصور
حوّل المسارات المحلية إلى عناوين URL أو حدّث المسارات لتتطابق مع الصيغة المتوقعة لـ Potato.
المكونات المخصصة
تحتاج المكونات المخصصة في Label Studio إلى إعادة إنشائها كقوالب مخصصة في Potato.
اختلافات API
إذا كنت تؤتمت Label Studio، حدّث السكريبتات لاستخدام API الخاص بـ Potato.
هل تحتاج مساعدة في الترحيل؟ راجع الوثائق الكاملة أو تواصل على GitHub.