feat: improve intake sheet context defaults
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-05 11:48:05 +08:00
parent 4270c3f586
commit 4adb545e0d
3 changed files with 48 additions and 6 deletions

View File

@@ -483,6 +483,7 @@
- 全局 `生成文案` 旧入口也已经做成相同分流:优先围绕最近完成任务直接生成,只有没有可承接任务时才回退到旧文案表单。
# 2026-04-05
- intake: `导入作品 / 导入文本 / 上传视频` 现在会先显示当前项目、默认 Agent 和默认知识库的上下文摘要,并预填更贴近当前工作流的标题提示。
- intake: 遗留 `导入主页` 入口现在会优先复用当前选中对标的主页链接 direct-execute只有缺少选中对象或主页链接时才回退到表单。
- agent: 遗留 `创建 Agent` 入口现在也会优先 direct-execute当前项目已就绪时直接创建 Agent只有缺上下文时才回退到旧表单。
- pipeline: 全局旧入口 `AI 视频 / 实拍剪辑` 现在也会优先围绕最近完成任务 direct-execute只有没有可承接任务时才回退到旧表单。

View File

@@ -356,6 +356,22 @@ function formatBytes(value) {
return `${fixed}${units[idx]}`;
}
function renderIntakeActionContextHtml(projectId = "", assistantId = "") {
const project = safeArray(appState.dashboard?.projects).find((item) => item.id === projectId)
|| getSelectedProject();
const assistant = safeArray(appState.dashboard?.assistants).find((item) => item.id === assistantId)
|| getSelectedAssistant();
const knowledgeBase = getProjectKnowledgeBases(project?.id || "")[0] || null;
return `
<div class="sheet-html">
<div class="task-item compact">
<h4>这次会写入哪里</h4>
<p>项目:${escapeHtml(project?.name || "当前项目")} · Agent${escapeHtml(assistant?.name || "暂不绑定")} · 知识库:${escapeHtml(knowledgeBase?.name || "默认知识库")}</p>
</div>
</div>
`;
}
function formatDateTime(value) {
if (!value) return "-";
const date = new Date(value);
@@ -9177,15 +9193,17 @@ function openTrackSelectedAccountAction() {
function openImportVideoLinkAction() {
const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
openActionModal({
title: "导入作品链接",
description: "直接把单条视频链接送进分析链。",
submitLabel: "开始分析",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "可选,不填则使用默认标题" },
{ name: "title", label: "标题", placeholder: "例如:当前对标高分视频" },
{ name: "videoUrl", label: "作品链接", type: "url", placeholder: "https://..." },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: assistants[0]?.value || "", options: [{ value: "", label: "暂不绑定" }, ...assistants] },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] },
{ name: "language", label: "语言", type: "select", value: "auto", options: [{ value: "auto", label: "自动" }, { value: "zh-CN", label: "中文" }] }
],
onSubmit: async (values) => {
@@ -9210,15 +9228,17 @@ function openImportVideoLinkAction() {
function openImportTextAction() {
const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
openActionModal({
title: "导入文本素材",
description: "把口播稿、拆解稿或灵感文本直接送进知识与分析链。",
submitLabel: "开始分析",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "例如:创业口播拆解" },
{ name: "title", label: "标题", placeholder: "例如:本轮要分析的口播逐字稿" },
{ name: "content", label: "正文", type: "textarea", rows: 8, placeholder: "粘贴需要分析的文本" },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: assistants[0]?.value || "", options: [{ value: "", label: "暂不绑定" }, ...assistants] }
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] }
],
onSubmit: async (values) => {
if (!values.title?.trim()) throw new Error("请填写标题");
@@ -9242,14 +9262,16 @@ function openImportTextAction() {
function openUploadVideoAction() {
const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
openActionModal({
title: "上传本地视频",
description: "上传本地素材,直接进入分析链。",
submitLabel: "上传并分析",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "可选,不填则用文件名" },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: assistants[0]?.value || "", options: [{ value: "", label: "暂不绑定" }, ...assistants] },
{ name: "title", label: "标题", placeholder: "默认使用文件名,可选补一个更容易识别的标题" },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] },
{ name: "file", label: "本地视频", type: "file", accept: ".mp4,.mov,.m4v,.avi,.mkv,.webm" }
],
onSubmit: async (values) => {

View File

@@ -1135,6 +1135,25 @@ test("import and tracking sheets submit through direct execute handlers", () =>
assert.doesNotMatch(importText, /storyforgeFetch\("\/v2\/explore\/text"/);
});
test("input-heavy intake sheets surface current context and smarter defaults", () => {
const importVideo = extractBetween(APP, "function openImportVideoLinkAction()", "function openImportTextAction()");
const importText = extractBetween(APP, "function openImportTextAction()", "function openUploadVideoAction()");
const uploadVideo = extractBetween(APP, "function openUploadVideoAction()", "function focusPlaybookOneLinerWorkspace(");
assert.match(APP, /function renderIntakeActionContextHtml\(/);
assert.match(importVideo, /label: "当前上下文", type: "html"/);
assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importVideo, /placeholder: "例如:当前对标高分视频"/);
assert.match(importText, /label: "当前上下文", type: "html"/);
assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importText, /placeholder: "例如:本轮要分析的口播逐字稿"/);
assert.match(uploadVideo, /label: "当前上下文", type: "html"/);
assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(uploadVideo, /placeholder: "默认使用文件名,可选补一个更容易识别的标题"/);
});
test("discovery analysis actions focus the most relevant detail tab after success", () => {
const analyzeAccount = extractBetween(APP, "function openAnalyzeSelectedAccountAction()", "function openAnalyzeTopVideosAction()");
const analyzeTopVideos = extractBetween(APP, "function openAnalyzeTopVideosAction()", "function openSimilaritySearchAction()");