feat: 素材选取评分注入随机噪声,降低成片查重率 (#1620)
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 6s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m30s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m58s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Successful in 35s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m49s
CI/CD Pipeline / Validate - Style (push) Successful in 6m35s
CI/CD Pipeline / Integration Tests (push) Successful in 6m37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m58s
CI/CD Pipeline / Validate - Security (push) Successful in 8m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m53s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m33s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m35s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 5m6s
CI/CD Pipeline / Unit Tests (push) Successful in 14m24s
CI/CD Pipeline / Production Browser E2E (push) Failing after 349h30m4s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 349h40m28s
CI/CD Pipeline / Canary Release to Production (push) Failing after 349h30m5s
CI/CD Pipeline / Deploy Production (push) Failing after 349h30m5s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 349h44m27s
CI/CD Pipeline / CI Gate (push) Failing after 349h30m6s
CI/CD Pipeline / PR Build Web Image (push) Failing after 349h44m30s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 349h30m6s
CI/CD Pipeline / PR Build API Image (push) Failing after 349h44m30s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 349h44m34s
CI/CD Pipeline / Build Production Web Image (push) Failing after 349h30m6s
CI/CD Pipeline / Build Production API Image (push) Failing after 349h30m6s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 350h14m47s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 350h18m48s
CI/CD Pipeline / Frontend Lint (push) Failing after 350h18m50s
CI/CD Pipeline / Dedup Check - skip PR tests when covered by push pipeline (push) Successful in 1s
CI/CD Pipeline / Check push changed paths (push) Successful in 6s
CI/CD Pipeline / Build Staging Worker Image (push) Successful in 3m30s
CI/CD Pipeline / Build Staging API Image (push) Successful in 3m58s
CI/CD Pipeline / Retag skipped Staging Web Image (push) Successful in 35s
CI/CD Pipeline / Validate - Python (mypy + alembic) (push) Successful in 5m49s
CI/CD Pipeline / Validate - Style (push) Successful in 6m35s
CI/CD Pipeline / Integration Tests (push) Successful in 6m37s
CI/CD Pipeline / Deploy Staging (Watchtower auto-deploy) (push) Successful in 1m58s
CI/CD Pipeline / Validate - Security (push) Successful in 8m18s
CI/CD Pipeline / Frontend Unit Tests (push) Successful in 8m53s
CI/CD Pipeline / ACR Image Cleanup (push) Successful in 2m33s
CI/CD Pipeline / Staging API Integration Tests (push) Successful in 4m35s
CI/CD Pipeline / Staging E2E Tests (push) Successful in 5m6s
CI/CD Pipeline / Unit Tests (push) Successful in 14m24s
CI/CD Pipeline / Production Browser E2E (push) Failing after 349h30m4s
CI/CD Pipeline / Retag skipped Staging API Image (push) Failing after 349h40m28s
CI/CD Pipeline / Canary Release to Production (push) Failing after 349h30m5s
CI/CD Pipeline / Deploy Production (push) Failing after 349h30m5s
CI/CD Pipeline / Build Staging Web Image (push) Failing after 349h44m27s
CI/CD Pipeline / CI Gate (push) Failing after 349h30m6s
CI/CD Pipeline / PR Build Web Image (push) Failing after 349h44m30s
CI/CD Pipeline / Build Production Worker Image (push) Failing after 349h30m6s
CI/CD Pipeline / PR Build API Image (push) Failing after 349h44m30s
CI/CD Pipeline / Check if frontend-only change (push) Failing after 349h44m34s
CI/CD Pipeline / Build Production Web Image (push) Failing after 349h30m6s
CI/CD Pipeline / Build Production API Image (push) Failing after 349h30m6s
CI/CD Pipeline / Retag skipped Staging Worker Image (push) Failing after 350h14m47s
CI/CD Pipeline / PR Build Worker Image (push) Failing after 350h18m48s
CI/CD Pipeline / Frontend Lint (push) Failing after 350h18m50s
Co-authored-by: xiaoxia <dev@xiaoxiajianji.com> Co-committed-by: xiaoxia <dev@xiaoxiajianji.com>
This commit was merged in pull request #1620.
This commit is contained in:
@@ -48,7 +48,7 @@ from packages.adapters.sqlalchemy_impl.template_repository import (
|
||||
SQLAlchemyTemplateRepository,
|
||||
)
|
||||
from packages.domain.plan_generator_utils import _calc_random_start_time
|
||||
from packages.domain.smart_match import score_asset
|
||||
from packages.domain.smart_match import SCORE_RANDOM_NOISE_MAX, score_asset
|
||||
from packages.shared.mediakit_client import get_mediakit_client
|
||||
|
||||
from .dependencies import get_draft_plan_id, get_editor_services
|
||||
@@ -744,14 +744,15 @@ def create_clips_from_assets_editor(
|
||||
clip_duration = 0.0
|
||||
start_time: float | None = None
|
||||
# 动态按使用次数排序:优先选使用最少的素材,同次数随机打散
|
||||
asset_use_counts = {
|
||||
aid: len(used_segments.get(aid, []))
|
||||
for aid in asset_ids
|
||||
}
|
||||
asset_use_counts = {aid: len(used_segments.get(aid, [])) for aid in asset_ids}
|
||||
# 排序键:smart_match 评分(注入随机噪声)→ 使用次数 → 纯随机。
|
||||
# 噪声让得分接近的素材排名每次浮动,避免同一批素材反复选出相同组合,
|
||||
# 从素材组合层面降低成片查重率;分差 > SCORE_RANDOM_NOISE_MAX 时排名稳定,
|
||||
# 质量差距显著的素材仍保持优先级。
|
||||
sorted_candidates = sorted(
|
||||
asset_ids,
|
||||
key=lambda aid: (
|
||||
-asset_smart_scores.get(aid, 0.0),
|
||||
-(asset_smart_scores.get(aid, 0.0) + random.uniform(0.0, SCORE_RANDOM_NOISE_MAX)),
|
||||
asset_use_counts.get(aid, 0),
|
||||
random.random(),
|
||||
),
|
||||
@@ -847,15 +848,15 @@ def create_clips_from_assets_editor(
|
||||
duplicate_warning = f"查重率 {dup_rate:.1f}% 超过50%,建议更换素材或模板"
|
||||
logger.warning(
|
||||
"from-assets 成片查重率超标: plan_id=%s dup_rate=%.1f%%",
|
||||
plan_id, dup_rate,
|
||||
plan_id,
|
||||
dup_rate,
|
||||
)
|
||||
|
||||
# 7. 素材耗尽提示
|
||||
exhaustion_warning = None
|
||||
if all_assets_exhausted and created_count < len(segments):
|
||||
exhaustion_warning = (
|
||||
"素材可切区间不足,部分片段使用了复用素材。"
|
||||
"建议:1) 补充更多素材到素材库 2) 使用不同的素材组合生成"
|
||||
"素材可切区间不足,部分片段使用了复用素材。" "建议:1) 补充更多素材到素材库 2) 使用不同的素材组合生成"
|
||||
)
|
||||
|
||||
# 8. 立即返回响应
|
||||
@@ -1022,9 +1023,11 @@ def _update_mediakit_recommendations_async( # pragma: no cover
|
||||
if cid != clip_id_inner and cid not in updated_clip_ids:
|
||||
segs.append((c.start_time, c.start_time + c.duration))
|
||||
segs.extend(updated_segments.get(asset_id_inner, []))
|
||||
|
||||
# 并入历史已用区间
|
||||
def _norm(segs_in):
|
||||
return {(round(float(a), 3), round(float(b), 3)) for a, b in segs_in}
|
||||
|
||||
return list(_norm(segs) | _norm(historical_segments.get(asset_id_inner, [])))
|
||||
|
||||
# 优先使用 SceneChange 策略
|
||||
@@ -1035,7 +1038,8 @@ def _update_mediakit_recommendations_async( # pragma: no cover
|
||||
scene_segments = _build_scene_segments(scene_changes, asset_total)
|
||||
logger.info(
|
||||
"后台任务: 素材场景检测完成: asset_id=%s scenes=%d",
|
||||
asset_id, len(scene_segments),
|
||||
asset_id,
|
||||
len(scene_segments),
|
||||
)
|
||||
|
||||
# SceneChange 未获得有效结果 → 尝试 analyze_videos 作为 fallback
|
||||
@@ -1047,7 +1051,8 @@ def _update_mediakit_recommendations_async( # pragma: no cover
|
||||
scene_segments = [(rec_start, asset_total)]
|
||||
logger.info(
|
||||
"后台任务: 使用 analyze_videos fallback: asset_id=%s start=%.2f",
|
||||
asset_id, rec_start,
|
||||
asset_id,
|
||||
rec_start,
|
||||
)
|
||||
|
||||
if not scene_segments:
|
||||
|
||||
Reference in New Issue
Block a user