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
2 changes: 1 addition & 1 deletion .github/workflows/video-runner.yml
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ jobs:
# Links the package to this public repo (and its README/license).
labels: |
org.opencontainers.image.source=https://github.com/${{ github.repository }}
org.opencontainers.image.description=c0mpute video runner (Wan 2.2, LTX-2.3)
org.opencontainers.image.description=c0mpute video runner (Wan 2.2 / 2.1, LTX-2.3)
org.opencontainers.image.licenses=MIT
# The context is plugins/video so module.toml — the runner's model
# registry — is part of the image.
Expand Down
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.89"
version = "0.2.90"
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.89",
"version": "0.2.90",
"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.89",
"version": "0.2.90",
"private": true,
"type": "module",
"scripts": {
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/app/plugins/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,10 @@ function modelSpec(model: ModelOption): string[] {
model.vram_gib ? `${model.vram_gib} GiB VRAM` : undefined,
model.resolution,
model.audio ? "video + audio" : undefined,
typeof model.cpu === "string" && model.cpu.length > 0
? `or CPU: ${model.cpu}`
: model.cpu === true
? "or CPU (slow, batch)"
: undefined,
].filter((v): v is string => typeof v === "string" && v.length > 0);
}
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.89";
const FALLBACK_VERSION = "0.2.90";
const FALLBACK_MIN_REQUIRED = "0.0.1";

type Channel = "stable" | "beta" | "nightly";
Expand Down
5 changes: 5 additions & 0 deletions apps/web/src/lib/plugins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,11 @@ export interface ModelOption {
audio?: boolean;
/** Few-step distilled checkpoint (fixed schedule, no CFG). */
distilled?: boolean;
/**
* CPU-only nodes can serve it too; the string says what that takes and
* how slow it is (CPU video is batch, minutes per clip).
*/
cpu?: string | boolean;
}

/**
Expand Down
54 changes: 51 additions & 3 deletions node/crates/c0mpute-cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,10 @@ enum VideoCmd {
/// Build from source without trying the registry first.
#[arg(long)]
build: bool,
/// No GPU: install CPU text-to-video instead (Wan 2.1 1.3B on
/// stable-diffusion.cpp, ~5.4 GB, slow batch clips). Opts this node in.
#[arg(long)]
cpu: bool,
},
/// Report whether this node can serve video, and why not if it cannot.
Check {
Expand Down Expand Up @@ -1680,6 +1684,7 @@ async fn run_worker(cmd: WorkerCmd, config_path: &std::path::Path) -> Result<()>
Role::WorkflowStep,
Role::Diffusion,
Role::Music,
Role::Video,
Role::Crawl,
Role::Hosting,
Role::Ocr,
Expand Down Expand Up @@ -2506,7 +2511,27 @@ async fn run_video(cmd: VideoCmd) -> Result<()> {
use c0mpute_core::video;

match cmd {
VideoCmd::Setup { build } => {
VideoCmd::Setup { cpu: true, .. } => {
use c0mpute_core::video_cpu;
println!(
"installing CPU video: stable-diffusion.cpp + Wan 2.1 T2V 1.3B ({:.1} GB of weights)",
video_cpu::download_bytes() as f64 / 1e9
);
video_cpu::install().await?;
println!("installed under {}", c0mpute_core::diffusion::diffusion_root().display());
if c0mpute_core::supervisor::which_ffmpeg().is_none() {
println!("ffmpeg is not on PATH: install it, or this node cannot encode clips");
}
println!(
"this node now serves {} text-to-video on CPU (at most {} frames of 480x272, {} steps; many minutes per clip)",
video_cpu::MODEL_ID,
video_cpu::MAX_FRAMES,
video_cpu::MAX_STEPS
);
println!("start (or restart) a worker with the video role: `c0mpute worker start`");
Ok(())
}
VideoCmd::Setup { build, .. } => {
let how = video::setup(build, &std::env::temp_dir(), &|line: &str| println!("{line}")).await?;
println!("runner image ready as {} ({how:?})", video::RUNNER_IMAGE);
match video::readiness(video::RUNNER_IMAGE) {
Expand All @@ -2527,9 +2552,32 @@ async fn run_video(cmd: VideoCmd) -> Result<()> {
}
VideoCmd::Check { selftest } => {
match video::readiness(video::RUNNER_IMAGE) {
None => println!("ready: GPU, container runtime and runner image are all present"),
None => {
println!("ready: GPU, container runtime and runner image are all present");
match video::nvidia_vram_mib() {
Some(mib) => println!(
"card: {mib} MiB; models it can run: {}",
video::models_for_vram(mib).join(", ")
),
None => println!("card memory unknown (nvidia-smi reported none)"),
}
}
Some(not_ready) => {
println!("not ready: {}", not_ready.reason());
println!("GPU video not ready: {}", not_ready.reason());
let cfg = Config::load_or_default(&config::default_config_path()).unwrap_or_default();
if c0mpute_core::video_cpu::installed() {
let serving = if c0mpute_core::video_cpu::can_serve(&cfg.video) {
"yes"
} else {
"no (disabled, busy, low RAM, small CPU budget or no ffmpeg)"
};
println!(
"CPU video: installed ({}); can take a clip right now: {serving}",
c0mpute_core::video_cpu::MODEL_ID
);
} else {
println!("CPU video: not installed (`c0mpute video setup --cpu` opts in)");
}
return Ok(());
}
}
Expand Down
7 changes: 6 additions & 1 deletion node/crates/c0mpute-core/src/capabilities.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,13 @@ pub fn role_tags(config: &Config) -> Vec<String> {
// Same rule as TTS: advertise only what this box can do now.
// A node without the GPU, the runtime or the image would win
// auctions and fail them.
// One model tag per model the card can hold. With no GPU,
// CPU video (opt-in) advertises the small Wan model while
// the box is idle with free RAM, re-checked each tick.
if crate::video::readiness_cached(crate::video::RUNNER_IMAGE).is_none() {
tags.push(crate::video::ROLE_TAG.to_string());
tags.extend(crate::video::gpu_tags());
} else if crate::video_cpu::can_serve(&config.video) {
tags.extend(crate::video_cpu::tags());
}
}
Role::Diffusion => {
Expand Down
Loading
Loading