Integrate pinned YuE2 community WebUI
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
FROM python:3.12-slim-bookworm
|
FROM python:3.12-slim-bookworm
|
||||||
|
|
||||||
ARG YUE2_COMMIT=9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
ARG YUE2_COMMIT=9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||||
|
ARG YUE2_WEBUI_COMMIT=8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||||
|
|
||||||
RUN apt-get update \
|
RUN apt-get update \
|
||||||
&& apt-get install -y --no-install-recommends ca-certificates git libsndfile1 \
|
&& 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}" \
|
&& git -C /opt/yue2 checkout "${YUE2_COMMIT}" \
|
||||||
&& python -m pip install --no-cache-dir /opt/yue2
|
&& 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
|
COPY ui /opt/yue2-playground
|
||||||
|
|
||||||
WORKDIR /workspace
|
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
|
The initial control request is a true empty-lyrics instrumental request. No
|
||||||
invented `[Instrumental]` lyrics marker is used.
|
invented `[Instrumental]` lyrics marker is used.
|
||||||
|
|
||||||
## Temporary playground
|
## Community WebUI
|
||||||
|
|
||||||
The optional `playground` profile provides a small German web interface for
|
The `community-ui` profile runs Ladypoly's YuE2 WebUI at the pinned commit
|
||||||
new-song generation. It lists persistent results, streams FLAC files with HTTP
|
`8fc05609bde5dcd345d7c6d57fff3da0839164c5`. Only the WebUI layer is copied
|
||||||
range support and permits explicit deletion. It is bound only to Athena's
|
from that repository. Athena continues to use the verified official YuE2
|
||||||
localhost on port 8014 and is not integrated into the profile router yet. The
|
`0.1.6` runtime and the existing model cache; the WebUI fork's bundled model
|
||||||
web process itself does not load the model; a click on **Song generieren**
|
code and Windows installers are not used.
|
||||||
starts one exclusive offline generation job.
|
|
||||||
|
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
|
```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)
|
## Manual test (only after GPU availability was checked)
|
||||||
|
|
||||||
From `/opt/mike-ai/yue2-3b` on Athena:
|
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: .
|
context: .
|
||||||
args:
|
args:
|
||||||
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||||
|
YUE2_WEBUI_COMMIT: 8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||||
image: mike-ai/yue2:3b-0.1.6
|
image: mike-ai/yue2:3b-0.1.6
|
||||||
restart: "no"
|
restart: "no"
|
||||||
environment:
|
environment:
|
||||||
@@ -23,22 +24,63 @@ services:
|
|||||||
capabilities: [gpu]
|
capabilities: [gpu]
|
||||||
|
|
||||||
yue2-ui:
|
yue2-ui:
|
||||||
profiles: ["playground"]
|
profiles: ["community-ui"]
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
args:
|
args:
|
||||||
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
YUE2_COMMIT: 9c6c4b349be978b06a9d0d958471a07a6cdeff4d
|
||||||
|
YUE2_WEBUI_COMMIT: 8fc05609bde5dcd345d7c6d57fff3da0839164c5
|
||||||
image: mike-ai/yue2:3b-0.1.6
|
image: mike-ai/yue2:3b-0.1.6
|
||||||
container_name: mike-ai-yue2-playground
|
container_name: mike-ai-yue2-playground
|
||||||
restart: "no"
|
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"]
|
entrypoint: ["python", "/opt/yue2-playground/server.py"]
|
||||||
environment:
|
environment:
|
||||||
NVIDIA_VISIBLE_DEVICES: "GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"
|
NVIDIA_VISIBLE_DEVICES: "GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"
|
||||||
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
NVIDIA_DRIVER_CAPABILITIES: compute,utility
|
||||||
YUE2_UI_HOST: "0.0.0.0"
|
YUE2_UI_HOST: "0.0.0.0"
|
||||||
YUE2_UI_PORT: "8014"
|
YUE2_UI_PORT: "8016"
|
||||||
ports:
|
ports:
|
||||||
- "127.0.0.1:8014:8014"
|
- "127.0.0.1:8016:8016"
|
||||||
volumes:
|
volumes:
|
||||||
- /data/models/yue2:/workspace/models:ro
|
- /data/models/yue2:/workspace/models:ro
|
||||||
- /data/music/yue2:/workspace/runs
|
- /data/music/yue2:/workspace/runs
|
||||||
@@ -49,9 +91,3 @@ services:
|
|||||||
- driver: nvidia
|
- driver: nvidia
|
||||||
device_ids: ["GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"]
|
device_ids: ["GPU-8ad38c6c-5a01-9d8e-1dfa-ed662ad78fbe"]
|
||||||
capabilities: [gpu]
|
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