1. 18 Sep, 2026 2 commits
  2. 17 Sep, 2026 7 commits
  3. 16 Sep, 2026 20 commits
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: ktransformers on pods — engines-kt image with SGLang + kt-kernel in their own venv · 37f46a33
      Stefy Lanza (nextime / spora ) authored
      kt was refused because it looked unshippable: a Python stack pinning its
      own torch, thought to be AMX-only. kt-kernel 0.7 ships prebuilt manylinux
      wheels that dispatch at runtime (AMX, AVX-512, AVX2 llamafile, AMD BLIS),
      and sglang-kt pins the matching torch — so it is a venv on the light
      core like the other split images. The worker now launches SGLang from
      that venv (CODERAI_KT_VENV / ktransformers.venv) instead of assuming
      coderai's interpreter has it, and accepts a HF repo id, which SGLang
      downloads into the volume's cache.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      37f46a33
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: engines image on the light core — 2.4 GB instead of 9.1 · c51a1ab7
      Stefy Lanza (nextime / spora ) authored
      The engines are C binaries and coderai only drives them; the full core's
      torch was dead weight. All they link is the CUDA runtime and cuBLAS,
      which NVIDIA ships as wheels at the 12.8 they were compiled against.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      c51a1ab7
    • Stefy Lanza (nextime / spora )'s avatar
      tools: docker_leak_audit — find overlay2 layers the daemon has lost · 643b78fe
      Stefy Lanza (nextime / spora ) authored
      Twice the build disk filled with 500+ GB of layers no image referenced,
      pinned by mount records of containers the daemon no longer knew about,
      while docker system df reported 90 GB. Nothing in docker can see them.
      This walks imagedb/layerdb/mounts the way a fresh daemon would, reports
      the stale set, and with --fix (daemon stopped) removes it.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      643b78fe
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: an engines pod image — ds4, colibri, k3 compiled for every pod GPU · 1e093d27
      Stefy Lanza (nextime / spora ) authored
      The local ds4-server is an sm_86 build against CUDA 13 and the local
      colibri has no GPU backend: neither could be copied into a pod. The new
      engines image compiles both, plus kimi-k3-in-c, in a CUDA 12.8 stage for
      sm_80/86/89/90/120a (ds4's Blackwell kernels need the arch-specific
      target; plain sm_120 fails in ptxas) on a portable x86-64-v3 baseline,
      and fails the build if a binary cannot find its libraries.
      
      A RunPod-only model names the engine on its runpod block (backend:
      runpod takes the pin slot); a local model pinned to the engine and
      bursting carries the pin. Either way the pod arrives with the engine
      enabled and this install's settings forwarded (CODERAI_<ENG>_CONFIG),
      and volume_path points it at weights already on the network volume —
      the only sane way to run 150 GB+ models. The model page warns loudly
      the moment one of these engines is picked. ktransformers is refused
      with a reason: it has no pod image.
      
      Also: the batch build/publish scripts no longer list core-light and
      venv profiles as images.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      1e093d27
    • Stefy Lanza (nextime / spora )'s avatar
      admin: make 'runs only on RunPod' a visible placement choice; host backend gets a form · 362ff475
      Stefy Lanza (nextime / spora ) authored
      RunPod-only was an entry in the compute-backend dropdown, between OpenCL
      and wav2vec2 — not where anyone deciding WHERE a model runs would look.
      The Placement section now asks 'Runs on' (this machine / RunPod only /
      a machine of yours) and the RunPod block sits under it; the radios and
      the backend select are one stored value, kept in sync.
      
      The host backend existed only as JSON. It now has its fields on the
      form, a save handler, and — like a pod — no local weight or VRAM
      bookkeeping.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      362ff475
    • Stefy Lanza (nextime / spora )'s avatar
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: multi-GPU pods (gpu_count) and remote requests on the Tasks page · 3ae88a89
      Stefy Lanza (nextime / spora ) authored
      gpu_count was passed to RunPod's gpuCount and then ignored: the price
      ceiling checked one card, min_vram_gb one card's memory, and the engine
      loaded on GPU 0 while the rest sat idle. Now the pod is ranked as a whole
      (price x N, VRAM x N, '2x A100'), vLLM gets --tensor-parallel-size N and
      llama.cpp --split-mode layer. Exposed on the model page, clamped 1-8.
      
      Requests forwarded to a pod or host never appeared on the Tasks page, so
      a running remote job was invisible from the admin. _forward now registers
      a 'remote' task whose message names the pod it landed on.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      3ae88a89
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: let the operator state a model's size instead of estimating it · aa15a695
      Stefy Lanza (nextime / spora ) authored
      weights_gb, on the model entry or its runpod block, is taken as-is and the
      HuggingFace estimate is skipped. It is the only honest answer for a URL
      download, an upload or a local file — none of which the estimator can see —
      and for an HF repo it beats a heuristic that deliberately errs high (SDXL:
      estimated 35 GB, actually ~7 for one precision). A nonsense value is ignored
      rather than trusted, and the field is never seeded to a pod: it describes the
      pod's disk, not the model.
      
      /v1/models/test/state now reports the disk a pod would be rented with, the
      weight size used, and whether that size was stated or estimated — decided
      before any money is spent.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      aa15a695
    • Stefy Lanza (nextime / spora )'s avatar
      docs: fifteen images, the light core, the host backend, and what a pod is told · 3dfec93b
      Stefy Lanza (nextime / spora ) authored
      remote-execution.md: the capability images are two kinds now — ten on the full
      core and five on a torch-free light core for stacks that cannot share a venv —
      and the doc says which, why each split was measured rather than assumed, what
      the .venv-*.check scripts catch that a bare import cannot, and why the light
      core exists (RunPod refuses images above ~10 GB; a specialised image on the
      full core carried 7 GB of torch it never used). The 'speaker rides stt' line
      was wrong — that image shipped nothing for speaker work — and is fixed. A new
      section covers what travels to a pod as environment: the HF token, licence
      acceptances, baked-venv paths, OCR engine gates. Surya on a pod is documented
      as served by docTR, with the reason. The host backend gets its own section:
      always-on and on-demand shapes, what it deliberately lacks, and service_token.
      
      runpod.md: the size line with the numbers behind it, EXITED as a dead pod
      rather than a slow pull, container-disk sizing from HF metadata, and the field
      table corrected — boot_timeout_s is 900, container_disk_gb grows to fit.
      
      README: the fifteen images and the host backend, one line each.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      3dfec93b
    • Stefy Lanza (nextime / spora )'s avatar
      gateway: ask a pod for the engine it can serve, in the request itself · 69746387
      Stefy Lanza (nextime / spora ) authored
      The pod was launched with docTR as its default and still answered 'OCR engine
      surya is not enabled' — because the request carried engine=surya, and the OCR
      route honours the request's own field over the configured default. Setting the
      pod's env changed the default; it did not change what the request asked for.
      
      A pod target for OCR now rewrites the request's engine field on the way out,
      to the engine the pod will actually serve (pod_ocr_engine mirrors the launch
      env). Multipart is edited on the bytes with every other part untouched and
      Content-Length corrected; verified through FastAPI's own parser with the real
      probe body, file intact.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      69746387
    • Stefy Lanza (nextime / spora )'s avatar
      xtts: keep the protocol clean and accept the licence; surya on a pod serves docTR · f0986acb
      Stefy Lanza (nextime / spora ) authored
      XTTS reached its own loader on a pod and died on 'unparseable worker reply'.
      coqui prints an interactive CPML licence prompt to stdout and then blocks on
      input() — on a pipe, that corrupts the JSON protocol and then waits forever.
      
      Two fixes. The service now keeps the real stdout for the protocol and sends
      everything else the process prints to stderr, so no library chatter can reach
      the caller's parser again. And the CPML acceptance travels as COQUI_TOS_AGREED,
      locally and to a pod: configuring an XTTS model at all IS the decision, exactly
      as surya's licence is handled, and the pod inherits it. Verified in the image:
      the load returns clean JSON with the full speaker list.
      
      Surya: 0.22 is a VLM (surya-ocr-2), not a self-contained OCR library. It needs
      a server — vLLM, which it spawns IN DOCKER, or llama-server on a GGUF — and the
      pod image has neither; locally it rides coderai's own vLLM engine. A pod asked
      for surya now serves the request with docTR, which is in the image and has
      passed, and logs why — instead of loading surya, reaching inference, and dying
      on 'docker binary not found'. Surya on a pod belongs with the engine images,
      where a llama-server and the GGUF are the same work as colibri and ds4.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      f0986acb
    • Stefy Lanza (nextime / spora )'s avatar
      ocr: match the surya the local install actually runs, and stop hiding its errors · 64ac2d05
      Stefy Lanza (nextime / spora ) authored
      The pod reported 'No module named surya.ocr' — an API that has not existed for
      a year. The real error was two tiers up: the loader wrapped each version branch
      in a bare except, so a failure INSIDE the right branch was swallowed and it fell
      through to the oldest one. The reported error was from code that never should
      have run.
      
      The real error was surya 0.17.1's config class choking on transformers 5.17.
      The pin came from a stale requirements-surya.txt. The local install — read from
      its venv's dist-info — runs surya 0.22.1 on transformers 5.15, and works. Both
      now pin 0.22.1.
      
      0.22 dropped surya.foundation and takes RecognitionPredictor() alone, which the
      loader already handled — but only as a fallback reached by swallowed exception.
      It now selects the API by what IMPORTS: foundation present is 0.17, absent is
      0.22 (or pre-0.17). Verified loading 0.22.1 through the engine class on the pod
      stack beside docTR.
      
      tts-xtts: coqui's TTS(name) splits on '/' and wants its own four-part catalogue
      name; a HuggingFace id has two parts and fails 'expected 4, got 2'. The service
      translates (coqui/XTTS-v2 -> tts_models/multilingual/multi-dataset/xtts_v2),
      verified against coqui's catalogue. This means XTTS through _CoquiBackend had
      never worked with an HF id anywhere, not only on a pod.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      64ac2d05
    • Stefy Lanza (nextime / spora )'s avatar
      host backend: a capability image on a machine you already have · 8310821e
      Stefy Lanza (nextime / spora ) authored
      The capability images are ordinary containers; nothing about them needs RunPod.
      The same image can run on a box you own, a server rented by the month, a second
      GPU in the next room — and coderai should use it the way it uses a pod: per
      model, with an endpoint and a token, and nothing else.
      
        always on:  {"backend": "host", "host": {"url": ..., "api_key": ...}}
        on demand:  add start_cmd (+ optional stop_cmd, boot_timeout_s, idle_timeout_s)
      
      start_cmd is whatever starts the thing — docker run, ssh box docker start, a
      systemd unit. coderai runs it, waits for /healthz, uses the host, and runs
      stop_cmd after idle_timeout_s with nothing in flight. It only ever stops a host
      it started itself; one that was already up is never touched.
      
      Deliberately absent: GPU search, price ranking, budgets, spot, capacity
      fallback, the orphan reaper. Those exist because a cloud rents an anonymous
      card by the second and can lose it. A host is a named machine you are
      responsible for — the machinery would be wrong, not just unnecessary.
      
      Verified for real: a capability container started by command from a cold
      state, healthy in 6s, used, and stopped by the idle timer.
      
      Also fixed on the way: a plain service_url carried no token, so a hand-run
      capability image behind one answered 401 to everything. service_token travels
      now. Neither host nor service_* is seeded to a pod: they say where a model runs
      from HERE, and would make a pod try to forward to itself.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      8310821e
    • Stefy Lanza (nextime / spora )'s avatar
      voice: give f5-tts a progress sink it can call either way · 19ca6c4d
      Stefy Lanza (nextime / spora ) authored
      'function object has no attribute tqdm', on a rented pod, after the model had
      loaded. Current f5-tts defaults its progress argument to the tqdm MODULE and
      calls progress.tqdm(iterable); older releases called progress(iterable). Our
      call site passed a bare lambda, written for the old shape, and the new shape
      went looking for a .tqdm attribute on it.
      
      _NoProgress answers both — callable, and with a .tqdm — and shows nothing,
      which is what a server wants. Confirmed against the f5-tts actually in the
      voice image: its infer_batch_process calls progress.tqdm(...).
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      19ca6c4d
    • Stefy Lanza (nextime / spora )'s avatar
      speaker: pyannote needs matplotlib — and a venv check has to reach the real load · 57f72ea3
      Stefy Lanza (nextime / spora ) authored
      The HF token fix worked: pyannote got past the gate and failed one layer deeper,
      instantiating the pipeline. Reproduced by running the real service with a GPU:
      ModuleNotFoundError: No module named 'matplotlib'. pyannote's segmentation tasks
      import matplotlib.pyplot at module load; it is not declared, and 'import
      pyannote.audio' never reaches it, so the build's import check passed and the
      venv shipped broken.
      
      This is the fourth venv whose bare import check passed while the real load
      failed. A <profile>.venv-<name>.check script now runs at build time in the
      venv's own python and imports what the REAL load reaches — pipeline modules,
      model classes — without a GPU or a token, which a build has neither of. The
      pyannote check fails on the shipped image and passes with the fix; the XTTS
      check passes as-is, so that venv is genuinely complete.
      
      Also: every isolated-venv worker reported failures as the LAST FIVE LINES of the
      subprocess tail. A Python traceback's last five lines are frame headers — the
      exception is the final line, and cutting to five dropped it whenever the trace
      was deep. Ten workers said where a process died and never why. Fixed in all of
      them.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      57f72ea3
    • Stefy Lanza (nextime / spora )'s avatar
      tts: run coqui XTTS from a venv of its own · ef38f017
      Stefy Lanza (nextime / spora ) authored
      coqui-tts imports a transformers 4.x symbol that 5.x removed. Unlike parler and
      the OCR engines it had never been isolated locally: _CoquiBackend did a plain
      'from TTS.api import TTS' and gave up when it was missing. On a pod that meant
      an image with a verified, working TTS venv answered 'pip install coqui-tts' —
      the venv was there and nothing knew to use it.
      
      xtts_worker finds the venv the way the others do (explicit env var, the baked
      /opt/coderai/venvs/TTS, then per-user) and drives tools/xtts_service.py in it
      over stdin/stdout. XttsSubprocess wears the TTS object's shape — speakers,
      tts(**kwargs), synthesizer.output_sample_rate, and the TypeError the backend
      relies on to retry without speed — so synthesize() runs unchanged whether the
      library is in this process or next door.
      
      Verified inside the pushed image: the venv is found and the service answers
      from it. The fall-through is unit-tested with a fake worker, and the error when
      no venv exists names the places it looked.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      ef38f017
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: send the HuggingFace token to a pod, as environment and nothing else · 3a223f58
      Stefy Lanza (nextime / spora ) authored
      pyannote is gated. On a pod it loaded from its baked venv, reached
      from_pretrained, and stopped: 'the model is gated/unavailable'. The local
      install has HF_TOKEN in its environment; a pod was never sent one — every gated
      model was unservable remotely, not just this one.
      
      It is resolved the way pyannote_worker already resolves it (request, env, token
      file) and travels as pod ENVIRONMENT only. A test proves it reaches the pod and
      appears nowhere else in the plan — not the seed list the pod parses, not the
      catalogue, not the args.
      
      Fixing this exposed a precedence bug: at provision time the plan's env was
      applied OVER the model's own env, so a token a model was explicitly configured
      with was silently replaced by whatever this process happened to have. The
      model's own env wins now.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      3a223f58
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: size the container disk for the weights before renting · ec7939d2
      Stefy Lanza (nextime / spora ) authored
      The failure this prevents was observable, not hypothetical: a pod boots, pulls
      the image, starts downloading, fills its 40 GB disk and dies at load_timeout_s
      having paid for every minute. The size of a HuggingFace repo is one metadata
      call, so it is asked before the pod exists, and the disk is grown to fit —
      weights plus ~25 GB for the unpacked image and the download cache.
      
      It counts what a load will actually FETCH, not the whole repo. SDXL's repo is
      77 GB, of which a diffusers load pulls 28: the rest is the same weights again
      as Flax .msgpack, legacy .bin and ONNX exports. Sizing to the repo would have
      rented 100 GB for a 28 GB model.
      
      An explicit container_disk_gb that is already large enough is respected. And
      with a network volume attached the weights land there, not on the container
      disk, so the disk stays at its configured size — which is the point of the
      volume.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      ec7939d2
    • Stefy Lanza (nextime / spora )'s avatar
      images: a light core, so a specialised image carries ONE GPU stack, not two · 6e7bd211
      Stefy Lanza (nextime / spora ) authored
      RunPod refuses images above a size line — measured: 10.1 GB boots, 14.5 GB is
      'Exited by Runpod' two seconds after rent on every machine, no other reason
      given. Container disk (tried 80 GB), layer format and the full image config were
      each ruled out; size was the only difference. All five specialised images were
      above the line.
      
      They were above it for one reason: each was built on the full core, so it
      carried 7 GB of CUDA, torch and triton the main venv never used on that pod,
      beside the venv that did the work. The speaker image was 14.8 GB, of which
      pyannote's own venv was 5.6.
      
      The light core is coderai's Python dependencies with no GPU stack: 1.2 GB.
      codai.api.app imports with no torch present (verified first), so the main
      interpreter still boots the API, serves /healthz and /boot, and drives the
      subprocess worker. A profile marked <name>.light builds on it, its main venv
      carries only what the API layer needs, and the build FAILS if a torch reaches
      that venv — because that is exactly the leak that would put the image back over
      the line.
      
      speaker: 14,796 MB -> 7,077 MB, complete, nothing on a volume.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      6e7bd211
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: fetch lastStatusChange, the field that says why a pod is EXITED · fe73b033
      Stefy Lanza (nextime / spora ) authored
      A dead pod produced three hundred seconds of 'still no port' and no reason at
      all, because the one Pod field that carries the reason was never queried. It
      now travels into the progress line and the failure message, so an EXITED pod
      says what RunPod says about it instead of leaving the cause to be guessed.
      
      The strict-mode removal in boot.sh was one such guess: the image boots cleanly
      here with a minimal environment and with a GPU exposed, so it does not
      reproduce the exit. This is how the real cause gets found.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      fe73b033
  4. 15 Sep, 2026 11 commits
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: a pod that EXITED is dead, not pulling — and the boot script must never be the reason · baa0d92a
      Stefy Lanza (nextime / spora ) authored
      A speaker pod reported EXITED with uptime 0s from its very first poll. The loop
      waited out the full budget on it — three machines in a row — printing 'image
      pull in progress', which it never was: wait_ready treated only TERMINATED and
      FAILED as terminal. EXITED past a short restart grace now fails fast and says
      what it means: the image pulled and the process died on boot.
      
      The budget it waited out was 300s, not the 900s set on the pool class: the
      dataclass default was never updated. Two numbers for one thing, and the smaller
      one silently won. There is one now.
      
      Why the process died: boot.sh ran under set -u, and every line before the exec
      is a diagnostic — it exists to describe the pod, and a diagnostic must never be
      able to stop the boot it describes. The image boots fine locally; on RunPod an
      environment difference tripped a strict-mode abort before uvicorn was reached.
      That is the best-supported explanation, not a proven one — RunPod publishes no
      log API to confirm it — so the script is now unable to abort before its exec
      under any environment, verified against a bare sh with nothing set.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      baa0d92a
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: fix a NameError in the provision path, and test for the whole class · b0d388de
      Stefy Lanza (nextime / spora ) authored
      The 150 GB warning's call site in _provision_one used a name that did not exist
      in that scope. The helper was unit-tested and passed; every pod test then failed
      in two seconds with "name 'entry' is not defined" before renting anything. A
      helper can be correct while the line that calls it is not.
      
      The entry is looked up the way the rest of the pool does it. And since pyflakes
      sees exactly this class of bug, a test now runs it over the modules a pod boot
      goes through, so an undefined name in that path fails the suite instead of the
      first real request.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      b0d388de
    • Stefy Lanza (nextime / spora )'s avatar
      tts-xtts: coqui-tts needs click, which it does not declare · 9539b3ef
      Stefy Lanza (nextime / spora ) authored
      The venv built and then failed its import check with ModuleNotFoundError.
      Verified the whole spec in a throwaway container first this time: with click,
      'from TTS.api import TTS' works on torch 2.5.1+cu124 with transformers 4.46.3 —
      the stack this image exists to provide.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      9539b3ef
    • Stefy Lanza (nextime / spora )'s avatar
      runpod: warn loudly before a 150 GB model is put on a rented card · b49b4936
      Stefy Lanza (nextime / spora ) authored
      Everything around pods is tuned for images of ~10 GB and models of a few. The
      native MoE engines are a different shape: DeepSeek-V4 is ~154 GB and they go
      well past that, so a pod spends one to two hours filling its disk before it
      answers anything — on EVERY cold start, since a pod is disposable storage.
      
      The warning names the model, the size, and the fix: attach a network volume so
      the weights are fetched once and every later pod attaches to them instead. It
      appears at provision time, boxed so it cannot be missed in a log, and in the
      test run — which is where someone looks BEFORE committing to a configuration,
      while at provision time the money is already being spent.
      
      It says nothing when a volume is attached, and nothing for ordinary models.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      b49b4936
    • Stefy Lanza (nextime / spora )'s avatar
      test-run: probe the speaker capability with real audio · 1460b575
      Stefy Lanza (nextime / spora ) authored
      Diarization had no probe, so a speaker pod could only ever report reachability —
      and reachability is what reported ok:true for an STT image that shipped nothing
      for speaker work at all. espeak provides the audio; the check is that the model
      returns at least one labelled turn, which a pod with no diarization stack
      cannot do.
      
      One speaker saying one sentence is a thin test musically and an honest one here.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      1460b575
    • Stefy Lanza (nextime / spora )'s avatar
    • Stefy Lanza (nextime / spora )'s avatar
      images: make the model matrix actually servable, splitting only where measured · 3fed6161
      Stefy Lanza (nextime / spora ) authored
      The pod images were built to satisfy imports, not to serve models. The audit
      found coqui/XTTS-v2, every whisper.cpp model, diarization, speaker ID, SALAD
      place recognition and Surya all unservable on a pod, and the OCR image shipping
      no OCR engine at all.
      
      Three of the eight 'isolated' stacks are not isolated any more. Surya, speechbrain
      and pytorch_lightning all import cleanly beside torch 2.11 — their venvs were
      decided against an older torch and never re-checked, exactly like audiocraft's
      torch==2.1.0. They go straight into the ocr, stt and embeddings profiles: place
      recognition, speaker ID and Surya now work for a few hundred MB instead of three
      new images. Surya's subprocess engine is pointed at the pod's own interpreter,
      since building a venv to hold what is already installed would only cost rental
      time.
      
      Five stacks genuinely cannot share, each verified rather than assumed:
      pyannote (torchaudio.AudioMetaData is gone in 2.11), coqui-tts (a transformers
      4.x symbol), CrisperWhisper (transformers 4.46 AND torch 2.5), NeMo (large, own
      torch) and paddle (its own CUDA runtime). Each gets an image carrying a baked
      venv, rather than 6 GB added to an image everyone pulls.
      
      The `speaker` capability no longer points at the STT image: that was the assumption that it was
      'the STT deps plus a bit', and it shipped nothing for diarization or voiceprints
      at all.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      3fed6161
    • Stefy Lanza (nextime / spora )'s avatar
      ocr: ship an engine in the image, and open the gate in front of it · 38482fc9
      Stefy Lanza (nextime / spora ) authored
      The OCR pod image installed NO OCR engine — only transformers and pypdfium2. A
      pod could boot, pass its health check, accept a request and have nothing to do
      it with. Three gates in front of that each reported their own refusal first —
      'OCR subsystem is disabled', then 'OCR engine surya is not enabled' — so it took
      three rounds to see that the engine was never there.
      
      docTR goes in, because it is the only one of the three that runs in-process.
      Surya caps pillow<11 and lives in an isolated venv by design; paddle wants
      paddlepaddle in one of its own. Either would put a second torch in the image —
      6 GB to avoid a Pillow conflict — and the venv mechanism is there if a pod ever
      needs Surya's layout quality specifically.
      
      Each engine also has its own enable flag on top of the subsystem's, and two of
      the three default to off. A pod now enables the engine it was asked for, falls
      back to docTR when the request names something the image cannot serve, and still
      inherits the Surya licence decision from here rather than making it itself.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      38482fc9
    • Stefy Lanza (nextime / spora )'s avatar
      audio: audiocraft in the main venv, and a setting to choose the backend · 0fba12e0
      Stefy Lanza (nextime / spora ) authored
      The isolated venv was solving a problem that was not real. audiocraft is pure
      Python: its torch==2.1.0 is a declared pin, not an ABI requirement, so --no-deps
      sidesteps it. The only genuine constraint was xformers, which it imports at
      module load — and 0.0.35 ships a py39-none wheel requiring torch>=2.10, which
      this image satisfies. I had ruled that out by grepping wheel filenames for
      cp312 and missing that abi3/py39 wheels cover 3.12.
      
      Verified in the built core image: torch 2.11.0+cu128 with xformers 0.0.35,
      MusicGen and AudioGen import, ops.memory_efficient_attention present.
      
      Cost in the main venv: 950 MB. The second venv cost 6.2 GB, because it carried a
      duplicate torch and a duplicate CUDA stack. The audio image drops from 15.8 GB
      to about 10.2 GB, which also removes the reason to split it in two.
      
      audio_backend (per model, or CODERAI_AUDIO_BACKEND for a pod) selects
      audiocraft or transformers explicitly, because they are not equivalent — melody
      conditioning and AudioGen exist only in the first. Asking for audiocraft when it
      is absent raises rather than quietly substituting something less capable. A
      model's own setting beats the environment it lands in, and the choice travels to
      a pod instead of being decided by what happens to be installed there.
      
      The isolated-venv worker stays in the tree: if audiocraft 1.3.0 turns out to
      misbehave against torch 2.11 at generation time, restoring one profile file
      brings it back.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      0fba12e0
    • Stefy Lanza (nextime / spora )'s avatar
      audio: give the audiocraft venv every dependency it declares · 299c492c
      Stefy Lanza (nextime / spora ) authored
      Three build cycles, three different missing modules — xformers, then torch at
      install time, then transformers. The list had been trimmed against what the MAIN
      venv provides, which is exactly backwards: an isolated venv starts with nothing,
      so it needs the whole declared set, minus only the torch pins we choose and the
      dev-only tools.
      
      Verified in a throwaway container against the real core image before building
      anything: audiocraft 1.3.0 on torch 2.5.1+cu121 with xformers 0.0.28.post3, and
      MusicGen and AudioGen both import. That check takes two minutes; the image build
      it replaces takes fifteen, which is why the last three rounds were so expensive.
      Co-Authored-By: 's avatarClaude Opus 5 (1M context) <noreply@anthropic.com>
      Claude-Session: https://claude.ai/code/session_0182DhR1eFNPQyGmDrpHbedY
      299c492c
    • Stefy Lanza (nextime / spora )'s avatar