Hermes Bot commited on
Commit
c192821
·
1 Parent(s): 6b83839

Run on CPU: replace GPU decorators and cuda providers

Browse files
app.py CHANGED
@@ -1,106 +1,106 @@
1
- import spaces
2
- import os
3
- import sys
4
- import site
5
-
6
- if "--use-sage-attention" not in sys.argv:
7
- sys.argv.append("--use-sage-attention")
8
- print("🚀 [SageAttention] Injected '--use-sage-attention' into sys.argv.")
9
-
10
- APP_DIR = os.path.dirname(os.path.abspath(__file__))
11
- if APP_DIR not in sys.path:
12
- sys.path.insert(0, APP_DIR)
13
- print(f"✅ Added project root '{APP_DIR}' to sys.path.")
14
-
15
- SAGE_PATCH_APPLIED = False
16
-
17
- def apply_sage_attention_patch():
18
- global SAGE_PATCH_APPLIED
19
- if SAGE_PATCH_APPLIED:
20
- return "SageAttention patch already applied."
21
-
22
- try:
23
- from comfy import model_management
24
- import sageattention
25
-
26
- print("--- [Runtime Patch] sageattention package found. Applying patch... ---")
27
- model_management.sage_attention_enabled = lambda: True
28
- model_management.pytorch_attention_enabled = lambda: False
29
-
30
- SAGE_PATCH_APPLIED = True
31
- return "✅ Successfully enabled SageAttention."
32
- except ImportError:
33
- SAGE_PATCH_APPLIED = False
34
- msg = "--- [Runtime Patch] ⚠️ sageattention package not found. Continuing with default attention. ---"
35
- print(msg)
36
- return msg
37
- except Exception as e:
38
- SAGE_PATCH_APPLIED = False
39
- msg = f"--- [Runtime Patch] ❌ An error occurred while applying SageAttention patch: {e} ---"
40
- print(msg)
41
- return msg
42
-
43
- @spaces.GPU
44
- def dummy_gpu_for_startup():
45
- try:
46
- print("--- [GPU Startup] Dummy function for startup check initiated. ---")
47
- patch_result = apply_sage_attention_patch()
48
- print(f"--- [GPU Startup] {patch_result} ---")
49
- print("--- [GPU Startup] Startup check passed. ---")
50
- return "Startup check passed."
51
- except BaseException as e:
52
- err_msg = str(e)
53
- if "uncorrectable ECC error" in err_msg or "cudaErrorECCUncorrectable" in err_msg:
54
- print("\n" + "="*80)
55
- print(f"🚨 [Fatal GPU Error] Captured uncorrectable ECC error during inference: {err_msg}")
56
- print("🚨 Terminating process to trigger an automatic container restart...")
57
- print("="*80 + "\n")
58
- os._exit(1)
59
- raise e
60
-
61
-
62
- def main():
63
- from comfy_integration import setup as setup_comfyui
64
- from utils.app_utils import load_ipadapter_presets
65
-
66
- print("--- [Setup] Starting ComfyUI initialization ---")
67
- setup_comfyui.initialize_comfyui()
68
-
69
- print("--- [Setup] Applying SageAttention Runtime Patch ---")
70
- patch_result = apply_sage_attention_patch()
71
- print(f"--- [Setup] {patch_result} ---")
72
-
73
- print("--- [Setup] Reloading site-packages to detect newly installed packages... ---")
74
- try:
75
- site.main()
76
- print("--- [Setup] ✅ Site-packages reloaded. ---")
77
- except Exception as e:
78
- print(f"--- [Setup] ⚠️ Warning: Could not fully reload site-packages: {e} ---")
79
-
80
- print("--- Initiating GPU Startup Check & SageAttention Patch Verification ---")
81
- try:
82
- dummy_gpu_for_startup()
83
- except Exception as e:
84
- print(f"--- [GPU Startup] ⚠️ Warning: Startup check failed: {e} ---")
85
-
86
- print("--- Starting Application Setup ---")
87
-
88
- print("--- Loading IPAdapter presets ---")
89
- load_ipadapter_presets()
90
- print("--- ✅ IPAdapter setup complete. ---")
91
-
92
-
93
- print("--- Environment configured. Proceeding with module imports. ---")
94
- from ui.layout import build_ui
95
- from ui.events import attach_event_handlers
96
-
97
- print(f"✅ Working directory is stable: {os.getcwd()}")
98
-
99
- demo = build_ui(attach_event_handlers)
100
-
101
- print("--- Launching Gradio Interface ---")
102
- demo.queue().launch(server_name="0.0.0.0", server_port=7860)
103
-
104
-
105
- if __name__ == "__main__":
106
  main()
 
1
+ import spaces
2
+ import os
3
+ import sys
4
+ import site
5
+
6
+ if "--use-sage-attention" not in sys.argv:
7
+ sys.argv.append("--use-sage-attention")
8
+ print("🚀 [SageAttention] Injected '--use-sage-attention' into sys.argv.")
9
+
10
+ APP_DIR = os.path.dirname(os.path.abspath(__file__))
11
+ if APP_DIR not in sys.path:
12
+ sys.path.insert(0, APP_DIR)
13
+ print(f"✅ Added project root '{APP_DIR}' to sys.path.")
14
+
15
+ SAGE_PATCH_APPLIED = False
16
+
17
+ def apply_sage_attention_patch():
18
+ global SAGE_PATCH_APPLIED
19
+ if SAGE_PATCH_APPLIED:
20
+ return "SageAttention patch already applied."
21
+
22
+ try:
23
+ from comfy import model_management
24
+ import sageattention
25
+
26
+ print("--- [Runtime Patch] sageattention package found. Applying patch... ---")
27
+ model_management.sage_attention_enabled = lambda: True
28
+ model_management.pytorch_attention_enabled = lambda: False
29
+
30
+ SAGE_PATCH_APPLIED = True
31
+ return "✅ Successfully enabled SageAttention."
32
+ except ImportError:
33
+ SAGE_PATCH_APPLIED = False
34
+ msg = "--- [Runtime Patch] ⚠️ sageattention package not found. Continuing with default attention. ---"
35
+ print(msg)
36
+ return msg
37
+ except Exception as e:
38
+ SAGE_PATCH_APPLIED = False
39
+ msg = f"--- [Runtime Patch] ❌ An error occurred while applying SageAttention patch: {e} ---"
40
+ print(msg)
41
+ return msg
42
+
43
+ # @spaces.cpu (disabled for CPU)
44
+ def dummy_gpu_for_startup():
45
+ try:
46
+ print("--- [GPU Startup] Dummy function for startup check initiated. ---")
47
+ patch_result = apply_sage_attention_patch()
48
+ print(f"--- [GPU Startup] {patch_result} ---")
49
+ print("--- [GPU Startup] Startup check passed. ---")
50
+ return "Startup check passed."
51
+ except BaseException as e:
52
+ err_msg = str(e)
53
+ if "uncorrectable ECC error" in err_msg or "cudaErrorECCUncorrectable" in err_msg:
54
+ print("\n" + "="*80)
55
+ print(f"🚨 [Fatal GPU Error] Captured uncorrectable ECC error during inference: {err_msg}")
56
+ print("🚨 Terminating process to trigger an automatic container restart...")
57
+ print("="*80 + "\n")
58
+ os._exit(1)
59
+ raise e
60
+
61
+
62
+ def main():
63
+ from comfy_integration import setup as setup_comfyui
64
+ from utils.app_utils import load_ipadapter_presets
65
+
66
+ print("--- [Setup] Starting ComfyUI initialization ---")
67
+ setup_comfyui.initialize_comfyui()
68
+
69
+ print("--- [Setup] Applying SageAttention Runtime Patch ---")
70
+ patch_result = apply_sage_attention_patch()
71
+ print(f"--- [Setup] {patch_result} ---")
72
+
73
+ print("--- [Setup] Reloading site-packages to detect newly installed packages... ---")
74
+ try:
75
+ site.main()
76
+ print("--- [Setup] ✅ Site-packages reloaded. ---")
77
+ except Exception as e:
78
+ print(f"--- [Setup] ⚠️ Warning: Could not fully reload site-packages: {e} ---")
79
+
80
+ print("--- Initiating GPU Startup Check & SageAttention Patch Verification ---")
81
+ try:
82
+ dummy_gpu_for_startup()
83
+ except Exception as e:
84
+ print(f"--- [GPU Startup] ⚠️ Warning: Startup check failed: {e} ---")
85
+
86
+ print("--- Starting Application Setup ---")
87
+
88
+ print("--- Loading IPAdapter presets ---")
89
+ load_ipadapter_presets()
90
+ print("--- ✅ IPAdapter setup complete. ---")
91
+
92
+
93
+ print("--- Environment configured. Proceeding with module imports. ---")
94
+ from ui.layout import build_ui
95
+ from ui.events import attach_event_handlers
96
+
97
+ print(f"✅ Working directory is stable: {os.getcwd()}")
98
+
99
+ demo = build_ui(attach_event_handlers)
100
+
101
+ print("--- Launching Gradio Interface ---")
102
+ demo.queue().launch(server_name="0.0.0.0", server_port=7860)
103
+
104
+
105
+ if __name__ == "__main__":
106
  main()
chain_injectors/flux1_ipadapter_injector.py CHANGED
@@ -1,46 +1,46 @@
1
- def inject(assembler, chain_definition, chain_items):
2
- if not chain_items:
3
- return
4
-
5
- ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
6
- if ksampler_name not in assembler.node_map:
7
- print(f"Warning: KSampler node '{ksampler_name}' not found for Flux1 IPAdapter chain. Skipping.")
8
- return
9
-
10
- ksampler_id = assembler.node_map[ksampler_name]
11
-
12
- if 'model' not in assembler.workflow[ksampler_id]['inputs']:
13
- print(f"Warning: KSampler node '{ksampler_name}' is missing 'model' input. Skipping Flux1 IPAdapter chain.")
14
- return
15
-
16
- current_model_connection = assembler.workflow[ksampler_id]['inputs']['model']
17
-
18
- for item_data in chain_items:
19
- image_loader_id = assembler._get_unique_id()
20
- image_loader_node = assembler._get_node_template("LoadImage")
21
- image_loader_node['inputs']['image'] = item_data['image']
22
- assembler.workflow[image_loader_id] = image_loader_node
23
-
24
- ipadapter_loader_id = assembler._get_unique_id()
25
- ipadapter_loader_node = assembler._get_node_template("IPAdapterFluxLoader")
26
- ipadapter_loader_node['inputs']['ipadapter'] = "ip-adapter.bin"
27
- ipadapter_loader_node['inputs']['clip_vision'] = "google/siglip-so400m-patch14-384"
28
- ipadapter_loader_node['inputs']['provider'] = "cuda"
29
- assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
30
-
31
- apply_ipa_id = assembler._get_unique_id()
32
- apply_ipa_node = assembler._get_node_template("ApplyIPAdapterFlux")
33
-
34
- apply_ipa_node['inputs']['weight'] = item_data['weight']
35
- apply_ipa_node['inputs']['start_percent'] = item_data.get('start_percent', 0.0)
36
- apply_ipa_node['inputs']['end_percent'] = item_data.get('end_percent', 0.6)
37
-
38
- apply_ipa_node['inputs']['model'] = current_model_connection
39
- apply_ipa_node['inputs']['ipadapter_flux'] = [ipadapter_loader_id, 0]
40
- apply_ipa_node['inputs']['image'] = [image_loader_id, 0]
41
-
42
- assembler.workflow[apply_ipa_id] = apply_ipa_node
43
- current_model_connection = [apply_ipa_id, 0]
44
-
45
- assembler.workflow[ksampler_id]['inputs']['model'] = current_model_connection
46
  print(f"Flux1 IPAdapter injector applied. KSampler model input re-routed through {len(chain_items)} IPAdapter(s).")
 
1
+ def inject(assembler, chain_definition, chain_items):
2
+ if not chain_items:
3
+ return
4
+
5
+ ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
6
+ if ksampler_name not in assembler.node_map:
7
+ print(f"Warning: KSampler node '{ksampler_name}' not found for Flux1 IPAdapter chain. Skipping.")
8
+ return
9
+
10
+ ksampler_id = assembler.node_map[ksampler_name]
11
+
12
+ if 'model' not in assembler.workflow[ksampler_id]['inputs']:
13
+ print(f"Warning: KSampler node '{ksampler_name}' is missing 'model' input. Skipping Flux1 IPAdapter chain.")
14
+ return
15
+
16
+ current_model_connection = assembler.workflow[ksampler_id]['inputs']['model']
17
+
18
+ for item_data in chain_items:
19
+ image_loader_id = assembler._get_unique_id()
20
+ image_loader_node = assembler._get_node_template("LoadImage")
21
+ image_loader_node['inputs']['image'] = item_data['image']
22
+ assembler.workflow[image_loader_id] = image_loader_node
23
+
24
+ ipadapter_loader_id = assembler._get_unique_id()
25
+ ipadapter_loader_node = assembler._get_node_template("IPAdapterFluxLoader")
26
+ ipadapter_loader_node['inputs']['ipadapter'] = "ip-adapter.bin"
27
+ ipadapter_loader_node['inputs']['clip_vision'] = "google/siglip-so400m-patch14-384"
28
+ ipadapter_loader_node['inputs']['provider'] = "cpu"
29
+ assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
30
+
31
+ apply_ipa_id = assembler._get_unique_id()
32
+ apply_ipa_node = assembler._get_node_template("ApplyIPAdapterFlux")
33
+
34
+ apply_ipa_node['inputs']['weight'] = item_data['weight']
35
+ apply_ipa_node['inputs']['start_percent'] = item_data.get('start_percent', 0.0)
36
+ apply_ipa_node['inputs']['end_percent'] = item_data.get('end_percent', 0.6)
37
+
38
+ apply_ipa_node['inputs']['model'] = current_model_connection
39
+ apply_ipa_node['inputs']['ipadapter_flux'] = [ipadapter_loader_id, 0]
40
+ apply_ipa_node['inputs']['image'] = [image_loader_id, 0]
41
+
42
+ assembler.workflow[apply_ipa_id] = apply_ipa_node
43
+ current_model_connection = [apply_ipa_id, 0]
44
+
45
+ assembler.workflow[ksampler_id]['inputs']['model'] = current_model_connection
46
  print(f"Flux1 IPAdapter injector applied. KSampler model input re-routed through {len(chain_items)} IPAdapter(s).")
chain_injectors/sd3_ipadapter_injector.py CHANGED
@@ -1,66 +1,66 @@
1
- def inject(assembler, chain_definition, chain_items):
2
- if not chain_items:
3
- return
4
-
5
- ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
6
- if ksampler_name not in assembler.node_map:
7
- print(f"Warning: KSampler node '{ksampler_name}' not found for SD3 IPAdapter chain. Skipping.")
8
- return
9
-
10
- ksampler_id = assembler.node_map[ksampler_name]
11
-
12
- if 'model' not in assembler.workflow[ksampler_id]['inputs']:
13
- print(f"Warning: KSampler node '{ksampler_name}' is missing 'model' input. Skipping SD3 IPAdapter chain.")
14
- return
15
-
16
- current_model_connection = assembler.workflow[ksampler_id]['inputs']['model']
17
-
18
- clip_vision_loader_id = assembler._get_unique_id()
19
- clip_vision_loader_node = assembler._get_node_template("CLIPVisionLoader")
20
- clip_vision_loader_node['inputs']['clip_name'] = "sigclip_vision_patch14_384.safetensors"
21
- assembler.workflow[clip_vision_loader_id] = clip_vision_loader_node
22
-
23
- ipadapter_loader_id = assembler._get_unique_id()
24
- ipadapter_loader_node = assembler._get_node_template("IPAdapterSD3Loader")
25
- ipadapter_loader_node['inputs']['ipadapter'] = "ip-adapter_sd35l_instantx.bin"
26
- ipadapter_loader_node['inputs']['provider'] = "cuda"
27
- assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
28
-
29
- for item_data in chain_items:
30
- image_loader_id = assembler._get_unique_id()
31
- image_loader_node = assembler._get_node_template("LoadImage")
32
- image_loader_node['inputs']['image'] = item_data['image']
33
- assembler.workflow[image_loader_id] = image_loader_node
34
-
35
- image_scaler_id = assembler._get_unique_id()
36
- image_scaler_node = assembler._get_node_template("ImageScaleToTotalPixels")
37
- image_scaler_node['inputs']['image'] = [image_loader_id, 0]
38
- image_scaler_node['inputs']['upscale_method'] = 'nearest-exact'
39
- image_scaler_node['inputs']['megapixels'] = 1.0
40
- assembler.workflow[image_scaler_id] = image_scaler_node
41
-
42
- clip_vision_encode_id = assembler._get_unique_id()
43
- clip_vision_encode_node = assembler._get_node_template("CLIPVisionEncode")
44
- clip_vision_encode_node['inputs']['crop'] = "center"
45
- clip_vision_encode_node['inputs']['clip_vision'] = [clip_vision_loader_id, 0]
46
- clip_vision_encode_node['inputs']['image'] = [image_scaler_id, 0]
47
- assembler.workflow[clip_vision_encode_id] = clip_vision_encode_node
48
-
49
- apply_ipa_id = assembler._get_unique_id()
50
- apply_ipa_node = assembler._get_node_template("ApplyIPAdapterSD3")
51
-
52
- apply_ipa_node['inputs']['weight'] = item_data.get('weight', 1.0)
53
- apply_ipa_node['inputs']['start_percent'] = item_data.get('start_percent', 0.0)
54
- apply_ipa_node['inputs']['end_percent'] = item_data.get('end_percent', 1.0)
55
-
56
- apply_ipa_node['inputs']['model'] = current_model_connection
57
- apply_ipa_node['inputs']['ipadapter'] = [ipadapter_loader_id, 0]
58
- apply_ipa_node['inputs']['image_embed'] = [clip_vision_encode_id, 0]
59
-
60
- assembler.workflow[apply_ipa_id] = apply_ipa_node
61
-
62
- current_model_connection = [apply_ipa_id, 0]
63
-
64
- assembler.workflow[ksampler_id]['inputs']['model'] = current_model_connection
65
-
66
  print(f"SD3 IPAdapter injector applied. KSampler model input re-routed through {len(chain_items)} IPAdapter(s).")
 
1
+ def inject(assembler, chain_definition, chain_items):
2
+ if not chain_items:
3
+ return
4
+
5
+ ksampler_name = chain_definition.get('ksampler_node', 'ksampler')
6
+ if ksampler_name not in assembler.node_map:
7
+ print(f"Warning: KSampler node '{ksampler_name}' not found for SD3 IPAdapter chain. Skipping.")
8
+ return
9
+
10
+ ksampler_id = assembler.node_map[ksampler_name]
11
+
12
+ if 'model' not in assembler.workflow[ksampler_id]['inputs']:
13
+ print(f"Warning: KSampler node '{ksampler_name}' is missing 'model' input. Skipping SD3 IPAdapter chain.")
14
+ return
15
+
16
+ current_model_connection = assembler.workflow[ksampler_id]['inputs']['model']
17
+
18
+ clip_vision_loader_id = assembler._get_unique_id()
19
+ clip_vision_loader_node = assembler._get_node_template("CLIPVisionLoader")
20
+ clip_vision_loader_node['inputs']['clip_name'] = "sigclip_vision_patch14_384.safetensors"
21
+ assembler.workflow[clip_vision_loader_id] = clip_vision_loader_node
22
+
23
+ ipadapter_loader_id = assembler._get_unique_id()
24
+ ipadapter_loader_node = assembler._get_node_template("IPAdapterSD3Loader")
25
+ ipadapter_loader_node['inputs']['ipadapter'] = "ip-adapter_sd35l_instantx.bin"
26
+ ipadapter_loader_node['inputs']['provider'] = "cpu"
27
+ assembler.workflow[ipadapter_loader_id] = ipadapter_loader_node
28
+
29
+ for item_data in chain_items:
30
+ image_loader_id = assembler._get_unique_id()
31
+ image_loader_node = assembler._get_node_template("LoadImage")
32
+ image_loader_node['inputs']['image'] = item_data['image']
33
+ assembler.workflow[image_loader_id] = image_loader_node
34
+
35
+ image_scaler_id = assembler._get_unique_id()
36
+ image_scaler_node = assembler._get_node_template("ImageScaleToTotalPixels")
37
+ image_scaler_node['inputs']['image'] = [image_loader_id, 0]
38
+ image_scaler_node['inputs']['upscale_method'] = 'nearest-exact'
39
+ image_scaler_node['inputs']['megapixels'] = 1.0
40
+ assembler.workflow[image_scaler_id] = image_scaler_node
41
+
42
+ clip_vision_encode_id = assembler._get_unique_id()
43
+ clip_vision_encode_node = assembler._get_node_template("CLIPVisionEncode")
44
+ clip_vision_encode_node['inputs']['crop'] = "center"
45
+ clip_vision_encode_node['inputs']['clip_vision'] = [clip_vision_loader_id, 0]
46
+ clip_vision_encode_node['inputs']['image'] = [image_scaler_id, 0]
47
+ assembler.workflow[clip_vision_encode_id] = clip_vision_encode_node
48
+
49
+ apply_ipa_id = assembler._get_unique_id()
50
+ apply_ipa_node = assembler._get_node_template("ApplyIPAdapterSD3")
51
+
52
+ apply_ipa_node['inputs']['weight'] = item_data.get('weight', 1.0)
53
+ apply_ipa_node['inputs']['start_percent'] = item_data.get('start_percent', 0.0)
54
+ apply_ipa_node['inputs']['end_percent'] = item_data.get('end_percent', 1.0)
55
+
56
+ apply_ipa_node['inputs']['model'] = current_model_connection
57
+ apply_ipa_node['inputs']['ipadapter'] = [ipadapter_loader_id, 0]
58
+ apply_ipa_node['inputs']['image_embed'] = [clip_vision_encode_id, 0]
59
+
60
+ assembler.workflow[apply_ipa_id] = apply_ipa_node
61
+
62
+ current_model_connection = [apply_ipa_id, 0]
63
+
64
+ assembler.workflow[ksampler_id]['inputs']['model'] = current_model_connection
65
+
66
  print(f"SD3 IPAdapter injector applied. KSampler model input re-routed through {len(chain_items)} IPAdapter(s).")
core/pipelines/base_pipeline.py CHANGED
@@ -1,65 +1,66 @@
1
- from abc import ABC, abstractmethod
2
- from typing import List, Any, Dict
3
- import gradio as gr
4
- import spaces
5
- import tempfile
6
- import imageio
7
- import numpy as np
8
- import sys
9
- import os
10
-
11
- class BasePipeline(ABC):
12
- def __init__(self):
13
- from core.model_manager import model_manager
14
- self.model_manager = model_manager
15
-
16
- @abstractmethod
17
- def get_required_models(self, **kwargs) -> List[str]:
18
- pass
19
-
20
- @abstractmethod
21
- def run(self, *args, progress: gr.Progress, **kwargs) -> Any:
22
- pass
23
-
24
- def _ensure_models_downloaded(self, progress: gr.Progress, **kwargs):
25
- """Ensures model files are downloaded before requesting GPU."""
26
- required_models = self.get_required_models(**kwargs)
27
- self.model_manager.ensure_models_downloaded(required_models, progress=progress)
28
-
29
- def _execute_gpu_logic(self, gpu_function: callable, duration: int, default_duration: int, task_name: str, *args, **kwargs):
30
- final_duration = default_duration
31
- try:
32
- if duration is not None and int(duration) > 0:
33
- final_duration = int(duration)
34
- except (ValueError, TypeError):
35
- print(f"Invalid ZeroGPU duration input for {task_name}. Using default {default_duration}s.")
36
- pass
37
-
38
- print(f"Requesting ZeroGPU for {task_name} with duration: {final_duration} seconds.")
39
- gpu_runner = spaces.GPU(duration=final_duration)(gpu_function)
40
-
41
- try:
42
- return gpu_runner(*args, **kwargs)
43
- except BaseException as e:
44
- err_msg = str(e)
45
- if "uncorrectable ECC error" in err_msg or "cudaErrorECCUncorrectable" in err_msg:
46
- print("\n" + "="*80)
47
- print(f"🚨 [Fatal GPU Error] Captured uncorrectable ECC error during inference: {err_msg}")
48
- print("🚨 Terminating process to trigger an automatic container restart...")
49
- print("="*80 + "\n")
50
- os._exit(1)
51
- raise e
52
-
53
- def _encode_video_from_frames(self, frames_tensor_cpu: 'torch.Tensor', fps: int, progress: gr.Progress) -> str:
54
- progress(0.9, desc="Encoding video on CPU...")
55
- frames_np = (frames_tensor_cpu.numpy() * 255.0).astype(np.uint8)
56
-
57
- with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as temp_video_file:
58
- video_path = temp_video_file.name
59
- writer = imageio.get_writer(video_path, fps=fps, codec='libx264', quality=8)
60
- for frame in frames_np:
61
- writer.append_data(frame)
62
- writer.close()
63
-
64
- progress(1.0, desc="Done!")
 
65
  return video_path
 
1
+ from abc import ABC, abstractmethod
2
+ from typing import List, Any, Dict
3
+ import gradio as gr
4
+ import spaces
5
+ import tempfile
6
+ import imageio
7
+ import numpy as np
8
+ import sys
9
+ import os
10
+
11
+ class BasePipeline(ABC):
12
+ def __init__(self):
13
+ from core.model_manager import model_manager
14
+ self.model_manager = model_manager
15
+
16
+ @abstractmethod
17
+ def get_required_models(self, **kwargs) -> List[str]:
18
+ pass
19
+
20
+ @abstractmethod
21
+ def run(self, *args, progress: gr.Progress, **kwargs) -> Any:
22
+ pass
23
+
24
+ def _ensure_models_downloaded(self, progress: gr.Progress, **kwargs):
25
+ """Ensures model files are downloaded before requesting GPU."""
26
+ required_models = self.get_required_models(**kwargs)
27
+ self.model_manager.ensure_models_downloaded(required_models, progress=progress)
28
+
29
+ def _execute_gpu_logic(self, gpu_function: callable, duration: int, default_duration: int, task_name: str, *args, **kwargs):
30
+ final_duration = default_duration
31
+ try:
32
+ if duration is not None and int(duration) > 0:
33
+ final_duration = int(duration)
34
+ except (ValueError, TypeError):
35
+ print(f"Invalid ZeroGPU duration input for {task_name}. Using default {default_duration}s.")
36
+ pass
37
+
38
+ print(f"Requesting ZeroGPU for {task_name} with duration: {final_duration} seconds.")
39
+ # Direct call without GPU allocation for CPU execution
40
+ gpu_runner = gpu_function
41
+
42
+ try:
43
+ return gpu_runner(*args, **kwargs)
44
+ except BaseException as e:
45
+ err_msg = str(e)
46
+ if "uncorrectable ECC error" in err_msg or "cudaErrorECCUncorrectable" in err_msg:
47
+ print("\n" + "="*80)
48
+ print(f"🚨 [Fatal GPU Error] Captured uncorrectable ECC error during inference: {err_msg}")
49
+ print("🚨 Terminating process to trigger an automatic container restart...")
50
+ print("="*80 + "\n")
51
+ os._exit(1)
52
+ raise e
53
+
54
+ def _encode_video_from_frames(self, frames_tensor_cpu: 'torch.Tensor', fps: int, progress: gr.Progress) -> str:
55
+ progress(0.9, desc="Encoding video on CPU...")
56
+ frames_np = (frames_tensor_cpu.numpy() * 255.0).astype(np.uint8)
57
+
58
+ with tempfile.NamedTemporaryFile(suffix=".mp4", delete=False) as temp_video_file:
59
+ video_path = temp_video_file.name
60
+ writer = imageio.get_writer(video_path, fps=fps, codec='libx264', quality=8)
61
+ for frame in frames_np:
62
+ writer.append_data(frame)
63
+ writer.close()
64
+
65
+ progress(1.0, desc="Done!")
66
  return video_path