Spaces:
Running
on
Zero
Running
on
Zero
Commit
·
1082c60
1
Parent(s):
da097bc
增强调试信息和异常处理,优化FIFO队列操作,确保生成过程中的信号推送和中断逻辑更加可靠
Browse files- app.py +70 -14
- diffusers_helper/thread_utils.py +50 -3
app.py
CHANGED
@@ -672,10 +672,23 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
672 |
|
673 |
try:
|
674 |
# 首先检查是否有停止信号
|
675 |
-
|
676 |
-
|
677 |
-
stream.
|
678 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
679 |
|
680 |
preview = d['denoised']
|
681 |
preview = vae_decode_fake(preview)
|
@@ -688,12 +701,15 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
688 |
hint = f'Sampling {current_step}/{steps}'
|
689 |
desc = f'Total generated frames: {int(max(0, total_generated_latent_frames * 4 - 3))}, Video length: {max(0, (total_generated_latent_frames * 4 - 3) / 30) :.2f} seconds (FPS-30). The video is being extended now ...'
|
690 |
stream.output_queue.push(('progress', (preview, desc, make_progress_bar_html(percentage, hint))))
|
691 |
-
except KeyboardInterrupt:
|
692 |
# 捕获并重新抛出中断异常,确保它能传播到采样函数
|
|
|
|
|
693 |
raise
|
694 |
except Exception as e:
|
695 |
-
print(f"
|
696 |
# 不中断采样过程
|
|
|
697 |
return
|
698 |
|
699 |
try:
|
@@ -701,6 +717,7 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
701 |
print(f"开始采样,设备: {device}, 数据类型: {transformer.dtype}, 使用TeaCache: {use_teacache and not cpu_fallback_mode}")
|
702 |
|
703 |
try:
|
|
|
704 |
generated_latents = sample_hunyuan(
|
705 |
transformer=transformer,
|
706 |
sampler='unipc',
|
@@ -732,20 +749,26 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
732 |
callback=callback,
|
733 |
)
|
734 |
|
735 |
-
print(f"
|
736 |
-
except KeyboardInterrupt:
|
737 |
# 用户主动中断
|
738 |
-
print("
|
|
|
739 |
|
740 |
# 如果已经有生成的视频,返回最后生成的视频
|
741 |
if last_output_filename:
|
|
|
742 |
stream.output_queue.push(('file', last_output_filename))
|
743 |
error_msg = "用户中断生成过程,但已生成部分视频"
|
744 |
else:
|
|
|
745 |
error_msg = "用户中断生成过程,未生成视频"
|
746 |
|
|
|
747 |
stream.output_queue.push(('error', error_msg))
|
|
|
748 |
stream.output_queue.push(('end', None))
|
|
|
749 |
return
|
750 |
except Exception as e:
|
751 |
print(f"采样过程中出错: {e}")
|
@@ -850,26 +873,39 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
850 |
if is_last_section:
|
851 |
break
|
852 |
except Exception as e:
|
853 |
-
print(f"
|
|
|
854 |
traceback.print_exc()
|
|
|
|
|
|
|
|
|
855 |
|
856 |
if not high_vram and not cpu_fallback_mode:
|
857 |
try:
|
|
|
858 |
unload_complete_models(
|
859 |
text_encoder, text_encoder_2, image_encoder, vae, transformer
|
860 |
)
|
861 |
-
|
|
|
|
|
862 |
pass
|
863 |
|
864 |
# 如果已经有生成的视频,返回最后生成的视频
|
865 |
if last_output_filename:
|
|
|
866 |
stream.output_queue.push(('file', last_output_filename))
|
|
|
|
|
867 |
|
868 |
# 返回错误信息
|
869 |
error_msg = f"处理过程中出现错误: {e}"
|
|
|
870 |
stream.output_queue.push(('error', error_msg))
|
871 |
|
872 |
# 确保总是返回end信号
|
|
|
873 |
stream.output_queue.push(('end', None))
|
874 |
return
|
875 |
|
@@ -1032,12 +1068,32 @@ else:
|
|
1032 |
|
1033 |
def end_process():
|
1034 |
"""停止生成过程函数 - 通过在队列中推送'end'信号来中断生成"""
|
1035 |
-
print("
|
1036 |
# 确保stream已初始化
|
1037 |
if 'stream' in globals() and stream is not None:
|
1038 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1039 |
else:
|
1040 |
-
print("
|
1041 |
return None
|
1042 |
|
1043 |
|
|
|
672 |
|
673 |
try:
|
674 |
# 首先检查是否有停止信号
|
675 |
+
print(f"【调试】回调函数: 步骤 {d['i']}, 检查是否有停止信号")
|
676 |
+
try:
|
677 |
+
queue_top = stream.input_queue.top()
|
678 |
+
print(f"【调试】回调函数: 队列顶部信号 = {queue_top}")
|
679 |
+
|
680 |
+
if queue_top == 'end':
|
681 |
+
print("【调试】回调函数: 检测到停止信号,准备中断...")
|
682 |
+
try:
|
683 |
+
stream.output_queue.push(('end', None))
|
684 |
+
print("【调试】回调函数: 成功向输出队列推送end信号")
|
685 |
+
except Exception as e:
|
686 |
+
print(f"【调试】回调函数: 向输出队列推送end信号失败: {e}")
|
687 |
+
|
688 |
+
print("【调试】回调函数: 即将抛出KeyboardInterrupt异常")
|
689 |
+
raise KeyboardInterrupt('用户主动结束任务')
|
690 |
+
except Exception as e:
|
691 |
+
print(f"【调试】回调函数: 检查队列顶部信号出错: {e}")
|
692 |
|
693 |
preview = d['denoised']
|
694 |
preview = vae_decode_fake(preview)
|
|
|
701 |
hint = f'Sampling {current_step}/{steps}'
|
702 |
desc = f'Total generated frames: {int(max(0, total_generated_latent_frames * 4 - 3))}, Video length: {max(0, (total_generated_latent_frames * 4 - 3) / 30) :.2f} seconds (FPS-30). The video is being extended now ...'
|
703 |
stream.output_queue.push(('progress', (preview, desc, make_progress_bar_html(percentage, hint))))
|
704 |
+
except KeyboardInterrupt as e:
|
705 |
# 捕获并重新抛出中断异常,确保它能传播到采样函数
|
706 |
+
print(f"【调试】回调函数: 捕获到KeyboardInterrupt: {e}")
|
707 |
+
print("【调试】回调函数: 重新抛出中断异常,确保传播到采样函数")
|
708 |
raise
|
709 |
except Exception as e:
|
710 |
+
print(f"【调试】回调函数中出错: {e}")
|
711 |
# 不中断采样过程
|
712 |
+
print(f"【调试】回调函数: 步骤 {d['i']} 完成")
|
713 |
return
|
714 |
|
715 |
try:
|
|
|
717 |
print(f"开始采样,设备: {device}, 数据类型: {transformer.dtype}, 使用TeaCache: {use_teacache and not cpu_fallback_mode}")
|
718 |
|
719 |
try:
|
720 |
+
print("【调试】开始sample_hunyuan采样流程")
|
721 |
generated_latents = sample_hunyuan(
|
722 |
transformer=transformer,
|
723 |
sampler='unipc',
|
|
|
749 |
callback=callback,
|
750 |
)
|
751 |
|
752 |
+
print(f"【调试】采样完成,用时: {time.time() - sampling_start_time:.2f}秒")
|
753 |
+
except KeyboardInterrupt as e:
|
754 |
# 用户主动中断
|
755 |
+
print(f"【调试】捕获到KeyboardInterrupt: {e}")
|
756 |
+
print("【调试】用户主动中断采样过程,处理中断逻辑")
|
757 |
|
758 |
# 如果已经有生成的视频,返回最后生成的视频
|
759 |
if last_output_filename:
|
760 |
+
print(f"【调试】已有部分生成视频: {last_output_filename},返回此视频")
|
761 |
stream.output_queue.push(('file', last_output_filename))
|
762 |
error_msg = "用户中断生成过程,但已生成部分视频"
|
763 |
else:
|
764 |
+
print("【调试】没有部分生成视频,返回中断消息")
|
765 |
error_msg = "用户中断生成过程,未生成视频"
|
766 |
|
767 |
+
print(f"【调试】推送错误消息: {error_msg}")
|
768 |
stream.output_queue.push(('error', error_msg))
|
769 |
+
print("【调试】推送end信号")
|
770 |
stream.output_queue.push(('end', None))
|
771 |
+
print("【调试】中断处理完成,返回")
|
772 |
return
|
773 |
except Exception as e:
|
774 |
print(f"采样过程中出错: {e}")
|
|
|
873 |
if is_last_section:
|
874 |
break
|
875 |
except Exception as e:
|
876 |
+
print(f"【调试】处理过程中出现错误: {e}, 类型: {type(e)}")
|
877 |
+
print(f"【调试】错误详情:")
|
878 |
traceback.print_exc()
|
879 |
+
|
880 |
+
# 检查是否是中断类型异常
|
881 |
+
if isinstance(e, KeyboardInterrupt):
|
882 |
+
print("【调试】捕获到外层KeyboardInterrupt异常")
|
883 |
|
884 |
if not high_vram and not cpu_fallback_mode:
|
885 |
try:
|
886 |
+
print("【调试】尝试卸载模型以释放资源")
|
887 |
unload_complete_models(
|
888 |
text_encoder, text_encoder_2, image_encoder, vae, transformer
|
889 |
)
|
890 |
+
print("【调试】模型卸载成功")
|
891 |
+
except Exception as unload_error:
|
892 |
+
print(f"【调试】卸载模型时出错: {unload_error}")
|
893 |
pass
|
894 |
|
895 |
# 如果已经有生成的视频,返回最后生成的视频
|
896 |
if last_output_filename:
|
897 |
+
print(f"【调试】外层异常处理: 返回已生成的部分视频 {last_output_filename}")
|
898 |
stream.output_queue.push(('file', last_output_filename))
|
899 |
+
else:
|
900 |
+
print("【调试】外层异常处理: 未找到已生成的视频")
|
901 |
|
902 |
# 返回错误信息
|
903 |
error_msg = f"处理过程中出现错误: {e}"
|
904 |
+
print(f"【调试】外层异常处理: 推送错误信息: {error_msg}")
|
905 |
stream.output_queue.push(('error', error_msg))
|
906 |
|
907 |
# 确保总是返回end信号
|
908 |
+
print("【调试】工作函数结束,推送end信号")
|
909 |
stream.output_queue.push(('end', None))
|
910 |
return
|
911 |
|
|
|
1068 |
|
1069 |
def end_process():
|
1070 |
"""停止生成过程函数 - 通过在队列中推送'end'信号来中断生成"""
|
1071 |
+
print("【调试】用户点击了停止按钮,发送停止信号...")
|
1072 |
# 确保stream已初始化
|
1073 |
if 'stream' in globals() and stream is not None:
|
1074 |
+
# 在推送前检查队列状态
|
1075 |
+
try:
|
1076 |
+
current_top = stream.input_queue.top()
|
1077 |
+
print(f"【调试】当前队列顶部信号: {current_top}")
|
1078 |
+
except Exception as e:
|
1079 |
+
print(f"【调试】检查队列状态出错: {e}")
|
1080 |
+
|
1081 |
+
# 推送end信号
|
1082 |
+
try:
|
1083 |
+
stream.input_queue.push('end')
|
1084 |
+
print("【调试】成功推送end信号到队列")
|
1085 |
+
|
1086 |
+
# 验证信号是否成功推送
|
1087 |
+
try:
|
1088 |
+
current_top_after = stream.input_queue.top()
|
1089 |
+
print(f"【调试】推送后队列顶部信号: {current_top_after}")
|
1090 |
+
except Exception as e:
|
1091 |
+
print(f"【调试】验证推送后队列状态出错: {e}")
|
1092 |
+
|
1093 |
+
except Exception as e:
|
1094 |
+
print(f"【调试】推送end信号到队列失败: {e}")
|
1095 |
else:
|
1096 |
+
print("【调试】警告: stream未初始化,无法发送停止信号")
|
1097 |
return None
|
1098 |
|
1099 |
|
diffusers_helper/thread_utils.py
CHANGED
@@ -44,28 +44,42 @@ class FIFOQueue:
|
|
44 |
def __init__(self):
|
45 |
self.queue = []
|
46 |
self.lock = Lock()
|
|
|
47 |
|
48 |
def push(self, item):
|
|
|
49 |
with self.lock:
|
50 |
self.queue.append(item)
|
|
|
51 |
|
52 |
def pop(self):
|
|
|
53 |
with self.lock:
|
54 |
if self.queue:
|
55 |
-
|
|
|
|
|
|
|
56 |
return None
|
57 |
|
58 |
def top(self):
|
|
|
59 |
with self.lock:
|
60 |
if self.queue:
|
61 |
-
|
|
|
|
|
|
|
62 |
return None
|
63 |
|
64 |
def next(self):
|
|
|
65 |
while True:
|
66 |
with self.lock:
|
67 |
if self.queue:
|
68 |
-
|
|
|
|
|
69 |
|
70 |
time.sleep(0.001)
|
71 |
|
@@ -74,3 +88,36 @@ class AsyncStream:
|
|
74 |
def __init__(self):
|
75 |
self.input_queue = FIFOQueue()
|
76 |
self.output_queue = FIFOQueue()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
def __init__(self):
|
45 |
self.queue = []
|
46 |
self.lock = Lock()
|
47 |
+
print("【调试】创建新的FIFOQueue")
|
48 |
|
49 |
def push(self, item):
|
50 |
+
print(f"【调试】FIFOQueue.push: 准备添加项目: {item}")
|
51 |
with self.lock:
|
52 |
self.queue.append(item)
|
53 |
+
print(f"【调试】FIFOQueue.push: 成功添加项目: {item}, 当前队列长度: {len(self.queue)}")
|
54 |
|
55 |
def pop(self):
|
56 |
+
print("【调试】FIFOQueue.pop: 准备弹出队列首项")
|
57 |
with self.lock:
|
58 |
if self.queue:
|
59 |
+
item = self.queue.pop(0)
|
60 |
+
print(f"【调试】FIFOQueue.pop: 成功弹出项目: {item}, 剩余队列长度: {len(self.queue)}")
|
61 |
+
return item
|
62 |
+
print("【调试】FIFOQueue.pop: 队列为空,返回None")
|
63 |
return None
|
64 |
|
65 |
def top(self):
|
66 |
+
print("【调试】FIFOQueue.top: 准备查看队列首项")
|
67 |
with self.lock:
|
68 |
if self.queue:
|
69 |
+
item = self.queue[0]
|
70 |
+
print(f"【调试】FIFOQueue.top: 队列首项为: {item}, 当前队列长度: {len(self.queue)}")
|
71 |
+
return item
|
72 |
+
print("【调试】FIFOQueue.top: 队列为空,返回None")
|
73 |
return None
|
74 |
|
75 |
def next(self):
|
76 |
+
print("【调试】FIFOQueue.next: 等待弹出队列首项")
|
77 |
while True:
|
78 |
with self.lock:
|
79 |
if self.queue:
|
80 |
+
item = self.queue.pop(0)
|
81 |
+
print(f"【调试】FIFOQueue.next: 成功弹出项目: {item}, 剩余队列长度: {len(self.queue)}")
|
82 |
+
return item
|
83 |
|
84 |
time.sleep(0.001)
|
85 |
|
|
|
88 |
def __init__(self):
|
89 |
self.input_queue = FIFOQueue()
|
90 |
self.output_queue = FIFOQueue()
|
91 |
+
|
92 |
+
|
93 |
+
class InterruptibleStreamData:
|
94 |
+
def __init__(self):
|
95 |
+
self.input_queue = FIFOQueue()
|
96 |
+
self.output_queue = FIFOQueue()
|
97 |
+
print("【调试】创建新的InterruptibleStreamData,初始化输入输出队列")
|
98 |
+
|
99 |
+
# 推送数据至输出队列
|
100 |
+
def push_output(self, item):
|
101 |
+
print(f"【调试】InterruptibleStreamData.push_output: 准备推送输出: {type(item)}")
|
102 |
+
self.output_queue.push(item)
|
103 |
+
print(f"【调试】InterruptibleStreamData.push_output: 成功推送输出")
|
104 |
+
|
105 |
+
# 获取下一个输出数据
|
106 |
+
def get_output(self):
|
107 |
+
print("【调试】InterruptibleStreamData.get_output: 准备获取下一个输出数据")
|
108 |
+
item = self.output_queue.next()
|
109 |
+
print(f"【调试】InterruptibleStreamData.get_output: 获取到输出数据: {type(item)}")
|
110 |
+
return item
|
111 |
+
|
112 |
+
# 推送数据至输入队列
|
113 |
+
def push_input(self, item):
|
114 |
+
print(f"【调试】InterruptibleStreamData.push_input: 准备推送输入: {type(item)}")
|
115 |
+
self.input_queue.push(item)
|
116 |
+
print(f"【调试】InterruptibleStreamData.push_input: 成功推送输入")
|
117 |
+
|
118 |
+
# 获取下一个输入数据
|
119 |
+
def get_input(self):
|
120 |
+
print("【调试】InterruptibleStreamData.get_input: 准备获取下一个输入数据")
|
121 |
+
item = self.input_queue.next()
|
122 |
+
print(f"【调试】InterruptibleStreamData.get_input: 获取到输入数据: {type(item)}")
|
123 |
+
return item
|