Update app.py
Browse files
app.py
CHANGED
|
@@ -1,71 +1,152 @@
|
|
| 1 |
-
import
|
| 2 |
import os
|
| 3 |
import tempfile
|
| 4 |
from pathlib import Path
|
| 5 |
-
|
| 6 |
-
|
| 7 |
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
"""
|
| 10 |
-
|
| 11 |
input_video: Gradio 上传的视频文件(路径为临时文件路径)
|
|
|
|
| 12 |
"""
|
| 13 |
try:
|
| 14 |
-
#
|
| 15 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as f:
|
| 16 |
-
f.write(input_video.read())
|
| 17 |
input_path = f.name
|
|
|
|
| 18 |
|
| 19 |
-
#
|
| 20 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
#
|
|
|
|
|
|
|
| 23 |
remover = VideoWatermarkRemover(
|
| 24 |
-
device="cpu", # 强制使用 CPU
|
| 25 |
-
model_path=
|
| 26 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 27 |
|
| 28 |
-
#
|
| 29 |
remover.remove_watermark(
|
| 30 |
input_path=input_path,
|
| 31 |
-
output_path=output_path
|
| 32 |
-
#
|
| 33 |
-
# watermark_region=(100, 100, 300, 200), #
|
| 34 |
-
# strength=0.8
|
| 35 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
|
| 37 |
-
return output_path #
|
| 38 |
|
| 39 |
except Exception as e:
|
| 40 |
-
|
|
|
|
|
|
|
| 41 |
|
| 42 |
-
# 创建 Gradio
|
| 43 |
-
with gr.Blocks(title="KLing
|
| 44 |
-
gr.Markdown("# 🚀 KLing
|
| 45 |
-
gr.Markdown("
|
| 46 |
|
|
|
|
| 47 |
with gr.Row():
|
| 48 |
input_video = gr.Video(
|
| 49 |
-
label="输入视频(支持 MP4、MOV
|
| 50 |
type="filepath", # 获取文件路径而非二进制数据
|
| 51 |
-
interactive=True
|
|
|
|
|
|
|
| 52 |
)
|
|
|
|
|
|
|
|
|
|
| 53 |
output_video = gr.Video(label="输出视频(去水印后)", interactive=False)
|
|
|
|
| 54 |
|
|
|
|
| 55 |
submit_btn = gr.Button("开始去水印", variant="primary")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
|
| 57 |
-
#
|
| 58 |
submit_btn.click(
|
| 59 |
-
fn=
|
| 60 |
inputs=input_video,
|
| 61 |
-
outputs=output_video
|
| 62 |
)
|
| 63 |
|
| 64 |
-
#
|
| 65 |
-
gr.Markdown("### 注意事项")
|
| 66 |
-
gr.Markdown("-
|
| 67 |
-
gr.Markdown("-
|
| 68 |
-
gr.Markdown("-
|
|
|
|
| 69 |
|
| 70 |
if __name__ == "__main__":
|
| 71 |
# 本地调试(可选,部署到 Space 时无需运行)
|
|
|
|
| 1 |
+
import sys
|
| 2 |
import os
|
| 3 |
import tempfile
|
| 4 |
from pathlib import Path
|
| 5 |
+
import subprocess
|
| 6 |
+
import gradio as gr
|
| 7 |
|
| 8 |
+
# -------------------------- 关键修复:添加项目根目录到 Python 路径 --------------------------
|
| 9 |
+
# 获取当前文件(app.py)的父目录(即 Hugging Face Space 的工作目录 /app)
|
| 10 |
+
project_root = Path(__file__).parent.resolve()
|
| 11 |
+
sys.path.append(str(project_root)) # 确保能导入 kling 模块
|
| 12 |
+
|
| 13 |
+
# -------------------------- 导入项目核心模块(修复子模块问题) --------------------------
|
| 14 |
+
try:
|
| 15 |
+
from kling.core import VideoWatermarkRemover # 替换为实际模块路径
|
| 16 |
+
except ImportError as e:
|
| 17 |
+
raise RuntimeError(
|
| 18 |
+
f"导入 kling 模块失败:{str(e)}\n"
|
| 19 |
+
"请检查:\n"
|
| 20 |
+
"1. 是否通过 `git submodule update --init --recursive` 初始化子模块?\n"
|
| 21 |
+
"2. 项目根目录是否正确添加到 sys.path?"
|
| 22 |
+
)
|
| 23 |
+
|
| 24 |
+
# -------------------------- 视频处理函数(含储存检视逻辑) --------------------------
|
| 25 |
+
def process_video(input_video, progress=gr.Progress()):
|
| 26 |
"""
|
| 27 |
+
处理输入视频(去水印)并生成可下载的输出视频
|
| 28 |
input_video: Gradio 上传的视频文件(路径为临时文件路径)
|
| 29 |
+
返回:(输出视频路径, 下载链接/None)
|
| 30 |
"""
|
| 31 |
try:
|
| 32 |
+
# -------------------- 步骤 1:保存输入视频到临时文件 --------------------
|
| 33 |
with tempfile.NamedTemporaryFile(delete=False, suffix=".mp4") as f:
|
| 34 |
+
f.write(input_video.read()) # 写入输入视频数据
|
| 35 |
input_path = f.name
|
| 36 |
+
progress(0.1, desc="✅ 输入视频已保存到临时文件")
|
| 37 |
|
| 38 |
+
# -------------------- 步骤 2:检查 FFmpeg 是否可用 --------------------
|
| 39 |
+
try:
|
| 40 |
+
subprocess.run(
|
| 41 |
+
["ffmpeg", "-version"],
|
| 42 |
+
check=True,
|
| 43 |
+
capture_output=True,
|
| 44 |
+
text=True
|
| 45 |
+
)
|
| 46 |
+
except Exception as e:
|
| 47 |
+
raise RuntimeError(f"❌ FFmpeg 未安装或不可用:{str(e)}")
|
| 48 |
|
| 49 |
+
# -------------------- 步骤 3:初始化去水印模型 --------------------
|
| 50 |
+
# 模型路径:假设模型文件位于项目的 kling/models 目录下(需上传至仓库)
|
| 51 |
+
model_path = str(project_root / "kling" / "models" / "watermark_remover.pth")
|
| 52 |
remover = VideoWatermarkRemover(
|
| 53 |
+
device="cpu", # 强制使用 CPU
|
| 54 |
+
model_path=model_path
|
| 55 |
)
|
| 56 |
+
progress(0.3, desc="✅ 模型加载完成")
|
| 57 |
+
|
| 58 |
+
# -------------------- 步骤 4:执行去水印推理 --------------------
|
| 59 |
+
# 生成唯一输出文件名(避免覆盖)
|
| 60 |
+
input_filename = os.path.splitext(os.path.basename(input_path))[0] # 输入文件名(不含后缀)
|
| 61 |
+
output_filename = f"{input_filename}_去水印后.mp4" # 自定义输出文件名
|
| 62 |
+
output_path = os.path.join(tempfile.gettempdir(), output_filename) # 临时输出路径
|
| 63 |
|
| 64 |
+
# 执行去水印(根据原项目实际函数名调整)
|
| 65 |
remover.remove_watermark(
|
| 66 |
input_path=input_path,
|
| 67 |
+
output_path=output_path
|
| 68 |
+
# 可选参数(根据原项目功能调整):
|
| 69 |
+
# watermark_region=(100, 100, 300, 200), # 水印区域 (x1, y1, x2, y2)
|
| 70 |
+
# strength=0.8 # 去水印强度
|
| 71 |
)
|
| 72 |
+
progress(0.9, desc="✅ 去水印完成")
|
| 73 |
+
|
| 74 |
+
# -------------------- 步骤 5:生成下载链接(Hugging Face Space 特性) --------------------
|
| 75 |
+
# Space 会自动将临时文件暴露为可下载链接(格式:/files/文件名)
|
| 76 |
+
# 注意:临时文件仅在当前会话有效(约 72 小时未访问会被清理)
|
| 77 |
+
download_link = f"/files/{output_filename}" # 下载链接路径
|
| 78 |
|
| 79 |
+
return output_path, download_link # 返回视���路径和下载链接
|
| 80 |
|
| 81 |
except Exception as e:
|
| 82 |
+
# 捕获所有异常并返回友好提示
|
| 83 |
+
error_msg = f"❌ 处理失败:{str(e)}"
|
| 84 |
+
return error_msg, None # 错误时返回 None 隐藏下载链接
|
| 85 |
|
| 86 |
+
# -------------------------- 创建 Gradio 界面(含储存检视组件) --------------------------
|
| 87 |
+
with gr.Blocks(title="KLing 视频去水印工具(CPU 版)") as demo:
|
| 88 |
+
gr.Markdown("# 🚀 KLing 视频去水印工具")
|
| 89 |
+
gr.Markdown("上传含水印视频,自动去除水印(支持下载处理结果)")
|
| 90 |
|
| 91 |
+
# -------------------- 输入组件 --------------------
|
| 92 |
with gr.Row():
|
| 93 |
input_video = gr.Video(
|
| 94 |
+
label="输入视频(支持 MP4、MOV)",
|
| 95 |
type="filepath", # 获取文件路径而非二进制数据
|
| 96 |
+
interactive=True,
|
| 97 |
+
max_file_size=1024 * 1024 * 200, # 限制 200MB
|
| 98 |
+
file_types=["video/mp4", "video/quicktime"]
|
| 99 |
)
|
| 100 |
+
|
| 101 |
+
# -------------------- 输出组件 --------------------
|
| 102 |
+
with gr.Row():
|
| 103 |
output_video = gr.Video(label="输出视频(去水印后)", interactive=False)
|
| 104 |
+
download_btn = gr.Button("⬇️ 下载视频", variant="secondary", interactive=False) # 初始不可用
|
| 105 |
|
| 106 |
+
# -------------------- 操作按钮 --------------------
|
| 107 |
submit_btn = gr.Button("开始去水印", variant="primary")
|
| 108 |
+
spinner = gr.Spinner(visible=False, label="处理中...") # 加载提示
|
| 109 |
+
|
| 110 |
+
# -------------------- 下载链接提示(可选) --------------------
|
| 111 |
+
download_link = gr.HTML(visible=False) # 隐藏的 HTML 组件(用于显示长链接)
|
| 112 |
+
|
| 113 |
+
# -------------------- 绑定事件(核心逻辑) --------------------
|
| 114 |
+
def process_wrapper(input_video):
|
| 115 |
+
"""包装处理函数,控制界面组件状态"""
|
| 116 |
+
spinner.visible = True # 显示加载提示
|
| 117 |
+
download_btn.interactive = False # 初始禁用下载按钮
|
| 118 |
+
|
| 119 |
+
# 执行去水印处理
|
| 120 |
+
output_path, download_path = process_video(input_video)
|
| 121 |
+
|
| 122 |
+
# 处理结果反馈
|
| 123 |
+
if download_path:
|
| 124 |
+
# 处理成功:显示输出视频、启用下载按钮、显示下载链接(可选)
|
| 125 |
+
output_video.value = output_path # 更新输出视频组件
|
| 126 |
+
download_btn.interactive = True # 启用下载按钮
|
| 127 |
+
# 可选:显示完整下载链接(适合需要复制链接的场景)
|
| 128 |
+
# download_link.value = f"🔗 下载链接:<a href='{download_path}'>点击下载</a>"
|
| 129 |
+
# download_link.visible = True
|
| 130 |
+
return output_video, download_btn, None # 隐藏错误提示
|
| 131 |
+
else:
|
| 132 |
+
# 处理失败:清空输出视频、禁用下载按钮、显示错误提示
|
| 133 |
+
output_video.value = None
|
| 134 |
+
download_btn.interactive = False
|
| 135 |
+
return output_video, download_btn, output_path # 显示错误信息
|
| 136 |
|
| 137 |
+
# 绑定提交按钮点击事件
|
| 138 |
submit_btn.click(
|
| 139 |
+
fn=process_wrapper,
|
| 140 |
inputs=input_video,
|
| 141 |
+
outputs=[output_video, download_btn, gr.Markdown()] # 关联输出组件和错误提示
|
| 142 |
)
|
| 143 |
|
| 144 |
+
# -------------------- 注意事项 --------------------------
|
| 145 |
+
gr.Markdown("### ⚠️ 注意事项")
|
| 146 |
+
gr.Markdown("- 处理后的视频仅保留 72 小时(Hugging Face Space 临时文件策略)")
|
| 147 |
+
gr.Markdown("- 大视频(>500MB)处理时间较长(CPU 推理较慢),请耐心等待")
|
| 148 |
+
gr.Markdown("- 若下载按钮不可用,说明处理失败,请检查上方错误提示")
|
| 149 |
+
gr.Markdown("- 模型文件需提前上传至 `kling/models` 目录(或 Hugging Face Hub)")
|
| 150 |
|
| 151 |
if __name__ == "__main__":
|
| 152 |
# 本地调试(可选,部署到 Space 时无需运行)
|