```python:inference/enterprise/workflows/enterprise_blocks/sinks/event_writer/v1.py
import logging
from typing import Any, Dict, List, Optional

import cv2
import numpy as np
from inference.core.workflows.execution_engine.entities.base import \
    WorkflowImageData


def _detections_to_v2_object_detections(detections: Any) -> List[Dict[str, Any]]:
    """Convert Supervision Detections to v2 objectDetections format.

    Uses center-based absolute pixel coordinates to match the main Roboflow
    annotation format: x,y = center of box, width,height = full dimensions.
    """
    if detections is None or not hasattr(detections, 'xyxy'):
        return []
    try:
        xyxy = detections.xyxy
        num_detections = len(xyxy)
        if num_detections == 0:
            return []
        
        confidence = detections.confidence
        data = detections.data
        class_names = data.get("class_name", []) if data else []
        
        results = []
        for i in range(num_detections):
            x1, y1, x2, y2 = xyxy[i]
            w = float(x2 - x1)
            h = float(y2 - y1)
            results.append(
                {
                    "class": class_names[i] if i < len(class_names) else "unknown",
                    "x": float((x1 + x2) / 2),
                    "y": float((y1 + y2) / 2),
                    "width": w,
                    "height": h,
                    "confidence": (
                        float(confidence[i]) if confidence is not None else 0.0
                    ),
                }
            )
        return results
    except Exception as e:
        logging.warning(f"Failed to convert object detections: {e}")
        return []




def _detections_to_v2_instance_segmentations(detections: Any) -> List[Dict[str, Any]]:
    """Convert Supervision Detections with masks to v2 instanceSegmentations format."""
    if detections is None or not hasattr(detections, 'xyxy'):
        return []
    try:
        xyxy = detections.xyxy
        num_detections = len(xyxy)
        if num_detections == 0:
            return []
        
        confidence = detections.confidence
        data = detections.data
        class_names = data.get("class_name", []) if data else []
        masks = detections.mask
        
        results = []
        for i in range(num_detections):
            x1, y1, x2, y2 = xyxy[i]
            w = float(x2 - x1)
            h = float(y2 - y1)
            entry = {
                "class": class_names[i] if i < len(class_names) else "unknown",
                "x": float((x1 + x2) / 2),
                "y": float((y1 + y2) / 2),
                "width": w,
                "height": h,
                "confidence": float(confidence[i]) if confidence is not None else 0.0,
                "points": [],
            }
            if masks is not None and i < len(masks):
                mask = masks[i].astype(np.uint8)
                contours, _ = cv2.findContours(
                    mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
                )
                if contours:
                    largest = max(contours, key=cv2.contourArea)
                    entry["points"] = [
                        [float(pt[0][0]), float(pt[0][1])] for pt in largest
                    ]
            if len(entry["points"]) >= 3:
                results.append(entry)
        return results
    except Exception as e:
        logging.warning(f"Failed to convert instance segmentations: {e}")
        return []




def _classifications_to_v2(predictions: Any) -> List[Dict[str, Any]]:
    """Convert classification predictions to v2 classifications format."""
    if predictions is None:
        return []
    try:
        if isinstance(predictions, dict):
            class_names = predictions.get("class_name", [])
            num_classes = len(class_names)
            if num_classes == 0:
                return []
            confidences = predictions.get("confidence", [])
            return [
                {
                    "class": class_names[i],
                    "confidence": float(confidences[i]) if i < len(confidences) else 0.0,
                }
                for i in range(num_classes)
            ]
        elif hasattr(predictions, "data"):
            data = predictions.data
            class_names = data.get("class_name", []) if data else []
            num_classes = len(class_names)
            if num_classes == 0:
                return []
            confidences = predictions.confidence
            return [
                {
                    "class": class_names[i],
                    "confidence": (
                        float(confidences[i])
                        if confidences is not None and i < len(confidences)
                        else 0.0
                    ),
                }
                for i in range(num_classes)
            ]
        return []
    except Exception as e:
        logging.warning(f"Failed to convert classifications: {e}")
        return []




def _keypoints_to_v2(detections: Any) -> List[Dict[str, Any]]:
    """Convert keypoint detection predictions to v2 keypoints format."""
    if detections is None or not hasattr(detections, 'xyxy'):
        return []
    try:
        xyxy = detections.xyxy
        num_detections = len(xyxy)
        if num_detections == 0:
            return []
        
        confidence = detections.confidence
        data = detections.data
        class_names = data.get("class_name", []) if data else []
        keypoints_xy = data.get("keypoints_xy") if data else None
        
        results = []
        for i in range(num_detections):
            x1, y1, x2, y2 = xyxy[i]
            w = float(x2 - x1)
            h = float(y2 - y1)
            entry = {
                "class": class_names[i] if i < len(class_names) else "unknown",
                "x": float((x1 + x2) / 2),
                "y": float((y1 + y2) / 2),
                "width": w,
                "height": h,
                "confidence": float(confidence[i]) if confidence is not None else 0.0,
                "keypoints": [],
            }
            if keypoints_xy is not None and i < len(keypoints_xy):
                kps = keypoints_xy[i]
                entry["keypoints"] = [
                    {
                        "id": j,
                        "x": float(kp[0]),
                        "y": float(kp[1]),
                    }
                    for j, kp in enumerate(kps)
                ]
            if entry["keypoints"]:
                results.append(entry)
        return results
    except Exception as e:
        logging.warning(f"Failed to convert keypoint detections: {e}")
        return []




def _build_image_entry(
    output_image: WorkflowImageData,
    input_image: Optional[WorkflowImageData] = None,
    image_label: Optional[str] = None,
    object_detections: Optional[Any] = None,
    classifications: Optional[Any] = None,
    instance_segmentations: Optional[Any] = None,
    keypoint_detections: Optional[Any] = None,
) -> Dict[str, Any]:
    """Build the single image object for the v2 API payload."""
    entry: Dict[str, Any] = {
        "base64Image": output_image.base64_image,
    }
    if input_image is not None:
        entry["inputBase64Image"] = input_image.base64_image
    if image_label is not None:
        entry["label"] = image_label

    od = _detections_to_v2_object_detections(object_detections)
    if od:
        entry["objectDetections"] = od

    cl = _classifications_to_v2(classifications)
    if cl:
        entry["classifications"] = cl

    seg = _detections_to_v2_instance_segmentations(instance_segmentations)
    if seg:
        entry["instanceSegmentations"] = seg

    kp = _keypoints_to_v2(keypoint_detections)
    if kp:
        entry["keypoints"] = kp

    return entry
```