# ComfyUI-OldTimeRadio v1.0 dependencies
# IMPORTANT: Do NOT pin torch — ComfyUI manages its own torch version
# Pin loosely to avoid conflicts with other node packs

# Core TTS — Bark via transformers. Gemma4Unified (12B writer) requires the
# official architecture implementation introduced in the 5.10 stable line.
# Legacy parler-tts 0.2.2 hard-pins Transformers 4.46.1 and cannot share this
# runtime; Parler is not an OTR dependency and must remain in an isolated env.
transformers>=5.10.4,<6.0

# Audio processing — WAV I/O and DSP
soundfile>=0.12
numpy>=1.24

# Science news fetching (REQUIRED — no fallback, pipeline will hard-fail without it)
feedparser>=6.0

# Article BODY scraping. feedparser gets the headline + teaser; THIS gets the
# methodology and findings the story is actually written from. It was never
# listed here, and on 2026-07-14 it was found simply absent from the venv --
# so _fetch_full_article() had been returning "" forever, every science episode
# had been written from a ~120-character RSS teaser, and the v4 source floor was
# failing runs with a message that blamed the feeds. Not optional.
beautifulsoup4>=4.12

# Tokenizers (required by transformers 5.10.x, listed for clarity)
tokenizers>=0.22,<=0.23
sentencepiece>=0.1.99

# CUDA-only; the bare line blocked the whole registry install on macOS (2026-09-01
# ship audit). Mirrors the marker in pyproject.toml (alpha.15).
bitsandbytes>=0.42.0; sys_platform != 'darwin'

# 2026-08-25: accelerate was NEVER declared, in either this file or
# pyproject.toml, and it is only a transformers EXTRA -- never a base
# requirement. But nodes/_otr_model_loader.py passes low_cpu_mem_usage=True
# UNCONDITIONALLY (:528), plus device_map / max_memory (:538-546) and
# quantization_config (:543), and transformers routes every one of those
# through accelerate. So a fresh registry install, or a bare
# `pip install -r requirements.txt`, got a writer that cannot load a model.
# This box only ever worked because accelerate 1.13.0 arrived transitively
# from ComfyUI core or another pack -- which is precisely why the gap was
# invisible here and fatal on the 8 GB scratch install that found it.
# Floor is 1.1.0, which is transformers 5.10's own extras floor (NOT the
# 0.26.0 an outside report suggested -- that predates the v5 line).
accelerate>=1.1.0

# Sprint 10A step 3 -- grammar-constrained generation for the Stage 1
# structural-plan call. Pure Python wheel, no compiled deps; works on
# the project's torch 2.10 + CUDA 13 + Blackwell sm_120 + Windows stack
# where prebuilt wheels for other constrained-decode libraries
# (xgrammar, outlines binary backends) are scarce. transformers v5
# compat is provided by nodes/_otr_lmfe_compat.py (the third-party
# integration hard-imports PreTrainedTokenizerBase from the v4 path).
lm-format-enforcer>=0.11.3,<1.0

# Queue item 8 (2026-08-08): spandrel for the shipped `spandrel_esrgan`
# upscale engine. Pinned to 0.4.x — the API this pack calls (ModelLoader
# device kwarg, load_from_file returning ImageModelDescriptor with a
# batch=1 __call__, descriptor.scale/.device/.to) was verified on 0.4.1.
# A 0.5 major bump may reshape those; a follow-up chip re-verifies then.
spandrel~=0.4.1

# 2026-08-22: both were imported UNGUARDED at module scope (pydantic in 21
# files, including _otr_visual_styles.py and _otr_story_brief.py which
# OTR_LedgerScriptWriter pulls in; yaml in _otr_engine_profiles.py) while
# never being declared here. They only worked because lm-format-enforcer
# happens to drag pydantic in transitively -- a resolver change would have
# silently dropped OTR_LedgerScriptWriter and OTR_ImageDirector from the
# node list. Declare what we actually import.
pydantic>=2.0
PyYAML>=6.0

# kokoro is the DEFAULT announcer voice in the shipped canonical workflow, and
# it was never declared here -- so a fresh install reached the first announcer
# line and failed on an import nobody had asked pip to satisfy. Declared
# 2026-08-29 alongside the cold-install fix in `eng_kokoro.py`, where the
# `repo_id` kwarg is now signature-gated: the current PyPI line (0.7.x) does
# not accept it and raised TypeError on the first clip, while newer builds
# (0.9.x) do. Both now work.
#
# NOT YET IN `pyproject.toml`, deliberately: that file's static dependency
# list is what the Comfy Registry reads, and editing it AUTO-FIRES a publish
# (see CLAUDE.md 7A). Both lines below ride the NEXT deliberate version bump.
#
# THE REASON FOR WAITING CHANGED ON 2026-08-29, so do not read the old one.
# It used to be "a version is still Pending". alpha.12 has since resolved --
# to Flagged, joining alpha.9, .10 and .11. `latest_version` therefore still
# resolves to alpha.8 (2026-08-25), which is what every registry install
# actually receives. A bump today would publish alpha.13 into the same wall
# and deliver nothing, so the bump waits on the flag being cleared -- which
# needs Comfy-Org, not us. When it clears, bump ONCE carrying both lines.
#
# 2026-09-01, MEASURED ON A CLEAN WINDOWS PORTABLE INSTALL (Python 3.13.14):
# kokoro cannot be pip-installed on Python 3.13 at all. 0.7.16 pins
# numpy==1.26.4 (no 3.13 wheel); 0.8.x/0.9.x and every misaki>=0.7.5 declare
# Requires-Python <3.13, and misaki[en] drags spacy/thinc/blis with no 3.13
# wheels. pip resolves this file all-or-nothing, so the bare kokoro line made
# `pip install -r requirements.txt` fail and install NONE of the 18 packages
# (verified: pip freeze before == after). ComfyUI Desktop and the portable
# build both ship Python 3.13, so that was every mainstream Windows install.
# The marker lets the other 17 install; the kokoro ENGINE then reports itself
# unusable by name and the announcer/character voice falls to the operator's
# dropdown choice (bark installs everywhere). What the 3.13 DEFAULT voice
# should be is an open operator decision -- see docs/GO_FORWARD_PLAN.md
# 2026-09-01. Mirror this marker into pyproject.toml on the next bump.
kokoro>=0.7.16; python_version < "3.13"
# 2026-09-02 (queue item 2): the SAME kokoro voices on Python 3.13, through ONNX
# Runtime instead of torch -- `nodes/_otr_audio_engines/_kokoro_backends.py`. The
# engine stays "kokoro" in every dropdown; it selects the torch package when that
# imports and kokoro-onnx otherwise. The two markers are COMPLEMENTARY on purpose:
# each interpreter gets exactly one backend, and the upper bound is there because
# kokoro-onnx 0.6.x declares Requires-Python <3.14 -- a bare line would repeat
# PBUG-20260901-04 on the day ComfyUI ships 3.14 (pip resolves this file
# all-or-nothing). onnxruntime, phonemizer and the bundled espeak-ng come with it.
# The ONNX model (326 MB) is fetched once at boot by the prefetch, never mid-render.
kokoro-onnx>=0.6.1; python_version >= "3.13" and python_version < "3.14"

# pyloudnorm was declared NOWHERE -- not here, not in pyproject.toml -- while
# `scene_sequencer.py` imports it to measure integrated loudness and master
# every episode to -14 LUFS. Its import sits in a try/except with a
# deliberate fallback to the legacy peak master, so a fresh install does not
# crash; it just quietly produces a QUIETER, differently-mastered episode
# than the one this project tunes and listens to, and says so only in a
# warning line. That is the worst shape a missing dependency can take: no
# error, no failed render, just worse audio for everyone who installed from
# the registry. Declared 2026-08-29. 0.2.0 is what this box has measured on.
pyloudnorm>=0.1.1

# 2026-08-31, found by scripts/otr_venv_audit.py -- the inventory the operator
# asked for after `accelerate` and `feedparser` both turned out to be declared
# but absent from ComfyUI's own interpreter. These three are the reverse case:
# imported by SHIPPING node code and never declared at all, so a fresh install
# has them only by luck of another pack pulling them in.
#
# pycairo: `import cairo` inside nodes/_otr_shared/scope_draw.py and
# eng_viz_mandala.py. Confirmed missing on the rented pod on 2026-08-31 while
# present here, which is exactly how a gap stays invisible on the box that
# authors it.
#
# WINDOWS-ONLY MARKER, 2026-09-03, and the reason is the registry node count.
# pycairo publishes 21 Windows wheels, 1 sdist and ZERO Linux wheels, so on
# Linux pip must build from the sdist and that needs the libcairo2-dev headers.
# Comfy-Org's `node-pack-extract` boots a headless CPU ComfyUI in a Linux
# container, runs `pip install -r requirements.txt` under `set -e`, and reads
# /object_info to publish the pack's node list; that list is what Algolia
# renders as "N Nodes" on the registry card. A pip failure kills the boot, so
# the pack has never produced rows: /versions/2.0.0-alpha.16/comfy-nodes
# returns `{"comfy_nodes": null, "totalNumberOfPages": 0}` where
# comfyui-videohelpersuite/versions/1.7.9 returns real ones. That extractor is
# independent of Flagged/Active -- an admin approval would not populate it.
#
# MEASURED BLAST RADIUS: exactly one function. The only `import cairo` in
# scope_draw.py is at line 629, indented INSIDE `paint_mandala`, so importing
# the module never imports cairo; `freq_bars_green`, `cfr_flags`,
# `find_ffmpeg` and `encode_silent_mp4` are all cairo-free, which leaves the
# scope overlays, caption burn, silent composite and encode sink untouched.
# eng_viz_mandala guards both `load()` and `assert_usable()` and raises
# EngineUnusable naming the pip command, and `viz_mxc_mandala` appears zero
# times in workflows/otr_canonical.json. So Windows installs exactly as before
# and Linux loses only the mandala visualizer, which fails loud with the fix in
# its own message. (The previous comment here claimed every scope overlay
# raises ImportError without it -- that was never true; only the mandala does.)
#
# Mirror this marker into pyproject.toml on the next deliberate version bump,
# the same way the kokoro lines above are waiting to ride one. The registry
# reads pyproject's static list for DISPLAY, but the extractor installs from
# THIS file, so this line is the one that unblocks the node count.
pycairo>=1.24; sys_platform == 'win32'
# Pillow: image handling in the cloud-image engine and the media canonicaliser.
pillow>=10.0
# aiohttp: imported by __init__.py itself, so it is on the pack's load path.
aiohttp>=3.9
