后端: - 新增 celery_health 生成前置闸——无 worker 在线时图片/视频生成入口 一律 503,防"提交到 ARK 后无人轮询、结果悬空+额度冻结"的数据丢失 - 拼接导出:帧率跟随源众数、字幕逐句重映射、原声/BGM 混音修复 - 资金核算审计脚本 + genesis 账目回填 + 滞留预留清理命令 - 接入 yunqi provider 与豆包 TTS 模型(catalog/migrations/bootstrap 命令) 前端:全站页面更新(pipeline/library/products/projects/team/account 等), 新增共享 pager 分页组件 QA:刷新 function-audit 全量输出,新增 full-qa 报告 文档:BP 产品介绍资料、design/CLAUDE.md Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
51 lines
2.3 KiB
Python
51 lines
2.3 KiB
Python
from rest_framework import status
|
|
from rest_framework.response import Response
|
|
from rest_framework.views import APIView
|
|
from rest_framework.viewsets import ReadOnlyModelViewSet
|
|
|
|
from apps.assets.serializers import AssetSerializer
|
|
from apps.common.api import TeamScopedViewSetMixin, get_current_team
|
|
from apps.common.celery_health import require_worker
|
|
|
|
from .models import AITask, ModelConfig
|
|
from .serializers import AITaskSerializer, ModelConfigSerializer
|
|
from .services import generate_standalone_image
|
|
|
|
|
|
class GenerateImageView(APIView):
|
|
"""POST /api/ai/generate-image/ — 独立生图(不绑项目)· 图片创作/模特图/平台套图共用。"""
|
|
|
|
def post(self, request):
|
|
require_worker()
|
|
prompt = str(request.data.get("prompt") or "").strip()
|
|
if not prompt:
|
|
return Response({"detail": "prompt 不能为空"}, status=status.HTTP_400_BAD_REQUEST)
|
|
mode = str(request.data.get("mode") or "image")
|
|
try:
|
|
count = int(request.data.get("count") or 1)
|
|
except (TypeError, ValueError):
|
|
count = 1
|
|
team = get_current_team(request.user)
|
|
try:
|
|
assets = generate_standalone_image(team=team, user=request.user, prompt=prompt, mode=mode, count=count)
|
|
except ValueError as exc:
|
|
return Response({"detail": str(exc)}, status=status.HTTP_400_BAD_REQUEST)
|
|
except Exception as exc: # noqa: BLE001 — 生成失败已回滚额度,返回明确错误给前端
|
|
return Response({"detail": f"生成失败: {exc}"}, status=status.HTTP_502_BAD_GATEWAY)
|
|
return Response({"assets": AssetSerializer(assets, many=True).data}, status=status.HTTP_201_CREATED)
|
|
|
|
|
|
class AITaskViewSet(TeamScopedViewSetMixin, ReadOnlyModelViewSet):
|
|
queryset = AITask.objects.select_related("team", "project", "model_config", "model_config__provider").all()
|
|
serializer_class = AITaskSerializer
|
|
search_fields = ["idempotency_key", "provider_task_id", "project__name"]
|
|
ordering_fields = ["created_at", "updated_at", "completed_at"]
|
|
|
|
|
|
class ModelConfigViewSet(ReadOnlyModelViewSet):
|
|
queryset = ModelConfig.objects.select_related("provider").filter(status=ModelConfig.Status.ACTIVE)
|
|
serializer_class = ModelConfigSerializer
|
|
search_fields = ["name", "display_name", "capability"]
|
|
ordering_fields = ["created_at", "display_name"]
|
|
|