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 .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): 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"]