File size: 4,926 Bytes
7fb47c4
 
 
 
 
 
 
 
6c983cf
 
 
1709520
7fb47c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6c983cf
7fb47c4
 
6c983cf
7fb47c4
 
 
 
 
 
6c983cf
7fb47c4
 
 
6c983cf
7fb47c4
 
 
 
 
 
6c983cf
 
7fb47c4
 
 
 
 
6c983cf
7fb47c4
 
 
 
 
 
 
 
 
 
 
 
6c983cf
7fb47c4
 
 
 
 
 
 
 
 
 
 
 
 
6c983cf
7fb47c4
 
 
 
6c983cf
7fb47c4
6c983cf
7fb47c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
"""
Blob conversion utilities for Gradio image components.
Handles conversion of blob data to proper image file formats.
"""

import hashlib
import os
from typing import Dict, Any
from logging_config import get_logger

# Module logger
logger = get_logger(__name__)


class BlobConverter:
    """Handles conversion of blob data to proper image file formats."""

    # File format signatures
    FORMAT_SIGNATURES = {
        b"\x89PNG\r\n\x1a\n": (".png", "image/png"),
        b"\xff\xd8\xff": (".jpg", "image/jpeg"),
        b"GIF87a": (".gif", "image/gif"),
        b"GIF89a": (".gif", "image/gif"),
    }

    @classmethod
    def is_blob_data(cls, image_data: Dict[str, Any]) -> bool:
        """
        Check if the image data represents a blob that needs conversion.

        Args:
            image_data: Dictionary containing image metadata

        Returns:
            True if the data is a blob that needs conversion
        """
        return (
            isinstance(image_data, dict)
            and "path" in image_data
            and "blob" in image_data["path"]
            and image_data.get("size") is None
            and image_data.get("orig_name") is None
            and image_data.get("mime_type") is None
        )

    @classmethod
    def detect_format(cls, content: bytes) -> tuple[str, str]:
        """
        Detect image format from file content.

        Args:
            content: Binary content of the file

        Returns:
            Tuple of (extension, mime_type)
        """
        for signature, (ext, mime_type) in cls.FORMAT_SIGNATURES.items():
            if content.startswith(signature):
                return ext, mime_type

        # Default to PNG if format cannot be determined
        return ".png", "image/png"

    @classmethod
    def generate_filename(cls, content: bytes, extension: str) -> str:
        """
        Generate a unique filename for the converted blob.

        Args:
            content: Binary content of the file
            extension: File extension to use

        Returns:
            Unique filename
        """
        content_hash = hashlib.md5(content).hexdigest()[:8]
        return f"flagged_image_{content_hash}{extension}"

    @classmethod
    def convert_blob(cls, image_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        Convert blob data to proper image file format.

        Args:
            image_data: Original image data dictionary

        Returns:
            Updated image data with proper file information
        """
        if not cls.is_blob_data(image_data):
            return image_data

        logger.info("Converting blob data: %s", image_data)

        blob_path = image_data["path"]
        logger.debug("Blob path: %s", blob_path)

        # Read blob content
        with open(blob_path, "rb") as f:
            content = f.read()

        file_size = len(content)
        logger.debug("File size: %d bytes", file_size)

        # Detect format
        extension, mime_type = cls.detect_format(content)
        logger.debug("Detected format: %s, MIME type: %s", extension, mime_type)

        # Generate filename and path
        filename = cls.generate_filename(content, extension)
        temp_dir = os.path.dirname(blob_path)
        new_path = os.path.join(temp_dir, filename)

        logger.debug("Generated filename: %s", filename)
        logger.debug("New path: %s", new_path)

        # Write converted file
        with open(new_path, "wb") as f:
            f.write(content)

        logger.info("Successfully converted blob to: %s", new_path)

        # Return updated image data
        converted_data = {
            "path": new_path,
            "url": image_data["url"].replace("blob", filename),
            "size": file_size,
            "orig_name": filename,
            "mime_type": mime_type,
            "is_stream": False,
            "meta": image_data.get("meta", {}),
        }

        logger.debug("Converted data: %s", converted_data)
        return converted_data


def decode_blob_data(image_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Convenience function to decode blob data from Gradio image component.

    Args:
        image_data: Image data dictionary from Gradio

    Returns:
        Converted image data or original data if not a blob
    """
    logger.debug("Processing image data: %s", image_data)

    result = BlobConverter.convert_blob(image_data)

    if result is image_data:
        logger.debug("Not a blob, skipping conversion")
    else:
        logger.info("Blob conversion completed")

    return result


def is_blob_data(image_data: Dict[str, Any]) -> bool:
    """
    Check if the image data represents a blob that needs conversion.

    Args:
        image_data: Dictionary containing image metadata

    Returns:
        True if the data is a blob that needs conversion
    """
    return BlobConverter.is_blob_data(image_data)