```python:inference/core/workflows/core_steps/sinks/roboflow/dataset_upload/v1.py
import json
from typing import Any, Dict, List, Optional, Tuple, Union

import supervision as sv
from inference.core.roboflow_api import (annotate_image_at_roboflow,
                                         register_image_at_roboflow)
from inference.core.workflows.core_steps.common.serializers import \
    serialise_sv_detections
from inference.core.workflows.execution_engine.constants import \
    INFERENCE_ID_KEY

DUPLICATED_STATUS = "Duplicated image"


def register_datapoint(
    target_project: str,
    encoded_image: bytes,
    local_image_id: str,
    prediction: Optional[Union[sv.Detections, dict]],
    api_key: str,
    batch_name: str,
    tags: List[str],
    metadata: Optional[Dict[str, Any]] = None,
) -> str:
    inference_id = None
    if isinstance(prediction, dict):
        inference_id = prediction.get(INFERENCE_ID_KEY)
    if isinstance(prediction, sv.Detections) and len(prediction) > 0:
        # TODO: Lack of inference ID for empty prediction -
        #  dependent on https://github.com/roboflow/inference/issues/567
        inference_id_array = prediction.data.get(INFERENCE_ID_KEY)
        if inference_id_array is not None:
            inference_id_list = inference_id_array.tolist()
            inference_id = inference_id_list[0]
    roboflow_image_id = safe_register_image_at_roboflow(
        target_project=target_project,
        encoded_image=encoded_image,
        local_image_id=local_image_id,
        api_key=api_key,
        batch_name=batch_name,
        tags=tags,
        inference_id=inference_id,
        metadata=metadata,
    )
    if roboflow_image_id is None:
        return DUPLICATED_STATUS
    if is_prediction_registration_forbidden(prediction=prediction):
        return "Successfully registered image"
    encoded_prediction, prediction_format = encode_prediction(prediction=prediction)
    _ = annotate_image_at_roboflow(
        api_key=api_key,
        dataset_id=target_project,
        local_image_id=local_image_id,
        roboflow_image_id=roboflow_image_id,
        annotation_content=encoded_prediction,
        annotation_file_type=prediction_format,
        is_prediction=True,
    )
    return "Successfully registered image and annotation"


def safe_register_image_at_roboflow(
    target_project: str,
    encoded_image: bytes,
    local_image_id: str,
    api_key: str,
    batch_name: str,
    tags: List[str],
    inference_id: Optional[str],
    metadata: Optional[Dict[str, Any]] = None,
) -> Optional[str]:
    registration_response = register_image_at_roboflow(
        api_key=api_key,
        dataset_id=target_project,
        local_image_id=local_image_id,
        image_bytes=encoded_image,
        batch_name=batch_name,
        tags=tags,
        inference_id=inference_id,
        metadata=metadata,
    )
    image_duplicated = registration_response.get("duplicate", False)
    if image_duplicated:
        return None
    return registration_response["id"]


def is_prediction_registration_forbidden(
    prediction: Optional[Union[sv.Detections, dict]],
) -> bool:
    if prediction is None:
        return True
    
    # Check dict type first as it's more common based on profiling
    if isinstance(prediction, dict):
        return "top" not in prediction and "predicted_classes" not in prediction
    
    # sv.Detections case
    return len(prediction) == 0




def encode_prediction(
    prediction: Union[sv.Detections, dict],
) -> Tuple[str, str]:
    if isinstance(prediction, dict):
        if "predicted_classes" in prediction:
            return ",".join(prediction["predicted_classes"]), "txt"
        return prediction["top"], "txt"
    detections_in_inference_format = serialise_sv_detections(detections=prediction)
    return json.dumps(detections_in_inference_format), "json"
```