Create modules/__init__.py

#1
Files changed (7) hide show
  1. .gitattributes +35 -0
  2. Dockerfile +5 -36
  3. README.md +5 -83
  4. app.py +141 -0
  5. modules/__init__.py +1 -0
  6. requirements.txt +8 -0
  7. run.sh +0 -21
.gitattributes ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
Dockerfile CHANGED
@@ -1,37 +1,6 @@
1
- FROM ubuntu:24.04
2
-
3
- # acestep.cpp builds from source with cmake. CPU-only path (matches
4
- # buildcpu.sh: cmake -DGGML_BLAS=ON). No CUDA/Vulkan/Metal.
5
- # pkg-config is REQUIRED: ggml-blas/CMakeLists.txt calls find_package(PkgConfig)
6
- # and fails the configure step without it (build died here on the first attempt).
7
- RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
8
- git cmake build-essential ca-certificates curl python3 \
9
- pkg-config \
10
- libblas-dev liblapack-dev libgomp1 libcurl4 \
11
- && rm -rf /var/lib/apt/lists/*
12
-
13
- WORKDIR /build
14
-
15
- # clone source + ggml submodule
16
- RUN git clone --depth 1 --recurse-submodules \
17
- https://github.com/ServeurpersoCom/acestep.cpp.git . \
18
- && rm -rf build && mkdir build && cd build \
19
- && cmake .. -DGGML_BLAS=ON -DCMAKE_BUILD_TYPE=Release \
20
- && cmake --build . --config Release -j "$(getconf _NPROCESSORS_ONLN)"
21
-
22
- # weights: 0.6B LM + Q8_0 DiT turbo + Q8_0 text encoder + BF16 VAE (~4.2 GB total)
23
- RUN mkdir -p /app/models \
24
- && curl -fL -o /app/models/acestep-5Hz-lm-0.6B-Q8_0.gguf \
25
- https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF/resolve/main/acestep-5Hz-lm-0.6B-Q8_0.gguf \
26
- && curl -fL -o /app/models/acestep-v15-turbo-Q8_0.gguf \
27
- https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF/resolve/main/acestep-v15-turbo-Q8_0.gguf \
28
- && curl -fL -o /app/models/Qwen3-Embedding-0.6B-Q8_0.gguf \
29
- https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF/resolve/main/Qwen3-Embedding-0.6B-Q8_0.gguf \
30
- && curl -fL -o /app/models/vae-BF16.gguf \
31
- https://huggingface.co/Serveurperso/ACE-Step-1.5-GGUF/resolve/main/vae-BF16.gguf
32
-
33
  WORKDIR /app
34
- COPY run.sh /app/run.sh
35
- RUN chmod +x /app/run.sh
36
- EXPOSE 7860
37
- CMD ["bash", "/app/run.sh"]
 
1
+ FROM python:3.10-slim
2
+ RUN apt-get update && apt-get install -y ffmpeg fonts-noto-cjk
3
+ COPY . /app
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  WORKDIR /app
5
+ RUN pip install -r requirements.txt
6
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
README.md CHANGED
@@ -1,88 +1,10 @@
1
  ---
2
- title: ACE-Step Music
3
- emoji: 🎵
4
- colorFrom: purple
5
- colorTo: pink
6
  sdk: docker
7
- app_port: 7860
8
  pinned: false
9
  ---
10
 
11
- # 🎵 ACE-Step Music (acestep.cpp, CPU)
12
-
13
- AI music generation on cpu-basic. Text + lyrics in, stereo 48kHz audio out.
14
- Built from source (`acestep.cpp` GGML) with the **0.6B** model set:
15
-
16
- | 部件 | 文件 | 大小 |
17
- |---|---|---|
18
- | LM(歌词+音频编码) | `acestep-5Hz-lm-0.6B-Q8_0.gguf` | 0.68 GB |
19
- | DiT(flow-matching 扩散,turbo 8 步) | `acestep-v15-turbo-Q8_0.gguf` | 2.4 GB |
20
- | 文本编码器 | `Qwen3-Embedding-0.6B-Q8_0.gguf` | 0.75 GB |
21
- | VAE | `vae-BF16.gguf` | 0.32 GB |
22
-
23
- 合计约 **4.2 GB**,16 GB 内存装得下。占用会随生成过程浮动,峰值约 6 GB。
24
-
25
- ## 使用
26
-
27
- 网页 UI 在 `/`(`ace-server` 内嵌的 WebUI,无需 npm)。写 caption → 设时长 → 生成 → 下载。
28
-
29
- ## REST API(给 pipeline 调用)
30
-
31
- 异步作业模型:POST 拿 id → 轮询 `/job?id=` → `result=1` 取文件。
32
-
33
- **请求体(`examples/dit-only.json` 格式):**
34
- ```json
35
- {
36
- "lm_model": "acestep-5Hz-lm-0.6B-Q8_0.gguf",
37
- "synth_model": "acestep-v15-turbo-Q8_0.gguf",
38
- "caption": "Ambient electronic soundscape with warm analog pads",
39
- "lyrics": "",
40
- "bpm": 90,
41
- "duration": 30,
42
- "keyscale": "C minor",
43
- "timesignature": "4",
44
- "vocal_language": "en",
45
- "inference_steps": 8,
46
- "guidance_scale": 1.0,
47
- "shift": 3.0
48
- }
49
- ```
50
-
51
- ### 出音乐(两步)
52
- ```bash
53
- # 1) LM: caption -> lyrics + audio codes
54
- LM_ID=$(curl -sX POST https://jacky3102-platform.hf.space/lm \
55
- -H 'Content-Type: application/json' -d @req.json | jq -r '.id')
56
-
57
- # 2) 轮询直到 done
58
- curl -s "https://jacky3102-platform.hf.space/job?id=$LM_ID&result=1" | jq '.[0]' > out.json
59
-
60
- # 3) synth: codes -> audio (WAV or MP3)
61
- SY_ID=$(curl -sX POST https://jacky3102-platform.hf.space/synth \
62
- -H 'Content-Type: application/json' -d @out.json | jq -r '.id')
63
- curl -s "https://jacky3102-platform.hf.space/job?id=$SY_ID&result=1" -o track.wav
64
- ```
65
-
66
- ### 可用模型 / 默认参数
67
- ```bash
68
- curl https://jacky3102-platform.hf.space/props
69
- ```
70
-
71
- ### 跳过 LM(直接用已知歌词)
72
- POST 同一个 `/synth`,带 `lyrics` + `lm_model` 即可(dit-only 模式)。
73
-
74
- ## 已知限制
75
-
76
- - **CPU 生成慢**:30 秒音乐在 2 vCPU 上预计几分钟到十几分钟,未实测。第一次请求会额外等模型加载(`--keep-loaded` 已开,之后不再重复加载)。
77
- - HF Space 有请求超时,长生成要用 `/job` 异步轮询,别在线等。
78
- - 官方 Space 用 ZeroGPU;这是 CPU 移植版,慢但免费。
79
-
80
- ## 模型质量档位(之后可换)
81
-
82
- | LM | 大小 | 说明 |
83
- |---|---|---|
84
- | `acestep-5Hz-lm-0.6B-Q8_0.gguf` | 0.68 GB | 最快(当前) |
85
- | `acestep-5Hz-lm-1.7B-Q8_0.gguf` | 1.9 GB | 折中 |
86
- | `acestep-5Hz-lm-4B-Q8_0.gguf` | 4.2 GB | 官方默认,音质最好 |
87
-
88
- DiT 也可换 `sft`(50 步,音质更高但慢一倍)。
 
1
  ---
2
+ title: Video Gen
3
+ emoji: 📊
4
+ colorFrom: green
5
+ colorTo: red
6
  sdk: docker
 
7
  pinned: false
8
  ---
9
 
10
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py ADDED
@@ -0,0 +1,141 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, File, UploadFile, HTTPException, Form
2
+ from fastapi.responses import Response
3
+ import tempfile
4
+ import os
5
+ import traceback
6
+ import sys
7
+ from pathlib import Path
8
+ from typing import Optional, List
9
+
10
+ from modules.video_processor import generate_video
11
+ from modules.lut import LUTS
12
+ from modules.particles import EFFECTS
13
+ from modules.titles import TITLE_STYLES, TITLE_ANIMATIONS, TITLE_POSITIONS
14
+
15
+ app = FastAPI(title="Video Generator with Effects API")
16
+
17
+ @app.get("/")
18
+ async def root():
19
+ return {
20
+ "message": "Video Generator API",
21
+ "effects": EFFECTS,
22
+ "luts": {k: v["name"] for k, v in LUTS.items()},
23
+ "title_styles": TITLE_STYLES,
24
+ "title_animations": TITLE_ANIMATIONS,
25
+ "title_positions": TITLE_POSITIONS,
26
+ "features": ["ken_burns", "typewriter", "cinemascope", "title", "video_input"],
27
+ }
28
+
29
+ @app.get("/health")
30
+ async def health():
31
+ return {"status": "healthy"}
32
+
33
+ @app.post("/generate")
34
+ async def generate(
35
+ images: List[UploadFile] = File(None),
36
+ video: UploadFile = File(None),
37
+ audio: UploadFile = File(...),
38
+ srt_text: str = Form(""),
39
+ bgm: Optional[UploadFile] = File(None),
40
+ effect: str = Form("snow"),
41
+ lut: str = Form("none"),
42
+ ken_burns: bool = Form(False),
43
+ typewriter: bool = Form(False),
44
+ cinemascope: bool = Form(False),
45
+ title_text: str = Form(""),
46
+ title_style: str = Form("3d"),
47
+ title_color: str = Form("white"),
48
+ title_animation: str = Form("fade_in"),
49
+ title_duration: float = Form(4.0),
50
+ title_position: str = Form("center"),
51
+ title_start: float = Form(0.0),
52
+ title_font_size: int = Form(0),
53
+ typewriter_font_size: int = Form(0),
54
+ typewriter_color: str = Form("white"),
55
+ subtitle_color: str = Form("white"),
56
+ subtitle_effect: str = Form("none"),
57
+ fps: int = Form(25),
58
+ ):
59
+ # 验证
60
+ if not images and not video:
61
+ raise HTTPException(400, "必须提供 images 或 video 中的一个")
62
+ if images and video:
63
+ raise HTTPException(400, "不能同时提供 images 和 video")
64
+
65
+ # 创建临时目录
66
+ tmp_dir = tempfile.mkdtemp()
67
+ try:
68
+ # 保存文件
69
+ image_paths = None
70
+ video_path = None
71
+ if images:
72
+ image_paths = []
73
+ for i, img in enumerate(images):
74
+ suffix = Path(img.filename).suffix if img.filename else ".jpg"
75
+ path = os.path.join(tmp_dir, f"image_{i}{suffix}")
76
+ with open(path, "wb") as f:
77
+ f.write(await img.read())
78
+ image_paths.append(path)
79
+ elif video:
80
+ suffix = Path(video.filename).suffix if video.filename else ".mp4"
81
+ video_path = os.path.join(tmp_dir, f"video{suffix}")
82
+ with open(video_path, "wb") as f:
83
+ f.write(await video.read())
84
+
85
+ audio_path = os.path.join(tmp_dir, "audio" + (Path(audio.filename).suffix or ".wav"))
86
+ with open(audio_path, "wb") as f:
87
+ f.write(await audio.read())
88
+
89
+ bgm_path = None
90
+ if bgm:
91
+ bgm_path = os.path.join(tmp_dir, "bgm" + (Path(bgm.filename).suffix or ".mp3"))
92
+ with open(bgm_path, "wb") as f:
93
+ f.write(await bgm.read())
94
+
95
+ output_path = os.path.join(tmp_dir, "output.mp4")
96
+
97
+ # 调用主合成函数
98
+ generate_video(
99
+ image_paths=image_paths,
100
+ video_path=video_path,
101
+ audio_path=audio_path,
102
+ srt_text=srt_text,
103
+ bgm_path=bgm_path,
104
+ effect=effect,
105
+ output_path=output_path,
106
+ lut=lut,
107
+ ken_burns=ken_burns,
108
+ typewriter=typewriter,
109
+ cinemascope=cinemascope,
110
+ title_text=title_text,
111
+ title_style=title_style,
112
+ title_color=title_color,
113
+ title_animation=title_animation,
114
+ title_duration=title_duration,
115
+ title_position=title_position,
116
+ title_start=title_start,
117
+ title_font_size=title_font_size,
118
+ typewriter_font_size=typewriter_font_size,
119
+ typewriter_color=typewriter_color,
120
+ subtitle_color=subtitle_color,
121
+ subtitle_effect=subtitle_effect,
122
+ fps=fps,
123
+ )
124
+
125
+ with open(output_path, "rb") as f:
126
+ video_bytes = f.read()
127
+
128
+ import shutil
129
+ shutil.rmtree(tmp_dir, ignore_errors=True)
130
+ return Response(content=video_bytes, media_type="video/mp4",
131
+ headers={"Content-Disposition": "attachment; filename=output.mp4"})
132
+
133
+ except Exception as e:
134
+ print(traceback.format_exc(), file=sys.stderr)
135
+ import shutil
136
+ shutil.rmtree(tmp_dir, ignore_errors=True)
137
+ raise HTTPException(500, detail=str(e))
138
+
139
+ if __name__ == "__main__":
140
+ import uvicorn
141
+ uvicorn.run(app, host="0.0.0.0", port=7860)
modules/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+ # 模块初始化
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ fastapi==0.104.1
2
+ uvicorn==0.24.0
3
+ python-multipart==0.0.6
4
+ numpy>=1.24.0
5
+ opencv-python-headless>=4.8.0
6
+ Pillow>=10.0.0
7
+ pydub>=0.25.0
8
+ librosa>=0.10.0
run.sh DELETED
@@ -1,21 +0,0 @@
1
- #!/bin/bash
2
- # Boot diagnostics + ace-server on the port HF expects (7860).
3
- # On a crash the container stays alive so the traceback stays readable in the
4
- # runtime logs (this is what finally exposed the gradio/huggingface_hub bug
5
- # on Platform).
6
- echo "=== boot $(date -u) ==="
7
- echo "--- binaries ---"; ls /build/build/ | grep -E "^ace-" | head
8
- echo "--- models ---"; ls -la /app/models/
9
- echo "--- nproc / mem ---"; nproc; free -m | head -2
10
- echo "--- starting ace-server on 7860 ---"
11
- /build/build/ace-server \
12
- --host 0.0.0.0 \
13
- --port "${PORT:-7860}" \
14
- --models /app/models \
15
- --adapters /build/adapters \
16
- --max-batch 1 \
17
- --keep-loaded \
18
- --device CPU
19
- echo "=== ace-server exited code=$? at $(date -u) ==="
20
- echo "--- holding container alive for log capture ---"
21
- sleep infinity