File size: 5,289 Bytes
b1acf7e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
"""
File handling utilities for different input types.
"""

import os
import tempfile
import logging
from typing import Optional, Union, Tuple
from pathlib import Path

from ..config.settings import (
    SUPPORTED_IMAGE_FORMATS,
    SUPPORTED_AUDIO_FORMATS,
    SUPPORTED_VIDEO_FORMATS,
)

logger = logging.getLogger(__name__)


def validate_file_format(filename: str, supported_formats: list) -> bool:
    """
    Validate if a file has a supported format.

    Args:
        filename: Name of the file to validate
        supported_formats: List of supported file extensions

    Returns:
        True if file format is supported, False otherwise
    """
    if not filename:
        return False

    file_extension = Path(filename).suffix.lower().lstrip(".")
    return file_extension in supported_formats


def validate_image_file(filename: str) -> bool:
    """Validate if a file is a supported image format."""
    return validate_file_format(filename, SUPPORTED_IMAGE_FORMATS)


def validate_audio_file(filename: str) -> bool:
    """Validate if a file is a supported audio format."""
    return validate_file_format(filename, SUPPORTED_AUDIO_FORMATS)


def validate_video_file(filename: str) -> bool:
    """Validate if a file is a supported video format."""
    return validate_file_format(filename, SUPPORTED_VIDEO_FORMATS)


def get_file_info(file_object) -> dict:
    """
    Extract file information from a file object.

    Args:
        file_object: File object (e.g., StreamlitUploadedFile)

    Returns:
        Dictionary containing file information
    """
    try:
        if hasattr(file_object, "getvalue"):
            file_size = len(file_object.getvalue())
            file_name = getattr(file_object, "name", "Unknown")
        else:
            file_size = len(file_object)
            file_name = "Unknown"

        file_extension = (
            Path(file_name).suffix.lower().lstrip(".")
            if file_name != "Unknown"
            else "Unknown"
        )

        return {
            "name": file_name,
            "size_bytes": file_size,
            "size_kb": file_size / 1024,
            "size_mb": file_size / (1024 * 1024),
            "extension": file_extension,
            "is_valid_image": (
                validate_image_file(file_name) if file_extension != "Unknown" else False
            ),
            "is_valid_audio": (
                validate_audio_file(file_name) if file_extension != "Unknown" else False
            ),
            "is_valid_video": (
                validate_video_file(file_name) if file_extension != "Unknown" else False
            ),
        }
    except Exception as e:
        logger.error(f"Error getting file info: {str(e)}")
        return {
            "name": "Unknown",
            "size_bytes": 0,
            "size_kb": 0,
            "size_mb": 0,
            "extension": "Unknown",
            "is_valid_image": False,
            "is_valid_audio": False,
            "is_valid_video": False,
        }


def create_temp_file(
    suffix: str = "", prefix: str = "temp_"
) -> Tuple[str, tempfile.NamedTemporaryFile]:
    """
    Create a temporary file with proper cleanup handling.

    Args:
        suffix: File extension suffix
        prefix: File name prefix

    Returns:
        Tuple of (file_path, temp_file_object)
    """
    temp_file = tempfile.NamedTemporaryFile(suffix=suffix, prefix=prefix, delete=False)
    return temp_file.name, temp_file


def cleanup_temp_file(file_path: str) -> bool:
    """
    Safely cleanup a temporary file.

    Args:
        file_path: Path to the temporary file

    Returns:
        True if cleanup was successful, False otherwise
    """
    try:
        if os.path.exists(file_path):
            os.unlink(file_path)
            return True
        return True
    except (OSError, PermissionError) as e:
        logger.warning(f"Could not delete temporary file {file_path}: {e}")
        return False


def format_file_size(size_bytes: int) -> str:
    """
    Format file size in human-readable format.

    Args:
        size_bytes: File size in bytes

    Returns:
        Formatted file size string
    """
    if size_bytes < 1024:
        return f"{size_bytes} B"
    elif size_bytes < 1024 * 1024:
        return f"{size_bytes / 1024:.1f} KB"
    elif size_bytes < 1024 * 1024 * 1024:
        return f"{size_bytes / (1024 * 1024):.1f} MB"
    else:
        return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"


def safe_file_operation(operation_func, *args, **kwargs):
    """
    Safely execute a file operation with proper error handling.

    Args:
        operation_func: Function to execute
        *args: Positional arguments for the function
        **kwargs: Keyword arguments for the function

    Returns:
        Result of the operation or None if it fails
    """
    try:
        return operation_func(*args, **kwargs)
    except FileNotFoundError as e:
        logger.error(f"File not found: {e}")
        return None
    except PermissionError as e:
        logger.error(f"Permission denied: {e}")
        return None
    except OSError as e:
        logger.error(f"OS error: {e}")
        return None
    except Exception as e:
        logger.error(f"Unexpected error in file operation: {e}")
        return None