mirror of
https://github.com/LostRuins/koboldcpp.git
synced 2026-08-26 15:15:16 +02:00
some fixes but some issues
This commit is contained in:
@@ -0,0 +1,496 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>KoboldCpp Music Generation</title>
|
||||
|
||||
<style>
|
||||
:root{
|
||||
--bg:#0f172a;
|
||||
--panel:#1e293b;
|
||||
--accent:#6366f1;
|
||||
--accent2:#22d3ee;
|
||||
--text:#f1f5f9;
|
||||
--muted:#94a3b8;
|
||||
--danger:#ef4444;
|
||||
}
|
||||
*{box-sizing:border-box}
|
||||
body{
|
||||
margin:0;
|
||||
font-family:Inter,system-ui,sans-serif;
|
||||
background:linear-gradient(135deg,#0f172a,#1e1b4b);
|
||||
color:var(--text);
|
||||
}
|
||||
header{
|
||||
padding:16px 20px;
|
||||
font-size:20px;
|
||||
font-weight:600;
|
||||
background:rgba(0,0,0,0.3);
|
||||
backdrop-filter:blur(10px);
|
||||
}
|
||||
.wrapper{
|
||||
display:grid;
|
||||
grid-template-columns:minmax(340px,500px) 1fr;
|
||||
gap:20px;
|
||||
padding:20px;
|
||||
}
|
||||
@media(max-width:1100px){
|
||||
.wrapper{grid-template-columns:1fr;}
|
||||
}
|
||||
.panel{
|
||||
background:var(--panel);
|
||||
padding:18px;
|
||||
border-radius:16px;
|
||||
box-shadow:0 10px 40px rgba(0,0,0,.4);
|
||||
}
|
||||
h2{
|
||||
margin:0 0 14px 0;
|
||||
font-size:16px;
|
||||
color:var(--accent2);
|
||||
}
|
||||
input,textarea{
|
||||
width:100%;
|
||||
padding:8px 10px;
|
||||
border-radius:8px;
|
||||
border:none;
|
||||
background:#0f172a;
|
||||
color:var(--text);
|
||||
font-size:14px;
|
||||
}
|
||||
textarea{resize:vertical;min-height:90px;}
|
||||
label{font-size:12px;color:var(--muted);}
|
||||
.form-grid{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(auto-fit,minmax(120px,1fr));
|
||||
gap:10px;
|
||||
}
|
||||
.compact-row{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(auto-fit,minmax(100px,1fr));
|
||||
gap:8px;
|
||||
}
|
||||
button{
|
||||
padding:8px 12px;
|
||||
border-radius:8px;
|
||||
border:none;
|
||||
cursor:pointer;
|
||||
font-weight:600;
|
||||
font-size:14px;
|
||||
}
|
||||
.primary{background:var(--accent);color:white;}
|
||||
.secondary{background:#334155;color:white;}
|
||||
.danger{background:var(--danger);color:white;}
|
||||
.actions{
|
||||
display:flex;
|
||||
gap:10px;
|
||||
margin-top:12px;
|
||||
flex-wrap:wrap;
|
||||
align-items:center;
|
||||
}
|
||||
.library-grid{
|
||||
display:grid;
|
||||
grid-template-columns:repeat(auto-fill,minmax(320px,1fr));
|
||||
gap:14px;
|
||||
}
|
||||
.library-item{
|
||||
background:#0f172a;
|
||||
padding:12px;
|
||||
border-radius:12px;
|
||||
display:flex;
|
||||
flex-direction:column;
|
||||
}
|
||||
.library-item h4{
|
||||
margin:0 0 6px 0;
|
||||
font-size:14px;
|
||||
}
|
||||
.meta{
|
||||
font-size:11px;
|
||||
color:var(--muted);
|
||||
margin-bottom:6px;
|
||||
}
|
||||
audio{width:100%;margin-top:6px;}
|
||||
.advanced-toggle{
|
||||
margin-top:8px;
|
||||
font-size:12px;
|
||||
cursor:pointer;
|
||||
color:var(--accent2);
|
||||
}
|
||||
.hidden{display:none}
|
||||
.pagination{
|
||||
margin-top:12px;
|
||||
display:flex;
|
||||
justify-content:center;
|
||||
align-items:center;
|
||||
gap:10px;
|
||||
}
|
||||
|
||||
/* Small inline spinner */
|
||||
.inline-spinner{
|
||||
width:18px;
|
||||
height:18px;
|
||||
border:3px solid rgba(255,255,255,.2);
|
||||
border-top:3px solid var(--accent2);
|
||||
border-radius:50%;
|
||||
animation:spin 1s linear infinite;
|
||||
}
|
||||
@keyframes spin{
|
||||
to{transform:rotate(360deg);}
|
||||
}
|
||||
|
||||
/* Message Box */
|
||||
#messageBox{
|
||||
position:fixed;
|
||||
bottom:20px;
|
||||
right:20px;
|
||||
background:#1e293b;
|
||||
padding:12px 16px;
|
||||
border-radius:12px;
|
||||
box-shadow:0 10px 30px rgba(0,0,0,.5);
|
||||
display:none;
|
||||
max-width:300px;
|
||||
font-size:13px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<header>🎵 KoboldCpp Music Generation</header>
|
||||
|
||||
<div class="wrapper">
|
||||
|
||||
<div class="panel">
|
||||
<h2>Song Setup</h2>
|
||||
|
||||
<label>Caption</label>
|
||||
<input id="caption">
|
||||
|
||||
<div style="margin-top:10px">
|
||||
<label>Lyrics</label>
|
||||
<textarea id="lyrics"></textarea>
|
||||
</div>
|
||||
|
||||
<div class="form-grid" style="margin-top:12px">
|
||||
<div><label>BPM</label><input id="bpm" type="number"></div>
|
||||
<div><label>Duration</label><input id="duration" type="number"></div>
|
||||
<div><label>Key</label><input id="keyscale"></div>
|
||||
<div><label>Time Sig</label><input id="timesignature"></div>
|
||||
<div><label>Language</label><input id="vocal_language"></div>
|
||||
</div>
|
||||
|
||||
<div class="advanced-toggle" onclick="toggleAdvanced()">⚙ Advanced Settings</div>
|
||||
|
||||
<div id="advanced" class="hidden">
|
||||
<div class="compact-row" style="margin-top:10px">
|
||||
<div><label>Seed</label><input id="seed" type="number"></div>
|
||||
<div><label>Temp</label><input id="lm_temperature" type="number" step="0.01"></div>
|
||||
<div><label>CFG</label><input id="lm_cfg_scale" type="number" step="0.1"></div>
|
||||
<div><label>Top P</label><input id="lm_top_p" type="number" step="0.01"></div>
|
||||
<div><label>Steps</label><input id="inference_steps" type="number"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="margin-top:14px">
|
||||
<label>API Base URL (optional)</label>
|
||||
<div style="display:flex; gap:6px;">
|
||||
<input id="baseUrl" placeholder="http://localhost:5001">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="actions" id="actionContainer">
|
||||
<div id="normalActions" style="display:flex; gap:10px; flex-wrap:wrap;">
|
||||
<button class="secondary" onclick="planSong()">Plan</button>
|
||||
<button class="primary" onclick="generateSong()">Generate</button>
|
||||
<button class="danger" onclick="clearFields()">Clear</button>
|
||||
<button onclick="exportPlan()">Export JSON</button>
|
||||
<button onclick="document.getElementById('importFile').click()">Import JSON</button>
|
||||
</div>
|
||||
|
||||
<button id="abortBtn" class="danger hidden" onclick="abortRequest()">Abort</button>
|
||||
<div id="inlineSpinner" class="inline-spinner hidden"></div>
|
||||
|
||||
<input type="file" id="importFile" hidden accept="application/json" onchange="importPlan(event)">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="panel">
|
||||
<h2>Your Library</h2>
|
||||
<div id="library" class="library-grid"></div>
|
||||
<div class="pagination">
|
||||
<button onclick="prevPage()">Prev</button>
|
||||
<span id="pageInfo"></span>
|
||||
<button onclick="nextPage()">Next</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="messageBox"><span id="messageText"></span></div>
|
||||
|
||||
<script>
|
||||
const DB_NAME="kobo_music_db";
|
||||
const STORE="kobo_music_tracks";
|
||||
const PAGE_SIZE=20;
|
||||
|
||||
let db;
|
||||
let currentPage=1;
|
||||
let totalItems=0;
|
||||
let currentController=null;
|
||||
|
||||
function setLoading(isLoading){
|
||||
document.getElementById("normalActions").style.display = isLoading ? "none" : "flex";
|
||||
document.getElementById("abortBtn").classList.toggle("hidden", !isLoading);
|
||||
document.getElementById("inlineSpinner").classList.toggle("hidden", !isLoading);
|
||||
}
|
||||
|
||||
function abortRequest(){
|
||||
if(currentController){
|
||||
currentController.abort();
|
||||
currentController=null;
|
||||
setLoading(false);
|
||||
showMessage("Request aborted.");
|
||||
}
|
||||
}
|
||||
|
||||
function showMessage(msg, timeout=3000){
|
||||
const box=document.getElementById("messageBox");
|
||||
document.getElementById("messageText").innerText=msg;
|
||||
box.style.display="block";
|
||||
setTimeout(()=>box.style.display="none",timeout);
|
||||
}
|
||||
|
||||
function buildUrl(path){
|
||||
let BASE_URL=document.getElementById("baseUrl").value.trim();
|
||||
if(!BASE_URL) return path;
|
||||
return BASE_URL.replace(/\/$/,"")+path;
|
||||
}
|
||||
|
||||
function initDB(){
|
||||
return new Promise((res,rej)=>{
|
||||
const req=indexedDB.open(DB_NAME,2);
|
||||
req.onupgradeneeded=e=>{
|
||||
db=e.target.result;
|
||||
db.createObjectStore(STORE,{keyPath:"id",autoIncrement:true});
|
||||
};
|
||||
req.onsuccess=e=>{db=e.target.result;res()};
|
||||
req.onerror=rej;
|
||||
});
|
||||
}
|
||||
|
||||
function toggleAdvanced(){
|
||||
document.getElementById("advanced").classList.toggle("hidden");
|
||||
}
|
||||
|
||||
function getFormData(){
|
||||
const ids=["caption","lyrics","bpm","duration","keyscale","timesignature",
|
||||
"vocal_language","seed","lm_temperature","lm_cfg_scale","lm_top_p","inference_steps"];
|
||||
const data={};
|
||||
ids.forEach(id=>{
|
||||
const el=document.getElementById(id);
|
||||
if(!el) return;
|
||||
const v=el.value;
|
||||
if(v!=="") data[id]=isNaN(v)?v:Number(v);
|
||||
});
|
||||
return data;
|
||||
}
|
||||
|
||||
function updateForm(data){
|
||||
Object.keys(data).forEach(k=>{
|
||||
if(document.getElementById(k))
|
||||
document.getElementById(k).value=data[k]??"";
|
||||
});
|
||||
}
|
||||
|
||||
function deriveTitle(caption){
|
||||
let rnd_id = Math.floor(Math.random() * 8999) + 1000;
|
||||
if(!caption)
|
||||
{
|
||||
caption = "Untitled";
|
||||
}
|
||||
let output = caption.trim().split("\n")[0].slice(0,30);
|
||||
output += ` ${rnd_id}`;
|
||||
return output;
|
||||
}
|
||||
|
||||
async function planSong(){
|
||||
try{
|
||||
currentController=new AbortController();
|
||||
setLoading(true);
|
||||
|
||||
const res=await fetch(buildUrl("/api/extra/music/prepare"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify(getFormData()),
|
||||
signal:currentController.signal
|
||||
});
|
||||
|
||||
if(!res.ok) throw new Error();
|
||||
const data=await res.json();
|
||||
updateForm(data);
|
||||
showMessage("Plan generated.");
|
||||
|
||||
}catch(e){
|
||||
if(e.name!=="AbortError")
|
||||
showMessage("⚠ Unable to connect to server.");
|
||||
}finally{
|
||||
currentController=null;
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
async function generateSong(){
|
||||
try{
|
||||
currentController=new AbortController();
|
||||
setLoading(true);
|
||||
|
||||
const payload=getFormData();
|
||||
const res=await fetch(buildUrl("/api/extra/music/generate"),{
|
||||
method:"POST",
|
||||
headers:{"Content-Type":"application/json"},
|
||||
body:JSON.stringify(payload),
|
||||
signal:currentController.signal
|
||||
});
|
||||
|
||||
if(!res.ok) throw new Error();
|
||||
const wavBlob=await res.blob();
|
||||
const tx=db.transaction(STORE,"readwrite");
|
||||
tx.objectStore(STORE).add({
|
||||
title:deriveTitle(payload.caption),
|
||||
date:new Date().toISOString(),
|
||||
params:JSON.parse(JSON.stringify(payload)),
|
||||
audio:wavBlob
|
||||
});
|
||||
|
||||
tx.oncomplete=()=>{
|
||||
currentPage=1;
|
||||
loadLibrary();
|
||||
showMessage("Song generated successfully!");
|
||||
};
|
||||
|
||||
}catch(e){
|
||||
if(e.name!=="AbortError")
|
||||
showMessage("⚠ Failed to generate song.");
|
||||
}finally{
|
||||
currentController=null;
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
function downloadTrackJSON(id){
|
||||
const tx = db.transaction(STORE, "readonly");
|
||||
const store = tx.objectStore(STORE);
|
||||
const req = store.get(id);
|
||||
|
||||
req.onsuccess = function(){
|
||||
const item = req.result;
|
||||
if(!item || !item.params){
|
||||
showMessage("No JSON data found.");
|
||||
return;
|
||||
}
|
||||
|
||||
const blob = new Blob(
|
||||
[JSON.stringify(item.params, null, 2)],
|
||||
{ type: "application/json" }
|
||||
);
|
||||
|
||||
const url = URL.createObjectURL(blob);
|
||||
const a = document.createElement("a");
|
||||
a.href = url;
|
||||
a.download = `${item.title}.json`;
|
||||
a.click();
|
||||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
req.onerror = function(){
|
||||
showMessage("Failed to load JSON.");
|
||||
};
|
||||
}
|
||||
|
||||
/* Library functions unchanged */
|
||||
|
||||
function loadLibrary(){
|
||||
const container=document.getElementById("library");
|
||||
container.innerHTML="";
|
||||
const tx=db.transaction(STORE,"readonly");
|
||||
const store=tx.objectStore(STORE);
|
||||
let items=[];
|
||||
store.openCursor(null,"prev").onsuccess=e=>{
|
||||
const cursor=e.target.result;
|
||||
if(cursor){
|
||||
items.push(cursor.value);
|
||||
cursor.continue();
|
||||
} else {
|
||||
totalItems=items.length;
|
||||
const start=(currentPage-1)*PAGE_SIZE;
|
||||
const pageItems=items.slice(start,start+PAGE_SIZE);
|
||||
pageItems.forEach(item=>{
|
||||
const div=document.createElement("div");
|
||||
div.className="library-item";
|
||||
const url=URL.createObjectURL(item.audio);
|
||||
div.innerHTML=`
|
||||
<h4>${item.title}</h4>
|
||||
<div class="meta">${new Date(item.date).toLocaleString()}</div>
|
||||
<audio controls src="${url}"></audio>
|
||||
<div style="margin-top:6px;display:flex;gap:6px;">
|
||||
<a href="${url}" download="${item.title}.wav">
|
||||
<button class="secondary">Download</button>
|
||||
</a>
|
||||
<button class="secondary" onclick="downloadTrackJSON(${item.id})">
|
||||
Get JSON
|
||||
</button>
|
||||
|
||||
<button class="danger" onclick="deleteTrack(${item.id})">Delete</button>
|
||||
</div>
|
||||
`;
|
||||
container.appendChild(div);
|
||||
});
|
||||
const totalPages=Math.ceil(totalItems/PAGE_SIZE)||1;
|
||||
document.getElementById("pageInfo").innerText=
|
||||
`Page ${currentPage} / ${totalPages}`;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function nextPage(){ if(currentPage<Math.ceil(totalItems/PAGE_SIZE)){currentPage++;loadLibrary();}}
|
||||
function prevPage(){ if(currentPage>1){currentPage--;loadLibrary();}}
|
||||
function deleteTrack(id){
|
||||
const tx=db.transaction(STORE,"readwrite");
|
||||
tx.objectStore(STORE).delete(id);
|
||||
tx.oncomplete=loadLibrary;
|
||||
}
|
||||
function clearFields()
|
||||
{
|
||||
const fields = document.querySelectorAll('.form-grid input, #advanced input');
|
||||
fields.forEach(field => {
|
||||
field.value = '';
|
||||
});
|
||||
document.getElementById("caption").value = "";
|
||||
document.getElementById("lyrics").value = "";
|
||||
}
|
||||
function exportPlan(){
|
||||
const data=getFormData();
|
||||
const blob=new Blob([JSON.stringify(data,null,2)],{type:"application/json"});
|
||||
const url=URL.createObjectURL(blob);
|
||||
const a=document.createElement("a");
|
||||
a.href=url;
|
||||
a.download="music_plan.json";
|
||||
a.click();
|
||||
}
|
||||
function importPlan(event){
|
||||
const file=event.target.files[0];
|
||||
if(!file) return;
|
||||
const reader=new FileReader();
|
||||
reader.onload=e=>{
|
||||
const data=JSON.parse(e.target.result);
|
||||
updateForm(data);
|
||||
};
|
||||
reader.readAsText(file);
|
||||
}
|
||||
|
||||
initDB().then(loadLibrary);
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
+28
-2
@@ -138,6 +138,8 @@ embedded_kcpp_docs_gz = None
|
||||
embedded_kcpp_sdui = None
|
||||
embedded_kcpp_sdui_gz = None
|
||||
embedded_lcpp_ui_gz = None
|
||||
embedded_musicui = None
|
||||
embedded_musicui_gz = None
|
||||
voicebank = {}
|
||||
voicelist = ["kobo","cheery","sleepy","shouty","chatty"]
|
||||
sslvalid = False
|
||||
@@ -3926,7 +3928,7 @@ Change Mode<br>
|
||||
self.wfile.write(finalhtml)
|
||||
|
||||
def do_GET(self):
|
||||
global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui, embedded_kailite_gz, embedded_kcpp_docs_gz, embedded_kcpp_sdui_gz, embedded_lcpp_ui_gz
|
||||
global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui, embedded_kailite_gz, embedded_kcpp_docs_gz, embedded_kcpp_sdui_gz, embedded_lcpp_ui_gz, embedded_musicui, embedded_musicui_gz
|
||||
global last_req_time, start_time, cached_chat_template, has_vision_support, has_audio_support, has_whisper, friendlymodelname
|
||||
global savedata_obj, has_multiplayer, multiplayer_turn_major, multiplayer_turn_minor, multiplayer_story_data_compressed, multiplayer_dataformat, multiplayer_lastactive, maxctx, maxhordelen, friendlymodelname, lastuploadedcomfyimg, lastgeneratedcomfyimg, KcppVersion, totalgens, preloaded_story, exitcounter, currentusergenkey, friendlysdmodelname, fullsdmodelpath, password, friendlyembeddingsmodelname, voicelist
|
||||
|
||||
@@ -4230,6 +4232,16 @@ Change Mode<br>
|
||||
else:
|
||||
response_body = ("KoboldCpp API is running, but KCPP SDUI is not loaded").encode()
|
||||
|
||||
elif clean_path.startswith(("/musicui")):
|
||||
content_type = 'text/html'
|
||||
if supports_gzip and embedded_musicui_gz is not None:
|
||||
response_body = embedded_musicui_gz
|
||||
content_encoding = 'gzip'
|
||||
elif embedded_musicui is not None:
|
||||
response_body = embedded_musicui
|
||||
else:
|
||||
response_body = ("KoboldCpp API is running, but KCPP MusicUI is not loaded").encode()
|
||||
|
||||
elif clean_path=="/v1":
|
||||
content_type = 'text/html'
|
||||
response_body = ("KoboldCpp OpenAI compatible endpoint is running!<br>For usage reference, see <a href='https://platform.openai.com/docs/api-reference'>https://platform.openai.com/docs/api-reference</a><br>For other endpoints, see <a href='/api'>KoboldCpp API Documentation</a>").encode()
|
||||
@@ -8269,7 +8281,7 @@ def main(launch_args, default_args):
|
||||
input()
|
||||
|
||||
def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False):
|
||||
global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui, embedded_kailite_gz, embedded_kcpp_docs_gz, embedded_kcpp_sdui_gz, embedded_lcpp_ui_gz, start_time, exitcounter, global_memory, using_gui_launcher
|
||||
global embedded_kailite, embedded_kcpp_docs, embedded_kcpp_sdui, embedded_kailite_gz, embedded_kcpp_docs_gz, embedded_kcpp_sdui_gz, embedded_lcpp_ui_gz, embedded_musicui, embedded_musicui_gz, start_time, exitcounter, global_memory, using_gui_launcher
|
||||
global libname, args, friendlymodelname, friendlysdmodelname, fullsdmodelpath, password, fullwhispermodelpath, ttsmodelpath, embeddingsmodelpath, musicdiffusionmodelpath, friendlyembeddingsmodelname, has_audio_support, has_vision_support, cached_chat_template
|
||||
|
||||
start_server = True
|
||||
@@ -8882,6 +8894,15 @@ def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False):
|
||||
except Exception:
|
||||
print("Could not find Embedded llama.cpp UI.")
|
||||
|
||||
try:
|
||||
with open(os.path.join(embddir, "kcpp_musicui.embd"), mode='rb') as f:
|
||||
embedded_musicui = f.read()
|
||||
embedded_musicui_gz = gzip.compress(embedded_musicui)
|
||||
if args.musicllm or args.musicdiffusion:
|
||||
print("Embedded MusicUI loaded.")
|
||||
except Exception:
|
||||
print("Could not find Embedded MusicUI.")
|
||||
|
||||
# load all TTS audio files
|
||||
if args.ttsdir and args.ttsmodel and os.path.isdir(args.ttsdir):
|
||||
try:
|
||||
@@ -8946,6 +8967,7 @@ def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False):
|
||||
enabledmlist.append("VectorEmbeddings") if "embeddings" in caps and caps["embeddings"] else disabledmlist.append("VectorEmbeddings")
|
||||
enabledmlist.append("AdminControl") if "admin" in caps and caps["admin"]!=0 else disabledmlist.append("AdminControl")
|
||||
enabledmlist.append("MCPBridge") if "mcp" in caps and caps["mcp"] else disabledmlist.append("MCPBridge")
|
||||
enabledmlist.append("MusicGen") if "music" in caps and caps["music"] else disabledmlist.append("MusicGen")
|
||||
|
||||
print(f"======\nActive Modules: {' '.join(enabledmlist)}")
|
||||
print(f"Inactive Modules: {' '.join(disabledmlist)}")
|
||||
@@ -8974,6 +8996,8 @@ def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False):
|
||||
print(f"Starting llama.cpp secondary WebUI at {endpoint_url}/lcpp/")
|
||||
if args.sdmodel:
|
||||
print(f"StableUI is available at {endpoint_url}/sdui/")
|
||||
if args.musicdiffusion or args.musicllm:
|
||||
print(f"MusicUI is available at {endpoint_url}/musicui/")
|
||||
elif global_memory:
|
||||
val = global_memory["tunnel_url"]
|
||||
if val:
|
||||
@@ -8984,6 +9008,8 @@ def kcpp_main_process(launch_args, g_memory=None, gui_launcher=False):
|
||||
print(f"Starting llama.cpp secondary WebUI at {endpoint_url}/lcpp/")
|
||||
if args.sdmodel:
|
||||
print(f"StableUI is available at {endpoint_url}/sdui/")
|
||||
if args.musicdiffusion or args.musicllm:
|
||||
print(f"MusicUI is available at {endpoint_url}/musicui/")
|
||||
global_memory["load_complete"] = True
|
||||
if args.launch:
|
||||
def launch_browser_thread():
|
||||
|
||||
@@ -1520,23 +1520,30 @@ std::string acestep_prepare_request(const music_generation_inputs inputs)
|
||||
bool user_has_codes = !req.audio_codes.empty();
|
||||
bool need_lm_codes = req.thinking && !user_has_codes;
|
||||
|
||||
bool is_simple = ace.lyrics.empty() &&
|
||||
ace.bpm <= 0 && ace.duration <= 0 &&
|
||||
ace.keyscale.empty() && ace.timesignature.empty();
|
||||
bool is_simple = ace.lyrics.empty();
|
||||
|
||||
std::vector<int> prompt;
|
||||
std::vector<AcePrompt> aces; // populated by Phase 1 (simple or partial)
|
||||
|
||||
// Preprocessor: simple mode generates lyrics + metas from caption
|
||||
if (is_simple) {
|
||||
fprintf(stderr, "[Simple] Inspiration\n");
|
||||
fprintf(stderr, "[Simple] Inspiration, Language: %s\n",ace.vocal_language.c_str());
|
||||
|
||||
|
||||
const char * sys =
|
||||
"# Instruction\n"
|
||||
"Expand the user's input into a more detailed"
|
||||
" and specific musical description:\n";
|
||||
std::string user_msg = ace.caption + "\n\ninstrumental: "
|
||||
+ std::string(req.instrumental ? "true" : "false");
|
||||
"Expand the user's input into a more detailed and specific musical description:\n";
|
||||
bool forcelang = (ace.vocal_language != "unknown" && !ace.vocal_language.empty());
|
||||
std::string langstr = forcelang?("language: "+ace.vocal_language+"\n"):"";
|
||||
std::string cap = "";
|
||||
std::string instru = "instrumental: false\n";
|
||||
if(ace.caption!="")
|
||||
{
|
||||
cap = "Music Caption: " + ace.caption;
|
||||
}
|
||||
std::string user_msg = cap + "\n\n"+instru+langstr;
|
||||
|
||||
printf("\n[Prompt: %s]\n",user_msg.c_str());
|
||||
prompt = build_custom_prompt(acestep_bpe, sys, user_msg.c_str());
|
||||
|
||||
// FSM: reset then optionally force language (shared for both paths)
|
||||
@@ -1549,7 +1556,7 @@ std::string acestep_prepare_request(const music_generation_inputs inputs)
|
||||
prompt.size(), batch_size, seed, seed + batch_size - 1);
|
||||
|
||||
auto phase1_texts = generate_phase1_batch(
|
||||
&acestep_llm, &acestep_bpe, prompt, 2048, temperature, 1.0f, 0,
|
||||
&acestep_llm, &acestep_bpe, prompt, 2048, temperature, 0.95f, 0,
|
||||
seed, batch_size, use_fsm ? &fsm : nullptr, true);
|
||||
|
||||
parse_phase1_into_aces(phase1_texts, ace, aces, seed, "Simple", true);
|
||||
|
||||
@@ -179,9 +179,21 @@ static void cond_ggml_forward(CondGGML * m,
|
||||
// Linear embed: [1024, S_lyric] -> [2048, S_lyric]
|
||||
struct ggml_tensor * lyric_h = qwen3_linear_bias(ctx, m->lyric_embed_w,
|
||||
m->lyric_embed_b, t_lyric_in);
|
||||
// 8 layers + final norm (bidirectional: mask=NULL)
|
||||
lyric_h = qwen3_build_layers(ctx, m->lyric_cfg, m->lyric_layers, m->lyric_norm,
|
||||
lyric_h, lyric_pos, NULL, S_lyric);
|
||||
|
||||
// Bidirectional sliding window mask for even layers (|i-j| <= 128)
|
||||
// Python: layer_types = [sliding, full, sliding, full, ...]
|
||||
// sliding_window = 128
|
||||
struct ggml_tensor * lyric_slide_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F16, S_lyric, S_lyric);
|
||||
ggml_set_name(lyric_slide_mask, "lyric_slide_mask");
|
||||
ggml_set_input(lyric_slide_mask);
|
||||
|
||||
// 8 layers with alternating masks + final norm
|
||||
for (int i = 0; i < m->lyric_cfg.n_layers; i++) {
|
||||
struct ggml_tensor * layer_mask = (i % 2 == 0) ? lyric_slide_mask : NULL;
|
||||
lyric_h = qwen3_build_layer(ctx, m->lyric_cfg, &m->lyric_layers[i],
|
||||
lyric_h, lyric_pos, layer_mask, S_lyric);
|
||||
}
|
||||
lyric_h = qwen3_rms_norm(ctx, lyric_h, m->lyric_norm, m->lyric_cfg.rms_norm_eps);
|
||||
|
||||
ggml_set_name(lyric_h, "lyric_out");
|
||||
ggml_set_output(lyric_h);
|
||||
@@ -200,6 +212,7 @@ static void cond_ggml_forward(CondGGML * m,
|
||||
struct ggml_tensor * timbre_out = NULL;
|
||||
struct ggml_tensor * t_timbre_in = NULL;
|
||||
struct ggml_tensor * timbre_pos = NULL;
|
||||
struct ggml_tensor * timbre_slide_mask = NULL;
|
||||
|
||||
if (has_timbre) {
|
||||
timbre_pos = ggml_new_tensor_1d(ctx, GGML_TYPE_I32, S_ref);
|
||||
@@ -213,9 +226,19 @@ static void cond_ggml_forward(CondGGML * m,
|
||||
// Linear embed: [64, S_ref] -> [2048, S_ref]
|
||||
struct ggml_tensor * timbre_h = qwen3_linear_bias(ctx, m->timbre_embed_w,
|
||||
m->timbre_embed_b, t_timbre_in);
|
||||
// 4 layers + final norm
|
||||
timbre_h = qwen3_build_layers(ctx, m->timbre_cfg, m->timbre_layers, m->timbre_norm,
|
||||
timbre_h, timbre_pos, NULL, S_ref);
|
||||
|
||||
// Bidirectional sliding window mask for even layers
|
||||
timbre_slide_mask = ggml_new_tensor_2d(ctx, GGML_TYPE_F16, S_ref, S_ref);
|
||||
ggml_set_name(timbre_slide_mask, "timbre_slide_mask");
|
||||
ggml_set_input(timbre_slide_mask);
|
||||
|
||||
// 4 layers with alternating masks + final norm
|
||||
for (int i = 0; i < m->timbre_cfg.n_layers; i++) {
|
||||
struct ggml_tensor * layer_mask = (i % 2 == 0) ? timbre_slide_mask : NULL;
|
||||
timbre_h = qwen3_build_layer(ctx, m->timbre_cfg, &m->timbre_layers[i],
|
||||
timbre_h, timbre_pos, layer_mask, S_ref);
|
||||
}
|
||||
timbre_h = qwen3_rms_norm(ctx, timbre_h, m->timbre_norm, m->timbre_cfg.rms_norm_eps);
|
||||
|
||||
// Take first frame: [2048, S_ref] -> view [2048, 1]
|
||||
timbre_out = ggml_view_2d(ctx, timbre_h, H, 1,
|
||||
@@ -242,11 +265,39 @@ static void cond_ggml_forward(CondGGML * m,
|
||||
ggml_backend_tensor_set(lyric_pos, pos.data(), 0, S_lyric * sizeof(int));
|
||||
}
|
||||
|
||||
// Lyric sliding window mask: bidirectional, |i-j| <= 128
|
||||
{
|
||||
const int W = 128;
|
||||
std::vector<uint16_t> mask_data(S_lyric * S_lyric);
|
||||
for (int i = 0; i < S_lyric; i++) {
|
||||
for (int j = 0; j < S_lyric; j++) {
|
||||
int d = i - j; if (d < 0) d = -d;
|
||||
mask_data[i * S_lyric + j] = ggml_fp32_to_fp16(d <= W ? 0.0f : -INFINITY);
|
||||
}
|
||||
}
|
||||
ggml_backend_tensor_set(lyric_slide_mask, mask_data.data(), 0,
|
||||
S_lyric * S_lyric * sizeof(uint16_t));
|
||||
fprintf(stderr, "[CondEnc] Lyric sliding mask: %dx%d, window=%d\n", S_lyric, S_lyric, W);
|
||||
}
|
||||
|
||||
if (has_timbre) {
|
||||
ggml_backend_tensor_set(t_timbre_in, timbre_feats, 0, 64 * S_ref * sizeof(float));
|
||||
std::vector<int> pos(S_ref);
|
||||
for (int i = 0; i < S_ref; i++) pos[i] = i;
|
||||
ggml_backend_tensor_set(timbre_pos, pos.data(), 0, S_ref * sizeof(int));
|
||||
|
||||
// Timbre sliding window mask: bidirectional, |i-j| <= 128
|
||||
const int W = 128;
|
||||
std::vector<uint16_t> mask_data(S_ref * S_ref);
|
||||
for (int i = 0; i < S_ref; i++) {
|
||||
for (int j = 0; j < S_ref; j++) {
|
||||
int d = i - j; if (d < 0) d = -d;
|
||||
mask_data[i * S_ref + j] = ggml_fp32_to_fp16(d <= W ? 0.0f : -INFINITY);
|
||||
}
|
||||
}
|
||||
ggml_backend_tensor_set(timbre_slide_mask, mask_data.data(), 0,
|
||||
S_ref * S_ref * sizeof(uint16_t));
|
||||
fprintf(stderr, "[CondEnc] Timbre sliding mask: %dx%d, window=%d\n", S_ref, S_ref, W);
|
||||
}
|
||||
|
||||
// Compute
|
||||
@@ -292,4 +343,4 @@ static void cond_ggml_free(CondGGML * m) {
|
||||
if (m->cpu_backend) ggml_backend_free(m->cpu_backend);
|
||||
wctx_free(&m->wctx);
|
||||
*m = {};
|
||||
}
|
||||
}
|
||||
@@ -762,7 +762,7 @@ std::string acestep_generate_audio(const music_generation_inputs inputs)
|
||||
const char * keyscale = req.keyscale.empty() ? "N/A" : req.keyscale.c_str();
|
||||
const char * timesig = req.timesignature.empty() ? "N/A" : req.timesignature.c_str();
|
||||
const char * language = req.vocal_language.empty() ? "en" : req.vocal_language.c_str();
|
||||
float duration = req.duration > 0 ? req.duration : 120.0f;
|
||||
float duration = req.duration > 0 ? req.duration : 60.0f;
|
||||
long long seed = req.seed;
|
||||
int num_steps = req.inference_steps > 0 ? req.inference_steps : 8;
|
||||
float guidance_scale = req.guidance_scale > 0 ? req.guidance_scale : 7.0f;
|
||||
@@ -869,8 +869,8 @@ std::string acestep_generate_audio(const music_generation_inputs inputs)
|
||||
|
||||
// Context building
|
||||
// Silence latent for this T
|
||||
std::vector<float> silence(Oc * T);
|
||||
memcpy(silence.data(), silence_full.data(), (size_t)(Oc * T) * sizeof(float));
|
||||
// std::vector<float> silence(Oc * T);
|
||||
// memcpy(silence.data(), silence_full.data(), (size_t)(Oc * T) * sizeof(float));
|
||||
|
||||
// Decode audio codes if provided
|
||||
int decoded_T = 0;
|
||||
@@ -896,7 +896,7 @@ std::string acestep_generate_audio(const music_generation_inputs inputs)
|
||||
for (int t = 0; t < T; t++) {
|
||||
const float * src = (t < decoded_T)
|
||||
? decoded_latents.data() + t * Oc
|
||||
: silence.data() + t * Oc;
|
||||
: silence_full.data() + (t - decoded_T) * Oc;
|
||||
for (int c = 0; c < Oc; c++)
|
||||
context_single[t * ctx_ch + c] = src[c];
|
||||
for (int c = 0; c < Oc; c++)
|
||||
|
||||
@@ -19,7 +19,7 @@ void request_init(AceRequest * r) {
|
||||
r->duration = -1.0f;
|
||||
r->keyscale = "";
|
||||
r->timesignature = "";
|
||||
r->vocal_language = "unknown";
|
||||
r->vocal_language = "en";
|
||||
r->task_type = "text2music";
|
||||
r->seed = -1;
|
||||
r->thinking = false;
|
||||
|
||||
Reference in New Issue
Block a user