Spaces:
Running
Running
Upload 4 files
Browse files- app.py +14 -5
- models.py +5 -1
- router_posts.py +15 -0
app.py
CHANGED
|
@@ -6,6 +6,7 @@ from sqlalchemy.orm import Session
|
|
| 6 |
from pydantic import BaseModel
|
| 7 |
from huggingface_hub import hf_hub_download, HfApi
|
| 8 |
import hashlib
|
|
|
|
| 9 |
import urllib.parse
|
| 10 |
import urllib.request
|
| 11 |
import urllib.error
|
|
@@ -325,14 +326,19 @@ def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
|
|
| 325 |
if file_type == "avatar":
|
| 326 |
max_size = 2 * 1024 * 1024
|
| 327 |
elif file_type == "cover":
|
| 328 |
-
max_size = 5 * 1024 * 1024
|
|
|
|
|
|
|
| 329 |
|
| 330 |
if len(content) > max_size:
|
| 331 |
raise HTTPException(status_code=400, detail=f"文件过大,{file_type} 类型请限制在 {max_size // (1024*1024)}MB 以内")
|
| 332 |
|
| 333 |
ext = file.filename.split(".")[-1].lower()
|
| 334 |
-
|
| 335 |
-
|
|
|
|
|
|
|
|
|
|
| 336 |
|
| 337 |
# 🔒 P0安全优化:图片内容审核
|
| 338 |
if ext in ["jpg", "jpeg", "png", "gif", "webp"]:
|
|
@@ -343,8 +349,11 @@ def upload_file(file: UploadFile = File(...), file_type: str = Form(...)):
|
|
| 343 |
detail=f"图片内容审核未通过:{moderation_result.label or '内容不合规'}"
|
| 344 |
)
|
| 345 |
|
| 346 |
-
|
| 347 |
-
|
|
|
|
|
|
|
|
|
|
| 348 |
|
| 349 |
local_tmp_path = f"/tmp/{safe_filename}"
|
| 350 |
with open(local_tmp_path, "wb") as f:
|
|
|
|
| 6 |
from pydantic import BaseModel
|
| 7 |
from huggingface_hub import hf_hub_download, HfApi
|
| 8 |
import hashlib
|
| 9 |
+
import uuid
|
| 10 |
import urllib.parse
|
| 11 |
import urllib.request
|
| 12 |
import urllib.error
|
|
|
|
| 326 |
if file_type == "avatar":
|
| 327 |
max_size = 2 * 1024 * 1024
|
| 328 |
elif file_type == "cover":
|
| 329 |
+
max_size = 5 * 1024 * 1024
|
| 330 |
+
elif file_type == "post_video":
|
| 331 |
+
max_size = 50 * 1024 * 1024
|
| 332 |
|
| 333 |
if len(content) > max_size:
|
| 334 |
raise HTTPException(status_code=400, detail=f"文件过大,{file_type} 类型请限制在 {max_size // (1024*1024)}MB 以内")
|
| 335 |
|
| 336 |
ext = file.filename.split(".")[-1].lower()
|
| 337 |
+
allowed_exts = ["jpg", "jpeg", "png", "gif", "webp", "json", "mp4"]
|
| 338 |
+
if file_type == "post_video":
|
| 339 |
+
allowed_exts = ["mp4", "webm", "mov"]
|
| 340 |
+
if ext not in allowed_exts:
|
| 341 |
+
raise HTTPException(status_code=400, detail=f"不支持的文件格式,{file_type} 类型仅支持 {', '.join(allowed_exts)}")
|
| 342 |
|
| 343 |
# 🔒 P0安全优化:图片内容审核
|
| 344 |
if ext in ["jpg", "jpeg", "png", "gif", "webp"]:
|
|
|
|
| 349 |
detail=f"图片内容审核未通过:{moderation_result.label or '内容不合规'}"
|
| 350 |
)
|
| 351 |
|
| 352 |
+
if file_type == "post_video":
|
| 353 |
+
safe_filename = f"post_video_{uuid.uuid4().hex[:8]}.{ext}"
|
| 354 |
+
else:
|
| 355 |
+
file_hash = hashlib.md5(content).hexdigest()[:10]
|
| 356 |
+
safe_filename = f"{file_type}_{file_hash}.{ext}"
|
| 357 |
|
| 358 |
local_tmp_path = f"/tmp/{safe_filename}"
|
| 359 |
with open(local_tmp_path, "wb") as f:
|
models.py
CHANGED
|
@@ -228,6 +228,8 @@ class PostCreate(BaseModel):
|
|
| 228 |
images: Optional[List[str]] = [] # 图片列表(最多9张)
|
| 229 |
author: str # 作者账号
|
| 230 |
is_original: Optional[bool] = False # 🎨 是否为原创作品
|
|
|
|
|
|
|
| 231 |
|
| 232 |
class PostUpdate(BaseModel):
|
| 233 |
""" 更新帖子 """
|
|
@@ -235,4 +237,6 @@ class PostUpdate(BaseModel):
|
|
| 235 |
content: Optional[str] = None
|
| 236 |
cover_image: Optional[str] = None
|
| 237 |
images: Optional[List[str]] = None
|
| 238 |
-
is_original: Optional[bool] = None # 🎨 是否为原创作品
|
|
|
|
|
|
|
|
|
| 228 |
images: Optional[List[str]] = [] # 图片列表(最多9张)
|
| 229 |
author: str # 作者账号
|
| 230 |
is_original: Optional[bool] = False # 🎨 是否为原创作品
|
| 231 |
+
post_type: str = "image" # "image" 或 "video"
|
| 232 |
+
video_url: Optional[str] = None # 视频 URL(仅 video 类型)
|
| 233 |
|
| 234 |
class PostUpdate(BaseModel):
|
| 235 |
""" 更新帖子 """
|
|
|
|
| 237 |
content: Optional[str] = None
|
| 238 |
cover_image: Optional[str] = None
|
| 239 |
images: Optional[List[str]] = None
|
| 240 |
+
is_original: Optional[bool] = None # 🎨 是否为原创作品
|
| 241 |
+
post_type: Optional[str] = None # "image" 或 "video"
|
| 242 |
+
video_url: Optional[str] = None # 视频 URL(仅 video 类型)
|
router_posts.py
CHANGED
|
@@ -152,6 +152,12 @@ async def create_post(post: PostCreate, current_user: str = Depends(require_auth
|
|
| 152 |
|
| 153 |
# 限制图片数量
|
| 154 |
images = (post.images or [])[:9]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
|
| 156 |
new_post = {
|
| 157 |
"id": f"post_{int(time.time())}_{uuid.uuid4().hex[:6]}",
|
|
@@ -162,6 +168,8 @@ async def create_post(post: PostCreate, current_user: str = Depends(require_auth
|
|
| 162 |
"author": current_user,
|
| 163 |
"created_at": int(time.time()),
|
| 164 |
"is_original": post.is_original if post.is_original is not None else False, # 🎨 原创作品标记
|
|
|
|
|
|
|
| 165 |
# 互动数据
|
| 166 |
"likes": 0,
|
| 167 |
"favorites": 0,
|
|
@@ -210,6 +218,13 @@ async def update_post(post_id: str, update_data: PostUpdate, current_user: str =
|
|
| 210 |
post["images"] = update_data.images[:9]
|
| 211 |
if update_data.is_original is not None:
|
| 212 |
post["is_original"] = update_data.is_original # 🎨 更新原创作品标记
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
result_holder["post"] = post
|
| 214 |
return True
|
| 215 |
result_holder["error"] = "not_found"
|
|
|
|
| 152 |
|
| 153 |
# 限制图片数量
|
| 154 |
images = (post.images or [])[:9]
|
| 155 |
+
post_type = post.post_type if hasattr(post, "post_type") else "image"
|
| 156 |
+
video_url = post.video_url if hasattr(post, "video_url") else None
|
| 157 |
+
|
| 158 |
+
# 视频帖:images 置为空列表
|
| 159 |
+
if post_type == "video":
|
| 160 |
+
images = []
|
| 161 |
|
| 162 |
new_post = {
|
| 163 |
"id": f"post_{int(time.time())}_{uuid.uuid4().hex[:6]}",
|
|
|
|
| 168 |
"author": current_user,
|
| 169 |
"created_at": int(time.time()),
|
| 170 |
"is_original": post.is_original if post.is_original is not None else False, # 🎨 原创作品标记
|
| 171 |
+
"post_type": post_type,
|
| 172 |
+
"video_url": video_url,
|
| 173 |
# 互动数据
|
| 174 |
"likes": 0,
|
| 175 |
"favorites": 0,
|
|
|
|
| 218 |
post["images"] = update_data.images[:9]
|
| 219 |
if update_data.is_original is not None:
|
| 220 |
post["is_original"] = update_data.is_original # 🎨 更新原创作品标记
|
| 221 |
+
if update_data.post_type is not None:
|
| 222 |
+
post["post_type"] = update_data.post_type
|
| 223 |
+
# 如果切换为视频帖,清空图片列表
|
| 224 |
+
if update_data.post_type == "video":
|
| 225 |
+
post["images"] = []
|
| 226 |
+
if update_data.video_url is not None:
|
| 227 |
+
post["video_url"] = update_data.video_url
|
| 228 |
result_holder["post"] = post
|
| 229 |
return True
|
| 230 |
result_holder["error"] = "not_found"
|