This commit is contained in:
fengchuanhn@gmail.com
2026-05-18 10:00:30 +08:00
parent 8007262e8f
commit fb1c3c55d6
3 changed files with 273 additions and 1 deletions

View File

@@ -83,6 +83,16 @@ export const useWorkflowStore = defineStore("workflow", {
scriptGenerating: false,
/** 爆款文案customPrompt 模式)生成中 */
hitScriptGenerating: false,
/** 爆款文案方案列表(最多 3 条) */
hitScriptOptions: [],
hitScriptSelectedIndex: 0,
hitScriptModalVisible: false,
legalChecking: false,
legalModalVisible: false,
@@ -355,6 +365,24 @@ export const useWorkflowStore = defineStore("workflow", {
},
async generateHitScript() {
return executeGenerateHitScript(this);
},
applyHitScriptOption(index) {
return applyHitScriptOptionToEditor(this, index);
},
closeHitScriptModal() {
this.hitScriptModalVisible = false;
},
async runLegalCheck() {
return executeLegalCheck(this);
@@ -664,6 +692,146 @@ const DEFAULT_SCRIPT_PROMPT = `请基于以下视频原文案,创作一个新
请直接输出仿写后的文案:`;
/**
* 解析爆款文案模型返回(对齐 zhenqianba ii
* @param {string} raw
* @returns {string[]}
*/
export function parseHitScriptOptions(raw) {
const text = String(raw || "");
const md = text.match(/```(?:json)?\s*([\s\S]*?)```/i);
const body = (md?.[1] || text).trim();
try {
const parsed = JSON.parse(body);
const list = Array.isArray(parsed)
? parsed
: Array.isArray(parsed?.options)
? parsed.options
: Array.isArray(parsed?.data)
? parsed.data
: [];
const options = list
.map((item) =>
typeof item === "string" ? item : item?.content || item?.text || "",
)
.map((s) => String(s).trim())
.filter(Boolean);
if (options.length) {
return Array.from(new Set(options)).slice(0, 3);
}
} catch (err) {
console.warn("[爆款文案] JSON 解析失败,转用文本拆分:", err);
}
const fallback = body
.split(/\n(?=(?:方案|选项)\s*[一二三123])|\n{2,}/)
.map((line) =>
line.replace(/^(?:方案|选项)\s*[一二三123][:.\s-]*/g, "").trim(),
)
.filter(Boolean);
return Array.from(new Set(fallback)).slice(0, 3);
}
/**
* 构建爆款文案提示词(对齐 zhenqianba Ti
* @param {ReturnType<typeof useWorkflowStore>} store
*/
export function buildHitScriptPrompt(store) {
const lines = [];
lines.push(
"你是一个爆款短视频文案专家,擅长创作高播放量、高互动的短视频口播文案。",
);
lines.push("请根据以下信息输出 3 个不同方向的爆款短视频文案方案。");
lines.push(`【视频类型】${store.videoType || "口播文案"}`);
lines.push(`【文案类型】${store.copyType || "人设型"}`);
const persona = String(store.industryPersona || "").trim();
if (persona) lines.push(`【行业+人设】${persona}`);
const product = String(store.productBusiness || "").trim();
if (product) lines.push(`【产品/业务】${product}`);
const selling = String(store.sellingPrice || "").trim();
if (selling) lines.push(`【卖点+价格】${selling}`);
const other = String(store.otherRequirements || "").trim();
if (other) lines.push(`【其他要求】${other}`);
const count = store.targetWords || 300;
lines.push("");
lines.push("要求:");
lines.push("1. 开头3秒必须有强吸引力的钩子一开口就能留住用户");
lines.push(`2. 内容贴合「${store.copyType || "人设型"}」风格特点`);
lines.push("3. 语言自然口语化,适合短视频口播");
lines.push("4. 结尾要有引导互动的话术(关注、点赞、评论、收藏)");
lines.push("5. 不使用表情符号和特殊符号");
lines.push(`6. 字数控制在${count}字左右`);
lines.push("7. 3 个方案要明显区分角度,不要只改几个词");
lines.push(
'8. 只返回 JSON格式必须是 {"options":["方案1","方案2","方案3"]},不要输出 markdown不要补充解释',
);
return lines.join("\n");
}
/**
* 生成爆款文案:调用 LLM 产出 3 个方案(对齐 zhenqianba Ti
* @param {ReturnType<typeof useWorkflowStore>} store
*/
export async function executeGenerateHitScript(store) {
const cfgReady = await ensureLlmConfigReady();
if (!cfgReady.ok) {
return { ok: false, message: cfgReady.message };
}
const prompt = buildHitScriptPrompt(store);
store.hitScriptGenerating = true;
store.hitScriptOptions = [];
try {
const result = await invoke("run_nodejs_script", {
scriptName: SCRIPT_GENERATE,
params: {
messages: [{ role: "user", content: prompt }],
temperature: 0.8,
max_tokens: 4000,
},
});
if (!result?.success || !result?.content) {
const err = result?.error || "文案生成失败,请重试";
return { ok: false, message: String(err) };
}
const options = parseHitScriptOptions(result.content);
if (!options.length) {
return { ok: false, message: "模型未返回可用文案方案" };
}
store.hitScriptOptions = options;
store.hitScriptSelectedIndex = 0;
store.hitScriptModalVisible = true;
return {
ok: true,
message: `已生成 ${options.length} 个爆款文案方案,请在弹窗中选择`,
};
} catch (err) {
const msg = err instanceof Error ? err.message : String(err || "未知错误");
return { ok: false, message: `生成文案失败:${msg}` };
} finally {
store.hitScriptGenerating = false;
}
}
/**
* 将所选爆款文案填入编辑区(对齐 zhenqianba Bn
* @param {ReturnType<typeof useWorkflowStore>} store
* @param {number} index
*/
export function applyHitScriptOptionToEditor(store, index) {
const i = Number(index);
const option = store.hitScriptOptions[i];
if (!option) {
return { ok: false, message: "请选择文案方案" };
}
store.scriptContent = String(option).trim();
store.hitScriptModalVisible = false;
return { ok: true, message: "已将所选文案填入编辑区" };
}
/**
* 构建撰写文案提示词(对齐 zhenqianba generateScriptFromVideoContent
* @param {ReturnType<typeof useWorkflowStore>} store