import { Injectable } from '@angular/core'; import { AssistantSuggestion } from './assistant.service'; import { CreationBriefService } from './creation-brief.service'; import { TopicPoolService } from './topic-pool.service'; import { ViralAnalysisService } from './viral-analysis.service'; import { CreationBrief } from '../models/creation-brief.model'; import { TopicIdea, ViralAnalysis } from '../models/douyin-insight.model'; import { ViralTopicBridgeService } from './viral-topic-bridge.service'; export type ContentEntryTarget = 'topic-to-video' | 'digital-human'; export interface ContentEntryNavigation { tab: ContentEntryTarget; brief: CreationBrief; message: string; } export interface SavedTopicResult { count: number; title: string; ids: string[]; } @Injectable({ providedIn: 'root' }) export class ContentProductionEntryService { constructor( private topicPool: TopicPoolService, private creationBriefs: CreationBriefService, private viralTopicBridge: ViralTopicBridgeService, private viralAnalysis: ViralAnalysisService, ) {} saveAssistantSuggestion(suggestion: AssistantSuggestion): TopicIdea { const payload = suggestion.payload || {}; const title = String(payload['title'] || payload['topic'] || suggestion.label || '').trim(); const angle = String(payload['angle'] || payload['description'] || payload['topic'] || title).trim(); const tags = this.normalizeTags(payload['tags']); return this.topicPool.saveTopic({ title: title || 'AI 助手选题', angle: angle || title || '来自 AI 助手的选题建议', sourceType: 'assistant', sourceVideoIds: [], sourceAuthorIds: [], tags: Array.from(new Set(['AI助手', ...tags])).slice(0, 12), audience: String(payload['audience'] || ''), hook: String(payload['hook'] || title || ''), outline: String(payload['outline'] || payload['scriptFrame'] || ''), status: 'idea', pipelineTarget: 'topic_video', confidence: 'medium', }); } enterTopic(target: ContentEntryTarget, topic: TopicIdea): ContentEntryNavigation { const brief = this.creationBriefs.savePendingTopic(target, topic); return { tab: target, brief, message: `已带入选题:${topic.title}`, }; } saveManualPrefill(target: ContentEntryTarget, payload: Record): CreationBrief { return this.creationBriefs.savePendingManualPrefill(target, payload); } saveDailyReportTopics(topics: TopicIdea[]): SavedTopicResult { const saved = topics.map((topic) => this.topicPool.saveTopic({ title: topic.title, angle: topic.angle, sourceType: 'daily_report', sourceVideoIds: topic.sourceVideoIds, sourceAuthorIds: topic.sourceAuthorIds, tags: topic.tags, audience: topic.audience, hook: topic.hook, outline: topic.outline, status: 'idea', pipelineTarget: topic.pipelineTarget, confidence: topic.confidence, })); return this.savedResult(saved); } enterDailyReportTopic(topic: TopicIdea): ContentEntryNavigation { return this.enterTopic('topic-to-video', topic); } saveViralAnalysisTopics(analysis: ViralAnalysis): { result: SavedTopicResult; analysis: ViralAnalysis } { const drafts = this.viralTopicBridge.buildTopicDrafts(analysis); const existing = this.topicPool.listTopics() .filter((topic) => topic.sourceType === 'viral_analysis' && topic.sourceVideoIds?.[0] === analysis.awemeId); const saved = drafts.map((draft) => { const matched = existing.find((topic) => topic.variantIndex === draft.variantIndex); return matched ? this.topicPool.updateTopic(matched.id, draft) : this.topicPool.saveTopic(draft); }); const savedIds = new Set(saved.map((topic) => topic.id)); existing .filter((topic) => !savedIds.has(topic.id) && topic.status !== 'archived') .forEach((topic) => this.topicPool.archiveTopic(topic.id)); return { result: this.savedResult(saved), analysis: this.viralAnalysis.markTopicsSaved(analysis.id, saved.map((item) => item.id)), }; } enterViralAnalysisTopicVideo(analysis: ViralAnalysis): ContentEntryNavigation { const brief = this.viralTopicBridge.buildTopicVideoBrief(analysis); this.creationBriefs.savePendingBrief('topic-to-video', brief); return { tab: 'topic-to-video', brief, message: `已整理选题:${brief.angle || brief.title}`, }; } private normalizeTags(value: unknown): string[] { if (Array.isArray(value)) { return value.map((tag) => String(tag || '').trim()).filter(Boolean); } return String(value || '').split(/[,,\s]+/).map((tag) => tag.trim()).filter(Boolean); } private savedResult(topics: TopicIdea[]): SavedTopicResult { return { count: topics.length, title: topics[0]?.title || '', ids: topics.map((topic) => topic.id), }; } }