feat: show source job context in creative sheets
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 12:08:20 +08:00
parent 6ef5d94fc6
commit fc17c8d90b
3 changed files with 31 additions and 2 deletions

View File

@@ -15,6 +15,12 @@
- `生成文案 / 创建 AI 视频 / 创建实拍剪辑 / 写复盘` 这四张高频创作表单,现在也会在顶部展示当前项目和默认 Agent 的上下文摘要。
- 这样高频创作动作不管是 direct-execute 还是必须补信息的表单,都已经统一到一套“先看当前上下文,再继续填写”的工作流体验里。
### 高优先级创作表单补齐来源任务摘要
-`生成文案 / 创建 AI 视频 / 创建实拍剪辑 / 写复盘` 是围绕某条已完成任务打开时,表单顶部现在会直接展示这条来源任务的摘要。
- `生成文案``写复盘` 也会优先继承来源任务的平台,避免用户再手工改一次平台。
- 这样从任务详情或主 Agent 结果卡继续往下做时,表单第一眼就知道自己承接的是哪条任务。
### 主 Agent 抖音相似搜索与对标关系 live 修复
- 修复 `search-similar-accounts` / `save-benchmark-link` 在抖音 live 数据上错误按 `project_id` 查询账号导致的 500。

View File

@@ -372,6 +372,18 @@ function renderIntakeActionContextHtml(projectId = "", assistantId = "") {
`;
}
function renderSourceJobContextHtml(job) {
if (!job) return "";
return `
<div class="sheet-html">
<div class="task-item compact">
<h4>当前承接任务</h4>
<p>${escapeHtml(job.title || "未命名任务")} · 平台:${escapeHtml(platformLabel(job.platform || "douyin"))} · 状态:${escapeHtml(job.status || "unknown")}</p>
</div>
</div>
`;
}
function formatDateTime(value) {
if (!value) return "-";
const date = new Date(value);
@@ -11322,8 +11334,9 @@ function openGenerateCopyAction(defaults = {}) {
submitLabel: "开始生成",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project?.id || "", assistant.id) },
...(sourceJob ? [{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml(sourceJob) }] : []),
{ name: "brief", label: "创作需求", type: "textarea", rows: 5, value: defaults.brief || getJobSeedBrief(sourceJob), placeholder: "例如:给创业者写一条 60 字内的短视频开场文案" },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(defaults.platform || "douyin"), options: getPlatformOptions() },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(defaults.platform || sourceJob?.platform || "douyin"), options: getPlatformOptions() },
{ name: "audience", label: "受众", value: "创业者" },
{ name: "extraRequirements", label: "额外要求", placeholder: "例如:强结论开头,结尾带 CTA" }
],
@@ -11375,6 +11388,7 @@ function openCreateAiVideoAction(defaults = {}) {
submitLabel: "开始生产",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
...(sourceJob ? [{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml(sourceJob) }] : []),
{ name: "title", label: "任务标题", value: defaults.title || (sourceJob ? `${sourceJob.title} · AI 视频` : ""), placeholder: "例如:创业口播 AI 视频测试" },
{ name: "brief", label: "视频 brief", type: "textarea", rows: 5, value: defaults.brief || getJobSeedBrief(sourceJob), placeholder: "写明主题、风格、镜头和目标受众" },
{ name: "sourceJobId", label: "关联源任务", type: "select", value: defaults.sourceJobId || sourceJob?.id || "", options: [{ value: "", label: "不关联" }, ...getCompletedJobOptions()] },
@@ -11490,6 +11504,7 @@ function openCreateRealCutAction(defaults = {}) {
submitLabel: "开始剪辑",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, assistant?.id || "") },
...(sourceJob ? [{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml(sourceJob) }] : []),
{ name: "title", label: "任务标题", value: defaults.title || (sourceJob ? `${sourceJob.title} · 实拍剪辑` : ""), placeholder: "例如:创业素材粗剪" },
{ name: "sourceJobId", label: "源任务", type: "select", value: defaults.sourceJobId || sourceJob?.id || getCompletedJobOptions()[0]?.value || "", options: getCompletedJobOptions() },
{ name: "targetDurationSec", label: "目标时长(秒)", type: "number", value: defaults.targetDurationSec || 60, min: 10, max: 300 },
@@ -11754,10 +11769,11 @@ function openReviewAction(defaults = {}) {
submitLabel: existingReview ? "保存复盘" : "创建复盘",
fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
...(sourceJob ? [{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml(sourceJob) }] : []),
{ name: "title", label: "标题", value: existingReview?.title || defaults.title || sourceJob?.title || "", placeholder: "例如:创业口播 3 月 22 日复盘" },
{ name: "sourceJobId", label: "关联任务", type: "select", value: existingReview?.source_job_id || defaults.sourceJobId || sourceJob?.id || "", options: [{ value: "", label: "不关联任务" }, ...getCompletedJobOptions()] },
{ name: "assistantId", label: "负责 Agent", type: "select", value: existingReview?.assistant_id || defaultAssistantId, options: [{ value: "", label: "先不绑定" }, ...assistants] },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(existingReview?.platform || defaults.platform || "douyin"), options: getPlatformOptions() },
{ name: "platform", label: "平台", type: "select", value: normalizePlatformValue(existingReview?.platform || defaults.platform || sourceJob?.platform || "douyin"), options: getPlatformOptions() },
{ name: "contentType", label: "内容类型", type: "select", value: existingReview?.content_type || "video", options: [
{ value: "video", label: "视频" },
{ value: "image_text", label: "图文" },

View File

@@ -1147,6 +1147,7 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
const createRealCut = extractBetween(APP, "function openCreateRealCutAction(defaults = {})", "function openLiveRecorderAction()");
const reviewAction = extractBetween(APP, "function openReviewAction(defaults = {})", "document.addEventListener(\"click\", async (event) => {");
assert.match(APP, /function renderIntakeActionContextHtml\(/);
assert.match(APP, /function renderSourceJobContextHtml\(job\)/);
assert.match(importHomepage, /label: "当前上下文", type: "html"/);
assert.match(importHomepage, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
@@ -1171,14 +1172,20 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
assert.match(uploadVideo, /placeholder: "默认使用文件名,可选补一个更容易识别的标题"/);
assert.match(generateCopy, /label: "当前上下文", type: "html"/);
assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/);
assert.match(generateCopy, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
assert.match(generateCopy, /normalizePlatformValue\(defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
assert.match(createAiVideo, /label: "当前上下文", type: "html"/);
assert.match(createAiVideo, /const defaultAssistantId = assistant\?\.id \|\| ""/);
assert.match(createAiVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(createAiVideo, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
assert.match(createRealCut, /label: "当前上下文", type: "html"/);
assert.match(createRealCut, /renderIntakeActionContextHtml\(project\.id, assistant\?\.id \|\| ""\)/);
assert.match(createRealCut, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
assert.match(reviewAction, /label: "当前上下文", type: "html"/);
assert.match(reviewAction, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(reviewAction, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(reviewAction, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);
assert.match(reviewAction, /normalizePlatformValue\(existingReview\?\.platform \|\| defaults\.platform \|\| sourceJob\?\.platform \|\| "douyin"\)/);
});
test("discovery analysis actions focus the most relevant detail tab after success", () => {