""" 统一图像生成服务基类 支持硅基流动平台的多种图像生成模型 """ import base64 import logging import uuid from pathlib import Path from typing import Dict, Any import httpx from src.core.config import settings logger = logging.getLogger(__name__) class ImageGenerationService: """统一的图像生成服务基类""" def __init__(self): self.base_url = "https://api.siliconflow.cn/v1/image/generations" self.api_key = settings.siliconflow_api_key self.timeout = 60 async def call_api(self, model: str, payload: dict) -> dict: """调用硅基流动 API""" logger.debug(f"调用SiliconFlow API: {self.base_url}") logger.debug(f"模型: {model}") logger.debug(f"请求参数: {payload}") async with httpx.AsyncClient(timeout=self.timeout) as client: response = await client.post( self.base_url, headers={ "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json" }, json={"model": model, **payload} ) response.raise_for_status() result = response.json() logger.debug(f"API响应状态: {response.status_code}") logger.debug(f"API响应类型: {type(result)}") logger.debug(f"API响应键: {list(result.keys()) if isinstance(result, dict) else '非字典类型'}") return result def save_image(self, image_id: str, base64_data: str) -> str: """保存 base64 图像到本地文件系统""" try: # 清理base64数据(移除可能的data URL前缀) if base64_data.startswith('data:image'): base64_data = base64_data.split(',')[1] # 移除可能的空白字符 base64_data = base64_data.strip() logger.debug(f"开始解码base64数据,长度: {len(base64_data)}") # 解码 base64 数据 image_bytes = base64.b64decode(base64_data) # 验证是否为有效的图片数据 if len(image_bytes) == 0: raise Exception("解码后的图像数据为空") logger.debug(f"图像数据大小: {len(image_bytes)} bytes") # 确保目录存在 image_dir = Path(settings.generated_images_dir) image_dir.mkdir(parents=True, exist_ok=True) # 保存图像文件 image_path = image_dir / f"{image_id}.png" with open(image_path, "wb") as f: f.write(image_bytes) logger.debug(f"图像已保存到: {image_path}") return str(image_path) except Exception as e: logger.error(f"保存图像失败: {str(e)}") logger.error(f"base64数据长度: {len(base64_data) if base64_data else 0}") logger.error(f"base64数据前100字符: {base64_data[:100] if base64_data else 'None'}") raise Exception(f"保存图像失败: {str(e)}") def generate_image_id(self) -> str: """生成唯一的图像ID""" return str(uuid.uuid4()) def get_image_url(self, image_id: str) -> str: """获取图像的访问URL""" return f"/generated_images/{image_id}.png"