feat: remember ai video provider per project
Some checks failed
StoryForge CI / Baseline checks (push) Has been cancelled
StoryForge CI / Backend tests (push) Has been cancelled
StoryForge CI / Web tests (push) Has been cancelled

This commit is contained in:
kris
2026-04-07 16:08:18 +08:00
parent 8dce288e3a
commit f0ce9ed80c
3 changed files with 47 additions and 2 deletions

View File

@@ -2,6 +2,7 @@ const STORAGE_KEY = "storyforge-web-v4-session";
const SESSION_STORE = StoryForgeSessionStore.create(STORAGE_KEY);
const DEFAULT_BACKEND_URL = StoryForgeApiClient.detectDefaultBackendUrl();
const RECOVERY_HISTORY_KEY = STORAGE_KEY + ":recovery-history";
const AI_VIDEO_DEFAULTS_KEY = STORAGE_KEY + ":ai-video-defaults";
const navButtons = document.querySelectorAll("[data-screen-target]");
const screens = Array.from(document.querySelectorAll("[data-screen]"));
@@ -578,6 +579,34 @@ function getCompletedJobById(jobId = "") {
|| null;
}
function getAiVideoPreferences(projectId = "") {
const normalizedProjectId = String(projectId || "").trim();
if (!normalizedProjectId) return {};
try {
const payload = JSON.parse(localStorage.getItem(AI_VIDEO_DEFAULTS_KEY) || "{}");
const saved = payload && typeof payload === "object" ? payload[normalizedProjectId] : null;
return saved && typeof saved === "object" ? saved : {};
} catch {
return {};
}
}
function saveAiVideoPreferences(projectId = "", values = {}) {
const normalizedProjectId = String(projectId || "").trim();
if (!normalizedProjectId) return;
try {
const payload = JSON.parse(localStorage.getItem(AI_VIDEO_DEFAULTS_KEY) || "{}");
const nextPayload = payload && typeof payload === "object" ? payload : {};
nextPayload[normalizedProjectId] = {
videoProvider: String(values.videoProvider || "doubao").trim() || "doubao",
videoModel: String(values.videoModel || "").trim()
};
localStorage.setItem(AI_VIDEO_DEFAULTS_KEY, JSON.stringify(nextPayload));
} catch {
// ignore local preference persistence failures
}
}
function bindCreativeSourceJobRecommendations(fields, options = {}) {
const sourceJobSelect = fields.querySelector('[data-action-field="sourceJobId"]');
if (!(sourceJobSelect instanceof HTMLSelectElement)) return;
@@ -12173,11 +12202,12 @@ function openCreateAiVideoAction(defaults = {}) {
const defaultAssistantId = assistant?.id || "";
const sourceJob = defaults.sourceJob || null;
const defaultPlatform = normalizePlatformValue(defaults.platform || sourceJob?.platform || "douyin");
const persistedDefaults = getAiVideoPreferences(project.id);
const defaultVideoProvider = String(
defaults.videoProvider || defaults.video_provider || sourceJob?.artifacts?.video_provider || "doubao"
defaults.videoProvider || defaults.video_provider || sourceJob?.artifacts?.video_provider || persistedDefaults.videoProvider || "doubao"
).trim() || "doubao";
const defaultVideoModel = String(
defaults.videoModel || defaults.video_model || sourceJob?.artifacts?.video_model || ""
defaults.videoModel || defaults.video_model || sourceJob?.artifacts?.video_model || persistedDefaults.videoModel || ""
).trim() || (defaultVideoProvider === "seedance2" ? "seedance-2.0-pro" : "");
openActionModal({
title: "创建 AI 视频任务",
@@ -12282,6 +12312,10 @@ function openCreateAiVideoAction(defaults = {}) {
video_model: values.videoModel || "",
}
});
saveAiVideoPreferences(project.id, {
videoProvider: values.videoProvider || "doubao",
videoModel: values.videoModel || ""
});
rememberAction(
"AI 视频任务已创建",
`已创建任务 ${job.title || job.id},引擎 ${normalizedProvider === "seedance2" ? "Seedance 2.0" : "当前默认引擎"}`,

View File

@@ -1126,8 +1126,13 @@ test("ai video form explains where Seedance 火山配置 lives", () => {
assert.match(APP, /id="integration-\$\{escapeHtml\(item\.key\)\}-anchor"/);
assert.match(APP, /function focusAutomationHealthWorkspace\(anchorId = "integration-huobao-anchor"\)/);
assert.match(APP, /function bindAiVideoProviderRecommendations\(fields, options = \{\}\)/);
assert.match(APP, /const AI_VIDEO_DEFAULTS_KEY = STORAGE_KEY \+ ":ai-video-defaults"/);
assert.match(APP, /function getAiVideoPreferences\(projectId = ""\)/);
assert.match(APP, /function saveAiVideoPreferences\(projectId = "", values = \{\}\)/);
assert.match(APP, /const persistedDefaults = getAiVideoPreferences\(project\.id\)/);
assert.match(APP, /modelInput\.placeholder = provider === "seedance2" \? "例如seedance-2\.0-pro" : "留空则沿用当前默认视频模型"/);
assert.match(APP, /bindAiVideoProviderRecommendations\(fields, \{ seedanceModel: defaultVideoModel \|\| "seedance-2\.0-pro" \}\)/);
assert.match(APP, /saveAiVideoPreferences\(project\.id, \{/);
assert.match(clickActions, /name === "focus-huobao-video-config"[\s\S]*focusAutomationHealthWorkspace\("integration-huobao-anchor"\)/);
});