音频文件上传 | AI创作模块兼容音频
This commit is contained in:
@@ -15,6 +15,13 @@ from app.models.project import Project
|
||||
from app.models.image_engine import ImageEngine
|
||||
from app.models.user import User
|
||||
from app.models.video_engine import VideoEngine
|
||||
from app.enums.audio_reference import (
|
||||
AUDIO_ALLOWED_EXTENSIONS,
|
||||
AUDIO_MAX_COUNT_LIMIT,
|
||||
AUDIO_MAX_DURATION_SECONDS,
|
||||
AUDIO_MAX_TOTAL_DURATION_SECONDS,
|
||||
AUDIO_MIN_DURATION_SECONDS,
|
||||
)
|
||||
from app.enums.generation_history import (
|
||||
GenerationHistorySourceEnum,
|
||||
get_generation_history_source_label,
|
||||
@@ -157,6 +164,7 @@ def _build_video_snapshot(engine: VideoEngine, ratio: str, resolution: str, dura
|
||||
"supported_resolutions": _parse_list(engine.supported_resolutions, []),
|
||||
"supported_durations": _parse_list(engine.supported_durations, []),
|
||||
"max_duration": engine.max_duration,
|
||||
"max_audio_count": engine.max_audio_count,
|
||||
"selected_ratio": ratio,
|
||||
"selected_resolution": resolution,
|
||||
"selected_duration": duration,
|
||||
@@ -203,6 +211,7 @@ async def list_generation_ai_engine_options(db: AsyncSession) -> GenerationAIEng
|
||||
priority=engine.priority or 0,
|
||||
max_image_count=engine.max_image_count,
|
||||
max_video_count=engine.max_video_count,
|
||||
max_audio_count=engine.max_audio_count,
|
||||
supports_first_last_frame=engine.supports_first_last_frame,
|
||||
supports_universal_reference=engine.supports_universal_reference,
|
||||
)
|
||||
@@ -244,6 +253,8 @@ async def create_async_generation_task(db: AsyncSession, current_user: User, req
|
||||
await assert_user_resource_capacity_available(db, current_user.id)
|
||||
|
||||
if gen_type == "image":
|
||||
if any((r.get("type") or "").lower() == "audio" for r in refs):
|
||||
raise HTTPException(status_code=400, detail="图片生成不支持音频参考素材")
|
||||
engine = await _get_image_engine(db, req.engine_id)
|
||||
sizes = _image_supported_sizes(engine)
|
||||
size = req.image_size or engine.default_size or IMAGE_DEFAULT_SIZE
|
||||
@@ -306,7 +317,7 @@ async def create_async_generation_task(db: AsyncSession, current_user: User, req
|
||||
|
||||
input_video_duration = 0.0
|
||||
if refs:
|
||||
video_refs = [r for r in refs if r.get("type") == "video"]
|
||||
video_refs = [r for r in refs if (r.get("type") or "").lower() == "video"]
|
||||
for ref in video_refs:
|
||||
ref_duration = float(ref.get("duration") or 0)
|
||||
if ref_duration < 2:
|
||||
@@ -315,6 +326,42 @@ async def create_async_generation_task(db: AsyncSession, current_user: User, req
|
||||
if input_video_duration > 15:
|
||||
raise HTTPException(status_code=400, detail=f"所有视频素材总时长不能超过 15 秒,当前 {input_video_duration:.1f} 秒")
|
||||
|
||||
audio_refs = [r for r in refs if (r.get("type") or "").lower() == "audio"]
|
||||
if audio_refs:
|
||||
max_audio_count = int(engine.max_audio_count or 0)
|
||||
if max_audio_count <= 0:
|
||||
raise HTTPException(status_code=400, detail="当前视频引擎不支持音频参考素材")
|
||||
if max_audio_count > AUDIO_MAX_COUNT_LIMIT:
|
||||
max_audio_count = AUDIO_MAX_COUNT_LIMIT
|
||||
if len(audio_refs) > max_audio_count:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"参考音频最多可传 {max_audio_count} 段,当前 {len(audio_refs)} 段",
|
||||
)
|
||||
|
||||
input_audio_duration = 0.0
|
||||
for ref in audio_refs:
|
||||
raw_duration = ref.get("duration")
|
||||
if raw_duration is None:
|
||||
raw_duration = 0.0
|
||||
try:
|
||||
ref_duration = float(raw_duration)
|
||||
except (TypeError, ValueError):
|
||||
ref_duration = 0.0
|
||||
|
||||
if ref_duration < AUDIO_MIN_DURATION_SECONDS or ref_duration > AUDIO_MAX_DURATION_SECONDS:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"单段参考音频时长必须在 {AUDIO_MIN_DURATION_SECONDS}-{AUDIO_MAX_DURATION_SECONDS} 秒之间",
|
||||
)
|
||||
input_audio_duration += ref_duration
|
||||
|
||||
if input_audio_duration > AUDIO_MAX_TOTAL_DURATION_SECONDS:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail=f"所有参考音频总时长不能超过 {AUDIO_MAX_TOTAL_DURATION_SECONDS} 秒,当前 {input_audio_duration:.1f} 秒",
|
||||
)
|
||||
|
||||
media_billing = await charge_generation_media_by_params(
|
||||
db,
|
||||
user_id=current_user.id,
|
||||
|
||||
@@ -135,6 +135,10 @@ async def submit_video_task(
|
||||
resolved = _resolve_url(ref_url)
|
||||
role = ref_role if ref_role else "reference_video"
|
||||
content.append({"type": "video_url", "video_url": {"url": resolved}, "role": role})
|
||||
elif ref_type == "audio" and ref_url:
|
||||
resolved = _resolve_url(ref_url)
|
||||
role = ref_role if ref_role else "reference_audio"
|
||||
content.append({"type": "audio_url", "audio_url": {"url": resolved}, "role": role})
|
||||
except (json.JSONDecodeError, TypeError):
|
||||
pass
|
||||
|
||||
|
||||
Reference in New Issue
Block a user