生成项目任务/chat任务软删|生成资源管控回收|生成资源token验签API预处理

This commit is contained in:
2026-06-01 11:10:09 +08:00
parent edef601f7c
commit dfbf51b5c0
26 changed files with 1296 additions and 63 deletions
+41 -5
View File
@@ -28,6 +28,11 @@ from app.schemas.generation import (
from app.services.credits import deduct_credits, calc_text_credits, calc_video_credits, calc_image_credits
from app.services.llm import optimize_prompt
from app.services.video_url import generate_temp_url, validate_and_get_record_id, get_video_stream_url
from app.services.resource_accounting_service import (
record_generation_record_generated_resource,
safe_file_size,
)
from app.services.resource_signed_url_service import build_resource_signed_url
from app.utils.id_gen import generate_id
from app.utils.exceptions import InsufficientCreditsError, RecordNotFoundError, InvalidStatusError
@@ -71,8 +76,8 @@ def _record_to_out(record: GenerationRecord, project_name: str) -> GenerationRec
image_proportion=record.image_proportion,
image_px=record.image_px,
status=record.status,
video_url=record.video_url,
image_url=record.image_url,
video_url=build_resource_signed_url(record.video_url) if record.video_url else '',
image_url=build_resource_signed_url(record.image_url) if record.image_url else '',
references=refs,
text_credits_cost=round(record.text_credits_cost or 0.00, 2),
# text_tokens_used=record.text_tokens_used or 0,
@@ -94,7 +99,11 @@ async def list_records(
query = (
select(GenerationRecord, Project.name)
.join(Project, GenerationRecord.project_id == Project.id)
.where(GenerationRecord.user_id == current_user.id)
.where(
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
Project.deleted_at.is_(None),
)
.order_by(GenerationRecord.created_at.desc())
)
if project_id:
@@ -133,6 +142,8 @@ async def optimize(
.join(Project, GenerationRecord.project_id == Project.id)
.where(
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
Project.deleted_at.is_(None),
GenerationRecord.idempotency_key == req.idempotency_key,
GenerationRecord.gen_type == req.gen_type,
GenerationRecord.status == "prompt_optimized",
@@ -155,6 +166,7 @@ async def optimize(
select(Project).where(
Project.id == req.project_id,
Project.user_id == current_user.id,
Project.deleted_at.is_(None),
)
)
project = proj_result.scalar_one_or_none()
@@ -243,6 +255,8 @@ async def generate(
.where(
GenerationRecord.id == record_id,
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
Project.deleted_at.is_(None),
)
)
row = result.first()
@@ -326,6 +340,8 @@ async def retry_generation(
.where(
GenerationRecord.id == record_id,
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
Project.deleted_at.is_(None),
)
)
row = result.first()
@@ -378,6 +394,7 @@ async def update_prompt(
select(GenerationRecord).where(
GenerationRecord.id == record_id,
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
)
)
record = result.scalar_one_or_none()
@@ -422,6 +439,7 @@ async def get_queue_status(
select(GenerationRecord).where(
GenerationRecord.id == record_id,
GenerationRecord.user_id == current_user.id,
GenerationRecord.deleted_at.is_(None),
)
)
record = result.scalar_one_or_none()
@@ -435,6 +453,7 @@ async def get_queue_status(
ahead_result = await db.execute(
select(func.count(GenerationRecord.id)).where(
GenerationRecord.status == "generating",
GenerationRecord.deleted_at.is_(None),
GenerationRecord.created_at < record.created_at,
)
)
@@ -461,7 +480,10 @@ async def seedance_callback(request: Request, db: AsyncSession = Depends(get_db)
return {"message": "ignored"}
result = await db.execute(
select(GenerationRecord).where(GenerationRecord.seedance_task_id == task_id)
select(GenerationRecord).where(
GenerationRecord.seedance_task_id == task_id,
GenerationRecord.deleted_at.is_(None),
)
)
record = result.scalar_one_or_none()
if not record:
@@ -470,19 +492,33 @@ async def seedance_callback(request: Request, db: AsyncSession = Depends(get_db)
if task_status == "succeeded":
remote_url = data.get("content", {}).get("video_url", "")
record.status = "completed"
storage_path = None
file_size_bytes = 0
# Download video to local storage
if settings.STORAGE_TYPE == "local" and remote_url:
try:
from app.services.video_gen import download_video
dest = os.path.join(settings.STORAGE_LOCAL_PATH, f"{record.id}.mp4")
await download_video(remote_url, dest)
record.video_url = f"/videos/{record.id}.mp4"
record.video_url = f"/generate/videos/{record.id}.mp4"
storage_path = dest
file_size_bytes = safe_file_size(dest)
except Exception as e:
logger.warning(f"Callback download failed, using remote URL: {e}")
record.video_url = remote_url
else:
record.video_url = remote_url
record.generated_at = datetime.now()
if record.video_url:
await record_generation_record_generated_resource(
db,
record,
resource_url=record.video_url,
storage_path=storage_path,
file_size_bytes=file_size_bytes,
remote_url=remote_url,
generated_at=record.generated_at,
)
# Extract video token usage from callback
usage = data.get("usage", {})
if usage: