Spaces:
Running
Running
| /** | |
| * 概念分析步骤 | |
| * 分析用户输入,决定生成策略 | |
| */ | |
| import { generateTwoStageAIManimCode } from '../../../services/concept-designer' | |
| import { ensureJobNotCancelled } from '../../../services/job-cancel' | |
| import { createLogger } from '../../../utils/logger' | |
| import type { CustomApiConfig, OutputMode, PromptOverrides, ReferenceImage } from '../../../types' | |
| const logger = createLogger('AnalysisStep') | |
| /** | |
| * 概念分析结果 | |
| */ | |
| export interface AnalysisResult { | |
| analysisType: 'latex' | 'template' | 'ai' | 'fallback' | |
| code: string | null | |
| needsAI: boolean | |
| } | |
| /** | |
| * 代码生成结果 | |
| */ | |
| export interface GenerationResult { | |
| code: string | |
| usedAI: boolean | |
| generationType: string | |
| sceneDesign?: string | |
| } | |
| /** | |
| * 分析概念 | |
| */ | |
| export async function analyzeConcept( | |
| jobId: string, | |
| concept: string, | |
| _quality: string, | |
| outputMode: OutputMode | |
| ): Promise<AnalysisResult> { | |
| logger.info('Analyzing concept', { jobId, concept, outputMode }) | |
| logger.info('Using AI for all concepts (template shortcuts disabled)', { jobId, outputMode }) | |
| return { | |
| analysisType: 'ai', | |
| code: null, | |
| needsAI: true | |
| } | |
| } | |
| /** | |
| * 生成代码 | |
| */ | |
| export async function generateCode( | |
| jobId: string, | |
| concept: string, | |
| _quality: string, | |
| outputMode: OutputMode, | |
| analyzeResult: AnalysisResult, | |
| customApiConfig?: CustomApiConfig, | |
| promptOverrides?: PromptOverrides, | |
| referenceImages?: ReferenceImage[] | |
| ): Promise<GenerationResult> { | |
| const { analysisType, code, needsAI } = analyzeResult | |
| logger.info('Generating code', { jobId, outputMode, needsAI, analysisType, hasImages: !!referenceImages?.length }) | |
| if (needsAI) { | |
| try { | |
| logger.info('Using two-stage AI generation', { jobId, hasImages: !!referenceImages?.length }) | |
| const result = await generateTwoStageAIManimCode( | |
| concept, | |
| outputMode, | |
| customApiConfig, | |
| promptOverrides, | |
| referenceImages, | |
| () => ensureJobNotCancelled(jobId) | |
| ) | |
| if (result.code && result.code.length > 0) { | |
| logger.info('Two-stage AI code generation succeeded', { jobId, length: result.code.length, hasSceneDesign: !!result.sceneDesign }) | |
| return { | |
| code: result.code, | |
| usedAI: true, | |
| generationType: 'two-stage-ai', | |
| sceneDesign: result.sceneDesign | |
| } | |
| } | |
| throw new Error('Two-stage AI returned an empty code result') | |
| } catch (error) { | |
| logger.error('AI generation failed', { jobId, error: String(error) }) | |
| throw error | |
| } | |
| } | |
| if (code) { | |
| logger.info('Using pre-generated code', { jobId, length: code.length }) | |
| return { code, usedAI: false, generationType: analysisType } | |
| } | |
| throw new Error('No renderable code was generated') | |
| } | |
| /** | |
| * 分析并生成(合并分析+生成) | |
| */ | |
| export async function analyzeAndGenerate( | |
| jobId: string, | |
| concept: string, | |
| quality: string, | |
| outputMode: OutputMode, | |
| _timings: Record<string, number>, | |
| customApiConfig?: CustomApiConfig, | |
| promptOverrides?: PromptOverrides, | |
| referenceImages?: ReferenceImage[] | |
| ): Promise<GenerationResult> { | |
| const analysisResult = await analyzeConcept(jobId, concept, quality, outputMode) | |
| return generateCode( | |
| jobId, | |
| concept, | |
| quality, | |
| outputMode, | |
| analysisResult, | |
| customApiConfig, | |
| promptOverrides, | |
| referenceImages | |
| ) | |
| } | |