397 lines
9.6 KiB
TypeScript
397 lines
9.6 KiB
TypeScript
import { config } from './config.ts';
|
|
import { readFileSync, writeFileSync } from 'node:fs';
|
|
import { Kevisual } from '@kevisual/ai';
|
|
|
|
// ============================================
|
|
// AI优化提示词配置
|
|
// ============================================
|
|
|
|
// 通用哲理句优化提示词
|
|
export const PERFECT_PROMPT = `你是一个深谙人生哲理的作家。请将以下不完整的哲理句补充完整,使其成为一句发人深省的哲理名言。
|
|
|
|
要求:
|
|
1. 保持原句的核心主题和结构
|
|
2. 语言要简洁有力,富有哲理深度
|
|
3. 让人读后有所思考和共鸣
|
|
4. 符合中文表达习惯
|
|
5. 字数控制在20-50字之间
|
|
|
|
原句:{{sentence}}
|
|
|
|
请直接输出优化后的句子,不需要任何解释。`;
|
|
|
|
// 不同主题的专项优化提示词
|
|
export const THEME_PROMPTS: Record<string, string> = {
|
|
人生: `你是一个智慧的导师。请将以下关于人生的句子优化成一句深刻的人生感悟:
|
|
|
|
要求:
|
|
- 语言平实却蕴含智慧
|
|
- 让人读后有所触动
|
|
- 适合作为人生格言
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
时间: `你是一个洞察时光的智者。请将以下关于时间的句子优化:
|
|
|
|
要求:
|
|
- 体现时间的珍贵与无情
|
|
- 让人珍惜当下
|
|
- 富有诗意但不晦涩
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
成长: `你是一个经历过蜕变的智者。请将以下关于成长的句子优化:
|
|
|
|
要求:
|
|
- 体现成长的代价与收获
|
|
- 让人对成长有新的理解
|
|
- 有力量感但不鸡汤
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
孤独: `你是一个深刻理解孤独的人。请将以下关于孤独的句子优化:
|
|
|
|
要求:
|
|
- 准确描述孤独的本质
|
|
- 不是消极,而是清醒
|
|
- 让人学会与孤独和解
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
爱: `你是一个懂得爱的人。请将以下关于爱的句子优化:
|
|
|
|
要求:
|
|
- 体现爱的真谛
|
|
- 不是空洞的情话
|
|
- 让人对爱有新的认识
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
选择: `你是一个善于抉择的人。请将以下关于选择的句子优化:
|
|
|
|
要求:
|
|
- 体现选择的重量
|
|
- 不是教条,而是智慧
|
|
- 让人更慎重地面对选择
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
自由: `你是一个追求自由的人。请将以下关于自由的句子优化:
|
|
|
|
要求:
|
|
- 准确描述自由的真谛
|
|
- 让人理解自由的代价
|
|
- 有深度但不晦涩
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`,
|
|
|
|
痛苦: `你是一个从痛苦中走过来的人。请将以下关于痛苦的句子优化:
|
|
|
|
要求:
|
|
- 不是宣泄负面情绪
|
|
- 而是让人从痛苦中获得力量
|
|
- 转化痛苦为成长
|
|
|
|
原句:{{sentence}}
|
|
|
|
直接输出优化后的句子。`
|
|
};
|
|
|
|
// ============================================
|
|
// AI客户端接口
|
|
// ============================================
|
|
|
|
export interface PerfectOptions {
|
|
/** Kevisual AI 实例 */
|
|
ai?: Kevisual;
|
|
/** 使用的提示词模板 */
|
|
promptTemplate?: string;
|
|
/** 并发请求数 */
|
|
concurrency?: number;
|
|
/** 重试次数 */
|
|
retryTimes?: number;
|
|
/** 成功后回调 */
|
|
onSuccess?: (item: PerfectItem) => void;
|
|
/** 失败后回调 */
|
|
onError?: (item: PerfectError) => void;
|
|
/** 进度回调 */
|
|
onProgress?: (progress: ProgressInfo) => void;
|
|
}
|
|
|
|
export interface PerfectItem {
|
|
index: number;
|
|
text: string;
|
|
template: string;
|
|
templateType: string;
|
|
optimized: string;
|
|
prompt?: string;
|
|
theme: string;
|
|
tags: string[];
|
|
}
|
|
|
|
export interface PerfectError {
|
|
index: number;
|
|
original: string;
|
|
error: string;
|
|
theme: string;
|
|
}
|
|
|
|
export interface ProgressInfo {
|
|
current: number;
|
|
total: number;
|
|
percentage: number;
|
|
successCount: number;
|
|
errorCount: number;
|
|
}
|
|
|
|
// ============================================
|
|
// 默认AI实例
|
|
// ============================================
|
|
|
|
function createDefaultAI(): Kevisual {
|
|
return new Kevisual({
|
|
apiKey: config.KEVISUAL_NEW_API_KEY || '',
|
|
});
|
|
}
|
|
|
|
// ============================================
|
|
// 句子优化器类
|
|
// ============================================
|
|
|
|
export class SentencePerfect {
|
|
private options: Required<PerfectOptions>;
|
|
private ai: Kevisual;
|
|
|
|
constructor(options: PerfectOptions = {}) {
|
|
this.ai = options.ai || createDefaultAI();
|
|
|
|
this.options = {
|
|
ai: this.ai,
|
|
promptTemplate: options.promptTemplate || PERFECT_PROMPT,
|
|
concurrency: options.concurrency ?? 5,
|
|
retryTimes: options.retryTimes ?? 3,
|
|
onSuccess: options.onSuccess || (() => { }),
|
|
onError: options.onError || (() => { }),
|
|
onProgress: options.onProgress || (() => { })
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 获取主题对应的提示词
|
|
*/
|
|
private getThemePrompt(theme: string, sentence: string): string {
|
|
const themePrompt = THEME_PROMPTS[theme];
|
|
if (themePrompt) {
|
|
return themePrompt.replace('{{sentence}}', sentence);
|
|
}
|
|
return this.options.promptTemplate.replace('{{sentence}}', sentence);
|
|
}
|
|
|
|
/**
|
|
* 优化单条句子(带重试)
|
|
*/
|
|
async perfectOne(item: PerfectItem): Promise<PerfectItem> {
|
|
const prompt = this.getThemePrompt(item.theme, item.text);
|
|
let lastError: Error | null = null;
|
|
|
|
for (let i = 0; i < this.options.retryTimes; i++) {
|
|
try {
|
|
await this.ai.chat([{ role: 'user', content: prompt }]);
|
|
let optimized = this.ai.responseText || '';
|
|
optimized = optimized.trim().replace(/^["']|["']$/g, '');
|
|
|
|
const result: PerfectItem = {
|
|
...item,
|
|
prompt: prompt,
|
|
optimized: optimized || item.text
|
|
};
|
|
|
|
this.options.onSuccess(result);
|
|
return result;
|
|
} catch (error) {
|
|
lastError = error as Error;
|
|
await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1)));
|
|
}
|
|
}
|
|
|
|
const error: PerfectError = {
|
|
index: item.index,
|
|
original: item.text,
|
|
error: lastError?.message || '未知错误',
|
|
theme: item.theme
|
|
};
|
|
|
|
this.options.onError(error);
|
|
return {
|
|
...item,
|
|
optimized: item.text
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 批量优化句子
|
|
*/
|
|
async perfectBatch(
|
|
items: PerfectItem[]
|
|
): Promise<PerfectItem[]> {
|
|
const total = items.length;
|
|
let successCount = 0;
|
|
let errorCount = 0;
|
|
const results: PerfectItem[] = [];
|
|
|
|
const batchSize = this.options.concurrency;
|
|
|
|
for (let i = 0; i < items.length; i += batchSize) {
|
|
const batch = items.slice(i, i + batchSize);
|
|
|
|
const promises = batch.map(async (item) => {
|
|
try {
|
|
const result = await this.perfectOne(item);
|
|
results.push(result);
|
|
successCount++;
|
|
} catch {
|
|
errorCount++;
|
|
}
|
|
|
|
const current = Math.min(i + batchSize, total);
|
|
const percentage = Math.round((current / total) * 100);
|
|
|
|
this.options.onProgress({
|
|
current,
|
|
total,
|
|
percentage,
|
|
successCount,
|
|
errorCount
|
|
});
|
|
});
|
|
|
|
await Promise.all(promises);
|
|
|
|
if (i + batchSize < items.length) {
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
}
|
|
}
|
|
|
|
return results;
|
|
}
|
|
|
|
/**
|
|
* 从文件加载句子并优化
|
|
*/
|
|
async perfectFromFile(
|
|
inputPath: string,
|
|
outputPath: string
|
|
): Promise<{ success: number; failed: number; results: any[] }> {
|
|
const data = JSON.parse(readFileSync(inputPath, 'utf-8'));
|
|
const sentences = data.sentences || data;
|
|
|
|
const items: PerfectItem[] = sentences.map((s: any, i: number) => ({
|
|
index: s.index || i + 1,
|
|
text: s.text || s,
|
|
template: s.template || '',
|
|
templateType: s.templateType || '',
|
|
theme: s.theme || '人生',
|
|
tags: s.tags || [],
|
|
optimized: ''
|
|
}));
|
|
|
|
const results = await this.perfectBatch(items);
|
|
|
|
// 合并原始数据与优化结果
|
|
const mergedResults = results.map((r, i) => {
|
|
return {
|
|
index: r.index,
|
|
text: r.text,
|
|
template: r.template,
|
|
templateType: r.templateType,
|
|
theme: r.theme,
|
|
tags: r.tags,
|
|
optimized: r.optimized
|
|
};
|
|
});
|
|
|
|
const successResults = results.filter(r => r.optimized !== r.text);
|
|
const failedResults = results.filter(r => r.optimized === r.text);
|
|
|
|
const output = {
|
|
meta: {
|
|
total: results.length,
|
|
success: successResults.length,
|
|
failed: failedResults.length,
|
|
optimizedAt: new Date().toISOString()
|
|
},
|
|
sentences: mergedResults
|
|
};
|
|
|
|
writeFileSync(outputPath, JSON.stringify(output, null, 2), 'utf-8');
|
|
|
|
return {
|
|
success: successResults.length,
|
|
failed: failedResults.length,
|
|
results: mergedResults
|
|
};
|
|
}
|
|
|
|
/**
|
|
* 设置AI实例
|
|
*/
|
|
setAI(ai: Kevisual): void {
|
|
this.ai = ai;
|
|
this.options.ai = ai;
|
|
}
|
|
}
|
|
|
|
// ============================================
|
|
// 便捷函数
|
|
// ============================================
|
|
|
|
/**
|
|
* 快速优化单条句子
|
|
*/
|
|
export async function quickPerfect(
|
|
sentence: string,
|
|
theme: string = '人生'
|
|
): Promise<string> {
|
|
const perfect = new SentencePerfect();
|
|
const item: PerfectItem = {
|
|
index: 0,
|
|
text: sentence,
|
|
template: '',
|
|
templateType: '',
|
|
theme,
|
|
tags: [],
|
|
optimized: ''
|
|
};
|
|
const result = await perfect.perfectOne(item);
|
|
return result.optimized;
|
|
}
|
|
|
|
/**
|
|
* 从JSON文件优化句子
|
|
*/
|
|
export async function perfectFromJSON(
|
|
inputPath: string,
|
|
outputPath: string,
|
|
options: Partial<PerfectOptions> = {}
|
|
): Promise<{ success: number; failed: number }> {
|
|
const perfect = new SentencePerfect(options);
|
|
const result = await perfect.perfectFromFile(inputPath, outputPath);
|
|
return { success: result.success, failed: result.failed };
|
|
}
|
|
|
|
export default SentencePerfect;
|