feat: recommend smarter intake titles
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-06 14:44:55 +08:00
parent 332064b088
commit 02231cfb6e
3 changed files with 37 additions and 9 deletions

View File

@@ -10,6 +10,7 @@
- 这样主 Agent 结果卡、动作注册表和工作台高频按钮现在共用同一套直执行链,后续回跳与结果落点也更一致。 - 这样主 Agent 结果卡、动作注册表和工作台高频按钮现在共用同一套直执行链,后续回跳与结果落点也更一致。
- `analyze_account / analyze_top_videos` 现在也统一切到 `direct-*`,并且在缺少当前选中账号时会自动回退到旧表单,不会把用户卡死在“缺少上下文”的提示上。 - `analyze_account / analyze_top_videos` 现在也统一切到 `direct-*`,并且在缺少当前选中账号时会自动回退到旧表单,不会把用户卡死在“缺少上下文”的提示上。
- `direct-search-similar / direct-save-benchmark-link` 现在也会在缺少当前账号或相似候选时自动回退到旧表单,避免“查相似 / 存对标”入口因为上下文不完整直接报错。 - `direct-search-similar / direct-save-benchmark-link` 现在也会在缺少当前账号或相似候选时自动回退到旧表单,避免“查相似 / 存对标”入口因为上下文不完整直接报错。
- `导入主页 / 导入作品链接 / 导入文本 / 上传视频` 这批输入型表单现在会按当前项目和当前平台自动推荐标题占位,不再一直停留在通用示例文案,打开就更贴近当前工作流。
### 依赖健康卡开始显示服务部署位置 ### 依赖健康卡开始显示服务部署位置

View File

@@ -470,6 +470,15 @@ function recommendLiveRecorderImportSamples(platform) {
].join("\n"); ].join("\n");
} }
function recommendManualIntakeTitle(project, platform, kind) {
const normalized = normalizePlatformValue(platform, "douyin");
const projectName = String(project?.name || "").trim();
const platformName = platformLabel(normalized);
const suffix = String(kind || "").trim() || "素材";
if (projectName) return `${brief(projectName, 12)} · ${platformName}${suffix}`;
return `${platformName}${suffix}`;
}
function formatDateTime(value) { function formatDateTime(value) {
if (!value) return "-"; if (!value) return "-";
const date = new Date(value); const date = new Date(value);
@@ -9255,6 +9264,8 @@ function openImportHomepageAction() {
const kb = getProjectKnowledgeBases(project.id)[0]; const kb = getProjectKnowledgeBases(project.id)[0];
const assistants = getAssistantOptions(project.id); const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || ""; const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
const defaultPlatform = normalizePlatformValue(getPreferredPlatform(), "douyin");
const titlePlaceholder = recommendManualIntakeTitle(project, defaultPlatform, "主页对标");
openActionModal({ openActionModal({
title: "导入主页并同步", title: "导入主页并同步",
description: "适合抖音 / 小红书 / B站 / 快手 / 视频号主页。先建内容源,再触发同步与分析。", description: "适合抖音 / 小红书 / B站 / 快手 / 视频号主页。先建内容源,再触发同步与分析。",
@@ -9262,8 +9273,8 @@ function openImportHomepageAction() {
fields: [ fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) }, { name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() }, { name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "platform", label: "平台", type: "select", value: "douyin", options: getPlatformOptions() }, { name: "platform", label: "平台", type: "select", value: defaultPlatform, options: getPlatformOptions() },
{ name: "title", label: "标题", placeholder: "例如:创业口播主页对标" }, { name: "title", label: "标题", placeholder: titlePlaceholder },
{ name: "handle", label: "账号名 / handle", placeholder: "可选" }, { name: "handle", label: "账号名 / handle", placeholder: "可选" },
{ name: "sourceUrl", label: "主页链接", type: "url", placeholder: "https://..." }, { name: "sourceUrl", label: "主页链接", type: "url", placeholder: "https://..." },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] }, { name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] },
@@ -9382,6 +9393,8 @@ function openImportVideoLinkAction() {
const project = requireSelectedProject(); const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id); const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || ""; const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
const defaultPlatform = normalizePlatformValue(getPreferredPlatform(), "douyin");
const titlePlaceholder = recommendManualIntakeTitle(project, defaultPlatform, "单条作品");
openActionModal({ openActionModal({
title: "导入作品链接", title: "导入作品链接",
description: "直接把单条视频链接送进分析链。", description: "直接把单条视频链接送进分析链。",
@@ -9389,7 +9402,7 @@ function openImportVideoLinkAction() {
fields: [ fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) }, { name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() }, { name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "例如:当前对标高分视频" }, { name: "title", label: "标题", placeholder: titlePlaceholder },
{ name: "videoUrl", label: "作品链接", type: "url", placeholder: "https://..." }, { name: "videoUrl", label: "作品链接", type: "url", placeholder: "https://..." },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, 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: "中文" }] } { name: "language", label: "语言", type: "select", value: "auto", options: [{ value: "auto", label: "自动" }, { value: "zh-CN", label: "中文" }] }
@@ -9417,6 +9430,8 @@ function openImportTextAction() {
const project = requireSelectedProject(); const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id); const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || ""; const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
const defaultPlatform = normalizePlatformValue(getPreferredPlatform(), "douyin");
const titlePlaceholder = recommendManualIntakeTitle(project, defaultPlatform, "文本素材");
openActionModal({ openActionModal({
title: "导入文本素材", title: "导入文本素材",
description: "把口播稿、拆解稿或灵感文本直接送进知识与分析链。", description: "把口播稿、拆解稿或灵感文本直接送进知识与分析链。",
@@ -9424,7 +9439,7 @@ function openImportTextAction() {
fields: [ fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) }, { name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() }, { name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "例如:本轮要分析的口播逐字稿" }, { name: "title", label: "标题", placeholder: titlePlaceholder },
{ name: "content", label: "正文", type: "textarea", rows: 8, placeholder: "粘贴需要分析的文本" }, { name: "content", label: "正文", type: "textarea", rows: 8, placeholder: "粘贴需要分析的文本" },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] } { name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] }
], ],
@@ -9451,6 +9466,8 @@ function openUploadVideoAction() {
const project = requireSelectedProject(); const project = requireSelectedProject();
const assistants = getAssistantOptions(project.id); const assistants = getAssistantOptions(project.id);
const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || ""; const defaultAssistantId = getSelectedAssistant()?.id || assistants[0]?.value || "";
const defaultPlatform = normalizePlatformValue(getPreferredPlatform(), "douyin");
const titlePlaceholder = recommendManualIntakeTitle(project, defaultPlatform, "本地视频");
openActionModal({ openActionModal({
title: "上传本地视频", title: "上传本地视频",
description: "上传本地素材,直接进入分析链。", description: "上传本地素材,直接进入分析链。",
@@ -9458,7 +9475,7 @@ function openUploadVideoAction() {
fields: [ fields: [
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) }, { name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
{ name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() }, { name: "projectId", label: "归属项目", type: "select", value: project.id, options: getProjectOptions() },
{ name: "title", label: "标题", placeholder: "默认使用文件名,可选补一个更容易识别的标题" }, { name: "title", label: "标题", placeholder: titlePlaceholder },
{ name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] }, { name: "assistantId", label: "绑定 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "暂不绑定" }, ...assistants] },
{ name: "file", label: "本地视频", type: "file", accept: ".mp4,.mov,.m4v,.avi,.mkv,.webm" } { name: "file", label: "本地视频", type: "file", accept: ".mp4,.mov,.m4v,.avi,.mkv,.webm" }
], ],

View File

@@ -1194,10 +1194,14 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
assert.match(APP, /function recommendRealCutObjective\(sourceJob\)/); assert.match(APP, /function recommendRealCutObjective\(sourceJob\)/);
assert.match(APP, /function recommendLiveRecorderTitle\(project, platform\)/); assert.match(APP, /function recommendLiveRecorderTitle\(project, platform\)/);
assert.match(APP, /function recommendLiveRecorderImportSamples\(platform\)/); assert.match(APP, /function recommendLiveRecorderImportSamples\(platform\)/);
assert.match(APP, /function recommendManualIntakeTitle\(project, platform, kind\)/);
assert.match(importHomepage, /label: "当前上下文", type: "html"/); assert.match(importHomepage, /label: "当前上下文", type: "html"/);
assert.match(importHomepage, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/); assert.match(importHomepage, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importHomepage, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
assert.match(importHomepage, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "主页对标"\)/);
assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importHomepage, /placeholder: "例如:创业口播主页对标"/); assert.match(importHomepage, /value: defaultPlatform/);
assert.match(importHomepage, /placeholder: titlePlaceholder/);
assert.match(importSelected, /label: "当前上下文", type: "html"/); assert.match(importSelected, /label: "当前上下文", type: "html"/);
assert.match(importSelected, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/); assert.match(importSelected, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(importSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
@@ -1206,16 +1210,22 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
assert.match(trackSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(trackSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importVideo, /label: "当前上下文", type: "html"/); assert.match(importVideo, /label: "当前上下文", type: "html"/);
assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/); assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
assert.match(importVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "单条作品"\)/);
assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importVideo, /placeholder: "例如:当前对标高分视频"/); assert.match(importVideo, /placeholder: titlePlaceholder/);
assert.match(importText, /label: "当前上下文", type: "html"/); assert.match(importText, /label: "当前上下文", type: "html"/);
assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/); assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(importText, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
assert.match(importText, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "文本素材"\)/);
assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(importText, /placeholder: "例如:本轮要分析的口播逐字稿"/); assert.match(importText, /placeholder: titlePlaceholder/);
assert.match(uploadVideo, /label: "当前上下文", type: "html"/); assert.match(uploadVideo, /label: "当前上下文", type: "html"/);
assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/); assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
assert.match(uploadVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
assert.match(uploadVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "本地视频"\)/);
assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/); assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
assert.match(uploadVideo, /placeholder: "默认使用文件名,可选补一个更容易识别的标题"/); assert.match(uploadVideo, /placeholder: titlePlaceholder/);
assert.match(generateCopy, /label: "当前上下文", type: "html"/); assert.match(generateCopy, /label: "当前上下文", type: "html"/);
assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/); assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/);
assert.match(generateCopy, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/); assert.match(generateCopy, /sourceJob \? \[\{ name: "sourceJobContext", label: "来源任务", type: "html", html: renderSourceJobContextHtml\(sourceJob\) \}\] : \[\]/);