acffe78750
All api.opendaw.studio → /api/opendaw (local proxy) Feature checks bypassed (crossOriginIsolated via Express headers) DemoProjects, PublishMusic, UserCounter, ErrorsPage all local
74 lines
4.6 KiB
JavaScript
74 lines
4.6 KiB
JavaScript
const http = require("http");
|
|
const { execFileSync } = require("child_process");
|
|
const fs = require("fs");
|
|
const PORT = 8301;
|
|
const TTS_URL = "http://127.0.0.1:9100";
|
|
const OLLAMA_URL = "http://127.0.0.1:11434";
|
|
|
|
function readBody(req) {
|
|
return new Promise(r => { const c = []; req.on("data", d => c.push(d)); req.on("end", () => r(Buffer.concat(c).toString())); });
|
|
}
|
|
|
|
const server = http.createServer(async (req, res) => {
|
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
|
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
if (req.method === "OPTIONS") { res.writeHead(200); res.end(); return; }
|
|
const url = new URL(req.url, `http://localhost:${PORT}`);
|
|
|
|
if (url.pathname === "/health") {
|
|
res.writeHead(200, {"Content-Type":"application/json"});
|
|
res.end(JSON.stringify({ok:true,service:"ai-bridge",backends:["tts","musicgen","noise","ollama"]}));
|
|
return;
|
|
}
|
|
if (url.pathname === "/generate/music" && req.method === "POST") {
|
|
const {prompt="ambient",duration=30,style="experimental"} = JSON.parse(await readBody(req));
|
|
try {
|
|
const r = await fetch(`${TTS_URL}/compose`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({prompt:`${prompt}, ${style}`,duration}),signal:AbortSignal.timeout(300000)});
|
|
if (!r.ok) throw new Error(`TTS ${r.status}`);
|
|
const buf = Buffer.from(await r.arrayBuffer());
|
|
res.writeHead(200,{"Content-Type":"audio/wav","Content-Length":buf.length}); res.end(buf);
|
|
} catch(e) { res.writeHead(500,{"Content-Type":"application/json"}); res.end(JSON.stringify({error:e.message})); }
|
|
return;
|
|
}
|
|
if (url.pathname === "/generate/voice" && req.method === "POST") {
|
|
const {text="Bonjour",persona="pharmacius"} = JSON.parse(await readBody(req));
|
|
try {
|
|
const r = await fetch(`${TTS_URL}/synthesize`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({text,persona}),signal:AbortSignal.timeout(30000)});
|
|
if (!r.ok) throw new Error(`TTS ${r.status}`);
|
|
const buf = Buffer.from(await r.arrayBuffer());
|
|
res.writeHead(200,{"Content-Type":"audio/wav","Content-Length":buf.length}); res.end(buf);
|
|
} catch(e) { res.writeHead(500,{"Content-Type":"application/json"}); res.end(JSON.stringify({error:e.message})); }
|
|
return;
|
|
}
|
|
if (url.pathname === "/generate/noise" && req.method === "POST") {
|
|
const {type="pink",duration=10} = JSON.parse(await readBody(req));
|
|
const types = {white:"anoisesrc=d=DUR:c=white",pink:"anoisesrc=d=DUR:c=pink",brown:"anoisesrc=d=DUR:c=brown",sine:"sine=frequency=220:duration=DUR",drone:"sine=frequency=55:duration=DUR,tremolo=f=0.1:d=0.7"};
|
|
const filter = (types[type]||types.pink).replace(/DUR/g,String(duration));
|
|
const tmp = `/tmp/ai-noise-${Date.now()}.wav`;
|
|
try {
|
|
execFileSync("ffmpeg",["-f","lavfi","-i",filter,"-t",String(duration),"-ar","44100","-ac","2","-y",tmp],{timeout:15000});
|
|
const buf = fs.readFileSync(tmp); fs.unlinkSync(tmp);
|
|
res.writeHead(200,{"Content-Type":"audio/wav","Content-Length":buf.length}); res.end(buf);
|
|
} catch(e) { res.writeHead(500,{"Content-Type":"application/json"}); res.end(JSON.stringify({error:e.message})); }
|
|
return;
|
|
}
|
|
if (url.pathname === "/generate/suggest" && req.method === "POST") {
|
|
const {tracks=[]} = JSON.parse(await readBody(req));
|
|
const list = tracks.map((t,i)=>`#${i+1} [${t.type}] ${t.name} (${t.duration}s)`).join("\n");
|
|
try {
|
|
const r = await fetch(`${OLLAMA_URL}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:"qwen3.5:9b",messages:[{role:"user",content:`Compositeur. Pistes:\n${list}\nSuggere en JSON: {"type":"music|voice|noise","prompt":"...","duration":30}`}],stream:false,options:{num_predict:100},keep_alive:"30m",think:false}),signal:AbortSignal.timeout(15000)});
|
|
const d = await r.json();
|
|
res.writeHead(200,{"Content-Type":"application/json"}); res.end(d.message?.content||'{"type":"noise","prompt":"pink","duration":10}');
|
|
} catch { res.writeHead(200,{"Content-Type":"application/json"}); res.end('{"type":"noise","prompt":"pink","duration":10}'); }
|
|
return;
|
|
}
|
|
if (url.pathname === "/personas") {
|
|
try { const r = await fetch("http://localhost:3333/api/personas"); const d = await r.json(); res.writeHead(200,{"Content-Type":"application/json"}); res.end(JSON.stringify(d)); }
|
|
catch { res.writeHead(200,{"Content-Type":"application/json"}); res.end('{"data":[]}'); }
|
|
return;
|
|
}
|
|
res.writeHead(404); res.end("Not found");
|
|
});
|
|
server.listen(PORT, () => console.log(`[ai-bridge] :${PORT}`));
|