大量优化修改扣积分规则

This commit is contained in:
Azmat@qq.com
2026-09-04 17:20:22 +08:00
parent 3e904479d9
commit 15718a60bf
41 changed files with 1590 additions and 429 deletions
+27 -3
View File
@@ -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
+18 -2
View File
@@ -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)