fix: 统一AI生成失败提示

This commit is contained in:
hh
2026-07-15 13:12:35 +08:00
parent 38d8c8ad54
commit e81d7170ed
19 changed files with 1220 additions and 88 deletions
+37 -14
View File
@@ -29,7 +29,8 @@ from apps.billing.services.ledger import charge_reserved_credit, release_credit,
from .models import AITask, ModelConfig
from .providers.volcano import VolcanoArkProvider
from .video_errors import map_video_error, parse_provider_error
from .generation_errors import classify_generation_error, public_error_for_task
from .video_errors import parse_provider_error
from .video_pricing import get_resolution
logger = logging.getLogger(__name__)
@@ -452,14 +453,23 @@ def submit_free_video(*, team, user, params: dict) -> AITask:
task.save(update_fields=["provider_task_id", "response_payload", "status", "submitted_at", "updated_at"])
except Exception as exc: # noqa: BLE001 — 创建失败:标失败退费,返回失败卡(不向上抛)
code, raw_message = parse_provider_error(exc)
friendly = map_video_error(code, raw_message)
public_error = classify_generation_error(
exc,
operation="video_generate",
provider_code=code,
reference_id=str(task.id),
)
task.status = AITask.Status.FAILED
task.error_code = (code or "CreateTaskError")[:64]
task.error_message = friendly
task.error_message = raw_message[:2000]
task.completed_at = timezone.now()
task.save(update_fields=["status", "error_code", "error_message", "completed_at", "updated_at"])
release_credit(reservation=task.credit_reservation, reason=friendly)
_notify_failure(task, raw=f"[{code}] {raw_message}" if code else raw_message)
release_credit(reservation=task.credit_reservation, reason=raw_message[:200])
_notify_failure(
task,
raw=f"[{code}] {raw_message}" if code else raw_message,
hint=public_error.fallback_message,
)
logger.warning("free video create failed: %s", exc)
return task
@@ -474,7 +484,7 @@ def submit_free_video(*, team, user, params: dict) -> AITask:
return task
def _notify_failure(task: AITask, *, raw: str) -> None:
def _notify_failure(task: AITask, *, raw: str, hint: str) -> None:
from .services import notify_generation_failure
notify_generation_failure(
@@ -483,7 +493,7 @@ def _notify_failure(task: AITask, *, raw: str) -> None:
recipient=task.created_by,
stage_label="自由创作视频",
raw=raw,
hint=task.error_message,
hint=hint,
)
@@ -586,21 +596,26 @@ def finalize_free_video(*, task: AITask) -> AITask:
err = response.get("error") or {}
code = str(err.get("code") or "")
raw_message = str(err.get("message") or "video generation failed")
friendly = map_video_error(code, raw_message)
public_error = classify_generation_error(
RuntimeError(raw_message),
operation="video_generate",
provider_code=code,
reference_id=str(task.id),
)
with transaction.atomic():
locked = AITask.objects.select_for_update().get(id=task.id)
if locked.status not in (AITask.Status.SUBMITTED, AITask.Status.POLLING):
return locked
locked.status = AITask.Status.FAILED
locked.error_code = code[:64]
locked.error_message = friendly
locked.error_message = raw_message[:2000]
locked.response_payload = response
locked.completed_at = timezone.now()
locked.save(
update_fields=["status", "error_code", "error_message", "response_payload", "completed_at", "updated_at"]
)
release_credit(reservation=locked.credit_reservation, reason=friendly)
_notify_failure(locked, raw=f"[{code}] {raw_message}")
release_credit(reservation=locked.credit_reservation, reason=raw_message[:200])
_notify_failure(locked, raw=f"[{code}] {raw_message}", hint=public_error.fallback_message)
return locked
# succeeded —— 认领 POSTPROCESSING(并发 finalize 只有一路进入慢活)
@@ -676,11 +691,17 @@ def finalize_free_video(*, task: AITask) -> AITask:
return locked
locked.status = AITask.Status.FAILED
locked.error_code = "PostprocessError"
locked.error_message = "视频结果处理失败,请重试"
public_error = classify_generation_error(
exc,
operation="video_generate",
internal_kind="processing_failed",
reference_id=str(locked.id),
)
locked.error_message = str(exc)[:2000]
locked.completed_at = timezone.now()
locked.save(update_fields=["status", "error_code", "error_message", "completed_at", "updated_at"])
release_credit(reservation=locked.credit_reservation, reason=str(exc)[:200])
_notify_failure(locked, raw=str(exc))
_notify_failure(locked, raw=str(exc), hint=public_error.fallback_message)
return locked
@@ -719,6 +740,7 @@ def serialize_free_video_task(task: AITask, *, include_deleted_assets: bool = Fa
if not video_url and not generated_assets:
video_url = payload.get("fallback_video_url") or ""
public_error = public_error_for_task(task, operation="video_generate")
return {
"id": str(task.id),
"status": task.status,
@@ -736,7 +758,8 @@ def serialize_free_video_task(task: AITask, *, include_deleted_assets: bool = Fa
"actual_tokens": payload.get("actual_tokens") or 0,
"estimated_cost": str(task.estimated_cost),
"actual_cost": str(task.actual_cost),
"error_message": task.error_message or "",
"error": public_error.as_dict() if public_error else None,
"error_message": public_error.fallback_message if public_error else "",
"fallback_note": payload.get("fallback_note") or "",
"is_favorited": task.is_favorited,
"video_url": video_url,