This commit is contained in:
2025-11-07 09:05:14 +08:00
parent 9dcfff077e
commit 9d37b0695d

View File

@@ -0,0 +1,318 @@
"""
图片服务数据模型
"""
from typing import List, Optional, Dict, Any, Union
from pydantic import BaseModel, Field
from enum import Enum
import time
from pathlib import Path
class ImageSourceType(str, Enum):
"""图片来源类型"""
AI_GENERATED = "ai_generated"
WEB_SEARCH = "web_search"
LOCAL_STORAGE = "local_storage"
class ImageProvider(str, Enum):
"""图片提供者"""
# AI生成
DALLE = "dalle"
STABLE_DIFFUSION = "stable_diffusion"
SILICONFLOW = "siliconflow"
POLLINATIONS = "pollinations"
# 网络搜索
UNSPLASH = "unsplash"
PIXABAY = "pixabay"
SEARXNG = "searxng"
GOOGLE_IMAGES = "google_images"
# 本地存储
LOCAL_STORAGE = "local_storage"
USER_UPLOAD = "user_upload"
SYSTEM_DEFAULT = "system_default"
class ImageFormat(str, Enum):
"""支持的图片格式"""
JPEG = "jpeg"
JPG = "jpg"
PNG = "png"
GIF = "gif"
WEBP = "webp"
BMP = "bmp"
TIFF = "tiff"
class ImagePosition(str, Enum):
"""图片在幻灯片中的位置"""
BACKGROUND = "background"
CONTENT = "content"
ICON = "icon"
DECORATION = "decoration"
HEADER = "header"
FOOTER = "footer"
class ImageLicense(str, Enum):
"""图片许可证类型"""
PUBLIC_DOMAIN = "public_domain"
CC0 = "cc0"
CC_BY = "cc_by"
CC_BY_SA = "cc_by_sa"
UNSPLASH_LICENSE = "unsplash_license"
PIXABAY_LICENSE = "pixabay_license"
CUSTOM = "custom"
UNKNOWN = "unknown"
class ImageMetadata(BaseModel):
"""图片元数据"""
width: int
height: int
format: ImageFormat
file_size: int
color_mode: Optional[str] = None
has_transparency: bool = False
dominant_colors: List[str] = Field(default_factory=list)
average_color: Optional[str] = None
brightness: Optional[float] = None
contrast: Optional[float] = None
class ImageTag(BaseModel):
"""图片标签"""
name: str
category: Optional[str] = None
confidence: float = 1.0
source: Optional[str] = None # 标签来源user, ai, api等
class ImageInfo(BaseModel):
"""图片信息"""
image_id: str
source_type: ImageSourceType
provider: ImageProvider
original_url: Optional[str] = None
local_path: str
filename: str
title: Optional[str] = None
description: Optional[str] = None
alt_text: Optional[str] = None
# 元数据
metadata: ImageMetadata
# 标签和关键词
tags: List[ImageTag] = Field(default_factory=list)
keywords: List[str] = Field(default_factory=list)
# 版权信息
license: ImageLicense = ImageLicense.UNKNOWN
license_info: Optional[str] = None
author: Optional[str] = None
author_url: Optional[str] = None
source_url: Optional[str] = None
# 使用统计
usage_count: int = 0
last_used_at: Optional[float] = None
# 时间戳
created_at: float = Field(default_factory=time.time)
updated_at: float = Field(default_factory=time.time)
def add_tag(self, name: str, category: Optional[str] = None, confidence: float = 1.0):
"""添加标签"""
tag = ImageTag(name=name, category=category, confidence=confidence)
if tag not in self.tags:
self.tags.append(tag)
def remove_tag(self, name: str):
"""移除标签"""
self.tags = [tag for tag in self.tags if tag.name != name]
def get_tags_by_category(self, category: str) -> List[ImageTag]:
"""按分类获取标签"""
return [tag for tag in self.tags if tag.category == category]
def update_usage(self):
"""更新使用统计"""
self.usage_count += 1
self.last_used_at = time.time()
self.updated_at = time.time()
class ImageSearchRequest(BaseModel):
"""图片搜索请求"""
query: str
keywords: List[str] = Field(default_factory=list)
tags: List[str] = Field(default_factory=list)
# 搜索参数
page: int = 1
per_page: int = 20
orientation: Optional[str] = None # landscape, portrait, squarish
category: Optional[str] = None
color: Optional[str] = None
# 尺寸要求
min_width: Optional[int] = None
min_height: Optional[int] = None
max_width: Optional[int] = None
max_height: Optional[int] = None
# 许可证要求
license_types: List[ImageLicense] = Field(default_factory=list)
# 提供者偏好
preferred_providers: List[ImageProvider] = Field(default_factory=list)
excluded_providers: List[ImageProvider] = Field(default_factory=list)
class ImageGenerationRequest(BaseModel):
"""AI图片生成请求"""
prompt: str
negative_prompt: Optional[str] = None
# 生成参数
width: int = 1024
height: int = 1024
quality: str = "standard" # standard, hd
style: Optional[str] = None # vivid, natural
# 提供者特定参数
provider: ImageProvider = ImageProvider.DALLE
model: Optional[str] = None
steps: Optional[int] = None
guidance_scale: Optional[float] = None
seed: Optional[int] = None
# 批量生成
num_images: int = 1
class ImageUploadRequest(BaseModel):
"""图片上传请求"""
filename: str
content_type: str
file_size: int
# 可选信息
title: Optional[str] = None
description: Optional[str] = None
tags: List[str] = Field(default_factory=list)
category: Optional[str] = None
# 来源信息
source_type: Optional[ImageSourceType] = None # 实际来源类型如果为None则默认为LOCAL_STORAGE
original_url: Optional[str] = None # 原始URL用于网络图片
# 处理选项
auto_resize: bool = True
auto_optimize: bool = True
generate_thumbnails: bool = True
class ImageProcessingOptions(BaseModel):
"""图片处理选项"""
# 尺寸调整
resize_width: Optional[int] = None
resize_height: Optional[int] = None
maintain_aspect_ratio: bool = True
resize_method: str = "lanczos" # lanczos, bicubic, bilinear
# 格式转换
output_format: Optional[ImageFormat] = None
# 质量优化
quality: Optional[int] = None # 1-100
optimize: bool = True
progressive: bool = False
# 图片增强
auto_enhance: bool = False
brightness: Optional[float] = None
contrast: Optional[float] = None
saturation: Optional[float] = None
sharpness: Optional[float] = None
# 水印
add_watermark: bool = False
watermark_text: Optional[str] = None
watermark_position: str = "bottom_right"
watermark_opacity: float = 0.5
class ImageSearchResult(BaseModel):
"""图片搜索结果"""
images: List[ImageInfo]
total_count: int
page: int
per_page: int
has_next: bool
has_prev: bool
# 搜索统计
search_time: float
provider_results: Dict[str, int] = Field(default_factory=dict)
provider: ImageProvider
error: Optional[str] = None
class ImageOperationResult(BaseModel):
"""图片操作结果"""
success: bool
message: str
image_info: Optional[ImageInfo] = None
error_code: Optional[str] = None
processing_time: Optional[float] = None
class ProjectImageAssociation(BaseModel):
"""项目图片关联"""
project_id: str
image_id: str
slide_index: int
position: ImagePosition
# 位置和样式信息
x: Optional[float] = None
y: Optional[float] = None
width: Optional[float] = None
height: Optional[float] = None
z_index: Optional[int] = None
# 样式属性
opacity: float = 1.0
rotation: float = 0.0
border_radius: Optional[float] = None
shadow: Optional[Dict[str, Any]] = None
# 动画效果
animation: Optional[Dict[str, Any]] = None
created_at: float = Field(default_factory=time.time)
class ImageCacheInfo(BaseModel):
"""图片缓存信息"""
cache_key: str
file_path: str
file_size: int
created_at: float
last_accessed: float
access_count: int
expires_at: Optional[float] = None
def is_expired(self) -> bool:
"""检查是否过期 - 图片永不过期"""
return False
def update_access(self):
"""更新访问信息"""
self.last_accessed = time.time()
self.access_count += 1