This commit is contained in:
949036910@qq.com
2026-05-31 23:22:11 +08:00
parent 620b022af0
commit da8bccf3c1

View File

@@ -8,17 +8,14 @@ const desktopConfig = require("./desktop_config.js");
const KEYWORD_GROUPS = ["重点词/成语词", "描述词", "行动词", "情感词"];
const DEFAULT_TITLE_TAG_PROMPT = `你是短视频标题与标签助手。分析以下文案内容,生成:
1. 一个最吸引人的标题不超过30字若需多个建议可写在 title 字段内用换行分隔)
2. 8-10 个相关话题标签(带 # 号)
3. 四个分组关键词,每组 0-2 个词:重点词/成语词、描述词、行动词、情感词
const ELECTRON_DEFAULT_TITLE_TAG_PROMPT =
"你是短视频标题与标签助手。分析文案内容 {{content}}生成5个吸引眼球的标题建议、10个相关标签、4个分组关键词每组重点词/成语词、描述词、行动词、情感词每个分组只要0-2个词不要多。";
文案内容:
{{content}}
const JSON_OUTPUT_SUFFIX = `
请只返回 JSON不要 markdown格式如下
{
"title": "标题",
"title": "最推荐标题(多个标题建议可用换行分隔)",
"tags": ["#标签1", "#标签2"],
"keywords": {
"重点词/成语词": ["词1"],
@@ -28,12 +25,28 @@ const DEFAULT_TITLE_TAG_PROMPT = `你是短视频标题与标签助手。分析
}
}`;
function logInfo(tag, payload) {
if (payload === undefined) {
console.info(tag);
return;
}
if (typeof payload === "string") {
console.info(`${tag} - ${payload}`);
return;
}
console.info(`${tag} - ${JSON.stringify(payload)}`);
}
function buildPrompt(template, content) {
let prompt = String(template || "").trim();
if (!prompt) prompt = DEFAULT_TITLE_TAG_PROMPT;
return prompt
if (!prompt) prompt = ELECTRON_DEFAULT_TITLE_TAG_PROMPT;
prompt = prompt
.replace(/\{\{content\}\}/g, content)
.replace(/\{content\}/g, content);
if (!/json|JSON/.test(prompt)) {
prompt += JSON_OUTPUT_SUFFIX;
}
return prompt;
}
function cleanJsonText(raw) {
@@ -76,6 +89,16 @@ function normalizeKeywordGroup(val) {
return "";
}
function normalizeTitle(val) {
if (Array.isArray(val)) {
return val
.map((t) => String(t || "").trim())
.filter(Boolean)
.join("\n");
}
return String(val || "").trim();
}
function parseTitleTagsContent(content) {
let title = "";
let tags = "";
@@ -83,7 +106,8 @@ function parseTitleTagsContent(content) {
try {
const parsed = JSON.parse(cleanJsonText(content));
title = String(parsed.title || "").trim();
logInfo("ipAgent.generateTitleTags.cleanedContent", cleanJsonText(content));
title = normalizeTitle(parsed.title || parsed.titles);
tags = normalizeTags(parsed.tags);
const kw = parsed.keywords;
if (kw && typeof kw === "object" && !Array.isArray(kw)) {
@@ -95,7 +119,12 @@ function parseTitleTagsContent(content) {
} else if (typeof kw === "string") {
keywords["重点词/成语词"] = normalizeKeywordGroup(kw);
}
} catch {
logInfo("ipAgent.generateTitleTags.parsed", { title, tags, keywords });
} catch (err) {
logInfo("ipAgent.generateTitleTags.jsonParseFailed", {
error: err instanceof Error ? err.message : String(err),
content,
});
const lines = String(content).split("\n");
for (const line of lines) {
if (/标题|Title/i.test(line)) {
@@ -121,6 +150,16 @@ function parseTitleTagsContent(content) {
return { title, tags, keywords };
}
function validateLlmConfig(modelConfig) {
if (!modelConfig.apiKey) {
return { ok: false, error: "缺少配置 LLM_API_KEYdesktop_configs 表)" };
}
if (!modelConfig.apiUrl) {
return { ok: false, error: "缺少配置 LLM_BASE_URL或 LLM_API_URL" };
}
return { ok: true };
}
globalThis.__nodejsMain = async function main(params) {
const p = params || {};
const content = String(p.content || p.script || "").trim();
@@ -129,12 +168,39 @@ globalThis.__nodejsMain = async function main(params) {
}
const modelConfig = desktopConfig.buildModelConfig();
const check = desktopConfig.validateModelConfig(modelConfig);
const check = validateLlmConfig(modelConfig);
if (!check.ok) {
return { success: false, error: check.error };
}
const prompt = buildPrompt(p.titleTagPrompt, content);
const requestPayload = {
model: modelConfig.apiModelId,
messages: [{ role: "user", content: prompt }],
};
logInfo("ipAgent.generateTitleTags", {
scriptLength: content.length,
modelConfig: {
providerId: modelConfig.providerId,
modelId: modelConfig.apiModelId,
apiUrl: modelConfig.apiUrl,
apiHost: "",
apiKey: modelConfig.apiKey,
type: modelConfig.type,
},
});
logInfo("ipAgent.generateTitleTags.REQUEST", {
apiUrl: modelConfig.apiUrl,
model: modelConfig.apiModelId,
promptLength: prompt.length,
hasApiKey: Boolean(modelConfig.apiKey),
});
logInfo("ipAgent.generateTitleTags.REQUEST_FULL_PROMPT", prompt);
logInfo(
"ipAgent.generateTitleTags.REQUEST_FULL_PAYLOAD",
JSON.stringify(requestPayload, null, 2),
);
globalThis.__native?.emitProgress?.("正在生成标题、标签和关键词…");
@@ -142,24 +208,35 @@ globalThis.__nodejsMain = async function main(params) {
apiUrl: modelConfig.apiUrl,
apiKey: modelConfig.apiKey,
model: modelConfig.apiModelId,
messages: [{ role: "user", content: prompt }],
messages: requestPayload.messages,
temperature: typeof p.temperature === "number" ? p.temperature : 0.7,
max_tokens: p.max_tokens || 2000,
});
if (!chat.success || !chat.content) {
logInfo("ipAgent.generateTitleTags.api.error", chat.error || "模型返回为空");
return { success: false, error: chat.error || "模型返回为空" };
}
logInfo("ipAgent.generateTitleTags.RESPONSE_CONTENT", chat.content);
logInfo("ipAgent.generateTitleTags.rawContent", { content: chat.content });
const parsed = parseTitleTagsContent(chat.content);
if (!parsed) {
logInfo("ipAgent.generateTitleTags.emptyResult", { content: chat.content });
return {
success: false,
error: "解析结果为空,请检查模型返回格式",
error: "解析结果为空,AI返回内容: " + chat.content,
rawContent: chat.content,
};
}
logInfo("ipAgent.generateTitleTags.success", {
title: parsed.title,
tags: parsed.tags,
keywords: parsed.keywords,
});
return {
success: true,
title: parsed.title,