This commit is contained in:
aaron 2025-04-09 23:00:06 +08:00
parent c79cf5186c
commit b2b7770de2
6 changed files with 118 additions and 45 deletions

View File

@ -137,11 +137,6 @@ async def read_clothes_by_category(
db: AsyncSession = Depends(get_db)
):
"""根据分类获取衣服"""
# 检查分类是否存在
category = await clothing_service.get_category(db, category_id=category_id)
if category is None:
raise BusinessError("分类不存在", code=404)
clothes = await clothing_service.get_clothes_by_category(
db=db,
category_id=category_id,
@ -151,46 +146,6 @@ async def read_clothes_by_category(
# 手动返回标准响应格式
return StandardResponse(code=200, data=[Clothing.model_validate(clothing) for clothing in clothes])
@router.get("/{clothing_id}", tags=["clothing"])
async def read_clothing(
clothing_id: int,
db: AsyncSession = Depends(get_db)
):
"""获取单个衣服"""
clothing = await clothing_service.get_clothing(db, clothing_id=clothing_id)
if clothing is None:
raise BusinessError("衣服不存在", code=404)
# 手动返回标准响应格式
return StandardResponse(code=200, data=Clothing.model_validate(clothing))
@router.put("/{clothing_id}", tags=["clothing"])
async def update_clothing(
clothing_id: int,
clothing: ClothingUpdate,
db: AsyncSession = Depends(get_db),
current_user: UserModel = Depends(get_current_user)
):
"""
更新衣服
需要JWT令牌认证
"""
# 检查分类是否存在
if clothing.clothing_category_id is not None:
category = await clothing_service.get_category(db, category_id=clothing.clothing_category_id)
if category is None:
raise BusinessError("指定的分类不存在", code=404)
clothing = await clothing_service.update_clothing(
db=db,
clothing_id=clothing_id,
clothing_update=clothing
)
if clothing is None:
raise BusinessError("衣服不存在", code=404)
# 手动返回标准响应格式
return StandardResponse(code=200, data=Clothing.model_validate(clothing))
@router.delete("/{clothing_id}", tags=["clothing"])
async def delete_clothing(
clothing_id: int,

70
app/api/v1/tryon.py Normal file
View File

@ -0,0 +1,70 @@
from fastapi import APIRouter, Depends, HTTPException, status, Response
from sqlalchemy.ext.asyncio import AsyncSession
import logging
from fastapi.security import OAuth2PasswordRequestForm
from app.api import deps
from app.core import security
from app.core.config import settings
from app.schemas.tryon import TryonRequest
from app.schemas.user import User
from app.services import person_image as person_image_service
from app.services import clothing as clothing_service
from app.api.deps import get_current_user
from app.services.dashscope_service import DashScopeService
from app.schemas.response import StandardResponse
from app.models.tryon import TryonHistory
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
router = APIRouter()
@router.post("/tryon", tags=["tryon"])
async def tryon(
tryon_request: TryonRequest,
db: AsyncSession = Depends(deps.get_db),
current_user: User = Depends(get_current_user)
):
# 获取当前用户的默认形象
person_image = await person_image_service.get_default_image(db, current_user.id)
if not person_image:
raise HTTPException(status_code=404, detail="默认形象不存在")
# 获取试穿请求中的衣物ID
top_clothing_id = tryon_request.top_clothing_id
bottom_clothing_id = tryon_request.bottom_clothing_id
# 获取衣物详情
top_clothing_url = tryon_request.top_clothing_url
bottom_clothing_url = tryon_request.bottom_clothing_url
if top_clothing_id:
top_clothing = await clothing_service.get_clothing(db, top_clothing_id)
top_clothing_url = top_clothing.image_url
if bottom_clothing_id:
bottom_clothing = await clothing_service.get_clothing(db, bottom_clothing_id)
bottom_clothing_url = bottom_clothing.image_url
# 调用试穿服务
dashscope_service = DashScopeService()
tryon_result = await dashscope_service.generate_tryon(person_image.image_url,
top_clothing_url,
bottom_clothing_url)
task_id = tryon_result.get("task_id")
if task_id:
tryon_history = TryonHistory(
user_id=current_user.id,
person_image_id=person_image.id,
top_clothing_id=top_clothing_id,
bottom_clothing_id=bottom_clothing_id,
top_clothing_url=top_clothing_url,
bottom_clothing_url=bottom_clothing_url,
task_id=task_id
)
db.add(tryon_history)
await db.commit()
return StandardResponse(code=200, message="试穿任务已提交", data=tryon_history.id)
else:
return StandardResponse(code=500, message="试穿任务提交失败")

View File

@ -3,6 +3,7 @@ from app.db.database import Base, engine
from app.models.users import User
from app.models.person_images import PersonImage
from app.models.clothing import ClothingCategory, Clothing
from app.models.tryon import TryonHistory
# 创建所有表格
async def init_db():

37
app/models/tryon.py Normal file
View File

@ -0,0 +1,37 @@
from sqlalchemy import Column, Integer, String, DateTime, ForeignKey, Enum
from sqlalchemy.sql import func
from sqlalchemy.orm import relationship
from app.db.database import Base
import enum
class TryonStatus(enum.Enum):
"""试穿状态枚举"""
GENERATING = "生成中"
COMPLETED = "已生成"
FAILED = "失败"
class TryonHistory(Base):
"""试穿记录数据模型"""
__tablename__ = "tryon_history"
id = Column(Integer, primary_key=True, autoincrement=True, index=True)
user_id = Column(Integer, ForeignKey("users.id"), nullable=False, index=True, comment="用户ID")
person_image_id = Column(Integer, ForeignKey("person_images.id"), nullable=False, index=True, comment="人物形象ID")
top_clothing_id = Column(Integer, ForeignKey("clothing.id"), nullable=True, comment="上衣ID")
bottom_clothing_id = Column(Integer, ForeignKey("clothing.id"), nullable=True, comment="下装ID")
top_clothing_url = Column(String(500), nullable=True, comment="上衣图片URL")
bottom_clothing_url = Column(String(500), nullable=True, comment="下装图片URL")
task_id = Column(String(100), nullable=True, index=True, comment="任务ID")
completion_url = Column(String(500), nullable=True, comment="生成结果URL")
status = Column(Enum(TryonStatus), default=TryonStatus.GENERATING, comment="状态")
create_time = Column(DateTime, default=func.now(), comment="创建时间")
update_time = Column(DateTime, default=func.now(), onupdate=func.now(), comment="更新时间")
# 关系
user = relationship("User", backref="tryon_histories")
person_image = relationship("PersonImage", backref="tryon_histories")
top_clothing = relationship("Clothing", foreign_keys=[top_clothing_id], backref="top_tryon_histories")
bottom_clothing = relationship("Clothing", foreign_keys=[bottom_clothing_id], backref="bottom_tryon_histories")
def __repr__(self):
return f"<TryonHistory(id={self.id}, status={self.status.name})>"

View File

@ -18,6 +18,7 @@ class User(Base):
# 关系
person_images = relationship("PersonImage", back_populates="user", cascade="all, delete-orphan")
clothings = relationship("Clothing", back_populates="user", cascade="all, delete-orphan")
# tryon_histories已通过backref在TryonHistory模型中定义
def __repr__(self):
return f"<User(id={self.id}, nickname={self.nickname})>"

9
app/schemas/tryon.py Normal file
View File

@ -0,0 +1,9 @@
from pydantic import BaseModel
from typing import Optional
class TryonRequest(BaseModel):
top_clothing_id: Optional[int] = None
bottom_clothing_id: Optional[int] = None
top_clothing_url: Optional[str] = None
bottom_clothing_url: Optional[str] = None