Files
WYF-koubo/electron/mapi/ipAgent/videoRewriteOptimizer.ts
2026-06-19 18:45:55 +08:00

248 lines
7.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 视频文案仿写优化器
* 特点:
* 1. 支持更复杂的提示词模板
* 2. 智能分批处理多个文案
* 3. 更好的错误恢复
* 4. 支持自定义的风格转换
*/
interface RewriteConfig {
style?: 'casual' | 'professional' | 'emotional' | 'humorous'; // 文案风格
length?: 'short' | 'medium' | 'long'; // 文案长度
keepHashtags?: boolean; // 是否保留话题标签
keepEmoji?: boolean; // 是否保留emoji
maxRetries?: number; // 重试次数
}
interface RewriteResult {
original: string;
rewritten: string;
confidence: number; // 0-1 的置信度
}
class VideoRewriteOptimizer {
/**
* 构建优化的仿写提示词
*/
static buildRewritePrompt(
content: string,
config: RewriteConfig = {},
customPrompt?: string
): string {
// 如果提供了自定义提示词,使用自定义的
if (customPrompt && customPrompt.trim()) {
return this.replacePromptVariables(customPrompt, content);
}
// 否则使用预设的提示词
return this.buildDefaultPrompt(content, config);
}
/**
* 替换提示词中的变量
*/
private static replacePromptVariables(template: string, content: string): string {
return template
.replace(/\{\{content\}\}/g, content)
.replace(/\{content\}/g, content)
.replace(/\{\{text\}\}/g, content)
.replace(/\{text\}/g, content);
}
/**
* 构建默认提示词
*/
private static buildDefaultPrompt(content: string, config: RewriteConfig): string {
const styleGuide = this.getStyleGuide(config.style || 'casual');
const lengthGuide = this.getLengthGuide(config.length || 'medium');
return `你是一个专业的视频内容创意编写专家,擅长创作吸引人的视频文案。
## 原始文案:
${content}
## 仿写要求:
1. **风格**: ${styleGuide}
2. **长度**: ${lengthGuide}
3. **核心保持**: 保留原文案的核心信息和主题
4. **创意提升**: 在措辞、表述角度、情感吸引力上创新
5. **格式**:
${config.keepHashtags !== false ? '- 保留原有话题标签(#开头的内容)' : '- 不使用话题标签'}
${config.keepEmoji !== false ? '- 可以适当添加表情符号增加生动性' : '- 不使用表情符号'}
6. **禁止事项**:
- 不要改变事实信息
- 不要添加虚假承诺
- 不要包含敏感词汇
请直接输出仿写后的文案,不需要任何额外说明或标记。`;
}
/**
* 获取风格指南
*/
private static getStyleGuide(style: string): string {
const guides: Record<string, string> = {
casual: '轻松随意、接地气、易产生共鸣,像和朋友聊天一样',
professional: '正式专业、有信服力、适合商务或教育内容',
emotional: '充满情感、富有感染力、能打动人心',
humorous: '幽默诙谐、容易引起笑声和转发、保持积极态度'
};
return guides[style] || guides.casual;
}
/**
* 获取长度指南
*/
private static getLengthGuide(length: string): string {
const guides: Record<string, string> = {
short: '简洁有力,100字以内,快速传达核心信息',
medium: '适中篇幅,100-300字,既能完整表达又不显冗长',
long: '详细深入,300-500字,充分展开论点和细节'
};
return guides[length] || guides.medium;
}
/**
* 批量仿写文案(支持多个内容同时处理)
*/
static buildBatchRewritePrompt(
contents: string[],
config: RewriteConfig = {},
customPrompt?: string
): string {
if (customPrompt && customPrompt.trim()) {
// 自定义提示词需要特殊处理,只能一个接一个
return this.replacePromptVariables(customPrompt, contents[0]);
}
const styleGuide = this.getStyleGuide(config.style || 'casual');
const lengthGuide = this.getLengthGuide(config.length || 'medium');
const itemsText = contents
.map((content, i) => `${i + 1}. ${content}`)
.join('\n');
return `你是一个专业的视频内容创意编写专家,擅长创作吸引人的视频文案。
## 原始文案列表:
${itemsText}
## 仿写要求:
1. **风格**: ${styleGuide}
2. **长度**: ${lengthGuide}
3. **核心保持**: 保留每篇原文案的核心信息和主题
4. **创意提升**: 在措辞、表述角度、情感吸引力上创新
5. **格式**:
${config.keepHashtags !== false ? '- 保留原有话题标签(#开头的内容)' : '- 不使用话题标签'}
${config.keepEmoji !== false ? '- 可以适当添加表情符号增加生动性' : '- 不使用表情符号'}
6. **禁止事项**:
- 不要改变事实信息
- 不要添加虚假承诺
- 不要包含敏感词汇
## 输出格式:
请按顺序输出仿写后的文案,每个文案一行,不需要编号或任何额外标记。`;
}
/**
* 解析仿写后的文案(处理可能的编号、特殊字符等)
*/
static parseRewriteResponse(response: string, count: number): string[] {
const lines = response
.trim()
.split('\n')
.map(line => line.trim())
.filter(line => line.length > 0);
// 清理可能的编号前缀
const cleaned = lines.map(line => {
// 去掉开头的编号(1. 2. 1) 2) 等)
return line
.replace(/^[\d\.\)]+\s*/, '')
.replace(/^[-•·\*]\s*/, '')
.trim();
});
// 如果数量不匹配,尝试智能截断或填充
if (cleaned.length > count) {
return cleaned.slice(0, count);
}
if (cleaned.length < count) {
// 填充原始文案(如果API返回不足)
while (cleaned.length < count) {
cleaned.push('精彩内容分享');
}
}
return cleaned;
}
/**
* 智能评估仿写质量
*/
static assessQuality(original: string, rewritten: string): number {
let score = 0.5; // 基础分数
// 加分项
if (rewritten.length > 0) score += 0.1; // 有内容
if (rewritten.length > original.length * 0.5 && rewritten.length < original.length * 1.5) {
score += 0.1; // 长度合理(±50%
}
if (rewritten.includes('') || rewritten.includes('。')) {
score += 0.05; // 有标点符号
}
// 检查是否过于相似(直接复制)
const similarity = this.calculateSimilarity(original, rewritten);
if (similarity > 0.9) {
score = Math.max(0.2, score - 0.3); // 过于相似减分
}
return Math.min(1.0, Math.max(0.0, score));
}
/**
* 计算两个文本的相似度(0-1)
*/
private static calculateSimilarity(text1: string, text2: string): number {
if (!text1 || !text2) return 0;
// 简单的字符重叠率计算
const chars1 = new Set(text1);
const chars2 = new Set(text2);
const intersection = Array.from(chars1).filter(char => chars2.has(char)).length;
const union = chars1.size + chars2.size - intersection;
return intersection / (union || 1);
}
/**
* 优化提示词中的文案内容部分
* 用于处理很长的原始文案
*/
static truncateContentForPrompt(content: string, maxLength: number = 500): string {
if (content.length <= maxLength) {
return content;
}
// 优先保留开头和结尾的关键信息
const startLength = Math.ceil(maxLength * 0.6);
const endLength = Math.floor(maxLength * 0.4);
const start = content.substring(0, startLength);
const end = content.substring(content.length - endLength);
// 找到最近的句号/标点符号作为截断点
const startEnd = start.lastIndexOf('。') >= 0
? start.lastIndexOf('。') + 1
: startLength;
return start.substring(0, startEnd) + ' [...] ' + end;
}
}
export { VideoRewriteOptimizer, RewriteConfig, RewriteResult };