fix(core): 交叉验证修复 — 单镜改稿按 DB 真实镜数(防截镜误扣)+ 模型框点外关闭选择器

critical:regenerate_segment_via_agent 改用 _draft_from_version 从 DB ScriptSegment 行重建基准稿(原读 stale content,用户增删镜后 normalize 会按 stale total_duration 截掉真实镜还照扣费)。低危:模型框容器补 chat-model-pick class,点外关闭选择器生效。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
seaislee1209
2026-06-17 22:17:47 +08:00
co-authored by Claude Opus 4.8
parent 03e7949307
commit c3306bcac3
2 changed files with 33 additions and 7 deletions
+32 -6
View File
@@ -675,6 +675,35 @@ def _load_base_draft(project, base_version_id: str) -> dict | None:
return None
def _draft_from_version(version) -> dict:
"""从 ScriptVersion 的 DB 行(segments + metadata)重建 ScriptDraft —— 比解析可能已 stale 的 content 可靠
(用户增删/改镜后 content 不一定同步)。total_duration 按真实镜数算,避免 normalize 按 stale 值截/补镜。"""
meta = version.metadata or {}
segs = list(version.segments.order_by("sort_order"))
return {
"hook": meta.get("hook", ""),
"tone": meta.get("tone", ""),
"aspect_ratio": meta.get("aspect_ratio", "9:16"),
"total_duration": max(int(meta.get("total_duration") or 0), 15 * len(segs)) or 60,
"segment_count": len(segs),
"entities": meta.get("entities", []),
"segments": [
{
"index": s.sort_order,
"duration": s.duration_seconds or 15,
"role": s.role or "",
"narration": s.narration or "",
"speaker": s.speaker or None,
"visual": s.visual_prompt or "",
"product_exposure": s.product_exposure or "",
"entity_refs": s.entity_refs or [],
"dialogue": s.dialogue or [],
}
for s in segs
],
}
def regenerate_segment_via_agent(*, project, user, model_config: ModelConfig, segment, instruction: str = ""):
"""非流式·精准改一镜(「场次刷新」按钮复用 agent 单镜逻辑):读全脚本上下文,只重写该镜,落新 ScriptVersion。
与 stream_script_agent 的 target_index 分支同源,但同步返回(不走 SSE)。计费 reserve→charge/release 闭环。"""
@@ -683,16 +712,13 @@ def regenerate_segment_via_agent(*, project, user, model_config: ModelConfig, se
from apps.ai.services import build_provider, create_ai_task
from apps.billing.services.ledger import charge_reserved_credit
base_version = segment.script_version
base_draft = _load_base_draft(project, str(base_version.id))
if base_draft is None:
raise ValueError("基准脚本无法解析,无法精准改镜")
base_draft = _draft_from_version(segment.script_version) # 用 DB 行重建基准,别用可能 stale 的 content
target_index = segment.sort_order
aspect_ratio = (base_draft.get("aspect_ratio") or "9:16").strip()
total_duration = base_draft.get("total_duration") or 60
seg_n = len(base_draft.get("segments", []))
seg_n = len(base_draft.get("segments") or [])
if not (0 <= target_index < seg_n):
raise ValueError(f"镜号越界:第 {target_index + 1} 镜(共 {seg_n} 镜)")
total_duration = base_draft["total_duration"] # 已按真实镜数算,normalize 不会截掉用户增删后的镜
messages = build_agent_messages(
project=project,