|
|
@@ -0,0 +1,418 @@
|
|
|
+/**
|
|
|
+ * AI内容生成服务
|
|
|
+ * 模拟LLM响应,实际生产环境应接入通义千问/DashScope API
|
|
|
+ */
|
|
|
+
|
|
|
+// 内容类型分类
|
|
|
+const contentTypes = {
|
|
|
+ '创作类': ['小说', '故事', '剧本', '诗歌', '散文'],
|
|
|
+ '营销类': ['产品介绍', '广告文案', '朋友圈', '小红书', '抖音脚本'],
|
|
|
+ '教育类': ['课件', '培训', '教程', '知识科普', '考试辅导'],
|
|
|
+ '商务类': ['销售话术', '客服话术', '商务邮件', '合同条款', '方案PPT'],
|
|
|
+ '媒体类': ['新闻播报', '天气预报', '体育解说', '财经评论', '娱乐八卦'],
|
|
|
+ '生活类': ['生日祝福', '婚礼致辞', '节日问候', '朋友圈文案', '签名设计'],
|
|
|
+ '专业类': ['法律文书', '医学说明', '技术文档', '产品手册', '操作指南'],
|
|
|
+};
|
|
|
+
|
|
|
+// 行业列表
|
|
|
+const industries = [
|
|
|
+ '通用', '医疗健康', '教育培训', '金融服务', '电子商务',
|
|
|
+ '法律服务', '新闻媒体', '餐饮美食', '房地产', '汽车销售'
|
|
|
+];
|
|
|
+
|
|
|
+// 情感选项
|
|
|
+const emotions = ['开心', '悲伤', '激动', '平静', '紧张', '温柔', '愤怒', '恐惧', '惊讶'];
|
|
|
+
|
|
|
+// 支持的语言
|
|
|
+const languages = ['中文', '英语', '日语', '韩语', '法语', '德语', '西班牙语', '葡萄牙语', '俄语', '阿拉伯语'];
|
|
|
+
|
|
|
+// 质量评分维度
|
|
|
+const qualityDimensions = ['fluency', 'naturalness', 'emotion_consistency', 'topic_adherence', 'structural_integrity'];
|
|
|
+
|
|
|
+export class AIContentService {
|
|
|
+ /**
|
|
|
+ * 智能意图识别
|
|
|
+ */
|
|
|
+ async recognizeIntent(input: string) {
|
|
|
+ // 模拟意图识别
|
|
|
+ const type = this.detectContentType(input);
|
|
|
+ const industry = this.detectIndustry(input);
|
|
|
+
|
|
|
+ return {
|
|
|
+ type,
|
|
|
+ industry,
|
|
|
+ style: '正式',
|
|
|
+ scale: input.length > 500 ? '长篇' : '短篇',
|
|
|
+ confidence: 0.85 + Math.random() * 0.1,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测内容类型
|
|
|
+ */
|
|
|
+ private detectContentType(input: string): { category: string; subType: string } {
|
|
|
+ const keywords: Record<string, string[]> = {
|
|
|
+ '小说': ['故事', '主角', '章节', '穿越', '都市', '玄幻'],
|
|
|
+ '广告': ['推广', '优惠', '打折', '促销', '产品'],
|
|
|
+ '培训': ['培训', '课程', '教学', '学员', '讲师'],
|
|
|
+ '销售': ['客户', '订单', '成交', '跟进', '话术'],
|
|
|
+ '祝福': ['祝福', '生日快乐', '节日', '贺卡'],
|
|
|
+ };
|
|
|
+
|
|
|
+ for (const [type, words] of Object.entries(keywords)) {
|
|
|
+ if (words.some(w => input.includes(w))) {
|
|
|
+ return { category: type, subType: type };
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return { category: '创作类', subType: '故事' };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测行业
|
|
|
+ */
|
|
|
+ private detectIndustry(input: string): string {
|
|
|
+ const keywords: Record<string, string[]> = {
|
|
|
+ '医疗健康': ['医生', '医院', '药品', '健康', '疾病'],
|
|
|
+ '教育培训': ['学校', '学生', '老师', '课程', '培训'],
|
|
|
+ '金融服务': ['银行', '理财', '投资', '股票', '基金'],
|
|
|
+ '电子商务': ['商品', '店铺', '买家', '电商', '快递'],
|
|
|
+ '餐饮美食': ['餐厅', '美食', '菜品', '厨师', '食物'],
|
|
|
+ };
|
|
|
+
|
|
|
+ for (const [industry, words] of Object.entries(keywords)) {
|
|
|
+ if (words.some(w => input.includes(w))) {
|
|
|
+ return industry;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return '通用';
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取内容类型列表
|
|
|
+ */
|
|
|
+ getContentTypes() {
|
|
|
+ return contentTypes;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取所有内容类型(扁平)
|
|
|
+ */
|
|
|
+ getAllContentTypes() {
|
|
|
+ const all: string[] = [];
|
|
|
+ Object.values(contentTypes).forEach(types => all.push(...types));
|
|
|
+ return [...new Set(all)];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取行业列表
|
|
|
+ */
|
|
|
+ getIndustries() {
|
|
|
+ return industries;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 行业适配
|
|
|
+ */
|
|
|
+ async adaptContent(content: string, industry: string) {
|
|
|
+ const industryConfig: Record<string, any> = {
|
|
|
+ '医疗健康': { terminology: true, compliance: '医疗广告法', sensitivity: 'high' },
|
|
|
+ '教育培训': { terminology: true, compliance: '教育规范', sensitivity: 'medium' },
|
|
|
+ '金融服务': { terminology: true, compliance: '金融监管', sensitivity: 'high' },
|
|
|
+ '电子商务': { terminology: false, compliance: '电商法规', sensitivity: 'low' },
|
|
|
+ };
|
|
|
+
|
|
|
+ return {
|
|
|
+ adapted: content,
|
|
|
+ config: industryConfig[industry] || { terminology: false, compliance: '通用', sensitivity: 'low' },
|
|
|
+ warnings: industryConfig[industry]?.sensitivity === 'high' ? ['需遵守相关法规'] : [],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内容规划
|
|
|
+ */
|
|
|
+ async planContent(type: string, theme: string, targetLength: number) {
|
|
|
+ const chapters = Math.ceil(targetLength / 5000);
|
|
|
+ const outline = [];
|
|
|
+
|
|
|
+ for (let i = 1; i <= chapters; i++) {
|
|
|
+ outline.push({
|
|
|
+ chapter: i,
|
|
|
+ title: `第${i}章`,
|
|
|
+ summary: `${theme} - 章节内容概要`,
|
|
|
+ estimatedLength: Math.ceil(targetLength / chapters),
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ return {
|
|
|
+ type,
|
|
|
+ theme,
|
|
|
+ totalChapters: chapters,
|
|
|
+ estimatedLength: targetLength,
|
|
|
+ outline,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成大纲
|
|
|
+ */
|
|
|
+ async generateOutline(type: string, theme: string, chapters: number) {
|
|
|
+ const outline = [];
|
|
|
+ for (let i = 1; i <= chapters; i++) {
|
|
|
+ outline.push({
|
|
|
+ id: `chapter-${i}`,
|
|
|
+ title: `第${i}章:${theme}的展开`,
|
|
|
+ description: `详细描述第${i}章的情节发展`,
|
|
|
+ wordCount: 3000 + Math.floor(Math.random() * 2000),
|
|
|
+ });
|
|
|
+ }
|
|
|
+ return { outlineId: `outline-${Date.now()}`, outline, theme };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成角色设定
|
|
|
+ */
|
|
|
+ async generateCharacters(type: string, genre: string) {
|
|
|
+ const characters = [
|
|
|
+ { id: 'char-1', name: '张三', age: 30, gender: '男', personality: '正直勇敢', role: '主角', avatar: '' },
|
|
|
+ { id: 'char-2', name: '李四', age: 28, gender: '女', personality: '聪明机智', role: '女主', avatar: '' },
|
|
|
+ ];
|
|
|
+ return { characters };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 分步生成内容
|
|
|
+ */
|
|
|
+ async generateChunk(outlineId: string, chapterIndex: number) {
|
|
|
+ return {
|
|
|
+ chunkId: `chunk-${Date.now()}-${chapterIndex}`,
|
|
|
+ chapterIndex,
|
|
|
+ content: `这是第${chapterIndex + 1}章的内容...\n\n[模拟生成的长文本内容,包含故事情节、人物对话等丰富元素。]`,
|
|
|
+ wordCount: 3500 + Math.floor(Math.random() * 1500),
|
|
|
+ status: 'completed',
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 流式生成(模拟SSE)
|
|
|
+ */
|
|
|
+ async *streamGenerate(outlineId: string) {
|
|
|
+ const chunks = ['第一章的内容开始...', '情节发展...', '高潮迭起...', '最终结局...'];
|
|
|
+
|
|
|
+ for (const chunk of chunks) {
|
|
|
+ await new Promise(resolve => setTimeout(resolve, 500));
|
|
|
+ yield { type: 'chunk', content: chunk };
|
|
|
+ }
|
|
|
+
|
|
|
+ yield { type: 'done', content: '' };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建生成任务
|
|
|
+ */
|
|
|
+ createTask(type: string, title: string) {
|
|
|
+ return {
|
|
|
+ taskId: `task-${Date.now()}`,
|
|
|
+ type,
|
|
|
+ title,
|
|
|
+ status: 'pending',
|
|
|
+ progress: 0,
|
|
|
+ createdAt: new Date().toISOString(),
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取任务列表
|
|
|
+ */
|
|
|
+ getTasks() {
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 章节连贯性检查
|
|
|
+ */
|
|
|
+ async checkCoherence(chapter1: string, chapter2: string) {
|
|
|
+ return {
|
|
|
+ score: 0.8 + Math.random() * 0.15,
|
|
|
+ issues: [],
|
|
|
+ suggestions: [],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 生成衔接段
|
|
|
+ */
|
|
|
+ async generateContinuity(previousChapter: string, nextTopic: string) {
|
|
|
+ return {
|
|
|
+ content: `[衔接段] 时光飞逝,转眼间来到了${nextTopic}...`,
|
|
|
+ wordCount: 200,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 敏感词检测
|
|
|
+ */
|
|
|
+ async checkSensitive(text: string) {
|
|
|
+ const sensitiveWords = ['敏感词1', '敏感词2', '违规词'];
|
|
|
+ const found = sensitiveWords.filter(w => text.includes(w));
|
|
|
+
|
|
|
+ return {
|
|
|
+ isClean: found.length === 0,
|
|
|
+ foundWords: found,
|
|
|
+ positions: found.map((w, i) => ({ word: w, index: text.indexOf(w) })),
|
|
|
+ suggestions: found.length > 0 ? ['建议替换敏感词'] : [],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 质量评分
|
|
|
+ */
|
|
|
+ async scoreQuality(text: string) {
|
|
|
+ const dimensions: Record<string, number> = {};
|
|
|
+ qualityDimensions.forEach(dim => {
|
|
|
+ dimensions[dim] = 70 + Math.random() * 25;
|
|
|
+ });
|
|
|
+
|
|
|
+ const overall = Object.values(dimensions).reduce((a, b) => a + b, 0) / Object.values(dimensions).length;
|
|
|
+
|
|
|
+ return {
|
|
|
+ overall: Math.round(overall),
|
|
|
+ dimensions,
|
|
|
+ report: '内容质量分析报告...',
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内容优化
|
|
|
+ */
|
|
|
+ async optimizeContent(text: string, target: string) {
|
|
|
+ return {
|
|
|
+ original: text,
|
|
|
+ optimized: `[优化后] ${text}`,
|
|
|
+ improvements: ['语言更生动', '结构更清晰'],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取支持的语言
|
|
|
+ */
|
|
|
+ getLanguages() {
|
|
|
+ return languages;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 翻译并生成
|
|
|
+ */
|
|
|
+ async translateAndGenerate(text: string, targetLang: string, voiceStyle: string) {
|
|
|
+ return {
|
|
|
+ translated: `[${targetLang}] ${text}`,
|
|
|
+ voiceStyle,
|
|
|
+ audioUrl: `https://example.com/audio/translated-${Date.now()}.mp3`,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 智能匹配BGM
|
|
|
+ */
|
|
|
+ async matchBGM(contentType: string, mood: string, genre: string) {
|
|
|
+ return {
|
|
|
+ bgmId: `bgm-${Date.now()}`,
|
|
|
+ name: `${mood}${genre}风格音乐`,
|
|
|
+ url: 'https://example.com/bgm/matched.mp3',
|
|
|
+ duration: 180,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取音效列表
|
|
|
+ */
|
|
|
+ getSounds() {
|
|
|
+ return [
|
|
|
+ { id: 'sound-1', name: '新闻开场', type: '转场' },
|
|
|
+ { id: 'sound-2', name: '轻快背景', type: '氛围' },
|
|
|
+ { id: 'sound-3', name: '紧张时刻', type: '情感' },
|
|
|
+ ];
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 情感调节
|
|
|
+ */
|
|
|
+ async adjustEmotion(text: string, targetEmotion: string) {
|
|
|
+ return {
|
|
|
+ original: text,
|
|
|
+ adjusted: `[${targetEmotion}风格] ${text}`,
|
|
|
+ emotion: targetEmotion,
|
|
|
+ intensity: 0.8,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取情感选项
|
|
|
+ */
|
|
|
+ getEmotions() {
|
|
|
+ return emotions;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 多角色对话生成
|
|
|
+ */
|
|
|
+ async generateDialogue(characters: Array<{ name: string; voice: string }>, scenario: string) {
|
|
|
+ const lines = characters.map((char, i) => ({
|
|
|
+ character: char.name,
|
|
|
+ voice: char.voice,
|
|
|
+ dialogue: `这是${char.name}的对话内容...`,
|
|
|
+ }));
|
|
|
+ return { lines, scenario };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * SEO优化
|
|
|
+ */
|
|
|
+ async optimizeSEO(title: string, content: string, platform: string) {
|
|
|
+ return {
|
|
|
+ optimizedTitle: `[SEO优化] ${title}`,
|
|
|
+ keywords: ['关键词1', '关键词2', '关键词3'],
|
|
|
+ suggestions: ['标题添加数字', '内容分段优化'],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 合规检查
|
|
|
+ */
|
|
|
+ async checkCompliance(text: string, industry: string) {
|
|
|
+ return {
|
|
|
+ passed: true,
|
|
|
+ issues: [],
|
|
|
+ warnings: industry === '医疗健康' ? ['注意医疗广告法规'] : [],
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 内容分析报告
|
|
|
+ */
|
|
|
+ async generateAnalytics(contentId: string) {
|
|
|
+ return {
|
|
|
+ contentId,
|
|
|
+ wordCount: 5000,
|
|
|
+ readingTime: 15,
|
|
|
+ emotionCurve: [0.3, 0.5, 0.8, 0.6, 0.4],
|
|
|
+ keywords: ['关键词1', '关键词2', '关键词3'],
|
|
|
+ reportUrl: `https://example.com/analytics/${contentId}`,
|
|
|
+ };
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 智能续写
|
|
|
+ */
|
|
|
+ async continueContent(text: string, direction: string) {
|
|
|
+ return {
|
|
|
+ continuations: [
|
|
|
+ { content: `续写方向1: ${text}...`, score: 0.9 },
|
|
|
+ { content: `续写方向2: ${text}...`, score: 0.8 },
|
|
|
+ ],
|
|
|
+ selected: 0,
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+export const aiContentService = new AIContentService();
|