File size: 7,465 Bytes
f0e2e50
 
 
 
 
 
 
db43315
 
f0e2e50
206fb7a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
722a506
 
206fb7a
 
 
 
 
722a506
 
f0e2e50
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
722a506
 
 
206fb7a
722a506
206fb7a
722a506
db43315
 
 
 
 
206fb7a
db43315
 
 
 
206fb7a
db43315
 
 
 
206fb7a
db43315
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
"""
Performance optimization utilities for Manim rendering
"""

import re
from typing import Dict, Tuple

class PerformanceOptimizer:
    """Optimize rendering performance and resource usage"""
    
    # Quality settings for different performance levels
    QUALITY_SETTINGS = {
        "low_quality": {
            "flag": "-ql",
            "description": "Low Quality (Fast)",
            "resolution": "480p",
            "fps": 30,
            "max_duration": 10,
            "max_objects": 20,
            "performance_threshold": {
                "render_time": 60,  # seconds
                "memory_usage": 1024  # MB
            }
        },
        "medium_quality": {
            "flag": "-qm",
            "description": "Medium Quality (Balanced)",
            "resolution": "720p",
            "fps": 30,
            "max_duration": 15,
            "max_objects": 30,
            "performance_threshold": {
                "render_time": 180,  # seconds
                "memory_usage": 2048  # MB
            }
        }
    }
    
    # Performance thresholds
    PERFORMANCE_THRESHOLDS = {
        "render_time": 300,  # seconds
        "memory_usage": 4096,  # MB
        "cpu_usage": 80  # percentage
    }
    
    @classmethod
    def estimate_render_time(cls, quality: str, complexity: str = "medium") -> int:
        """Estimate rendering time in seconds"""
        base_times = {
            "low_quality": 30,
            "medium_quality": 60,
            "high_quality": 120,
            "production_quality": 300
        }
        
        complexity_multipliers = {
            "simple": 0.5,
            "medium": 1.0,
            "complex": 2.0,
            "very_complex": 3.0
        }
        
        base_time = base_times.get(quality, 60)
        multiplier = complexity_multipliers.get(complexity, 1.0)
        
        return int(base_time * multiplier)
    
    @classmethod
    def analyze_code_complexity(cls, code: str) -> str:
        """Analyze code complexity to estimate render time"""
        complexity_indicators = {
            "simple": ["Text", "Write", "Create"],
            "medium": ["Transform", "FadeIn", "FadeOut", "MoveTo"],
            "complex": ["Axes", "plot", "FunctionGraph", "BarChart"],
            "very_complex": ["ThreeDScene", "rotate", "complex", "integral"]
        }
        
        code_lower = code.lower()
        scores = {"simple": 0, "medium": 0, "complex": 0, "very_complex": 0}
        
        for complexity, indicators in complexity_indicators.items():
            for indicator in indicators:
                scores[complexity] += code_lower.count(indicator.lower())
        
        # Determine overall complexity
        max_score = max(scores.values())
        if max_score == 0:
            return "simple"
        
        return max(scores, key=scores.get)
    
    @classmethod
    def get_recommended_quality(cls, prompt_length: int, has_complex_math: bool) -> str:
        """Recommend quality based on prompt complexity"""
        if prompt_length < 50 and not has_complex_math:
            return "medium_quality"
        elif prompt_length < 100:
            return "medium_quality" 
        else:
            return "low_quality"  # Start with lower quality for complex animations
    
    @classmethod
    def optimize_code_for_performance(cls, code: str) -> str:
        """Optimize Manim code for better performance"""
        optimized_code = code
        
        # Limit excessive wait times
        optimized_code = re.sub(r'self\.wait\((\d+)\)', 
                               lambda m: f'self.wait({min(int(m.group(1)), 3)})', 
                               optimized_code)
        
        # Optimize animation run times
        optimized_code = re.sub(r'run_time=(\d+)', 
                               lambda m: f'run_time={min(int(m.group(1)), 5)}', 
                               optimized_code)
        
        # Add performance hints as comments
        performance_hints = [
            "# Performance optimized: Limited wait times to 3 seconds max",
            "# Performance optimized: Limited animation run times to 5 seconds max"
        ]
        
        if any(hint.split(": ")[1] in optimized_code for hint in performance_hints):
            optimized_code = "\n".join(performance_hints) + "\n" + optimized_code
        
        return optimized_code
    
    @classmethod
    def get_memory_efficient_settings(cls) -> Dict[str, str]:
        """Get settings for memory-efficient rendering"""
        return {
            "preview": True,
            "disable_caching": True,
            "low_quality": True,
            "save_last_frame": False,
            "write_to_movie": True
        }
    
    @classmethod
    def calculate_estimated_file_size(cls, quality: str, duration: int = 10) -> Tuple[float, str]:
        """Calculate estimated output file size in MB"""
        # Rough estimates based on quality settings
        bitrate_estimates = {
            "low_quality": 1.0,  # MB per minute
            "medium_quality": 3.0,
            "high_quality": 8.0,
            "production_quality": 25.0
        }
        
        bitrate = bitrate_estimates.get(quality, 3.0)
        size_mb = (bitrate * duration) / 60  # Convert to actual duration
        
        if size_mb < 1:
            return size_mb * 1024, "KB"
        else:
            return size_mb, "MB"
    
    @classmethod
    def get_optimization_tips(cls, quality: str, complexity: str) -> list:
        """Get optimization tips based on settings"""
        tips = []
        
        if quality in ["high_quality", "production_quality"]:
            tips.append("Consider using medium quality for faster rendering during development")
        
        if complexity in ["complex", "very_complex"]:
            tips.append("Break complex animations into smaller scenes for easier debugging")
            tips.append("Use preview mode (-p flag) to quickly test animations")
        
        tips.append("Close other applications to free up system resources")
        tips.append("Ensure sufficient disk space for temporary files")
        
        return tips

    def optimize_quality(self, available_memory: float, estimated_render_time: float) -> str:
        if available_memory < self.PERFORMANCE_THRESHOLDS["memory_usage"]:
            return "low_quality"
        if estimated_render_time > self.PERFORMANCE_THRESHOLDS["render_time"]:
            return "low_quality"
        return "medium_quality"

    @staticmethod
    def estimate_render_time(quality_level: str) -> int:
        """Estimate render time based on quality level"""
        return PerformanceOptimizer.QUALITY_SETTINGS[quality_level]["performance_threshold"]["render_time"]
    
    @staticmethod
    def get_quality_settings(quality_level: str) -> dict:
        """Get quality settings for the specified level"""
        return PerformanceOptimizer.QUALITY_SETTINGS[quality_level]
    
    @staticmethod
    def optimize_for_performance(quality_level: str, scene_complexity: int) -> dict:
        """Optimize settings based on quality level and scene complexity"""
        settings = PerformanceOptimizer.QUALITY_SETTINGS[quality_level].copy()
        
        # Adjust settings based on scene complexity
        if scene_complexity > settings["max_objects"]:
            settings["max_objects"] = min(scene_complexity, settings["max_objects"] * 2)
        
        return settings