-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsetup.py
More file actions
349 lines (281 loc) · 9.34 KB
/
setup.py
File metadata and controls
349 lines (281 loc) · 9.34 KB
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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
#!/usr/bin/env python3
"""
video-edit skill universal installer
Supports: Claude Code / OpenCode / Hermes Agent
Usage:
python setup.py install # auto-detect agent
python setup.py install --agent hermes
python setup.py install --agent opencode
python setup.py install --agent claude
python setup.py doctor # check environment
"""
import argparse
import os
import shutil
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parent
VENV_DIR = ROOT / ".venv"
if sys.platform == "win32":
VENV_PY = VENV_DIR / "Scripts" / "python.exe"
VENV_PIP = VENV_DIR / "Scripts" / "pip.exe"
ENTRY_CMD = str(ROOT / "veditor.bat")
else:
VENV_PY = VENV_DIR / "bin" / "python"
VENV_PIP = VENV_DIR / "bin" / "pip"
ENTRY_CMD = str(VENV_PY) + " " + str(ROOT / "video_editor.py")
AGENT_CONFIGS = {
"hermes": {
"skill_dir": Path.home() / ".hermes" / "skills" / "video-edit",
"label": "Hermes Agent",
},
"opencode": {
"skill_dir": Path.home() / ".opencode" / "skills" / "video-edit",
"label": "OpenCode",
},
"claude": {
"skill_dir": ROOT / ".claude" / "skills" / "video-edit",
"label": "Claude Code",
},
}
SKILL_TEMPLATE = """---
name: video-edit
description: >
小语种听写视频自动剪辑。识别韩语/小语种发音、写字画面、笔尖点击声并保留,
删除单词之间的无声空白,自动计算倍速命中目标时长,音量最大化+扩音器特效后导出。
当用户要求:剪辑听写视频、处理听写录像、自动剪辑学习视频、去除视频静音、
批量处理视频时触发。
version: 1.0.0
author: user
license: MIT
{extra_frontmatter}---
# 小语种听写视频自动剪辑
## 工具入口
```bash
{entry_cmd} <input.mp4> [options]
```
## 推荐命令
### 单个视频(自动倍速命中 10-20 秒)
```bash
{entry_cmd} input.mp4 -o output.mp4 --target-duration 10-20
```
### 批量处理
```bash
{entry_cmd} --batch ./raw_videos --output-dir ./processed --target-duration 10-20
```
### 手动指定倍速
```bash
{entry_cmd} input.mp4 --speed 1.4
```
## 关键参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--target-duration` | - | 目标时长,如 `15` 或 `10-20`(自动计算倍速) |
| `--speed` | 1.4 | 手动倍速(与 target-duration 二选一) |
| `--silence-db` | -28 | 静音阈值 dB,越小越保守 |
| `--margin` | 0.1 | 裁剪边距(秒) |
| `--loudness` | -8 | 目标响度 LUFS |
| `--no-megaphone` | - | 禁用扩音器音效 |
| `--codec` | libx264 | 编码器,h264_nvenc 启用 GPU |
## 注意事项
- 不要对听写视频使用 `--separate-audio`,会把发音当人声去除
- 输出保持输入视频的原始分辨率
- 工具目录: `{tool_dir}`
"""
EXTRA_FRONTMATTER = {
"hermes": "metadata:\n hermes:\n tags: [video, editing, automation, language-learning]\n",
"opencode": "",
"claude": "allowed-tools:\n - Bash\n - Read\n - Write\n - Glob\n",
}
def log(msg, level="ok"):
prefix = {"ok": "[ OK ]", "warn": "[WARN]", "err": "[ERR ]", "info": "[INFO]", "step": "[STEP]"}
print(f"{prefix.get(level, '[INFO]')} {msg}")
def find_system_python():
for cmd in ["python", "py", "python3"]:
path = shutil.which(cmd)
if not path:
continue
try:
r = subprocess.run([cmd, "--version"], capture_output=True, text=True, timeout=5)
if r.returncode == 0 and "Python 3" in r.stdout:
return cmd
except Exception:
continue
if sys.platform == "win32":
search = [
Path(os.environ.get("LOCALAPPDATA", "")) / "Programs" / "Python",
Path.home() / "anaconda3",
Path.home() / "miniconda3",
]
for d in search:
if d.exists():
for py in sorted(d.rglob("python.exe"), reverse=True):
return str(py)
return None
def pip_has(pkg):
return subprocess.run([str(VENV_PIP), "show", pkg], capture_output=True).returncode == 0
def setup_venv():
log("Setting up Python virtual environment...", "step")
if VENV_PY.exists():
r = subprocess.run([str(VENV_PY), "--version"], capture_output=True, text=True)
if r.returncode == 0:
log(f".venv exists ({r.stdout.strip()})")
return True
sys_py = find_system_python()
if not sys_py:
log("Python 3 not found!", "err")
log(" Install: https://python.org", "err")
return False
log(f"Found Python: {sys_py}")
log(f"Creating .venv at {VENV_DIR}...")
if VENV_DIR.exists():
shutil.rmtree(VENV_DIR)
r = subprocess.run([sys_py, "-m", "venv", str(VENV_DIR)])
if r.returncode != 0:
log("Failed to create .venv", "err")
return False
log(".venv created")
return True
def install_deps():
log("Installing Python dependencies...", "step")
deps = [
("auto-editor", ["auto-editor"]),
("audio-separator", ["audio-separator", "onnxruntime"]),
]
for name, pkgs in deps:
if pip_has(name):
log(f"{name} already installed")
else:
log(f"Installing {name}...", "info")
r = subprocess.run([str(VENV_PIP), "install"] + pkgs, capture_output=True)
if r.returncode == 0:
log(f"{name} installed")
else:
log(f"{name} install failed (non-critical)", "warn")
def check_ffmpeg():
log("Checking FFmpeg...", "step")
if shutil.which("ffmpeg") and shutil.which("ffprobe"):
log("FFmpeg ready")
return True
log("FFmpeg not found in PATH!", "warn")
if sys.platform == "win32":
log(" Install: winget install FFmpeg", "warn")
else:
log(" Install: sudo apt install ffmpeg (or brew install ffmpeg)", "warn")
return False
def install_skill(agent):
cfg = AGENT_CONFIGS[agent]
log(f"Installing skill for {cfg['label']}...", "step")
skill_dir = cfg["skill_dir"]
skill_dir.mkdir(parents=True, exist_ok=True)
content = SKILL_TEMPLATE.format(
entry_cmd=ENTRY_CMD,
tool_dir=str(ROOT),
extra_frontmatter=EXTRA_FRONTMATTER[agent],
)
(skill_dir / "SKILL.md").write_text(content, encoding="utf-8")
log(f"SKILL.md -> {skill_dir}")
return True
def detect_agents():
found = []
if (Path.home() / ".hermes").exists():
found.append("hermes")
if (Path.home() / ".opencode").exists():
found.append("opencode")
found.append("claude")
return found
def cmd_install(args):
print("=" * 55)
print(" video-edit skill installer")
print("=" * 55)
print()
# 1. venv
if not setup_venv():
sys.exit(1)
print()
# 2. deps
install_deps()
print()
# 3. ffmpeg
check_ffmpeg()
print()
# 4. skill
agents = [args.agent] if args.agent else detect_agents()
for agent in agents:
install_skill(agent)
print()
# summary
print("=" * 55)
print(" Installation complete!")
print()
print(f" Tool dir: {ROOT}")
print(f" Venv: {VENV_DIR}")
print(f" Entry: {ENTRY_CMD}")
print(f" Agents: {', '.join(agents)}")
print()
print(" Usage:")
print(f' {ENTRY_CMD} input.mp4 --target-duration 10-20')
print("=" * 55)
def cmd_doctor(args):
print("=" * 55)
print(" video-edit environment check")
print("=" * 55)
print()
all_ok = True
# Python venv
if VENV_PY.exists():
r = subprocess.run([str(VENV_PY), "--version"], capture_output=True, text=True)
log(f"Python venv: {r.stdout.strip()}")
else:
log("Python venv: NOT FOUND", "err")
all_ok = False
# pip packages
for pkg in ["auto-editor", "audio-separator", "onnxruntime"]:
if pip_has(pkg):
log(f"{pkg}: installed")
else:
log(f"{pkg}: NOT INSTALLED", "warn")
all_ok = False
# FFmpeg
if shutil.which("ffmpeg"):
log("FFmpeg: installed")
else:
log("FFmpeg: NOT FOUND", "err")
all_ok = False
# video_editor.py
if (ROOT / "video_editor.py").exists():
log("video_editor.py: found")
else:
log("video_editor.py: NOT FOUND", "err")
all_ok = False
# Skills
print()
log("Installed skills:", "info")
for name, cfg in AGENT_CONFIGS.items():
skill_file = cfg["skill_dir"] / "SKILL.md"
if skill_file.exists():
log(f" {cfg['label']}: {skill_file}")
else:
log(f" {cfg['label']}: not installed", "info")
print()
if all_ok:
log("All checks passed!", "ok")
else:
log("Some issues found. Run: python setup.py install", "warn")
def main():
parser = argparse.ArgumentParser(description="video-edit skill setup tool")
sub = parser.add_subparsers(dest="command")
p_install = sub.add_parser("install", help="Install skill and dependencies")
p_install.add_argument("--agent", choices=["hermes", "opencode", "claude"],
help="Target agent (auto-detect if omitted)")
sub.add_parser("doctor", help="Check environment status")
args = parser.parse_args()
if args.command == "install":
cmd_install(args)
elif args.command == "doctor":
cmd_doctor(args)
else:
parser.print_help()
if __name__ == "__main__":
main()