Spaces:
Running
Running
Commit
·
217c6bd
1
Parent(s):
1064203
重构处理函数以支持Hugging Face Spaces GPU,优化错误消息处理逻辑,确保用户界面友好性
Browse files
app.py
CHANGED
|
@@ -854,179 +854,164 @@ def worker(input_image, prompt, n_prompt, seed, total_second_length, latent_wind
|
|
| 854 |
return
|
| 855 |
|
| 856 |
|
| 857 |
-
#
|
| 858 |
-
|
| 859 |
-
|
| 860 |
-
|
| 861 |
-
|
| 862 |
-
|
| 863 |
-
|
| 864 |
-
if is_timeout:
|
| 865 |
-
en_msg = "Processing timed out, but partial video may have been generated" if "部分视频" in error_msg else f"Processing timed out: {error_msg}"
|
| 866 |
-
zh_msg = "处理超时,但已生成部分视频" if "部分视频" in error_msg else f"处理超时: {error_msg}"
|
| 867 |
-
elif "模型加载失败" in error_msg:
|
| 868 |
-
en_msg = "Failed to load models. The Space may be experiencing high traffic or GPU issues."
|
| 869 |
-
zh_msg = "模型加载失败,可能是Space流量过高或GPU资源不足。"
|
| 870 |
-
elif "GPU" in error_msg or "CUDA" in error_msg or "内存" in error_msg or "memory" in error_msg:
|
| 871 |
-
en_msg = "GPU memory insufficient or GPU error. Try increasing GPU memory preservation value or reduce video length."
|
| 872 |
-
zh_msg = "GPU内存不足或GPU错误,请尝试增加GPU推理保留内存值或降低视频长度。"
|
| 873 |
-
elif "采样过程中出错" in error_msg:
|
| 874 |
-
if "部分" in error_msg:
|
| 875 |
-
en_msg = "Error during sampling process, but partial video has been generated."
|
| 876 |
-
zh_msg = "采样过程中出错,但已生成部分视频。"
|
| 877 |
-
else:
|
| 878 |
-
en_msg = "Error during sampling process. Unable to generate video."
|
| 879 |
-
zh_msg = "采样过程中出错,无法生成视频。"
|
| 880 |
-
elif "模型下载超时" in error_msg or "网络连接不稳定" in error_msg or "ReadTimeoutError" in error_msg or "ConnectionError" in error_msg:
|
| 881 |
-
en_msg = "Network connection is unstable, model download timed out. Please try again later."
|
| 882 |
-
zh_msg = "网络连接不稳定,模型下载超时。请稍后再试。"
|
| 883 |
-
elif "VAE" in error_msg or "解码" in error_msg or "decode" in error_msg:
|
| 884 |
-
en_msg = "Error during video decoding or saving process. Try again with a different seed."
|
| 885 |
-
zh_msg = "视频解码或保存过程中出错,请尝试使用不同的随机种子。"
|
| 886 |
-
else:
|
| 887 |
-
en_msg = f"Processing error: {error_msg}"
|
| 888 |
-
zh_msg = f"处理过程出错: {error_msg}"
|
| 889 |
-
|
| 890 |
-
# 创建双语错误消息HTML - 添加有用的图标并确保CSS样式适用
|
| 891 |
-
return f"""
|
| 892 |
-
<div class="error-message" id="custom-error-container">
|
| 893 |
-
<div class="error-msg-en" data-lang="en">
|
| 894 |
-
<span class="error-icon">⚠️</span> {en_msg}
|
| 895 |
-
</div>
|
| 896 |
-
<div class="error-msg-zh" data-lang="zh">
|
| 897 |
-
<span class="error-icon">⚠️</span> {zh_msg}
|
| 898 |
-
</div>
|
| 899 |
-
</div>
|
| 900 |
-
<script>
|
| 901 |
-
// 根据当前语言显示相应的错误消息
|
| 902 |
-
(function() {{
|
| 903 |
-
const errorContainer = document.getElementById('custom-error-container');
|
| 904 |
-
if (errorContainer) {{
|
| 905 |
-
const currentLang = window.currentLang || 'en'; // 默认英语
|
| 906 |
-
const errMsgs = errorContainer.querySelectorAll('[data-lang]');
|
| 907 |
-
errMsgs.forEach(msg => {{
|
| 908 |
-
msg.style.display = msg.getAttribute('data-lang') === currentLang ? 'block' : 'none';
|
| 909 |
-
}});
|
| 910 |
-
|
| 911 |
-
// 确保Gradio默认错误UI不显示
|
| 912 |
-
const defaultErrorElements = document.querySelectorAll('.error');
|
| 913 |
-
defaultErrorElements.forEach(el => {{
|
| 914 |
-
el.style.display = 'none';
|
| 915 |
-
}});
|
| 916 |
-
}}
|
| 917 |
-
}})();
|
| 918 |
-
</script>
|
| 919 |
-
"""
|
| 920 |
|
| 921 |
-
#
|
| 922 |
-
|
| 923 |
-
global stream
|
| 924 |
-
assert input_image is not None, 'No input image!'
|
| 925 |
|
| 926 |
-
# 检查是否有正在运行的任务并清理
|
| 927 |
-
if hasattr(stream, 'is_running') and stream.is_running:
|
| 928 |
try:
|
| 929 |
-
|
| 930 |
-
stream.input_queue.push('end')
|
| 931 |
-
time.sleep(0.5) # 给一点时间让旧任务结束
|
| 932 |
-
except:
|
| 933 |
-
pass
|
| 934 |
-
|
| 935 |
-
# 创建新的流实例
|
| 936 |
-
stream = AsyncStream()
|
| 937 |
-
stream.is_running = True
|
| 938 |
-
|
| 939 |
-
# 初始化UI状态
|
| 940 |
-
yield None, None, '', '', gr.update(interactive=False), gr.update(interactive=True)
|
| 941 |
|
| 942 |
-
|
| 943 |
-
|
| 944 |
-
async_run(worker, input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache)
|
| 945 |
|
| 946 |
-
|
| 947 |
-
|
| 948 |
-
|
| 949 |
|
| 950 |
-
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
|
| 955 |
-
|
| 956 |
-
|
| 957 |
-
|
| 958 |
-
|
| 959 |
-
|
| 960 |
-
|
| 961 |
-
|
| 962 |
-
|
| 963 |
-
|
| 964 |
-
|
| 965 |
-
|
| 966 |
-
if flag == 'error':
|
| 967 |
-
error_message = data
|
| 968 |
-
print(f"收到错误消息: {error_message}")
|
| 969 |
-
# 不立即显示,等待end信号
|
| 970 |
-
|
| 971 |
-
if flag == 'end':
|
| 972 |
-
# 如果有最后的视频文件,确保返回
|
| 973 |
-
if output_filename is None and prev_output_filename is not None:
|
| 974 |
-
output_filename = prev_output_filename
|
| 975 |
|
| 976 |
-
|
| 977 |
-
|
| 978 |
-
|
| 979 |
-
|
| 980 |
-
|
| 981 |
-
|
| 982 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 983 |
|
| 984 |
-
|
| 985 |
-
|
| 986 |
-
|
| 987 |
-
|
| 988 |
-
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 993 |
|
| 994 |
-
|
| 995 |
-
|
| 996 |
-
|
| 997 |
-
|
| 998 |
-
|
| 999 |
-
|
| 1000 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1001 |
|
| 1002 |
-
|
| 1003 |
-
|
| 1004 |
-
|
| 1005 |
-
|
| 1006 |
-
|
| 1007 |
-
|
| 1008 |
-
|
| 1009 |
-
error_msg = str(e)
|
| 1010 |
-
|
| 1011 |
-
error_html = create_error_html(error_msg)
|
| 1012 |
-
yield None, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 1013 |
-
|
| 1014 |
-
# 标记任务已结束
|
| 1015 |
-
stream.is_running = False
|
| 1016 |
-
|
| 1017 |
-
def end_process():
|
| 1018 |
-
if hasattr(stream, 'input_queue'):
|
| 1019 |
-
stream.input_queue.push('end')
|
| 1020 |
-
if hasattr(stream, 'is_running'):
|
| 1021 |
-
stream.is_running = False
|
| 1022 |
|
| 1023 |
|
| 1024 |
-
|
| 1025 |
-
|
| 1026 |
-
@spaces.GPU
|
| 1027 |
-
def process_with_gpu(input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache):
|
| 1028 |
-
# 调用普通的process函数实现,以避免重复代码
|
| 1029 |
-
return process(input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache)
|
| 1030 |
|
| 1031 |
|
| 1032 |
quick_prompts = [
|
|
@@ -1148,65 +1133,56 @@ def make_custom_css():
|
|
| 1148 |
/* 进度条样式增强 */
|
| 1149 |
.progress-container {
|
| 1150 |
margin-top: 10px;
|
|
|
|
| 1151 |
}
|
| 1152 |
|
| 1153 |
/* 错误消息样式 */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1154 |
.error-message {
|
| 1155 |
-
background-color: rgba(255,
|
| 1156 |
-
|
| 1157 |
-
border-radius:
|
| 1158 |
-
|
| 1159 |
-
|
| 1160 |
-
font-size: 15px;
|
| 1161 |
-
display: flex;
|
| 1162 |
-
flex-direction: column;
|
| 1163 |
-
gap: 4px;
|
| 1164 |
}
|
| 1165 |
|
| 1166 |
-
|
| 1167 |
-
|
| 1168 |
-
|
| 1169 |
-
border: none;
|
| 1170 |
-
padding: 0;
|
| 1171 |
-
margin: 0;
|
| 1172 |
}
|
| 1173 |
|
|
|
|
| 1174 |
.error-icon {
|
|
|
|
|
|
|
| 1175 |
margin-right: 8px;
|
| 1176 |
-
font-size: 16px;
|
| 1177 |
}
|
| 1178 |
|
| 1179 |
-
|
| 1180 |
-
|
| 1181 |
-
|
| 1182 |
-
|
| 1183 |
-
|
| 1184 |
-
|
| 1185 |
-
#custom-error-container + .error {
|
| 1186 |
-
display: none !important;
|
| 1187 |
}
|
| 1188 |
|
| 1189 |
-
/*
|
| 1190 |
-
|
| 1191 |
-
#custom-error-container:empty {
|
| 1192 |
display: none !important;
|
| 1193 |
-
background: none !important;
|
| 1194 |
-
border: none !important;
|
| 1195 |
-
padding: 0 !important;
|
| 1196 |
-
margin: 0 !important;
|
| 1197 |
-
}
|
| 1198 |
-
|
| 1199 |
-
/* 黑暗模式下的错误消息 */
|
| 1200 |
-
@media (prefers-color-scheme: dark) {
|
| 1201 |
-
.error-message {
|
| 1202 |
-
background-color: rgba(80, 0, 0, 0.95);
|
| 1203 |
-
border-color: #ff5555;
|
| 1204 |
-
color: #ffdddd;
|
| 1205 |
-
}
|
| 1206 |
}
|
| 1207 |
"""
|
| 1208 |
|
| 1209 |
-
|
|
|
|
|
|
|
| 1210 |
|
| 1211 |
|
| 1212 |
css = make_custom_css()
|
|
@@ -1519,18 +1495,77 @@ with block:
|
|
| 1519 |
|
| 1520 |
# 错误信息区域 - 确保使用HTML组件以支持我们的自定义错误消息格式
|
| 1521 |
error_message = gr.HTML('', elem_id='error-message', visible=True)
|
| 1522 |
-
|
| 1523 |
-
#
|
| 1524 |
ips = [input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache]
|
| 1525 |
|
| 1526 |
# 开始和结束按钮事件
|
| 1527 |
-
|
| 1528 |
-
# 使用带GPU装饰器的处理函数
|
| 1529 |
-
start_button.click(fn=process_with_gpu, inputs=ips, outputs=[result_video, preview_image, progress_desc, progress_bar, start_button, end_button])
|
| 1530 |
-
else:
|
| 1531 |
-
# 使用普通处理函数
|
| 1532 |
-
start_button.click(fn=process, inputs=ips, outputs=[result_video, preview_image, progress_desc, progress_bar, start_button, end_button])
|
| 1533 |
-
|
| 1534 |
end_button.click(fn=end_process)
|
| 1535 |
|
| 1536 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 854 |
return
|
| 855 |
|
| 856 |
|
| 857 |
+
# 使用Hugging Face Spaces GPU装饰器处理进程函数
|
| 858 |
+
if IN_HF_SPACE and 'spaces' in globals():
|
| 859 |
+
@spaces.GPU
|
| 860 |
+
def process_with_gpu(input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache):
|
| 861 |
+
global stream
|
| 862 |
+
assert input_image is not None, 'No input image!'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 863 |
|
| 864 |
+
# 初始化UI状态
|
| 865 |
+
yield None, None, '', '', gr.update(interactive=False), gr.update(interactive=True)
|
|
|
|
|
|
|
| 866 |
|
|
|
|
|
|
|
| 867 |
try:
|
| 868 |
+
stream = AsyncStream()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 869 |
|
| 870 |
+
# 异步启动worker
|
| 871 |
+
async_run(worker, input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache)
|
|
|
|
| 872 |
|
| 873 |
+
output_filename = None
|
| 874 |
+
prev_output_filename = None
|
| 875 |
+
error_message = None
|
| 876 |
|
| 877 |
+
# 持续检查worker的输出
|
| 878 |
+
while True:
|
| 879 |
+
try:
|
| 880 |
+
flag, data = stream.output_queue.next()
|
| 881 |
+
|
| 882 |
+
if flag == 'file':
|
| 883 |
+
output_filename = data
|
| 884 |
+
prev_output_filename = output_filename
|
| 885 |
+
# 清除错误显示,确保文件成功时不显示错误
|
| 886 |
+
yield output_filename, gr.update(), gr.update(), '', gr.update(interactive=False), gr.update(interactive=True)
|
| 887 |
+
|
| 888 |
+
if flag == 'progress':
|
| 889 |
+
preview, desc, html = data
|
| 890 |
+
# 更新进度时不改变错误信息
|
| 891 |
+
yield gr.update(), gr.update(visible=True, value=preview), desc, html, gr.update(interactive=False), gr.update(interactive=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 892 |
|
| 893 |
+
if flag == 'error':
|
| 894 |
+
error_message = data
|
| 895 |
+
print(f"收到错误消息: {error_message}")
|
| 896 |
+
# 不立即显示,等待end信号
|
| 897 |
+
|
| 898 |
+
if flag == 'end':
|
| 899 |
+
# 如果有最后的视频文件,确保返回
|
| 900 |
+
if output_filename is None and prev_output_filename is not None:
|
| 901 |
+
output_filename = prev_output_filename
|
| 902 |
+
|
| 903 |
+
# 如果有错误消息,创建友好的错误显示
|
| 904 |
+
if error_message:
|
| 905 |
+
error_html = create_error_html(error_message)
|
| 906 |
+
yield output_filename, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 907 |
+
else:
|
| 908 |
+
# 确保成功完成时不显示任何错误
|
| 909 |
+
yield output_filename, gr.update(visible=False), gr.update(), '', gr.update(interactive=True), gr.update(interactive=False)
|
| 910 |
+
break
|
| 911 |
+
except Exception as e:
|
| 912 |
+
print(f"处理输出时出错: {e}")
|
| 913 |
+
# 检查是否长时间没有更新
|
| 914 |
+
current_time = time.time()
|
| 915 |
+
if current_time - last_update_time > 60: # 60秒没有更新,可能卡住了
|
| 916 |
+
print(f"处理似乎卡住了,已经 {current_time - last_update_time:.1f} 秒没有更新")
|
| 917 |
+
|
| 918 |
+
# 如果有部分生成的视频,返回
|
| 919 |
+
if prev_output_filename:
|
| 920 |
+
error_html = create_error_html("处理超时,但已生成部分视频", is_timeout=True)
|
| 921 |
+
yield prev_output_filename, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 922 |
+
else:
|
| 923 |
+
error_html = create_error_html(f"处理超时: {e}", is_timeout=True)
|
| 924 |
+
yield None, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 925 |
+
break
|
| 926 |
|
| 927 |
+
except Exception as e:
|
| 928 |
+
print(f"启动处理时出错: {e}")
|
| 929 |
+
traceback.print_exc()
|
| 930 |
+
error_msg = str(e)
|
| 931 |
+
|
| 932 |
+
error_html = create_error_html(error_msg)
|
| 933 |
+
yield None, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 934 |
+
|
| 935 |
+
process = process_with_gpu
|
| 936 |
+
else:
|
| 937 |
+
def process(input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache):
|
| 938 |
+
global stream
|
| 939 |
+
assert input_image is not None, 'No input image!'
|
| 940 |
+
|
| 941 |
+
# 初始化UI状态
|
| 942 |
+
yield None, None, '', '', gr.update(interactive=False), gr.update(interactive=True)
|
| 943 |
+
|
| 944 |
+
try:
|
| 945 |
+
stream = AsyncStream()
|
| 946 |
+
|
| 947 |
+
# 异步启动worker
|
| 948 |
+
async_run(worker, input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache)
|
| 949 |
+
|
| 950 |
+
output_filename = None
|
| 951 |
+
prev_output_filename = None
|
| 952 |
+
error_message = None
|
| 953 |
+
|
| 954 |
+
# 持续检查worker的输出
|
| 955 |
+
while True:
|
| 956 |
+
try:
|
| 957 |
+
flag, data = stream.output_queue.next()
|
| 958 |
+
|
| 959 |
+
if flag == 'file':
|
| 960 |
+
output_filename = data
|
| 961 |
+
prev_output_filename = output_filename
|
| 962 |
+
# 清除错误显示,确保文件成功时不显示错误
|
| 963 |
+
yield output_filename, gr.update(), gr.update(), '', gr.update(interactive=False), gr.update(interactive=True)
|
| 964 |
+
|
| 965 |
+
if flag == 'progress':
|
| 966 |
+
preview, desc, html = data
|
| 967 |
+
# 更新进度时不改变错误信息
|
| 968 |
+
yield gr.update(), gr.update(visible=True, value=preview), desc, html, gr.update(interactive=False), gr.update(interactive=True)
|
| 969 |
|
| 970 |
+
if flag == 'error':
|
| 971 |
+
error_message = data
|
| 972 |
+
print(f"收到错误消息: {error_message}")
|
| 973 |
+
# 不立即显示,等待end信号
|
| 974 |
+
|
| 975 |
+
if flag == 'end':
|
| 976 |
+
# 如果有最后的视频文件,确保返回
|
| 977 |
+
if output_filename is None and prev_output_filename is not None:
|
| 978 |
+
output_filename = prev_output_filename
|
| 979 |
+
|
| 980 |
+
# 如果有错误消息,创建友好的错误显示
|
| 981 |
+
if error_message:
|
| 982 |
+
error_html = create_error_html(error_message)
|
| 983 |
+
yield output_filename, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 984 |
+
else:
|
| 985 |
+
# 确保成功完成时不显示任何错误
|
| 986 |
+
yield output_filename, gr.update(visible=False), gr.update(), '', gr.update(interactive=True), gr.update(interactive=False)
|
| 987 |
+
break
|
| 988 |
+
except Exception as e:
|
| 989 |
+
print(f"处理输出时出错: {e}")
|
| 990 |
+
# 检查是否长时间没有更新
|
| 991 |
+
current_time = time.time()
|
| 992 |
+
if current_time - last_update_time > 60: # 60秒没有更新,可能卡住了
|
| 993 |
+
print(f"处理似乎卡住了,已经 {current_time - last_update_time:.1f} 秒没有更新")
|
| 994 |
+
|
| 995 |
+
# 如果有部分生成的视频,返回
|
| 996 |
+
if prev_output_filename:
|
| 997 |
+
error_html = create_error_html("处理超时,但已生成部分视频", is_timeout=True)
|
| 998 |
+
yield prev_output_filename, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 999 |
+
else:
|
| 1000 |
+
error_html = create_error_html(f"处理超时: {e}", is_timeout=True)
|
| 1001 |
+
yield None, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
| 1002 |
+
break
|
| 1003 |
|
| 1004 |
+
except Exception as e:
|
| 1005 |
+
print(f"启动处理时出错: {e}")
|
| 1006 |
+
traceback.print_exc()
|
| 1007 |
+
error_msg = str(e)
|
| 1008 |
+
|
| 1009 |
+
error_html = create_error_html(error_msg)
|
| 1010 |
+
yield None, gr.update(visible=False), gr.update(), error_html, gr.update(interactive=True), gr.update(interactive=False)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1011 |
|
| 1012 |
|
| 1013 |
+
def end_process():
|
| 1014 |
+
stream.input_queue.push('end')
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1015 |
|
| 1016 |
|
| 1017 |
quick_prompts = [
|
|
|
|
| 1133 |
/* 进度条样式增强 */
|
| 1134 |
.progress-container {
|
| 1135 |
margin-top: 10px;
|
| 1136 |
+
margin-bottom: 10px;
|
| 1137 |
}
|
| 1138 |
|
| 1139 |
/* 错误消息样式 */
|
| 1140 |
+
#error-message {
|
| 1141 |
+
color: #ff4444;
|
| 1142 |
+
font-weight: bold;
|
| 1143 |
+
padding: 10px;
|
| 1144 |
+
border-radius: 4px;
|
| 1145 |
+
margin-top: 10px;
|
| 1146 |
+
}
|
| 1147 |
+
|
| 1148 |
+
/* 确保错误容器正确显示 */
|
| 1149 |
.error-message {
|
| 1150 |
+
background-color: rgba(255, 0, 0, 0.1);
|
| 1151 |
+
padding: 10px;
|
| 1152 |
+
border-radius: 4px;
|
| 1153 |
+
margin-top: 10px;
|
| 1154 |
+
border: 1px solid #ffcccc;
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1155 |
}
|
| 1156 |
|
| 1157 |
+
/* 处理多语言错误消息 */
|
| 1158 |
+
.error-msg-en, .error-msg-zh {
|
| 1159 |
+
font-weight: bold;
|
|
|
|
|
|
|
|
|
|
| 1160 |
}
|
| 1161 |
|
| 1162 |
+
/* 错误图标 */
|
| 1163 |
.error-icon {
|
| 1164 |
+
color: #ff4444;
|
| 1165 |
+
font-size: 18px;
|
| 1166 |
margin-right: 8px;
|
|
|
|
| 1167 |
}
|
| 1168 |
|
| 1169 |
+
/* 确保空错误消息不显示背景和边框 */
|
| 1170 |
+
#error-message:empty {
|
| 1171 |
+
background-color: transparent;
|
| 1172 |
+
border: none;
|
| 1173 |
+
padding: 0;
|
| 1174 |
+
margin: 0;
|
|
|
|
|
|
|
| 1175 |
}
|
| 1176 |
|
| 1177 |
+
/* 修复Gradio默认错误显示 */
|
| 1178 |
+
.error {
|
|
|
|
| 1179 |
display: none !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1180 |
}
|
| 1181 |
"""
|
| 1182 |
|
| 1183 |
+
# 合并CSS
|
| 1184 |
+
combined_css = progress_bar_css + responsive_css
|
| 1185 |
+
return combined_css
|
| 1186 |
|
| 1187 |
|
| 1188 |
css = make_custom_css()
|
|
|
|
| 1495 |
|
| 1496 |
# 错误信息区域 - 确保使用HTML组件以支持我们的自定义错误消息格式
|
| 1497 |
error_message = gr.HTML('', elem_id='error-message', visible=True)
|
| 1498 |
+
|
| 1499 |
+
# 处理函数
|
| 1500 |
ips = [input_image, prompt, n_prompt, seed, total_second_length, latent_window_size, steps, cfg, gs, rs, gpu_memory_preservation, use_teacache]
|
| 1501 |
|
| 1502 |
# 开始和结束按钮事件
|
| 1503 |
+
start_button.click(fn=process, inputs=ips, outputs=[result_video, preview_image, progress_desc, progress_bar, start_button, end_button])
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1504 |
end_button.click(fn=end_process)
|
| 1505 |
|
| 1506 |
+
|
| 1507 |
+
block.launch()
|
| 1508 |
+
|
| 1509 |
+
# 创建友好的错误显示HTML
|
| 1510 |
+
def create_error_html(error_msg, is_timeout=False):
|
| 1511 |
+
"""创建双语错误消息HTML"""
|
| 1512 |
+
# 提供更友好的中英文双语错误信息
|
| 1513 |
+
en_msg = ""
|
| 1514 |
+
zh_msg = ""
|
| 1515 |
+
|
| 1516 |
+
if is_timeout:
|
| 1517 |
+
en_msg = "Processing timed out, but partial video may have been generated" if "部分视频" in error_msg else f"Processing timed out: {error_msg}"
|
| 1518 |
+
zh_msg = "处理超时,但已生成部分视频" if "部分视频" in error_msg else f"处理超时: {error_msg}"
|
| 1519 |
+
elif "模型加载失败" in error_msg:
|
| 1520 |
+
en_msg = "Failed to load models. The Space may be experiencing high traffic or GPU issues."
|
| 1521 |
+
zh_msg = "模型加载失败,可能是Space流量过高或GPU资源不足。"
|
| 1522 |
+
elif "GPU" in error_msg or "CUDA" in error_msg or "内存" in error_msg or "memory" in error_msg:
|
| 1523 |
+
en_msg = "GPU memory insufficient or GPU error. Try increasing GPU memory preservation value or reduce video length."
|
| 1524 |
+
zh_msg = "GPU内存不足或GPU错误,请尝试增加GPU推理保留内存值或降低视频长度。"
|
| 1525 |
+
elif "采样过程中出错" in error_msg:
|
| 1526 |
+
if "部分" in error_msg:
|
| 1527 |
+
en_msg = "Error during sampling process, but partial video has been generated."
|
| 1528 |
+
zh_msg = "采样过程中出错,但已生成部分视频。"
|
| 1529 |
+
else:
|
| 1530 |
+
en_msg = "Error during sampling process. Unable to generate video."
|
| 1531 |
+
zh_msg = "采样过程中出错,无法生成视频。"
|
| 1532 |
+
elif "模型下载超时" in error_msg or "网络连接不稳定" in error_msg or "ReadTimeoutError" in error_msg or "ConnectionError" in error_msg:
|
| 1533 |
+
en_msg = "Network connection is unstable, model download timed out. Please try again later."
|
| 1534 |
+
zh_msg = "网络连接不稳定,模型下载超时。请稍后再试。"
|
| 1535 |
+
elif "VAE" in error_msg or "解码" in error_msg or "decode" in error_msg:
|
| 1536 |
+
en_msg = "Error during video decoding or saving process. Try again with a different seed."
|
| 1537 |
+
zh_msg = "视频解码或保存过程中出错,请尝试使用不同的随机种子。"
|
| 1538 |
+
else:
|
| 1539 |
+
en_msg = f"Processing error: {error_msg}"
|
| 1540 |
+
zh_msg = f"处理过程出错: {error_msg}"
|
| 1541 |
+
|
| 1542 |
+
# 创建双语错误消息HTML - 添加有用的图标并确保CSS样式适用
|
| 1543 |
+
return f"""
|
| 1544 |
+
<div class="error-message" id="custom-error-container">
|
| 1545 |
+
<div class="error-msg-en" data-lang="en">
|
| 1546 |
+
<span class="error-icon">⚠️</span> {en_msg}
|
| 1547 |
+
</div>
|
| 1548 |
+
<div class="error-msg-zh" data-lang="zh">
|
| 1549 |
+
<span class="error-icon">⚠️</span> {zh_msg}
|
| 1550 |
+
</div>
|
| 1551 |
+
</div>
|
| 1552 |
+
<script>
|
| 1553 |
+
// 根据当前语言显示相应的错误消息
|
| 1554 |
+
(function() {{
|
| 1555 |
+
const errorContainer = document.getElementById('custom-error-container');
|
| 1556 |
+
if (errorContainer) {{
|
| 1557 |
+
const currentLang = window.currentLang || 'en'; // 默认英语
|
| 1558 |
+
const errMsgs = errorContainer.querySelectorAll('[data-lang]');
|
| 1559 |
+
errMsgs.forEach(msg => {{
|
| 1560 |
+
msg.style.display = msg.getAttribute('data-lang') === currentLang ? 'block' : 'none';
|
| 1561 |
+
}});
|
| 1562 |
+
|
| 1563 |
+
// 确保Gradio默认错误UI不显示
|
| 1564 |
+
const defaultErrorElements = document.querySelectorAll('.error');
|
| 1565 |
+
defaultErrorElements.forEach(el => {{
|
| 1566 |
+
el.style.display = 'none';
|
| 1567 |
+
}});
|
| 1568 |
+
}}
|
| 1569 |
+
}})();
|
| 1570 |
+
</script>
|
| 1571 |
+
"""
|