返回 Pixelle-Video
linear.py
1 # Copyright (C) 2025 AIDC-AI
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 # http://www.apache.org/licenses/LICENSE-2.0
7 # Unless required by applicable law or agreed to in writing, software
8 # distributed under the License is distributed on an "AS IS" BASIS,
9 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 # See the License for the specific language governing permissions and
11 # limitations under the License.
12
13 """
14 Linear Video Pipeline Base Class
15
16 This module defines the template method pattern for linear video generation workflows.
17 It introduces `PipelineContext` for state management and `LinearVideoPipeline` for
18 process orchestration.
19 """
20
21 from dataclasses import dataclass, field
22 from typing import Optional, List, Dict, Any, Callable
23 from loguru import logger
24
25 from pixelle_video.pipelines.base import BasePipeline
26 from pixelle_video.models.storyboard import (
27 Storyboard,
28 VideoGenerationResult,
29 StoryboardConfig
30 )
31 from pixelle_video.models.progress import ProgressEvent
32
33
34 @dataclass
35 class PipelineContext:
36 """
37 Context object holding the state of a single pipeline execution.
38
39 This object is passed between steps in the LinearVideoPipeline lifecycle.
40 """
41 # === Input ===
42 input_text: str
43 params: Dict[str, Any]
44 progress_callback: Optional[Callable[[ProgressEvent], None]] = None
45
46 # === Task State ===
47 task_id: Optional[str] = None
48 task_dir: Optional[str] = None
49
50 # === Content ===
51 title: Optional[str] = None
52 narrations: List[str] = field(default_factory=list)
53
54 # === Visuals ===
55 image_prompts: List[Optional[str]] = field(default_factory=list)
56
57 # === Configuration & Storyboard ===
58 config: Optional[StoryboardConfig] = None
59 storyboard: Optional[Storyboard] = None
60
61 # === Output ===
62 final_video_path: Optional[str] = None
63 result: Optional[VideoGenerationResult] = None
64
65
66 class LinearVideoPipeline(BasePipeline):
67 """
68 Base class for linear video generation pipelines using the Template Method pattern.
69
70 This class orchestrates the video generation process into distinct lifecycle steps:
71 1. setup_environment
72 2. generate_content
73 3. determine_title
74 4. plan_visuals
75 5. initialize_storyboard
76 6. produce_assets
77 7. post_production
78 8. finalize
79
80 Subclasses should override specific steps to customize behavior while maintaining
81 the overall workflow structure.
82 """
83
84 async def __call__(
85 self,
86 text: str,
87 progress_callback: Optional[Callable[[ProgressEvent], None]] = None,
88 **kwargs
89 ) -> VideoGenerationResult:
90 """
91 Execute the pipeline using the template method.
92 """
93 # 1. Initialize context
94 ctx = PipelineContext(
95 input_text=text,
96 params=kwargs,
97 progress_callback=progress_callback
98 )
99
100 try:
101 # === Phase 1: Preparation ===
102 await self.setup_environment(ctx)
103
104 # === Phase 2: Content Creation ===
105 await self.generate_content(ctx)
106 await self.determine_title(ctx)
107
108 # === Phase 3: Visual Planning ===
109 await self.plan_visuals(ctx)
110 await self.initialize_storyboard(ctx)
111
112 # === Phase 4: Asset Production ===
113 await self.produce_assets(ctx)
114
115 # === Phase 5: Post Production ===
116 await self.post_production(ctx)
117
118 # === Phase 6: Finalization ===
119 return await self.finalize(ctx)
120
121 except Exception as e:
122 await self.handle_exception(ctx, e)
123 raise
124
125 # ==================== Lifecycle Methods ====================
126
127 async def setup_environment(self, ctx: PipelineContext):
128 """Step 1: Setup task directory and environment."""
129 pass
130
131 async def generate_content(self, ctx: PipelineContext):
132 """Step 2: Generate or process script/narrations."""
133 pass
134
135 async def determine_title(self, ctx: PipelineContext):
136 """Step 3: Determine or generate video title."""
137 pass
138
139 async def plan_visuals(self, ctx: PipelineContext):
140 """Step 4: Generate image prompts or visual descriptions."""
141 pass
142
143 async def initialize_storyboard(self, ctx: PipelineContext):
144 """Step 5: Create Storyboard object and frames."""
145 pass
146
147 async def produce_assets(self, ctx: PipelineContext):
148 """Step 6: Generate audio, images, and render frames (Core processing)."""
149 pass
150
151 async def post_production(self, ctx: PipelineContext):
152 """Step 7: Concatenate videos and add BGM."""
153 pass
154
155 async def finalize(self, ctx: PipelineContext) -> VideoGenerationResult:
156 """Step 8: Create result object and persist metadata."""
157 raise NotImplementedError("finalize must be implemented by subclass")
158
159 async def handle_exception(self, ctx: PipelineContext, error: Exception):
160 """Handle exceptions during pipeline execution."""
161 logger.error(f"Pipeline execution failed: {error}")
162
162 lines PYTHON