Skip to content
Guides8 min read

الترحيل من Label Studio إلى Potato

دليل خطوة بخطوة لتحويل مشاريع وقوالب وتوسيمات Label Studio يدوياً إلى صيغة Potato.

Potato Team·

الترحيل من Label Studio إلى Potato

يساعدك هذا الدليل في ترحيل مشاريع Label Studio الحالية إلى Potato يدوياً. يتضمن الترحيل تحويل التكوينات يدوياً وكتابة سكريبتات Python لتحويل صيغ البيانات.

لاحظ أنه لا توجد أداة ترحيل رسمية - هذه عملية يدوية تتطلب فهم كلتا المنصتين.

لماذا الترحيل؟

يوفر Potato مزايا لحالات استخدام معينة:

  • تركيز بحثي: مصمم لدراسات التوسيم الأكاديمية
  • التعهيد الجماعي: تكامل أصلي مع Prolific و MTurk
  • البساطة: تكوين قائم على YAML، لا حاجة لقاعدة بيانات
  • التخصيص: سهل التمديد باستخدام Python
  • خفيف الوزن: تخزين قائم على الملفات، سهل النشر

نظرة عامة على الترحيل

الترحيل عملية يدوية تتضمن هذه الخطوات:

  1. تحويل قالب XML الخاص بـ Label Studio إلى تكوين YAML الخاص بـ Potato يدوياً
  2. كتابة سكريبتات Python لتحويل صيغة البيانات (من JSON إلى JSONL)
  3. كتابة سكريبتات لترحيل التوسيمات الموجودة (إن وجدت)
  4. الاختبار الشامل والتحقق من البيانات المحولة

تحويل القوالب

تصنيف النصوص

Label Studio XML:

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:

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:

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:

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:

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:

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:

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:

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:

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:

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:

xml
<View>
  <Text name="text" value="$text"/>
  <Rating name="quality" toName="text" maxRating="5"/>
</View>

Potato YAML:

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:

json
[
  {
    "id": 1,
    "data": {
      "text": "This is great!",
      "meta_info": "source1"
    }
  },
  {
    "id": 2,
    "data": {
      "text": "This is terrible.",
      "meta_info": "source2"
    }
  }
]

صيغة Potato JSONL:

json
{"id": "1", "text": "This is great!", "metadata": {"source": "source1"}}
{"id": "2", "text": "This is terrible.", "metadata": {"source": "source2"}}

سكريبت التحويل

python
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")

ترحيل التوسيمات

تحويل التوسيمات الموجودة

python
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، لذا التحويل مباشر:

python
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 StudioPotato
Choices (single)radio
Choices (multiple)multiselect
Labelsspan
Ratinglikert
TextAreatext
RectangleLabelsbounding_box
PolygonLabelspolygon
Taxonomy(استخدم multiselect متداخل)
Pairwisecomparison

اعتبارات ضبط الجودة

عند الترحيل من Label Studio، ستحتاج إلى تنفيذ تدابير ضبط الجودة يدوياً. يوفر Potato بعض إمكانيات ضبط الجودة الأساسية، لكن لا يوجد نظام ضبط جودة شامل مدمج.

مناهج ضبط الجودة

فحوصات الانتباه: يمكنك إضافة عناصر فحص الانتباه يدوياً إلى ملف البيانات. هذه عناصر عادية بإجابات صحيحة معروفة تُضمنها للتحقق من يقظة المُوسِّم:

python
# 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)

حساب الاتفاق: احسب اتفاق المُوسِّمين دون اتصال باستخدام التوسيمات المجمعة:

python
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

python
# 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

yaml
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: "..."

اختبار الترحيل

سكريبت التحقق

python
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.