|
1 | 1 | from fastapi import APIRouter |
2 | 2 | from pydantic import BaseModel |
3 | 3 | from core.image_generator import get_image_generator |
4 | | -from fastapi.responses import FileResponse |
5 | | -from fastapi import HTTPException |
| 4 | +from fastapi.responses import FileResponse, StreamingResponse |
| 5 | +from fastapi import HTTPException, Query |
| 6 | +import httpx |
| 7 | +import io |
| 8 | +from PIL import Image |
| 9 | +import logging |
6 | 10 |
|
7 | 11 | router = APIRouter(prefix="/api", tags=["Image Generation"]) |
8 | 12 | image_generator = get_image_generator() |
9 | 13 | class ImageGenerationRequest(BaseModel): |
10 | 14 | prompt: str = "" |
11 | 15 | negative_prompt: str = "" |
12 | | - workflow: str = "1.yml" |
| 16 | + workflow: str = "1.yaml" |
13 | 17 | width: int = 512 |
14 | 18 | height: int = 512 |
15 | 19 | batch_size: int = 4 |
@@ -67,3 +71,76 @@ async def get_workflows(): |
67 | 71 | return data |
68 | 72 | except Exception as e: |
69 | 73 | raise HTTPException(status_code=404, detail=f"获取文件失败: {str(e)}") |
| 74 | + |
| 75 | +@router.get("/proxy_image") |
| 76 | +async def proxy_image(url: str = Query(..., description="要代理的远程图片URL")): |
| 77 | + """ |
| 78 | + 代理远程图片资源 |
| 79 | + |
| 80 | + 通过代理访问远程图片,解决跨域问题 |
| 81 | + """ |
| 82 | + try: |
| 83 | + # 设置请求头,模拟浏览器访问 |
| 84 | + headers = { |
| 85 | + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36", |
| 86 | + "Accept": "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8", |
| 87 | + "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8", |
| 88 | + "Accept-Encoding": "gzip, deflate, br", |
| 89 | + "Connection": "keep-alive", |
| 90 | + "Upgrade-Insecure-Requests": "1", |
| 91 | + } |
| 92 | + |
| 93 | + # 使用httpx客户端获取远程图片 |
| 94 | + with httpx.Client(timeout=30.0, follow_redirects=True) as client: |
| 95 | + response = client.get(url, headers=headers) |
| 96 | + response.raise_for_status() |
| 97 | + |
| 98 | + # 检查响应内容类型 |
| 99 | + content_type = response.headers.get("content-type", "") |
| 100 | + if not content_type.startswith("image/"): |
| 101 | + raise HTTPException(status_code=400, detail="URL不是有效的图片资源") |
| 102 | + |
| 103 | + # 获取图片数据 |
| 104 | + image_data = response.content |
| 105 | + |
| 106 | + # 尝试使用PIL验证图片格式 |
| 107 | + try: |
| 108 | + image = Image.open(io.BytesIO(image_data)) |
| 109 | + # 重新保存为JPEG格式(可根据需要调整) |
| 110 | + img_buffer = io.BytesIO() |
| 111 | + |
| 112 | + # 根据原始格式选择保存格式 |
| 113 | + if image.format == "PNG": |
| 114 | + image.save(img_buffer, format="PNG", quality=95) |
| 115 | + content_type = "image/png" |
| 116 | + elif image.format == "GIF": |
| 117 | + image.save(img_buffer, format="GIF") |
| 118 | + content_type = "image/gif" |
| 119 | + else: |
| 120 | + image.save(img_buffer, format="JPEG", quality=95, optimize=True) |
| 121 | + content_type = "image/jpeg" |
| 122 | + |
| 123 | + img_buffer.seek(0) |
| 124 | + image_data = img_buffer.getvalue() |
| 125 | + |
| 126 | + except Exception as img_error: |
| 127 | + logging.warning(f"图片处理失败,直接返回原始数据: {img_error}") |
| 128 | + |
| 129 | + # 返回图片流响应 |
| 130 | + return StreamingResponse( |
| 131 | + io.BytesIO(image_data), |
| 132 | + media_type=content_type, |
| 133 | + headers={ |
| 134 | + "Cache-Control": "public, max-age=3600", # 缓存1小时 |
| 135 | + "Access-Control-Allow-Origin": "*", # 允许跨域 |
| 136 | + "Access-Control-Allow-Methods": "GET", |
| 137 | + "Access-Control-Allow-Headers": "*", |
| 138 | + } |
| 139 | + ) |
| 140 | + |
| 141 | + except httpx.HTTPStatusError as e: |
| 142 | + raise HTTPException(status_code=e.response.status_code, detail=f"获取远程图片失败: {e.response.status_code}") |
| 143 | + except httpx.RequestError as e: |
| 144 | + raise HTTPException(status_code=500, detail=f"请求远程图片失败: {str(e)}") |
| 145 | + except Exception as e: |
| 146 | + raise HTTPException(status_code=500, detail=f"代理图片失败: {str(e)}") |
0 commit comments