Integrate pinned YuE2 community WebUI
This commit is contained in:
1 parent
72c9d8c485
commit
af25425aee
4 files changed
+165
-17
No files matched your search
@@ -1,6 +1,7 @@
|
||||
FROM python:3.12-slim-bookworm
|
||||
|
||||
ARG YUE2_COMMIT=9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||
ARG YUE2_WEBUI_COMMIT=8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends ca-certificates git libsndfile1 \
|
||||
@@ -10,6 +11,20 @@ RUN git clone https://github.com/multimodal-art-projection/YuE.git /opt/yue2 \
|
||||
&& git -C /opt/yue2 checkout "${YUE2_COMMIT}" \
|
||||
&& python -m pip install --no-cache-dir /opt/yue2
|
||||
|
||||
# The community console is intentionally layered onto the already verified,
|
||||
# pinned YuE2 runtime. We use only its webui/ directory; its bundled YuE2 fork
|
||||
# and Windows installers never become part of the Athena image.
|
||||
RUN git clone https://github.com/Ladypoly/YuE2_WebUI.git /tmp/yue2-webui \
|
||||
&& git -C /tmp/yue2-webui checkout "${YUE2_WEBUI_COMMIT}" \
|
||||
&& cp -a /tmp/yue2-webui/webui /opt/yue2/webui \
|
||||
&& cp /tmp/yue2-webui/LICENSE /opt/yue2/YuE2_WebUI-LICENSE \
|
||||
&& python -m pip install --no-cache-dir -r /opt/yue2/webui/requirements.txt \
|
||||
&& rm -rf /tmp/yue2-webui
|
||||
|
||||
COPY community-webui-patches /tmp/community-webui-patches
|
||||
RUN python /tmp/community-webui-patches/patch_webui.py /opt/yue2/webui \
|
||||
&& rm -rf /tmp/community-webui-patches
|
||||
|
||||
COPY ui /opt/yue2-playground
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
@@ -30,19 +30,33 @@ image is built, but no YuE2 container has been created or started.
|
||||
The initial control request is a true empty-lyrics instrumental request. No
|
||||
invented `[Instrumental]` lyrics marker is used.
|
||||
|
||||
## Temporary playground
|
||||
## Community WebUI
|
||||
|
||||
The optional `playground` profile provides a small German web interface for
|
||||
new-song generation. It lists persistent results, streams FLAC files with HTTP
|
||||
range support and permits explicit deletion. It is bound only to Athena's
|
||||
localhost on port 8014 and is not integrated into the profile router yet. The
|
||||
web process itself does not load the model; a click on **Song generieren**
|
||||
starts one exclusive offline generation job.
|
||||
The `community-ui` profile runs Ladypoly's YuE2 WebUI at the pinned commit
|
||||
`8fc05609bde5dcd345d7c6d57fff3da0839164c5`. Only the WebUI layer is copied
|
||||
from that repository. Athena continues to use the verified official YuE2
|
||||
`0.1.6` runtime and the existing model cache; the WebUI fork's bundled model
|
||||
code and Windows installers are not used.
|
||||
|
||||
The UI is bound only to Athena's localhost on port 8014 and stores complete
|
||||
takes below `/data/music/yue2`. Optional Windows-only installers for llama.cpp
|
||||
and stable-diffusion.cpp are not part of the Athena setup. Manual composition,
|
||||
generation, result playback, score editing and the take library work without
|
||||
those optional components.
|
||||
|
||||
The small integration patch under `community-webui-patches/` fixes the
|
||||
community release's missing `refreshArt()` function on Linux and permits the
|
||||
native YuE2 empty-lyrics request for true instrumentals. It deliberately does
|
||||
not modify the model runtime.
|
||||
|
||||
```sh
|
||||
docker compose --profile playground up -d yue2-ui
|
||||
docker compose --profile community-ui up -d yue2-ui
|
||||
```
|
||||
|
||||
The original small German playground remains available as a stopped fallback
|
||||
on localhost port 8016 through the `playground-fallback` profile. Do not run
|
||||
both frontends concurrently because both can submit work to the same GPU.
|
||||
|
||||
## Manual test (only after GPU availability was checked)
|
||||
|
||||
From `/opt/mike-ai/yue2-3b` on Athena:
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"""Small Linux integration fixes for the pinned community WebUI.
|
||||
|
||||
Keep these transformations explicit and fail the image build if upstream moves
|
||||
the expected code. That prevents a future upstream update from silently
|
||||
producing a half-patched console.
|
||||
"""
|
||||
from pathlib import Path
|
||||
import sys
|
||||
|
||||
|
||||
root = Path(sys.argv[1])
|
||||
app_js = root / "static" / "app.js"
|
||||
index_html = root / "static" / "index.html"
|
||||
server_py = root / "server.py"
|
||||
|
||||
|
||||
def replace_once(path: Path, old: str, new: str) -> None:
|
||||
text = path.read_text(encoding="utf-8")
|
||||
if text.count(old) != 1:
|
||||
raise RuntimeError(f"expected exactly one patch marker in {path}: {old[:80]!r}")
|
||||
path.write_text(text.replace(old, new, 1), encoding="utf-8")
|
||||
|
||||
|
||||
# The published UI calls refreshArt() during startup, but does not define it.
|
||||
# Athena does not install the Windows-only stable-diffusion.cpp helper, so show
|
||||
# that state honestly and keep the optional controls inert instead of crashing
|
||||
# the whole page.
|
||||
art_marker = ''' $("artDirAdd").addEventListener("click", function () {
|
||||
'''
|
||||
art_fix = ''' function refreshArt() {
|
||||
return api("/api/art/status").then(function (data) {
|
||||
STATE.art = data;
|
||||
var installed = !!data.installed;
|
||||
var supported = !!data.supported;
|
||||
$("artState").textContent = data.busy || (installed ? "installed" :
|
||||
(supported ? "not installed" : "not available on Linux"));
|
||||
$("artState").dataset.s = data.busy ? "busy" : (installed ? "ready" : "missing");
|
||||
$("artInstall").disabled = !!data.busy || !supported;
|
||||
$("artInstall").textContent = installed ? "Reinstall" : "Install";
|
||||
$("setArtAuto").checked = !!data.auto;
|
||||
$("setArtAuto").disabled = !installed;
|
||||
$("setArtModel").innerHTML = (data.models || []).length
|
||||
? data.models.map(function (m) {
|
||||
return '<option value="' + escape(m.path) + '">' + escape(m.name || m.file) + '</option>';
|
||||
}).join("")
|
||||
: '<option value="">no art model available</option>';
|
||||
if (data.selected) $("setArtModel").value = data.selected;
|
||||
$("setArtModel").disabled = !installed;
|
||||
$("artDir").disabled = !supported;
|
||||
$("artDirAdd").disabled = !supported;
|
||||
$("artDirs").textContent = supported
|
||||
? ((data.dirs || []).length ? "Also scanning: " + data.dirs.join(" · ") : "No extra folders configured.")
|
||||
: "The community release only provides the cover-art installer for Windows; song generation is unaffected.";
|
||||
$("artCatalog").innerHTML = "";
|
||||
return data;
|
||||
}).catch(function (error) {
|
||||
$("artState").textContent = "unavailable";
|
||||
$("artInstall").disabled = true;
|
||||
$("artDirs").textContent = error.message;
|
||||
});
|
||||
}
|
||||
|
||||
$("artDirAdd").addEventListener("click", function () {
|
||||
'''
|
||||
replace_once(app_js, art_marker, art_fix)
|
||||
|
||||
# YuE2 natively supports an empty lyric string for true instrumentals. The
|
||||
# community server rejected that valid request even though the browser did not.
|
||||
replace_once(
|
||||
server_py,
|
||||
''' if not body.style.strip() or not body.lyrics.strip():
|
||||
raise HTTPException(400, "A style prompt and lyrics are both required")
|
||||
''',
|
||||
''' if not body.style.strip():
|
||||
raise HTTPException(400, "A style prompt is required")
|
||||
''',
|
||||
)
|
||||
|
||||
replace_once(
|
||||
index_html,
|
||||
'''<span class="label">Lyrics <em>section tags on their own line</em></span>''',
|
||||
'''<span class="label">Lyrics <em>section tags on their own line · leave empty for a true instrumental</em></span>''',
|
||||
)
|
||||
@@ -5,6 +5,7 @@ services:
|
||||
context: .
|
||||
args:
|
||||
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||
YUE2_WEBUI_COMMIT: 8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||
image: mike-ai/yue2:3b-0.1.6
|
||||
restart: "no"
|
||||
environment:
|
||||
@@ -23,22 +24,63 @@ services:
|
||||
capabilities: [gpu]
|
||||
|
||||
yue2-ui:
|
||||
profiles: ["playground"]
|
||||
profiles: ["community-ui"]
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||
YUE2_WEBUI_COMMIT: 8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||
image: mike-ai/yue2:3b-0.1.6
|
||||
container_name: mike-ai-yue2-playground
|
||||
restart: "no"
|
||||
entrypoint: ["python", "/opt/yue2/webui/server.py"]
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: "GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"
|
||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||
YUE2_HOST: "0.0.0.0"
|
||||
YUE2_PORT: "8014"
|
||||
YUE2_OUTPUTS: "/workspace/runs"
|
||||
HF_HUB_OFFLINE: "1"
|
||||
TRANSFORMERS_OFFLINE: "1"
|
||||
ports:
|
||||
- "127.0.0.1:8014:8014"
|
||||
volumes:
|
||||
- /data/models/yue2:/opt/yue2/models:ro
|
||||
- /data/music/yue2:/workspace/runs
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
device_ids: ["GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"]
|
||||
capabilities: [gpu]
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8014/api/state', timeout=2)"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 12
|
||||
start_period: 5s
|
||||
|
||||
# Kept as a deliberately non-default fallback until the community console
|
||||
# has completed a real generation on Athena.
|
||||
yue2-playground-fallback:
|
||||
profiles: ["playground-fallback"]
|
||||
build:
|
||||
context: .
|
||||
args:
|
||||
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||
YUE2_WEBUI_COMMIT: 8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||
image: mike-ai/yue2:3b-0.1.6
|
||||
container_name: mike-ai-yue2-playground-fallback
|
||||
restart: "no"
|
||||
entrypoint: ["python", "/opt/yue2-playground/server.py"]
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: "GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"
|
||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||
YUE2_UI_HOST: "0.0.0.0"
|
||||
YUE2_UI_PORT: "8014"
|
||||
YUE2_UI_PORT: "8016"
|
||||
ports:
|
||||
- "127.0.0.1:8014:8014"
|
||||
- "127.0.0.1:8016:8016"
|
||||
volumes:
|
||||
- /data/models/yue2:/workspace/models:ro
|
||||
- /data/music/yue2:/workspace/runs
|
||||
@@ -49,9 +91,3 @@ services:
|
||||
- driver: nvidia
|
||||
device_ids: ["GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"]
|
||||
capabilities: [gpu]
|
||||
healthcheck:
|
||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8014/health', timeout=2)"]
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 12
|
||||
start_period: 5s
|
||||
Reference in new issue
Block a user