> ## Documentation Index
> Fetch the complete documentation index at: https://docs.labelbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Import conversational text annotations

> Developer guide for importing annotations on conversational text data and sample import formats.

<CardGroup cols={2}>
  <Card title="Open In Colab" icon="infinity" iconType="solid" horizontal href="https://colab.research.google.com/github/Labelbox/labelbox-notebooks/blob/main/annotation_import/conversational.ipynb" />

  <Card title="GitHub" icon="github" iconType="solid" horizontal href="https://github.com/Labelbox/labelbox-notebooks/blob/main/annotation_import/conversational.ipynb" />
</CardGroup>

## Overview

To import annotations in Labelbox, you need to create an annotations payload. In this section, we provide this payload for every supported annotation type.

### Annotation payload types

Labelbox supports two formats for the annotations payload:

* Python annotation types (recommended)
  * Provides a seamless transition between third-party platforms, machine learning pipelines, and Labelbox.
  * Allows you to build annotations locally with local file paths, numpy arrays, or URLs
  * Easily convert Python Annotation Type format to NDJSON format to quickly import annotations to Labelbox
  * Supports one-level nested classification (radio, checklist, or free-form text) under a tool or classification annotation.
* JSON
  * Skips formatting annotation payload in the Labelbox Python annotation type
  * Supports any levels of nested classification (radio, checklist, or free-form text) under a tool or classification annotation.

### Label import types

Labelbox additionally supports two types of label imports:

* [Model-assisted labeling (MAL)](/docs/model-assisted-labeling)
  * This workflow allows you to import computer-generated predictions (or simply annotations created outside of Labelbox) as pre-labels on an asset.
* [Ground truth](https://www.google.com/url?q=https%3A%2F%2Fdocs.labelbox.com%2Fdocs%2Fimport-ground-truth)
  * This workflow functionality allows you to bulk import your ground truth annotations from an external or third-party labeling system into Labelbox *Annotate*. Using the label import API to import external data is a useful way to consolidate and migrate all annotations into Labelbox as a single source of truth.

## Supported annotations

The following annotations are supported for a conversational text data row:

* Radio
* Checklist
* Free-form text
* Entity
* Relationship

<Info>
  ### Annotations can be message or global based

  Classification annotations can be supported both message and global based while tool annotations are supported only message specific. Removing the message\_id key inside a conversation text classification annotation results in the annotation becoming global.
</Info>

## Classifications

### Radio (single-choice, message-based)

<CodeGroup>
  ```python Python Annotation theme={null}
  radio_annotation = lb_types.ClassificationAnnotation(
      name="radio_convo",
      value=lb_types.Radio(answer = lb_types.ClassificationAnswer(name = "first_radio_answer")),
      message_id="0" # Remove argument if importing annotation as a global classification (not message-based)
  )
  ```

  ```python NDJSON theme={null}
  radio_annotation_ndjson = {
      "name": "radio_convo",
      "answer": {
          "name": "first_radio_answer"
      },
      "messageId": "0", # Remove argument if importing global classifications
  }
  ```
</CodeGroup>

### Checklist (multi-choice, message-based)

<CodeGroup>
  ```python Python Annotation theme={null}
  checklist_annotation= lb_types.ClassificationAnnotation(
    name="checklist_convo", # must match your ontology feature"s name
    value=lb_types.Checklist(
        answer = [
          lb_types.ClassificationAnswer(
              name = "first_checklist_answer"
          ),
          lb_types.ClassificationAnswer(
              name = "second_checklist_answer"
          )
        ]
      ),
    message_id="2" # Remove argument if importing annotation as a global classification (not message-based)
   )
  ```

  ```python NDJSON theme={null}
  checklist_annotation_ndjson = {
      "name": "checklist_convo",
      "answers": [
          {"name": "first_checklist_answer"},
          {"name": "second_checklist_answer"}
      ],
      "messageId": "2" # Remove argument if importing annotation as a global classification (not message-based)
  }
  ```
</CodeGroup>

### Free-form text (message-based)

<CodeGroup>
  ```python Python Annotation theme={null}
  text_annotation = lb_types.ClassificationAnnotation(
      name="text_convo",
      value=lb_types.Text(answer="the answer to the text questions right here"),
      message_id="0" # Remove argument if importing annotation as a global classification (not message-based)
  )
  ```

  ```python NDJSON theme={null}
  text_annotation_ndjson = {
      "name": "text_convo",
      "answer": "the answer to the text questions right here",
      "messageId": "0" # Remove argument if importing annotation as a global classification (not message-based)
  }
  ```
</CodeGroup>

## Tools

### Entity (message-based)

<CodeGroup>
  ```python Python Annotation theme={null}
  ner_annotation = lb_types.ObjectAnnotation(
      name="ner",
      value=lb_types.ConversationEntity(
          start=0,
          end=8,
          message_id="4"
      )
  )
  ```

  ```python NDJSON theme={null}
  ner_annotation = {
      "name": "ner",
      "location": {
        "start": 0,
        "end": 8
      },
      "messageId": "4" # this should match the message
  }
  ```
</CodeGroup>

## Relationships (message-based)

<CodeGroup>
  ```python Python Annotation theme={null}
  ner_source = lb_types.ObjectAnnotation(
      name="ner",
      value=lb_types.ConversationEntity(
          start=16,
          end=26,
          message_id="4"
      )
  )
  ner_target = lb_types.ObjectAnnotation(
      name="ner",
      value=lb_types.ConversationEntity(
          start=29, 
          end=34, 
          message_id="4"
      )
  )

  ner_relationship = lb_types.RelationshipAnnotation(
      name="relationship",
      value=lb_types.Relationship(
          source=ner_source, # Alternatively, specify a source_ontology_name
          target=ner_target,
          type=lb_types.Relationship.Type.UNIDIRECTIONAL,
      ))
  ```

  ```python NDJSON theme={null}
  uuid_source = str(uuid.uuid4())
  uuid_target = str(uuid.uuid4())

  ner_source_ndjson = {
          "uuid": uuid_source,
          "name": "ner",
          "location": {
              "start": 16,
              "end": 26
          },
          "messageId": "4"
      }

  ner_target_ndjson = {
          "uuid": uuid_target,
          "name": "ner",
          "location": {
              "start": 29,
              "end": 34
          },
          "messageId": "4"
      }

  ner_relationship_annotation_ndjson = {
      "name": "relationship",
      "relationship": {
        "source": uuid_source, #UUID reference to the source annotation
        "target": uuid_target, # UUID reference to the target annotation
        "type": "bidirectional"
      }
  }
  ```
</CodeGroup>

## Example: Import pre-labels or ground truths

The steps to import annotations as pre-labels (machine-assisted learning) are similar to those to import annotations as ground truth labels. However, they vary slightly, and we will describe the differences for each scenario.

### Before you start

The below imports are needed to use the code examples in this section.

<CodeGroup>
  ```python Python theme={null}
  import labelbox as lb
  import labelbox.types as lb_types
  import uuid
  import json
  import numpy as np
  ```
</CodeGroup>

Replace the value of `API_KEY` with a valid [API key](/reference/create-api-key) to connect to the Labelbox client.

<CodeGroup>
  ```python Python theme={null}
  API_KEY = None
  client = lb.Client(API_KEY)
  ```
</CodeGroup>

### Step 1: Import data rows

Data rows must first be uploaded to **Catalog** to attach annotations.

This example shows how to create a data row in **Catalog** by attaching it to a [dataset](/reference/dataset) .

<CodeGroup>
  ```python Python theme={null}
  # Create one Labelbox dataset

  global_key = "conversation-1.json"

  asset = {
      "row_data": "https://storage.googleapis.com/labelbox-developer-testing-assets/conversational_text/1000-conversations/conversation-1.json",
      "global_key": global_key
  }

  dataset = client.create_dataset(name="conversational_annotation_import_demo_dataset")
  task = dataset.create_data_rows([asset])
  task.wait_till_done()
  print("Errors:", task.errors)
  print("Failed data rows: ", task.failed_data_rows)
  ```
</CodeGroup>

### Step 2: Set up ontology

Your project ontology should support the tools and classifications required by your annotations. To ensure accurate schema feature mapping, the value used as the `name` parameter should match the value of the `name` field in your annotation.

For example, when we created an annotation above, we provided a name`annotation_name`. Now, when we set up our ontology, we must ensure that the name of our bounding box tool is also `anotations_name`. The same alignment must hold true for the other tools and classifications we create in our ontology.

This example shows how to create an ontology containing all supported [annotation types](#supported-annotations) .

<CodeGroup>
  ```python Python theme={null}
  ontology_builder = lb.OntologyBuilder(
    tools=[
      lb.Tool(tool=lb.Tool.Type.NER,name="ner"),
      lb.Tool(tool=lb.Tool.Type.RELATIONSHIP,name="relationship")
      ],
    classifications=[
      lb.Classification(
        class_type=lb.Classification.Type.TEXT,
        scope=lb.Classification.Scope.INDEX,  # Remove this line or set scope to "GLOBAL" if importing global text annotations
        instructions="text_convo"),
      lb.Classification(
        class_type=lb.Classification.Type.CHECKLIST,
        scope=lb.Classification.Scope.INDEX,  # Remove this line or set scope to "GLOBAL" if importing global checklist annotations
        instructions="checklist_convo",
        options=[
          lb.Option(value="first_checklist_answer"),
          lb.Option(value="second_checklist_answer")
        ]
      ),
      lb.Classification(
        class_type=lb.Classification.Type.RADIO,
        instructions="radio_convo",
        scope=lb.Classification.Scope.INDEX, # Remove this line or set scope to "GLOBAL" if importing global radio  annotations
        options=[
          lb.Option(value="first_radio_answer"),
          lb.Option(value="second_radio_answer")
        ]
      )
    ]
  )

  ontology = client.create_ontology("Ontology Conversation Annotations", ontology_builder.asdict())
  ```
</CodeGroup>

### Step 3: Set Up a Labeling Project

<CodeGroup>
  ```python Python theme={null}
  # Create Labelbox project
  project = client.create_project(name="conversational_project",
                                      media_type=lb.MediaType.Conversational)

  # Setup your ontology

  project.connect_ontology(ontology) # Connect your ontology
  ```
</CodeGroup>

### Step 4: Send Data Rows to Project

<CodeGroup>
  ```python Python theme={null}
  # Setup Batches and Ontology

  # Create a batch to send to your MAL project
  batch = project.create_batch(
    "first-batch-convo-demo", # Each batch in a project must have a unique name
    global_keys=[global_key], # a list of global keys, data row ids or global keys
    priority=5 # priority between 1(highest) - 5(lowest)
  )

  print("Batch: ", batch)
  ```
</CodeGroup>

### Step 5: Create annotation payloads

For help understanding annotation payloads, see [overview](#overview). To declare payloads, you can use Python annotation types (*preferred*) or NDJSON objects.

These examples demonstrate each format and how to compose annotations into labels attached to data rows.

<CodeGroup>
  ```python Python Annotation Payload theme={null}
  label = []
  label.append(
    lb_types.Label(
  		data={"global_key" : global_key },
      annotations=[
        ner_annotation,
        text_annotation,
        checklist_annotation,
        radio_annotation,
        ner_source,
        ner_target,
        ner_relationship
      ]
    )
  )
  ```

  ```python NDJSON Payload theme={null}
  label_ndjson = []
  for annotations in [
      ner_annotation_ndjson,
      text_annotation_ndjson,
      checklist_annotation_ndjson,
      radio_annotation_ndjson,
      ner_source_ndjson,
      ner_target_ndjson,
      ner_relationship_annotation_ndjson,
      ]:
    annotations.update({
        "dataRow": {
            "globalKey": global_key
        }
    })
    label_ndjson.append(annotations)
  ```
</CodeGroup>

### Step 6: Import annotation payload

For prelabeled (model-assisted labeling) scenarios, pass your payload as the value of the `predictions` parameter. For ground truths, pass the payload to the `labels` parameter.

<Warning>
  ### Warning

  Relationship annotations are not supported for ground truth import jobs.
</Warning>

#### Option A: Upload as [prelabels (model assisted labeling)](/docs/model-assisted-labeling)

This option is helpful for speeding up the initial labeling process and reducing the manual labeling workload for high-volume datasets.

<CodeGroup>
  ```python MAL import theme={null}
  # Upload MAL label for this data row in project
  upload_job = lb.MALPredictionImport.create_from_objects(
      client = client,
      project_id = project.uid,
      name="mal_job"+str(uuid.uuid4()),
      predictions=label
  )

  print(f"Errors: {upload_job.errors}", )
  print(f"Status of uploads: {upload_job.statuses}")
  ```
</CodeGroup>

#### Option B: Upload to a labeling project as [ground truth](/docs/import-ground-truth)

This option is helpful for loading high-confidence labels from another platform or previous projects that just need review rather than manual labeling effort.

<CodeGroup>
  ```python Label import theme={null}
  # Upload label for this data row in project
  upload_job = lb.LabelImport.create_from_objects(
      client = client,
      project_id = project.uid,
      name="label_import_job"+str(uuid.uuid4()),
      labels=label
  )

  print(f"Errors: {upload_job.errors}", )
  print(f"Status of uploads: {upload_job.statuses}")
  ```
</CodeGroup>
