diff --git a/python-api/app/api/v1/image.py b/python-api/app/api/v1/image.py index 1bd5bc6..253dc28 100644 --- a/python-api/app/api/v1/image.py +++ b/python-api/app/api/v1/image.py @@ -7,17 +7,20 @@ import io import logging +import time import uuid from pathlib import Path import httpx from fastapi import APIRouter, Depends, File, HTTPException, Request, UploadFile from pydantic import BaseModel, Field +from sqlalchemy.ext.asyncio import AsyncSession -from app.api.deps import get_current_user +from app.api.deps import get_current_user, get_db from app.config import get_settings from app.models.user import User from app.schemas.common import ApiResponse, success_response +from app.services import point_service as ps from app.services.qiniu_service import get_qiniu_service from app.services.volcengine_mediakit_service import VolcengineMediakitService from app.utils.file_validation import check_upload_file @@ -163,12 +166,23 @@ async def remove_background( req: RemoveBackgroundRequest, current_user: User = Depends(get_current_user), mediakit_service: VolcengineMediakitService = Depends(get_mediakit_service), + db: AsyncSession = Depends(get_db), ) -> ApiResponse[RemoveBackgroundResponse]: """ AI 抠图(火山引擎 MediaKit) 移除图片背景,返回透明背景图片 URL。 + 每次调用消耗 10 积分。 """ + # 前置积分检查 + required_points = ps._calculate_cost("cover_avatar") + check = await ps.check_balance(db, current_user.id, required_points) + if not check["sufficient"]: + raise HTTPException( + status_code=402, + detail=f"积分不足,需要 {required_points} 积分,当前余额 {check['balance']}", + ) + try: logger.info( f"[RemoveBackground] 开始抠图: image_url={req.image_url[:80]}..., scene={req.scene}" @@ -216,6 +230,17 @@ async def remove_background( logger.info(f"[RemoveBackground] 结果已转存七牛云: {qiniu_url[:80]}...") + # 后置扣费(服务已调用成功) + await ps.consume( + db, + user_id=current_user.id, + points=required_points, + source_type="cover_avatar", + source_id=f"cover_avatar_{current_user.id}_{int(time.time() * 1000)}", + description="【封面形象抠图】", + ) + await db.commit() + return success_response( data=RemoveBackgroundResponse(url=qiniu_url), message="抠图成功", diff --git a/python-api/app/services/point_service.py b/python-api/app/services/point_service.py index 9820020..0e5d79e 100644 --- a/python-api/app/services/point_service.py +++ b/python-api/app/services/point_service.py @@ -329,6 +329,7 @@ _CATEGORY_MAP: dict[str, str] = { "compose": "压制成片", "subtitle_burn": "字幕烧录", "cover_design": "封面设计", + "cover_avatar": "封面形象", "wxpay": "充值", "compensation": "充值", "invite": "充值", diff --git a/python-api/config/points-config.yaml b/python-api/config/points-config.yaml index fefc61d..6e4c736 100644 --- a/python-api/config/points-config.yaml +++ b/python-api/config/points-config.yaml @@ -29,6 +29,9 @@ fixed_costs: # 封面设计:根据视频内容自动生成封面图 cover_design: 5 + # 封面形象:上传人物照片 AI 抠图生成透明背景形象 + cover_avatar: 10 + # 压制成片:将多个素材片段合并为最终视频(FFmpeg 拼接) compose: 5 diff --git a/tauri-app/src/pages/ContentManagement/CoverAvatarLibrary.tsx b/tauri-app/src/pages/ContentManagement/CoverAvatarLibrary.tsx index f1dfa3c..1bcd4c1 100644 --- a/tauri-app/src/pages/ContentManagement/CoverAvatarLibrary.tsx +++ b/tauri-app/src/pages/ContentManagement/CoverAvatarLibrary.tsx @@ -103,8 +103,13 @@ export default function CoverAvatarLibrary() { toast.success(`「${avatar.name}」已保存`); } catch (err) { const msg = err instanceof Error ? err.message : '上传失败'; - progress.error(msg); - toast.error(msg); + if (msg.includes('积分不足')) { + progress.error('积分不足'); + toast.error('积分不足,每次上传封面形象消耗 10 积分,请先充值'); + } else { + progress.error(msg); + toast.error(msg); + } } setUploadName(''); @@ -256,15 +261,20 @@ export default function CoverAvatarLibrary() { -