def import_from_scale(
    dataset,
    labels_dir_or_json,
    label_prefix=None,
    scale_id_field="scale_id",
    progress=None,
):
    """Imports the Scale AI labels into the FiftyOne dataset.

    This method supports importing annotations from the following Scale API
    endpoints:

    -   `General Image Annotation <https://docs.scale.com/reference/general-image-annotation>`_
    -   `Semantic Segmentation Annotation <https://docs.scale.com/reference/semantic-segmentation-annotation>`_
    -   `General Video Annotation <https://docs.scale.com/reference/general-video-annotation>`_
    -   `Video Playback <https://docs.scale.com/reference/video-playback>`_

    The ``scale_id_field`` of the FiftyOne samples are used to associate
    samples with their corresponding Scale task IDs.

    The provided ``labels_dir_or_json`` can either be the path to a JSON
    export in the following format::

        [
            {
                "task_id": <scale-task-id1>,
                "response": {...},
                ...
            },
            {
                "task_id": <scale-task-id2>,
                "response": {...},
                ...
            },
            ...
        ]

    or a directory of per-task JSON files, which can either (a) directly
    contain the elements of the list above, or (b) contain task labels
    organized in the following format::

        labels_dir/
            <scale-task-id1>.json
            <scale-task-id2>.json
            ...

    where each JSON file contains only the contents of the ``response`` field
    for the task.

    The contents of the ``response`` field should be as follows:

    -   `General Image Annotation <https://docs.scale.com/reference/general-image-annotation>`_::

            {
                "annotations": [...]
                "global_attributes": {...}
            }

    -   `Semantic Segmentation Annotation <https://docs.scale.com/reference/semantic-segmentation-annotation>`_::

            {
                "annotations": {
                    ...
                    "combined": {
                        ...
                        "indexedImage": <url-or-filepath>
                    }
                },
                "labelMapping": {...}
            }

        where the ``indexedImage`` field (which is the only version of the
        segmentation used by this method) can contain either a URL, in which
        case the mask is downloaded from the web, or the path to the mask on
        disk.

    -   `General Video Annotation <https://docs.scale.com/reference/general-video-annotation>`_::

            {
                "annotations": {
                    "url": <url-or-filepath>
                },
                "events": {
                    "url": <url-or-filepath>
                }
            }

        where the ``url`` fields can contain either a URL, in which case the
        file is downloaded from the web, or the path to JSON file on disk.

        The annotations file should contain per-frame annotations in the
        following format::

            [
                {
                    "annotations": [...],
                    "global_attributes": {...}
                },
                {
                    "annotations": [...],
                    "global_attributes": {...}
                },
                ...
            ]

        where the n-th element in the list contains the labels for the n-th
        frame that was labeled.

        Note that, if parameters such as ``duration_time``, ``frame_rate``, and
        ``start_time`` were used to specify which frames of the video to
        annotate, then you must ensure that the ``labels_dir_or_json`` JSON
        that you provide to this method contains the ``task`` fields for each
        Scale task so that the correct frame numbers can be determined from
        these values.

        The optional events file should contain a list of events in the video::

            {
                "events": [...]
            }

    -   `Video Playback <https://docs.scale.com/reference/video-playback>`_::

            {
                "annotations": {
                    "url": <url-or-filepath>
                },
                "events": {
                    "url": <url-or-filepath>
                }
            }

        where the ``url`` fields can contain either a URL, in which case the
        file is downloaded from the web, or the path to JSON files on disk.

        The annotations file should contain a dictionary of object
        trajectories::

            {
                "annotations": {...}
            }

        The optional events file should contain a list of events in the video::

            {
                "events": [...]
            }

    Args:
        dataset: a :class:`fiftyone.core.dataset.Dataset`
        labels_dir_or_json: the path to a Scale AI JSON export or a directory
            of JSON exports as per the formats described above
        label_prefix (None): a prefix to prepend to the sample label field(s)
            that are created, separated by an underscore
        scale_id_field ("scale_id"): the sample field to use to associate Scale
            task IDs with FiftyOne samples
        progress (None): whether to render a progress bar (True/False), use the
            default value ``fiftyone.config.show_progress_bars`` (None), or a
            progress callback function to invoke instead
    """
    fov.validate_collection(dataset, media_type=(fomm.IMAGE, fomm.VIDEO))
    is_video = dataset.media_type == fomm.VIDEO

    # Load labels
    if labels_dir_or_json.endswith(".json"):
        labels = _load_labels(labels_dir_or_json)
    else:
        labels = _load_labels_dir(labels_dir_or_json)

    id_map = {k: v for k, v in zip(*dataset.values([scale_id_field, "id"]))}

    if label_prefix:
        label_key = lambda k: label_prefix + "_" + k
    else:
        label_key = lambda k: k

    pb = fou.ProgressBar(total=len(labels), progress=progress)
    ctx = foc.SaveContext(dataset)
    with pb, ctx:
        for task_id, task_labels in pb(labels.items()):
            if task_id not in id_map:
                logger.info(
                    "Skipping labels for unknown Scale ID '%s'", task_id
                )
                continue

            sample = dataset[id_map[task_id]]

            if sample.metadata is None:
                if is_video:
                    sample.metadata = fom.VideoMetadata.build_for(
                        sample.filepath
                    )
                else:
                    sample.metadata = fom.ImageMetadata.build_for(
                        sample.filepath
                    )

            if is_video:
                frames = _parse_video_labels(task_labels, sample.metadata)
                sample.frames.merge(
                    {
                        frame_number: {
                            label_key(fname): flabel
                            for fname, flabel in frame_dict.items()
                        }
                        for frame_number, frame_dict in frames.items()
                    }
                )
            else:
                frame_size = (sample.metadata.width, sample.metadata.height)
                anno_dict = task_labels["response"]
                labels_dict = _parse_image_labels(anno_dict, frame_size)
                sample.update_fields(
                    {label_key(k): v for k, v in labels_dict.items()}
                )

            ctx.save(sample)
Imports the Scale AI labels into the FiftyOne dataset.

    This method supports importing annotations from the following Scale API
    endpoints:

    -   `General Image Annotation <https://docs.scale.com/reference/general-image-annotation>`_
    -   `Semantic Segmentation Annotation <https://docs.scale.com/reference/semantic-segmentation-annotation>`_
    -   `General Video Annotation <https://docs.scale.com/reference/general-video-annotation>`_
    -   `Video Playback <https://docs.scale.com/reference/video-playback>`_

    The ``scale_id_field`` of the FiftyOne samples are used to associate
    samples with their corresponding Scale task IDs.

    The provided ``labels_dir_or_json`` can either be the path to a JSON
    export in the following format::

        [
            {
                "task_id": <scale-task-id1>,
                "response": {...},
                ...
            },
            {
                "task_id": <scale-task-id2>,
                "response": {...},
                ...
            },
            ...
        ]

    or a directory of per-task JSON files, which can either (a) directly
    contain the elements of the list above, or (b) contain task labels
    organized in the following format::

        labels_dir/
            <scale-task-id1>.json
            <scale-task-id2>.json
            ...

    where each JSON file contains only the contents of the ``response`` field
    for the task.

    The contents of the ``response`` field should be as follows:

    -   `General Image Annotation <https://docs.scale.com/reference/general-image-annotation>`_::

            {
                "annotations": [...]
                "global_attributes": {...}
            }

    -   `Semantic Segmentation Annotation <https://docs.scale.com/reference/semantic-segmentation-annotation>`_::

            {
                "annotations": {
                    ...
                    "combined": {
                        ...
                        "indexedImage": <url-or-filepath>
                    }
                },
                "labelMapping": {...}
            }

        where the ``indexedImage`` field (which is the only version of the
        segmentation used by this method) can contain either a URL, in which
        case the mask is downloaded from the web, or the path to the mask on
        disk.

    -   `General Video Annotation <https://docs.scale.com/reference/general-video-annotation>`_::

            {
                "annotations": {
                    "url": <url-or-filepath>
                },
                "events": {
                    "url": <url-or-filepath>
                }
            }

        where the ``url`` fields can contain either a URL, in which case the
        file is downloaded from the web, or the path to JSON file on disk.

        The annotations file should contain per-frame annotations in the
        following format::

            [
                {
                    "annotations": [...],
                    "global_attributes": {...}
                },
                {
                    "annotations": [...],
                    "global_attributes": {...}
                },
                ...
            ]

        where the n-th element in the list contains the labels for the n-th
        frame that was labeled.

        Note that, if parameters such as ``duration_time``, ``frame_rate``, and
        ``start_time`` were used to specify which frames of the video to
        annotate, then you must ensure that the ``labels_dir_or_json`` JSON
        that you provide to this method contains the ``task`` fields for each
        Scale task so that the correct frame numbers can be determined from
        these values.

        The optional events file should contain a list of events in the video::

            {
                "events": [...]
            }

    -   `Video Playback <https://docs.scale.com/reference/video-playback>`_::

            {
                "annotations": {
                    "url": <url-or-filepath>
                },
                "events": {
                    "url": <url-or-filepath>
                }
            }

        where the ``url`` fields can contain either a URL, in which case the
        file is downloaded from the web, or the path to JSON files on disk.

        The annotations file should contain a dictionary of object
        trajectories::

            {
                "annotations": {...}
            }

        The optional events file should contain a list of events in the video::

            {
                "events": [...]
            }

    Args:
        dataset: a :class:`fiftyone.core.dataset.Dataset`
        labels_dir_or_json: the path to a Scale AI JSON export or a directory
            of JSON exports as per the formats described above
        label_prefix (None): a prefix to prepend to the sample label field(s)
            that are created, separated by an underscore
        scale_id_field ("scale_id"): the sample field to use to associate Scale
            task IDs with FiftyOne samples
        progress (None): whether to render a progress bar (True/False), use the
            default value ``fiftyone.config.show_progress_bars`` (None), or a
            progress callback function to invoke instead
    
fiftyone/utils/scale.py