fix: 统一AI生成失败提示
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user