Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ members = [
]

[workspace.package]
version = "0.2.83"
version = "0.2.84"
edition = "2024"
license = "MIT"
repository = "https://github.com/profullstack/c0mpute"
Expand Down
2 changes: 1 addition & 1 deletion apps/tui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@c0mpute/tui",
"version": "0.2.83",
"version": "0.2.84",
"private": true,
"type": "module",
"bin": {
Expand Down
2 changes: 1 addition & 1 deletion apps/web/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c0mpute",
"version": "0.2.83",
"version": "0.2.84",
"private": true,
"type": "module",
"scripts": {
Expand Down
10 changes: 9 additions & 1 deletion apps/web/src/app/api/v1/music/[id]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,14 @@ export async function GET(req: Request, { params }: { params: Promise<{ id: stri
return json({ error: { message: "the c0mpute network is restarting; try again in a minute", code: 503 } }, 503);
}
const body = (await upstream.json().catch(() => ({}))) as Record<string, unknown>;
if (upstream.status === 202) return json({ id, status: "pending", seconds: body.seconds ?? null }, 202, { "cache-control": "no-store" });
if (upstream.status === 202) {
// Infernet writes lyrics from a brief first; pass what it wrote along.
const pick = (k: string) => (typeof body[k] === "string" || typeof body[k] === "number" ? body[k] : undefined);
return json(
{ id, status: "pending", seconds: body.seconds ?? null, stage: pick("stage"), caption: pick("caption"), lyrics: pick("lyrics"), duration: pick("duration") },
202,
{ "cache-control": "no-store" },
);
}
return json({ error: { message: typeof body.error === "string" ? body.error : "song failed", code: upstream.status } }, upstream.status);
}
16 changes: 13 additions & 3 deletions apps/web/src/app/chat/chat-app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -267,15 +267,25 @@ export function ChatApp({ error }: { error: string | null }) {
});
const start = await res.json().catch(() => ({}));
if (res.status !== 202 || !start.poll) throw new Error(start.error?.message ?? `HTTP ${res.status}`);
const deadline = Date.now() + 20 * 60_000;
// Infernet may write lyrics from the brief first; keep what it wrote.
let written: { caption: string; lyrics: string } | null = null;
const deadline = Date.now() + 45 * 60_000;
let done: Response | null = null;
while (!done) {
if (Date.now() > deadline) throw new Error("song timed out");
await new Promise((r) => setTimeout(r, 5000));
if (ctrl.signal.aborted) throw new DOMException("aborted", "AbortError");
const poll = await fetch(start.poll, { cache: "no-store", signal: ctrl.signal });
if (poll.status === 202) {
setLast({ content: `// composing with ACE-Step 1.5 on a c0mpute worker… ${Math.round((Date.now() - started) / 1000)}s` });
const p = await poll.json().catch(() => ({}));
const secs = Math.round((Date.now() - started) / 1000);
if (typeof p.caption === "string") written = { caption: p.caption, lyrics: typeof p.lyrics === "string" ? p.lyrics : "" };
setLast({
content:
p.stage === "writing"
? `// writing lyrics and a style from your brief… ${secs}s`
: `// composing with ACE-Step 1.5 on a c0mpute worker… ${secs}s${written?.lyrics ? `\n\n${written.lyrics}` : ""}`,
});
continue;
}
if (!poll.ok) {
Expand All @@ -287,7 +297,7 @@ export function ChatApp({ error }: { error: string | null }) {
const blob = await done.blob();
const url = URL.createObjectURL(blob);
setLast({
content: `[music: ${music.prompt}${music.lyrics ? " (with lyrics)" : ", instrumental"}] (${Math.round((Date.now() - started) / 1000)}s on a c0mpute worker)`,
content: `[music: ${(written?.caption ?? music.prompt).slice(0, 300)}${written?.lyrics || music.lyrics ? " (with lyrics)" : ", instrumental"}] (${Math.round((Date.now() - started) / 1000)}s on a c0mpute worker)${written?.lyrics ? `\n\n${written.lyrics}` : ""}`,
audio: url,
audioType: blob.type || "audio/mpeg",
});
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/releases/latest.json/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const dynamic = "force-dynamic";
* this in sync with the workspace version in `Cargo.toml` on each release so a
* freshly built CLI reports "already latest" rather than a phantom upgrade.
*/
const FALLBACK_VERSION = "0.2.83";
const FALLBACK_VERSION = "0.2.84";
const FALLBACK_MIN_REQUIRED = "0.0.1";

type Channel = "stable" | "beta" | "nightly";
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/lib/chat/music.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function parseMusicCommand(text: string): MusicCommand | null {

export const MAX_TEXT_CHARS = 100_000;
export const MIN_SECONDS = 10;
export const MAX_SECONDS = 120;
export const MAX_SECONDS = 180;

/** Validate a POST body; returns the body to forward or an error string. */
export function parseMusicRequest(
Expand Down
4 changes: 2 additions & 2 deletions node/crates/c0mpute-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ fn default_music_min_ram_gb() -> u64 {
24
}
fn default_music_min_free_ram_gb() -> u64 {
// A bf16 DiT-only job peaks around 9 GB; keep some to spare.
12
// A bf16 DiT-only song peaked at 8.5 GB RSS (measured 2026-11-09).
10
}
fn default_music_min_free_disk_gb() -> u64 {
30
Expand Down
21 changes: 15 additions & 6 deletions node/crates/c0mpute-core/src/music.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ pub const MODEL_ID: &str = "ace-step-1.5";
pub const MODEL_TAG: &str = "c0mpute:music:model:ace-step-1.5";

/// Largest song a worker returns or a buyer accepts. A 2-minute 128 kb/s MP3
/// is ~2 MB; the FLAC fallback for the same song is up to ~20 MB.
pub const MAX_RESULT_BYTES: usize = 32 * 1024 * 1024;
/// is ~2 MB; the FLAC fallback for a 3-minute song is up to ~30 MB.
pub const MAX_RESULT_BYTES: usize = 48 * 1024 * 1024;
/// What a buyer may send. Longer than the model reads on purpose: callers
/// paste whole briefs and songs, and `clip_for_model` trims them.
pub const MAX_PROMPT_CHARS: usize = 100_000;
Expand All @@ -55,10 +55,12 @@ pub const MAX_LYRICS_CHARS: usize = 100_000;
pub const MODEL_PROMPT_CHARS: usize = 1_000;
pub const MODEL_LYRICS_CHARS: usize = 4_000;
pub const MIN_SECONDS: u32 = 10;
pub const MAX_SECONDS: u32 = 120;
pub const MAX_SECONDS: u32 = 180;
pub const DEFAULT_SECONDS: u32 = 30;
/// Worker-side limit for one song, model load included.
pub const JOB_TIMEOUT: Duration = Duration::from_secs(15 * 60);
/// Worker-side limit for one song, model load included. A 30 s song takes
/// ~130 s on 16 CPU threads and time grows with length, so a 3-minute song
/// on a busy box needs well over 10 minutes.
pub const JOB_TIMEOUT: Duration = Duration::from_secs(25 * 60);
const INSTALL_RETRY_BACKOFF_SECS: u64 = 6 * 60 * 60;

const WORKER: &str = include_str!("music_worker.py");
Expand Down Expand Up @@ -508,6 +510,13 @@ pub async fn generate(spec: &Txt2MusicSpec, job_dir: &Path) -> Result<PathBuf> {
.current_dir(job_dir)
.env("HF_HOME", music_root().join("hf-home"))
.env("ACESTEP_TMPDIR", job_dir)
// ACE-Step aborts its own diffusion loop after 600 s, which an 8-thread
// CPU budget passes on a 2-minute song (vienna, 2026-11-09). Our job
// timeout is the real limit; leave a margin for model load and decode.
.env(
"ACESTEP_GENERATION_TIMEOUT",
JOB_TIMEOUT.saturating_sub(Duration::from_secs(3 * 60)).as_secs().to_string(),
)
.env("TMPDIR", job_dir)
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::piped())
Expand Down Expand Up @@ -657,7 +666,7 @@ async fn run_job(
let path = generate(&spec, &job_dir).await?;
let bytes = tokio::fs::read(&path).await?;
if audio_content_type(&bytes).is_none() || bytes.len() > MAX_RESULT_BYTES {
bail!("ACE-Step output is not MP3/FLAC audio under the 32 MiB result limit");
bail!("ACE-Step output is not MP3/FLAC audio under the 48 MiB result limit");
}
// Over 1 MiB goes back as pieces: one chunk fetch caps out near 5 MiB.
crate::pieces::publish_result_bytes(net, store, &bytes).await
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "c0mpute-monorepo",
"version": "0.2.83",
"version": "0.2.84",
"private": true,
"workspaces": [
"apps/*",
Expand Down
2 changes: 1 addition & 1 deletion packages/shared/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@c0mpute/shared",
"version": "0.2.83",
"version": "0.2.84",
"private": true,
"type": "module",
"main": "./dist/index.js",
Expand Down
2 changes: 1 addition & 1 deletion plugins/ad-generator-agent/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
[module]
id = "ad-generator-agent"
name = "Ad Generator Agent — every ad type from one URL"
version = "0.2.83"
version = "0.2.84"
kind = "service"
category = "applications"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/ads-manager/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
[module]
id = "ads-manager"
name = "Ads Manager — shared ad operations layer"
version = "0.2.83"
version = "0.2.84"
kind = "service"
category = "applications"
status = "partial"
Expand Down
2 changes: 1 addition & 1 deletion plugins/coinpay/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
[module]
id = "coinpay"
name = "CoinPay — DID, payments, escrow, reputation"
version = "0.2.83"
version = "0.2.84"
kind = "service"
category = "applications"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/crawl/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[module]
id = "crawl"
name = "Crawl — distributed web fetching"
version = "0.2.83"
version = "0.2.84"
kind = "workload"
category = "data"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/ctv-ads/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
[module]
id = "ctv-ads"
name = "CTV Ads — VAST and VMAP from every gateway"
version = "0.2.83"
version = "0.2.84"
kind = "service"
category = "applications"
status = "partial"
Expand Down
2 changes: 1 addition & 1 deletion plugins/diffusion/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
[module]
id = "diffusion"
name = "Diffusion — image generation"
version = "0.2.83"
version = "0.2.84"
kind = "workload"
category = "ai"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/embed/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
[module]
id = "embed"
name = "Embeddings — vector generation"
version = "0.2.83"
version = "0.2.84"
kind = "workload"
category = "ai"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/gameserver/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
[module]
id = "gameserver"
name = "Game server — Minecraft / Factorio / Valheim"
version = "0.2.83"
version = "0.2.84"
kind = "workload"
category = "infrastructure"
status = "available"
Expand Down
2 changes: 1 addition & 1 deletion plugins/hosting/module.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
[module]
id = "hosting"
name = "Hosting — p2p static sites"
version = "0.2.83"
version = "0.2.84"
kind = "service"
category = "data"
status = "available"
Expand Down
Loading
Loading