大量优化修改扣积分规则
This commit is contained in:
@@ -4,6 +4,7 @@ from rest_framework import serializers
|
||||
|
||||
from apps.accounts.models import Team, TeamMember, User
|
||||
from apps.ai.model_routing import model_metadata_errors, provider_metadata_errors
|
||||
from apps.billing.points_rules import normalize_points_pricing_for_save, points_pricing_errors
|
||||
from apps.ai.models import AIModelAttempt, AITask, ModelConfig, ModelProvider, PromptTemplate, QualityWord
|
||||
from apps.assets.models import Asset
|
||||
from apps.billing.models import CreditLedger, QuotaPolicy
|
||||
@@ -247,12 +248,35 @@ class AdminModelConfigSerializer(serializers.ModelSerializer):
|
||||
|
||||
def validate(self, attrs):
|
||||
attrs = super().validate(attrs)
|
||||
if self.instance is None or "metadata" in attrs or "capability" in attrs:
|
||||
if self.instance is None or "metadata" in attrs or "capability" in attrs or "unit_price" in attrs:
|
||||
capability = attrs.get("capability", getattr(self.instance, "capability", ""))
|
||||
metadata = attrs.get("metadata", getattr(self.instance, "metadata", {}))
|
||||
errors = model_metadata_errors(capability, metadata)
|
||||
if not isinstance(metadata, dict):
|
||||
metadata = {}
|
||||
metadata = normalize_points_pricing_for_save(capability, metadata)
|
||||
# 图片/文本:表单 unit_price 与挂牌积分同步
|
||||
if "unit_price" in attrs and capability in {"image", "text", "vision"}:
|
||||
from decimal import Decimal
|
||||
try:
|
||||
pts = int(Decimal(str(attrs.get("unit_price") or 0)))
|
||||
except Exception:
|
||||
pts = 0
|
||||
pricing = dict(metadata.get("points_pricing") or {})
|
||||
if capability == "image":
|
||||
pricing.update({"mode": "per_image", "points_per_image": max(pts, 0)})
|
||||
else:
|
||||
pricing.update({"mode": "per_call", "points_per_call": max(pts, 0)})
|
||||
metadata["points_pricing"] = pricing
|
||||
attrs["metadata"] = metadata
|
||||
# 视频有挂牌秒价时,把展示用 unit_price 写成最低档秒积分,列表更好读
|
||||
if capability == "video":
|
||||
tiers = (metadata.get("points_pricing") or {}).get("tiers") or []
|
||||
secs = [t.get("points_per_second") for t in tiers if isinstance(t, dict) and t.get("points_per_second") is not None]
|
||||
if secs:
|
||||
attrs["unit_price"] = min(int(x) for x in secs)
|
||||
errors = list(model_metadata_errors(capability, metadata)) + list(points_pricing_errors(capability, metadata))
|
||||
if errors:
|
||||
raise serializers.ValidationError({"metadata": list(errors)})
|
||||
raise serializers.ValidationError({"metadata": errors})
|
||||
return attrs
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ from apps.accounts.audit import log_admin_action
|
||||
from apps.accounts.models import Invitation, Team, User
|
||||
from apps.accounts.permissions import IsPlatformAdmin
|
||||
from apps.accounts.serializers import InvitationSerializer
|
||||
from apps.ai.model_catalog import invalidate_model_catalog_cache
|
||||
from apps.ai.models import AITask, ModelConfig, ModelProvider, PromptTemplate, QualityWord
|
||||
from apps.assets.models import Asset
|
||||
from apps.assets.review import poll_asset_review, submit_asset_for_review
|
||||
@@ -45,6 +46,14 @@ logger = logging.getLogger(__name__)
|
||||
# 后台「刷新状态」只向供应商拉取已提交的异步视频任务;单次上限避免请求拖死。
|
||||
_ADMIN_TASK_POLL_LIMIT = 20
|
||||
_ADMIN_TASK_POLL_STATUSES = (AITask.Status.SUBMITTED, AITask.Status.POLLING)
|
||||
# 任务监控「生成中」Tab:含已创建/已预留/已提交/轮询/后处理(与自由创作 IN_FLIGHT 对齐)
|
||||
_ADMIN_TASK_INFLIGHT_STATUSES = (
|
||||
AITask.Status.CREATED,
|
||||
AITask.Status.RESERVED,
|
||||
AITask.Status.SUBMITTED,
|
||||
AITask.Status.POLLING,
|
||||
AITask.Status.POSTPROCESSING,
|
||||
)
|
||||
|
||||
|
||||
def _team_qs():
|
||||
@@ -463,7 +472,9 @@ def admin_tasks(request):
|
||||
.order_by("-created_at")
|
||||
)
|
||||
st = request.query_params.get("status")
|
||||
if st in dict(AITask.Status.choices):
|
||||
if st in {"generating", "running", "in_flight"}:
|
||||
qs = qs.filter(status__in=_ADMIN_TASK_INFLIGHT_STATUSES)
|
||||
elif st in dict(AITask.Status.choices):
|
||||
qs = qs.filter(status=st)
|
||||
tt = request.query_params.get("task_type")
|
||||
if tt in dict(AITask.Type.choices):
|
||||
@@ -772,11 +783,12 @@ def admin_provider_detail(request, provider_id):
|
||||
return Response(AdminModelProviderSerializer(ModelProvider.objects.annotate(model_count_anno=Count("models", distinct=True)).get(id=obj.id)).data)
|
||||
|
||||
|
||||
|
||||
@api_view(["GET", "POST"])
|
||||
@permission_classes([IsPlatformAdmin])
|
||||
def admin_models(request):
|
||||
if request.method == "GET":
|
||||
qs = ModelConfig.objects.select_related("provider").order_by("provider__name", "capability", "created_at")
|
||||
qs = ModelConfig.objects.select_related("provider").order_by("-is_default", "status", "capability", "provider__name", "created_at")
|
||||
prov = request.query_params.get("provider")
|
||||
if prov:
|
||||
qs = qs.filter(provider_id=prov)
|
||||
@@ -787,6 +799,7 @@ def admin_models(request):
|
||||
serializer = AdminModelConfigSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
obj = serializer.save()
|
||||
invalidate_model_catalog_cache()
|
||||
log_admin_action(request, "model.create", target_type="model_config", target_id=obj.id, target_name=f"{obj.provider_id}:{obj.name}")
|
||||
return Response(AdminModelConfigSerializer(obj).data, status=status.HTTP_201_CREATED)
|
||||
|
||||
@@ -800,10 +813,12 @@ def admin_model_detail(request, model_id):
|
||||
if request.method == "DELETE":
|
||||
log_admin_action(request, "model.delete", target_type="model_config", target_id=obj.id, target_name=obj.name)
|
||||
obj.delete()
|
||||
invalidate_model_catalog_cache()
|
||||
return Response(status=status.HTTP_204_NO_CONTENT)
|
||||
serializer = AdminModelConfigSerializer(obj, data=request.data, partial=True)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
serializer.save()
|
||||
invalidate_model_catalog_cache()
|
||||
log_admin_action(request, "model.update", target_type="model_config", target_id=obj.id, target_name=obj.name)
|
||||
return Response(AdminModelConfigSerializer(ModelConfig.objects.select_related("provider").get(id=obj.id)).data)
|
||||
|
||||
@@ -821,6 +836,7 @@ def admin_model_set_default(request, model_id):
|
||||
ModelConfig.objects.filter(capability=obj.capability).exclude(id=obj.id).update(is_default=False)
|
||||
obj.is_default = True
|
||||
obj.save(update_fields=["is_default", "updated_at"])
|
||||
invalidate_model_catalog_cache()
|
||||
log_admin_action(request, "model.set_default", target_type="model_config", target_id=obj.id, target_name=f"{obj.capability}:{obj.name}")
|
||||
return Response(AdminModelConfigSerializer(ModelConfig.objects.select_related("provider").get(id=obj.id)).data)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user