Spaces:
Running
Running
Upload app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# ⚙️ 后端逻辑/核心服务端.py (Hugging Face Spaces app.py)
|
| 2 |
from fastapi import FastAPI, File, UploadFile, Form, Depends, HTTPException
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
-
from fastapi.responses import Response, JSONResponse
|
| 5 |
from sqlalchemy.orm import Session
|
| 6 |
from pydantic import BaseModel
|
| 7 |
from huggingface_hub import hf_hub_download, HfApi
|
|
@@ -10,6 +10,7 @@ import urllib.parse
|
|
| 10 |
import urllib.request
|
| 11 |
import urllib.error
|
| 12 |
import os
|
|
|
|
| 13 |
import 数据库连接 as db
|
| 14 |
|
| 15 |
from router_users import router as users_router
|
|
@@ -24,9 +25,6 @@ from models_sql import Ownership
|
|
| 24 |
|
| 25 |
app = FastAPI(title="ComfyUI Ranking Community API")
|
| 26 |
|
| 27 |
-
# ==========================================
|
| 28 |
-
# 增加一个根目录健康检查接口,专治 HF Spaces 的 "Restarting" 误判
|
| 29 |
-
# ==========================================
|
| 30 |
@app.get("/")
|
| 31 |
def health_check():
|
| 32 |
return {"status": "ok", "message": "ComfyUI Ranking API is running perfectly!"}
|
|
@@ -36,7 +34,6 @@ def on_startup():
|
|
| 36 |
init_sql_db()
|
| 37 |
print("关系型数据库加载完毕,金融表同步完成。")
|
| 38 |
|
| 39 |
-
# 🟢 致命 BUG 修复:allow_credentials 必须为 False 才能配合 origins=["*"]
|
| 40 |
app.add_middleware(
|
| 41 |
CORSMiddleware,
|
| 42 |
allow_origins=["*"],
|
|
@@ -52,18 +49,60 @@ app.include_router(messages_router)
|
|
| 52 |
app.include_router(wallet_router)
|
| 53 |
app.include_router(proxy_router)
|
| 54 |
|
| 55 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
@app.post("/api/upload")
|
| 57 |
def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
|
| 58 |
-
# 同步读取文件内容
|
| 59 |
content = file.file.read()
|
| 60 |
|
| 61 |
-
#
|
| 62 |
-
max_size = 10 * 1024 * 1024
|
| 63 |
if file_type == "avatar":
|
| 64 |
-
max_size = 2 * 1024 * 1024
|
| 65 |
elif file_type == "cover":
|
| 66 |
-
max_size = 5 * 1024 * 1024
|
| 67 |
|
| 68 |
if len(content) > max_size:
|
| 69 |
raise HTTPException(status_code=400, detail=f"文件过大,{file_type} 类型请限制在 {max_size // (1024*1024)}MB 以内")
|
|
@@ -98,7 +137,8 @@ def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
|
|
| 98 |
if os.path.exists(local_tmp_path):
|
| 99 |
os.remove(local_tmp_path)
|
| 100 |
|
| 101 |
-
|
|
|
|
| 102 |
return {"status": "success", "url": permanent_url}
|
| 103 |
|
| 104 |
|
|
@@ -107,7 +147,6 @@ class ValidateResourceRequest(BaseModel):
|
|
| 107 |
item_id: str
|
| 108 |
account: str
|
| 109 |
|
| 110 |
-
# 🟢 性能隐患修复:去掉 async def,防止 urllib.request 阻塞事件循环
|
| 111 |
@app.post("/api/validate_resource")
|
| 112 |
def validate_resource(req_data: ValidateResourceRequest, sql_db: Session = Depends(get_db)):
|
| 113 |
target_url = req_data.url
|
|
|
|
| 1 |
# ⚙️ 后端逻辑/核心服务端.py (Hugging Face Spaces app.py)
|
| 2 |
from fastapi import FastAPI, File, UploadFile, Form, Depends, HTTPException
|
| 3 |
from fastapi.middleware.cors import CORSMiddleware
|
| 4 |
+
from fastapi.responses import Response, JSONResponse, FileResponse # 🟢 新增 FileResponse
|
| 5 |
from sqlalchemy.orm import Session
|
| 6 |
from pydantic import BaseModel
|
| 7 |
from huggingface_hub import hf_hub_download, HfApi
|
|
|
|
| 10 |
import urllib.request
|
| 11 |
import urllib.error
|
| 12 |
import os
|
| 13 |
+
import mimetypes # 🟢 新增,用于识别图片类型
|
| 14 |
import 数据库连接 as db
|
| 15 |
|
| 16 |
from router_users import router as users_router
|
|
|
|
| 25 |
|
| 26 |
app = FastAPI(title="ComfyUI Ranking Community API")
|
| 27 |
|
|
|
|
|
|
|
|
|
|
| 28 |
@app.get("/")
|
| 29 |
def health_check():
|
| 30 |
return {"status": "ok", "message": "ComfyUI Ranking API is running perfectly!"}
|
|
|
|
| 34 |
init_sql_db()
|
| 35 |
print("关系型数据库加载完毕,金融表同步完成。")
|
| 36 |
|
|
|
|
| 37 |
app.add_middleware(
|
| 38 |
CORSMiddleware,
|
| 39 |
allow_origins=["*"],
|
|
|
|
| 49 |
app.include_router(wallet_router)
|
| 50 |
app.include_router(proxy_router)
|
| 51 |
|
| 52 |
+
# ==========================================
|
| 53 |
+
# 🟢 新增:私有图床代理中心 (Image Proxy)
|
| 54 |
+
# 解决 Private 仓库下,本地客户端报 401 Unauthorized 的终极方案
|
| 55 |
+
# ==========================================
|
| 56 |
+
@app.get("/api/image_proxy")
|
| 57 |
+
def proxy_hf_image(url: str = None, path: str = None):
|
| 58 |
+
"""云端图片代理:使用云端的 HF_TOKEN 提取私有图床图片并返回给没有任何权限的本地端"""
|
| 59 |
+
|
| 60 |
+
# 兼容处理:如果本地发来的是已经被污染的老版本 HF 直链,我们自动将其转换为相对路径
|
| 61 |
+
if url and url.startswith("https://huggingface.co/datasets/"):
|
| 62 |
+
try:
|
| 63 |
+
path = url.split("resolve/main/")[-1]
|
| 64 |
+
path = urllib.parse.unquote(path)
|
| 65 |
+
except:
|
| 66 |
+
raise HTTPException(status_code=400, detail="无效的 HF 原链接格式")
|
| 67 |
+
|
| 68 |
+
if not path:
|
| 69 |
+
raise HTTPException(status_code=400, detail="缺少路径参数")
|
| 70 |
+
|
| 71 |
+
# 🛡️ 绝对的安全红线:限制只能代理下载图片目录,严禁黑客通过此接口下载 users.json 或账本数据!
|
| 72 |
+
allowed_dirs = ["uploads/", "avatars/", "covers/"]
|
| 73 |
+
if not any(path.startswith(d) for d in allowed_dirs):
|
| 74 |
+
raise HTTPException(status_code=403, detail="非法访问:该接口仅允许代理图片资源")
|
| 75 |
+
|
| 76 |
+
hf_token = os.environ.get("HF_TOKEN")
|
| 77 |
+
dataset_repo_id = db.DATASET_REPO_ID
|
| 78 |
+
|
| 79 |
+
try:
|
| 80 |
+
# hf_hub_download 会自动利用云端容器的缓存,只有第一次会去真实请求 Dataset
|
| 81 |
+
cached_file_path = hf_hub_download(
|
| 82 |
+
repo_id=dataset_repo_id,
|
| 83 |
+
repo_type="dataset",
|
| 84 |
+
filename=path,
|
| 85 |
+
token=hf_token
|
| 86 |
+
)
|
| 87 |
+
# 智能识别文件类型 (image/jpeg, image/png 等)
|
| 88 |
+
content_type, _ = mimetypes.guess_type(cached_file_path)
|
| 89 |
+
return FileResponse(cached_file_path, media_type=content_type or "application/octet-stream")
|
| 90 |
+
except Exception as e:
|
| 91 |
+
return JSONResponse(content={"error": f"代理获取图片失败: {str(e)}"}, status_code=404)
|
| 92 |
+
|
| 93 |
+
# ==========================================
|
| 94 |
+
# 上传接口 (将返回的 URL 替换为 Proxy 代理链接)
|
| 95 |
+
# ==========================================
|
| 96 |
@app.post("/api/upload")
|
| 97 |
def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
|
|
|
|
| 98 |
content = file.file.read()
|
| 99 |
|
| 100 |
+
# 动态文件大小风控
|
| 101 |
+
max_size = 10 * 1024 * 1024
|
| 102 |
if file_type == "avatar":
|
| 103 |
+
max_size = 2 * 1024 * 1024
|
| 104 |
elif file_type == "cover":
|
| 105 |
+
max_size = 5 * 1024 * 1024
|
| 106 |
|
| 107 |
if len(content) > max_size:
|
| 108 |
raise HTTPException(status_code=400, detail=f"文件过大,{file_type} 类型请限制在 {max_size // (1024*1024)}MB 以内")
|
|
|
|
| 137 |
if os.path.exists(local_tmp_path):
|
| 138 |
os.remove(local_tmp_path)
|
| 139 |
|
| 140 |
+
# 🚀 核心修复:不再返回暴露隐私且报 401 的 HF 直链,而是返回我们刚写好的 Proxy 代理链接
|
| 141 |
+
permanent_url = f"https://zhiwei666-comfyui-ranking-api.hf.space/api/image_proxy?path=uploads/{file_type}/{safe_filename}"
|
| 142 |
return {"status": "success", "url": permanent_url}
|
| 143 |
|
| 144 |
|
|
|
|
| 147 |
item_id: str
|
| 148 |
account: str
|
| 149 |
|
|
|
|
| 150 |
@app.post("/api/validate_resource")
|
| 151 |
def validate_resource(req_data: ValidateResourceRequest, sql_db: Session = Depends(get_db)):
|
| 152 |
target_url = req_data.url
|