File size: 4,683 Bytes
0953bf7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import re
from typing import Optional, Tuple
from PIL import Image
from io import BytesIO
from config import Config


class ValidationError(Exception):
    """Validation error"""
    pass


def validate_api_key(api_key: str) -> bool:
    """Validate API key format"""
    if not api_key:
        return False

    # Basic format check: length and characters
    if len(api_key) < 20 or not re.match(r'^[A-Za-z0-9_\-]+$', api_key):
        return False

    return True


def validate_prompt(prompt: str, max_length: int = 2000) -> Tuple[bool, Optional[str]]:
    """
    Validate prompt

    Returns:
        (is_valid, error_message)
    """
    if not prompt or not prompt.strip():
        return False, "Prompt cannot be empty"

    if len(prompt) > max_length:
        return False, f"Prompt length cannot exceed {max_length} characters"

    # Check for potentially harmful content keywords
    harmful_keywords = [
        'violence', 'gore', 'explicit', 'nsfw', 'nude', 'sexual',
        '暴力', '色情', '裸体', '性', '血腥'
    ]

    prompt_lower = prompt.lower()
    for keyword in harmful_keywords:
        if keyword in prompt_lower:
            return False, f"Prompt contains inappropriate content: {keyword}"

    return True, None


def validate_image(image_file) -> Tuple[bool, Optional[str], Optional[Image.Image]]:
    """
    Validate uploaded image

    Returns:
        (is_valid, error_message, processed_image)
    """
    try:
        # Check file size
        if hasattr(image_file, 'size') and image_file.size > Config.MAX_FILE_SIZE_MB * 1024 * 1024:
            return False, f"Image size cannot exceed {Config.MAX_FILE_SIZE_MB}MB", None

        # Try to open image
        image = Image.open(image_file)

        # Check image format
        if image.format.lower() not in ['png', 'jpeg', 'jpg']:
            return False, "Only PNG, JPG, JPEG formats are supported", None

        # Check image dimensions
        width, height = image.size

        # Minimum size check
        if width < 64 or height < 64:
            return False, "Image size too small (minimum 64x64 pixels)", None

        # Maximum size check
        max_dimension = 4096
        if width > max_dimension or height > max_dimension:
            return False, f"Image size too large (maximum {max_dimension}x{max_dimension} pixels)", None

        # Aspect ratio check (extreme ratios may not work well)
        ratio = max(width, height) / min(width, height)
        if ratio > 10:
            return False, "Image aspect ratio too extreme", None

        # If RGBA, convert to RGB
        if image.mode == 'RGBA':
            rgb_image = Image.new('RGB', image.size, (255, 255, 255))
            rgb_image.paste(image, mask=image.split()[-1])
            image = rgb_image
        elif image.mode != 'RGB':
            image = image.convert('RGB')

        return True, None, image

    except Exception as e:
        return False, f"Image processing error: {str(e)}", None


def validate_model_parameters(model_type: str, resolution: str, duration: int,
                            aspect_ratio: str) -> Tuple[bool, Optional[str]]:
    """Validate model parameters"""

    # Validate model type
    valid_models = list(Config.MODEL_OPTIONS.values())
    if model_type not in valid_models:
        return False, f"Unsupported model type: {model_type}"

    # Validate resolution
    if resolution not in Config.RESOLUTIONS:
        return False, f"Unsupported resolution: {resolution}"

    # Validate duration
    if duration not in Config.DURATIONS:
        return False, f"Unsupported duration: {duration}"

    # Validate aspect ratio
    if aspect_ratio not in Config.ASPECT_RATIOS:
        return False, f"Unsupported aspect ratio: {aspect_ratio}"

    return True, None


def sanitize_filename(filename: str) -> str:
    """Clean filename, remove unsafe characters"""
    # Remove path separators and special characters
    sanitized = re.sub(r'[<>:"/\\|?*]', '_', filename)
    # Remove control characters
    sanitized = re.sub(r'[\x00-\x1f\x7f-\x9f]', '', sanitized)
    # Limit length
    if len(sanitized) > 255:
        name, ext = sanitized.rsplit('.', 1) if '.' in sanitized else (sanitized, '')
        sanitized = name[:250] + ('.' + ext if ext else '')

    return sanitized or 'untitled'


def validate_seed(seed: Optional[int]) -> Tuple[bool, Optional[str]]:
    """Validate random seed"""
    if seed is None:
        return True, None

    if not isinstance(seed, int):
        return False, "Seed must be an integer"

    if seed < 0 or seed > 2147483647:
        return False, "Seed value must be between 0 and 2147483647"

    return True, None