Skip to content

Celune 4.1.0#19

Merged
celunah merged 34 commits into
mainfrom
dev
Jun 15, 2026
Merged

Celune 4.1.0#19
celunah merged 34 commits into
mainfrom
dev

Conversation

@celunah

@celunah celunah commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Now THAT is an update. CodeRabbit, do your summary below.

Summary by CodeRabbit

  • New Features
    • Browser Web UI at /ui; / redirects to /ui
    • /play <path> [volume] supports an optional volume argument
    • New dots.tts backend, YouTube SFX playback, and improved compiled auto-update flow
    • CI now builds and uploads Linux/Windows launcher artifacts
  • Documentation
    • Added gallery page; refreshed README (install/run, Web UI, license notes) and added developer guidance
  • Improvements
    • Unified playback mixer, smoother energy-based device glow, Qwen3-VL upgrade, version bumped to 4.1.0
    • Reference-audio truncation and volume support across playback
  • Tests
    • Expanded coverage for Web UI, mixing/DSP behavior, updater, persona, and pipeline behavior

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
📝 Walkthrough

Walkthrough

Build, update, UI, runtime-state, and audio/backend flows were reworked together. The PR also adds a new backend, shared typing/dataclass modules, updated docs, and broader test coverage.

Changes

Release + Runtime Refactor

Layer / File(s) Summary
Build and update flow
*.github/workflows/*, launcher.c, main.py, celune/updater.py, pyproject.toml, requirements.txt, scripts/build_nuitka.*, scripts/run_ci.py, tests/test_main_doctor.py, tests/test_runtime_paths.py, tests/test_namedays_i18n_updater.py, .gitignore, nuitka_main.py
CI now builds launcher artifacts, compiled update handling and launcher restart logic were added, version/dependency metadata was bumped, and the build scripts and path/doctor/update tests were updated for compiled installs.
WebUI and API wiring
celune/api.py, celune/ui/app.py, celune/ui/commands.py, celune/ui/resources.py, celune/ui/theme.py, celune/ui/protocols.py, README.md, tests/test_api_webui.py, tests/test_runtime_and_ui_commands.py
The FastAPI app mounts a Gradio WebUI under /ui, mirrors Celune state into browser-facing UI buffers, updates slash-command playback handling, and extends WebUI-focused tests and docs.
Runtime state and typing surface
celune/analysis.py, celune/cevoice.py, celune/colors.py, celune/config.py, celune/constants.py, celune/__init__.py, celune/paths.py, celune/runtime.py, celune/terminal.py, celune/utils.py, celune/vram.py, celune/dataclasses/*, celune/typing/*, tests/test_runtime_paths.py, tests/test_config_and_utils.py, tests/test_modeling.py, tests/test_persona_api.py, tests/test_persona_memory.py
Shared type aliases, dataclasses, property forwarding, path resolution, constants, versioning, and related runtime helpers were centralized into new modules and imported throughout the package.
Audio, backends, and core playback
celune/celune.py, celune/pipeline.py, celune/dsp.py, celune/chroma.py, celune/backends/*, celune/persona/*, celune/extensions/*, default_config.yaml, tests/test_analysis_and_chroma.py, tests/test_backends_and_extensions.py, tests/test_backends_mini.py, tests/test_celune_core.py, tests/test_colors_and_dsp.py, tests/test_pipeline.py
Playback now uses a per-source mixer with volume/ducking and YouTube audio support, audio-reactive glow uses smoothed levels, backend loading was expanded for dotstts and Qwen3-VL, and the core runtime/persona/extension/audio tests were updated to match.
Docs and supporting material
AGENTS.md, GALLERY.md, README.md
Contributor guidance, UI gallery content, and README usage/licensing/installation notes were updated to match the new release and runtime behavior.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • celunah/celune#6: Related to the same audio-reactive glow and playback flow touched in celune/chroma.py, celune/dsp.py, and celune/pipeline.py.
  • celunah/celune#7: Related backend framework changes in celune/backends/base.py, celune/backends/voxcpm2.py, and the backend registration flow.
  • celunah/celune#15: Related API and versioning changes in celune/api.py and celune/__init__.py.

"A little rabbit tapped the keys,
And built new wheels and UI seas.
The mixer hummed, the glow shone bright,
Update paths leapt into night,
Bun-bun bows: the build feels right! 🐰"

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (7)
celune/ui/app.py (1)

107-114: ⚡ Quick win

Simplify the default value assignment.

Lines 107-109 wrap None in parentheses across multiple lines, which is unnecessarily verbose.

♻️ Simplify formatting
-    runtime_redirect_original_handlers: Optional[dict[str, list[logging.Handler]]] = (
-        None
-    )
+    runtime_redirect_original_handlers: Optional[dict[str, list[logging.Handler]]] = None
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/ui/app.py` around lines 107 - 114, The three attribute defaults are
written with unnecessary multi-line parentheses; simplify by assigning None
directly to runtime_redirect_original_handlers and
runtime_redirect_original_propagate and use single-line declarations for
runtime_redirect_original_handlers, runtime_redirect_original_propagate, and
warnings_capture_enabled in the class where they are defined (referencing
runtime_redirect_original_handlers, runtime_redirect_original_propagate, and
warnings_capture_enabled) so each default is a direct simple literal (e.g.,
runtime_redirect_original_handlers: Optional[dict[str, list[logging.Handler]]] =
None) instead of the wrapped multi-line form.
celune/entrypoint.py (1)

285-291: 💤 Low value

Document why compiled execution uses venv Python for doctor repairs.

The _doctor_subprocess_python() function returns _doctor_venv_python() when running_compiled() instead of the current interpreter. This design choice should be briefly commented to explain that the compiled binary cannot directly invoke setup.py, so doctor repairs delegate to the venv interpreter.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/entrypoint.py` around lines 285 - 291, Add a brief inline comment to
_doctor_subprocess_python explaining that when running_compiled() is true the
compiled binary cannot directly invoke setup.py or perform interpreter-based
repairs, so doctor fixes must be executed via the virtualenv interpreter
returned by _doctor_venv_python(); otherwise use _doctor_running_python() for
normal (non-compiled) runs. This clarifies the rationale behind choosing
_doctor_venv_python over the current interpreter.
celune/extensions/manager.py (1)

24-24: 💤 Low value

Consider using typing.Type for consistency with classic typing syntax guideline.

The built-in type[CeluneExtension] (PEP 585) is valid for Python 3.12+, but the coding guideline prefers classic typing syntax. Consider:

from typing import Type

def register(self, extension_cls: Type[CeluneExtension]) -> CeluneExtension:

This maintains consistency with the project's stated preference for classic typing module usage.

As per coding guidelines: prefer classic typing syntax.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/extensions/manager.py` at line 24, Replace the PEP 585-style
annotation in the register method with the classic typing.Type usage: update the
register signature in class Manager (register(self, extension_cls:
type[CeluneExtension]) -> CeluneExtension) to use typing.Type for extension_cls
and add the corresponding import from typing; ensure CeluneExtension remains the
return type and the new Type[CeluneExtension] annotation references the same
CeluneExtension symbol.

Source: Coding guidelines

.github/workflows/ci.yml (2)

60-99: 💤 Low value

Consider pinning GitHub Actions to commit hashes for supply-chain security.

Static analysis flagged unpinned action references at lines 74 and 96. While version tags (@v5, @v7) provide convenience, pinning to commit hashes prevents unexpected behavior from tag reassignments.

Example:

- uses: astral-sh/setup-uv@bbf0a5ef00a28e8f6e8e6d245bd7b381b4cf1b68  # v7

Note: This may be an intentional trade-off between security and maintainability.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 60 - 99, The workflow uses unpinned
action tags (actions/checkout@v5, astral-sh/setup-uv@v7,
actions/upload-artifact@v6) which can be maliciously reassigned; update each
uses: reference to pin them to their specific commit SHA instead of the tag
(replace `@v5/`@v7/@v6 with the corresponding full commit hash for each action)
and verify the chosen SHAs match the intended tag versions before committing.

Source: Linters/SAST tools


101-131: 💤 Low value

Consider pinning GitHub Actions to commit hashes for supply-chain security.

Static analysis flagged unpinned action references at lines 110 and 128. Additionally, line 106-107 has a credential persistence warning—consider adding persist-credentials: false to the checkout action if the workflow doesn't need to push commits.

Example:

- name: Checkout repository
  uses: actions/checkout@<hash>  # v5
  with:
    persist-credentials: false

Note: These may be intentional trade-offs for this project.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/ci.yml around lines 101 - 131, Update the workflow to pin
third-party actions to immutable commit SHAs instead of tags for the steps named
"Checkout repository" (uses: actions/checkout@v5), "Install uv" (uses:
astral-sh/setup-uv@v7) and "Upload Windows launcher artifacts" (uses:
actions/upload-artifact@v6) by replacing the tag with the corresponding commit
hash; also add the with: persist-credentials: false option to the "Checkout
repository" step to avoid leaking credentials when not needed. Ensure you
reference and update the exact steps by their step names ("Checkout repository",
"Install uv", "Upload Windows launcher artifacts") so the SHA pins and the
persist-credentials setting are applied in the correct places.

Source: Linters/SAST tools

celune/colors.py (1)

17-17: ⚡ Quick win

Use classic type alias syntax instead of PEP 695 type statement.

The coding guideline prefers classic typing syntax. The type RGB = ... statement is PEP 695 syntax (Python 3.12+). Consider using the classic type alias pattern:

RGB = tuple[int, int, int]

or with explicit annotation:

from typing import TypeAlias
RGB: TypeAlias = tuple[int, int, int]

As per coding guidelines: prefer classic typing syntax over newer PEP syntax features.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/colors.py` at line 17, Replace the PEP 695 "type" statement that
defines the RGB alias with the classic type-alias pattern: change the RGB
declaration to a simple assignment-style alias to a 3-tuple of ints, or
alternatively annotate RGB using typing.TypeAlias, so the name RGB resolves as
the intended tuple[int, int, int] type; update the RGB declaration in colors.py
accordingly.

Source: Coding guidelines

celune/api.py (1)

556-732: 💤 Low value

Dynamic attribute injection for callback tracking.

Line 732 uses setattr(celune, "_webui_callbacks_wrapped", True) to track whether callbacks have been wrapped. While functional, this injects a private attribute onto the Celune instance.

Consider adding a typed attribute to the Celune class if this pattern persists, or documenting the convention. For now, the approach works and prevents double-wrapping.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/api.py` around lines 556 - 732, The current callback-wrapping uses
dynamic attribute injection via setattr(celune, "_webui_callbacks_wrapped",
True) in _wrap_celune_callbacks which mutates the Celune instance at runtime;
instead add a typed attribute _webui_callbacks_wrapped: bool = False to the
Celune class definition and update _wrap_celune_callbacks to read and set that
attribute directly (e.g., check getattr/celune._webui_callbacks_wrapped and
assign celune._webui_callbacks_wrapped = True) so the flag is part of the class
surface rather than injected dynamically.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@celune/pipeline.py`:
- Around line 2356-2361: When _ensure_playback_stream(engine, BASE_SR) returns
False you must call release_pipeline(engine) before clearing mixer state and
breaking so engine.locked is cleared; update the failure branch that currently
clears
source_buffers/source_done/_playback_source_statuses(engine)/_playback_source_meta(engine)
to first call release_pipeline(engine) (or the appropriate release_pipeline call
used elsewhere) and then clear state and break, ensuring subsequent say()/play()
calls are not rejected due to engine.locked remaining True.
- Around line 833-858: The subprocess call in _download_youtube_sfx uses
subprocess.run without a timeout which can hang; add a reasonable timeout
argument (e.g., timeout=<seconds>) to the subprocess.run call that invokes
yt_dlp_module and wrap the call in a try/except that catches
subprocess.TimeoutExpired and handles it the same way as the current non-zero
return/error paths (log the timeout, set completed/return appropriate failure
state, and clean up any partial output) so behavior matches existing error
handling for _download_youtube_sfx.

In `@GALLERY.md`:
- Around line 17-19: The "Change voice" section heading is plain text and needs
to be a Markdown heading; update the line containing "Change voice" to a proper
heading (e.g., prefix with a Markdown header token like "### " or the same
heading level used by other gallery sections) so the section renders
consistently with the other headings and leaves the existing image/link block
intact.

In `@scripts/build_nuitka.ps1`:
- Line 76: After running the Nuitka command invocation (& uv `@arguments`) check
the PowerShell exit code stored in $LASTEXITCODE and abort the script if it is
non-zero; specifically, immediately after the & uv `@arguments` call inspect
$LASTEXITCODE and call exit or throw an error to prevent continuing to the C
launcher compilation step (the subsequent launcher build), so the script only
proceeds to compile the launcher when the Nuitka step succeeded.
- Around line 12-13: The environment variables $env:CL and $env:_CL_ are set
globally before the Nuitka invocation (& uv `@arguments`) so they affect both
Nuitka's MSVC invocation and the later manual compile/link command stored in
$compileCmd; scope them only for the launcher build by setting and restoring
them immediately around the launcher invocation (or explicitly pass equivalent
flags to Nuitka) instead of leaving them set for the whole script—wrap the
temporary assignments in a local/try/finally or save original values, set
$env:CL and $env:_CL_ just before running cmd /c $compileCmd (or before & uv
`@arguments` if the intent is for Nuitka only), then restore the originals after
that command completes so $compileCmd runs with the original environment.

In `@scripts/build_nuitka.sh`:
- Around line 99-143: The manifest currently hardcodes "Celune-linux-x64"; pass
the detected appimage_arch into the Python block and use it when building
manifest["artifact"]. Concretely, set CELUNE_ARCH="$appimage_arch" when invoking
the Python runner (or export it beforehand) where you call appimage_arch and run
uv run python -, and inside that Python snippet read os.environ["CELUNE_ARCH"]
and set manifest["artifact"] to "Celune-linux-" + that value (use the existing
manifest variable in the Python block). This ensures the artifact string
reflects the appimage_arch value determined earlier.

---

Nitpick comments:
In @.github/workflows/ci.yml:
- Around line 60-99: The workflow uses unpinned action tags
(actions/checkout@v5, astral-sh/setup-uv@v7, actions/upload-artifact@v6) which
can be maliciously reassigned; update each uses: reference to pin them to their
specific commit SHA instead of the tag (replace `@v5/`@v7/@v6 with the
corresponding full commit hash for each action) and verify the chosen SHAs match
the intended tag versions before committing.
- Around line 101-131: Update the workflow to pin third-party actions to
immutable commit SHAs instead of tags for the steps named "Checkout repository"
(uses: actions/checkout@v5), "Install uv" (uses: astral-sh/setup-uv@v7) and
"Upload Windows launcher artifacts" (uses: actions/upload-artifact@v6) by
replacing the tag with the corresponding commit hash; also add the with:
persist-credentials: false option to the "Checkout repository" step to avoid
leaking credentials when not needed. Ensure you reference and update the exact
steps by their step names ("Checkout repository", "Install uv", "Upload Windows
launcher artifacts") so the SHA pins and the persist-credentials setting are
applied in the correct places.

In `@celune/api.py`:
- Around line 556-732: The current callback-wrapping uses dynamic attribute
injection via setattr(celune, "_webui_callbacks_wrapped", True) in
_wrap_celune_callbacks which mutates the Celune instance at runtime; instead add
a typed attribute _webui_callbacks_wrapped: bool = False to the Celune class
definition and update _wrap_celune_callbacks to read and set that attribute
directly (e.g., check getattr/celune._webui_callbacks_wrapped and assign
celune._webui_callbacks_wrapped = True) so the flag is part of the class surface
rather than injected dynamically.

In `@celune/colors.py`:
- Line 17: Replace the PEP 695 "type" statement that defines the RGB alias with
the classic type-alias pattern: change the RGB declaration to a simple
assignment-style alias to a 3-tuple of ints, or alternatively annotate RGB using
typing.TypeAlias, so the name RGB resolves as the intended tuple[int, int, int]
type; update the RGB declaration in colors.py accordingly.

In `@celune/entrypoint.py`:
- Around line 285-291: Add a brief inline comment to _doctor_subprocess_python
explaining that when running_compiled() is true the compiled binary cannot
directly invoke setup.py or perform interpreter-based repairs, so doctor fixes
must be executed via the virtualenv interpreter returned by
_doctor_venv_python(); otherwise use _doctor_running_python() for normal
(non-compiled) runs. This clarifies the rationale behind choosing
_doctor_venv_python over the current interpreter.

In `@celune/extensions/manager.py`:
- Line 24: Replace the PEP 585-style annotation in the register method with the
classic typing.Type usage: update the register signature in class Manager
(register(self, extension_cls: type[CeluneExtension]) -> CeluneExtension) to use
typing.Type for extension_cls and add the corresponding import from typing;
ensure CeluneExtension remains the return type and the new Type[CeluneExtension]
annotation references the same CeluneExtension symbol.

In `@celune/ui/app.py`:
- Around line 107-114: The three attribute defaults are written with unnecessary
multi-line parentheses; simplify by assigning None directly to
runtime_redirect_original_handlers and runtime_redirect_original_propagate and
use single-line declarations for runtime_redirect_original_handlers,
runtime_redirect_original_propagate, and warnings_capture_enabled in the class
where they are defined (referencing runtime_redirect_original_handlers,
runtime_redirect_original_propagate, and warnings_capture_enabled) so each
default is a direct simple literal (e.g., runtime_redirect_original_handlers:
Optional[dict[str, list[logging.Handler]]] = None) instead of the wrapped
multi-line form.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 8c426611-2f3e-4cf7-96c7-3a1c593cd1fe

📥 Commits

Reviewing files that changed from the base of the PR and between 238443f and 812ebd5.

⛔ Files ignored due to path filters (12)
  • celune.exe is excluded by !**/*.exe
  • resources/branding/celune.svg is excluded by !**/*.svg
  • resources/branding/celune_88x31_206.png is excluded by !**/*.png
  • resources/branding/celune_88x31_206_light.png is excluded by !**/*.png
  • resources/branding/celune_88x31_basic.png is excluded by !**/*.png
  • resources/branding/celune_88x31_basic_light.png is excluded by !**/*.png
  • resources/branding/celune_dark.svg is excluded by !**/*.svg
  • resources/branding/celune_wordmark.png is excluded by !**/*.png
  • resources/branding/celune_wordmark_dark.png is excluded by !**/*.png
  • resources/branding/celune_wordmark_transparent.png is excluded by !**/*.png
  • resources/celune.ico is excluded by !**/*.ico
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (68)
  • .github/workflows/build-linux.yml
  • .github/workflows/build-windows.yml
  • .github/workflows/ci.yml
  • .gitignore
  • AGENTS.md
  • GALLERY.md
  • README.md
  • celune.AppImage
  • celune/__init__.py
  • celune/analysis.py
  • celune/api.py
  • celune/backends/base.py
  • celune/backends/mini.py
  • celune/backends/qwen3.py
  • celune/backends/voxcpm2.py
  • celune/celune.py
  • celune/cevoice.py
  • celune/chroma.py
  • celune/colors.py
  • celune/config.py
  • celune/constants.py
  • celune/entrypoint.py
  • celune/extensions/base.py
  • celune/extensions/manager.py
  • celune/modeling.py
  • celune/namedays.py
  • celune/paths.py
  • celune/persona/impl.py
  • celune/persona/memory.py
  • celune/persona/runtime.py
  • celune/pipeline.py
  • celune/runtime.py
  • celune/ui/app.py
  • celune/ui/commands.py
  • celune/ui/headless.py
  • celune/ui/resources.py
  • celune/ui/terminal.py
  • celune/ui/theme.py
  • celune/updater.py
  • celune/utils.py
  • celune/vram.py
  • default_config.yaml
  • launcher.c
  • main.py
  • nuitka_main.py
  • pyproject.toml
  • requirements.txt
  • resources/celune.res
  • scripts/build_nuitka.ps1
  • scripts/build_nuitka.sh
  • scripts/run_ci.py
  • tests/support.py
  • tests/test_analysis_and_chroma.py
  • tests/test_api_audio.py
  • tests/test_api_think.py
  • tests/test_api_webui.py
  • tests/test_backends_and_extensions.py
  • tests/test_backends_mini.py
  • tests/test_celune_core.py
  • tests/test_config_and_utils.py
  • tests/test_main_doctor.py
  • tests/test_modeling.py
  • tests/test_namedays_i18n_updater.py
  • tests/test_persona_api.py
  • tests/test_persona_memory.py
  • tests/test_pipeline.py
  • tests/test_runtime_and_ui_commands.py
  • tests/test_runtime_paths.py
💤 Files with no reviewable changes (2)
  • .github/workflows/build-windows.yml
  • .github/workflows/build-linux.yml

Comment thread celune/pipeline.py Outdated
Comment thread celune/pipeline.py
Comment thread GALLERY.md Outdated
Comment thread scripts/build_nuitka.ps1
Comment on lines +12 to +13
$env:CL = "/O2 /GL /GS /guard:cf /DNDEBUG"
$env:_CL_ = "/link /LTCG /OPT:REF /OPT:ICF /DYNAMICBASE /NXCOMPAT"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if Nuitka or other tools invoke additional C/C++ compilations
rg -n 'cl\.exe|cl\s|msvc|compiler' scripts/build_nuitka.ps1

Repository: celunah/celune

Length of output: 335


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show relevant parts of the script (small enough to be safe)
sed -n '1,140p' scripts/build_nuitka.ps1 | nl -ba

# Find all uses of these env vars
rg -n '\$env:CL|\$env:_CL_' scripts/build_nuitka.ps1

# Find all cl.exe invocations (or other C/C++ compile drivers) in the script
rg -n 'cl\.exe|(^|\s)cl(\s|$)|msvc|compiler' scripts/build_nuitka.ps1

# Check if Nuitka or other tools are invoked in a way that might trigger extra C/C++ compilations
rg -n 'nuitka|pip|subprocess|build|compile|MSVC|vswhere|VsDevCmd|vcvars' scripts/build_nuitka.ps1

Repository: celunah/celune

Length of output: 101


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show relevant parts of the script with line numbers (use cat -n instead of nl)
sed -n '1,160p' scripts/build_nuitka.ps1 | cat -n

# Find all uses of these env vars
rg -n '\$env:CL|\$env:_CL_' scripts/build_nuitka.ps1

# Find all cl.exe invocations (or other C/C++ compile drivers) in the script
rg -n 'cl\.exe|(^|\s)cl(\s|$)|msvc|compiler' scripts/build_nuitka.ps1

# Check how/if Nuitka is invoked and whether the script resets env vars
rg -n 'nuitka|pip|subprocess|build|compile|MSVC|vswhere|VsDevCmd|vcvars|$env:CL\s*=|$env:_CL_\s*=' scripts/build_nuitka.ps1

Repository: celunah/celune

Length of output: 6746


Scope $env:CL / $env:_CL_ to the launcher build (or explicitly apply them to Nuitka).
In scripts/build_nuitka.ps1, $env:CL and $env:_CL_ are set at lines 12–13 before & uv @arguments`` runs Nuitka (line ~76), so they will affect both Nuitka’s MSVC cl usage and the later manual `cl`/link step in `$compileCmd` (line 98). If these flags are intended only for the launcher, set/restore the env vars just around `cmd /c $compileCmd` instead of leaving them for the whole script.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/build_nuitka.ps1` around lines 12 - 13, The environment variables
$env:CL and $env:_CL_ are set globally before the Nuitka invocation (& uv
`@arguments`) so they affect both Nuitka's MSVC invocation and the later manual
compile/link command stored in $compileCmd; scope them only for the launcher
build by setting and restoring them immediately around the launcher invocation
(or explicitly pass equivalent flags to Nuitka) instead of leaving them set for
the whole script—wrap the temporary assignments in a local/try/finally or save
original values, set $env:CL and $env:_CL_ just before running cmd /c
$compileCmd (or before & uv `@arguments` if the intent is for Nuitka only), then
restore the originals after that command completes so $compileCmd runs with the
original environment.

Comment thread scripts/build_nuitka.ps1
Comment thread scripts/build_nuitka.sh

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@celune/backends/dotstts.py`:
- Around line 227-242: The code temporarily flips the process-global
HF_HUB_OFFLINE around the DotsTtsRuntime.from_pretrained call (inside the
try/finally block) which can race with other threads/processes; fix by
serializing this mutation with a dedicated lock (e.g., create or reuse a
module-level threading.Lock) around the set/use/restore sequence or, if
DotsTtsRuntime.from_pretrained supports a per-call offline flag, remove the env
mutation and pass that flag instead; specifically update the block that sets
os.environ["HF_HUB_OFFLINE"] and calls DotsTtsRuntime.from_pretrained (and the
surrounding try/finally) to acquire the lock before changing HF_HUB_OFFLINE and
release it after restoring, or refactor to call
DotsTtsRuntime.from_pretrained(target, ..., offline=True) if supported, leaving
the rest of the logic (self._suppress_backend_output, precision, optimize,
max_generate_length) unchanged.
- Around line 269-296: The code currently uses self.default_voice as the
fallback before consulting the active pack, causing "unknown voice 'balanced'"
when that default isn't present in the pack; fix generate_stream() by selecting
the pack-defined voice when the requested/default voice isn't in the loaded
bundle: after calling self._require_compatible_bundle() (the loader variable),
check if voice is a key in loader.bundle.voices and if not, set voice =
next(iter(loader.bundle.voices)) (or raise a ValueError if loader.bundle.voices
is empty); then continue to call loader.materialize(voice, "wav") and use
loader.bundle.voices[voice].get("reference_text") as before so the backend uses
the pack's actual voice IDs instead of self.default_voice.

In `@celune/dataclasses/celune.py`:
- Around line 150-307: The CELUNE_FORWARDED_PROPERTIES list contains a duplicate
for the audio stream: ForwardedPropertySpec("_stream", "_audio_state", "stream")
and ForwardedPropertySpec("stream", "_audio_state", "stream"); remove the
unintended duplicate (preferably drop the private "_stream" entry and keep
ForwardedPropertySpec("stream", "_audio_state", "stream") unless you
specifically need both private and public access) or, if both were intentional,
make the intent explicit by renaming one and documenting it; update the
CELUNE_FORWARDED_PROPERTIES list accordingly so only the intended spec(s) for
the stream property remain.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6bd4571c-9daa-4f2b-81fa-b2a1323e1b9e

📥 Commits

Reviewing files that changed from the base of the PR and between d7913dc and a34fe01.

⛔ Files ignored due to path filters (9)
  • demos/balanced_lc_qwen.wav is excluded by !**/*.wav
  • demos/bold_lc_old.wav is excluded by !**/*.wav
  • demos/bold_lc_qwen.wav is excluded by !**/*.wav
  • demos/calm_lc_old.wav is excluded by !**/*.wav
  • demos/calm_lc_qwen.wav is excluded by !**/*.wav
  • demos/upbeat_lc_qwen.wav is excluded by !**/*.wav
  • demos/webui_desktop.png is excluded by !**/*.png
  • demos/webui_mobile_responsive.png is excluded by !**/*.png
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (46)
  • AGENTS.md
  • celune/analysis.py
  • celune/api.py
  • celune/backends/__init__.py
  • celune/backends/base.py
  • celune/backends/dotstts.py
  • celune/backends/mini.py
  • celune/backends/voxcpm2.py
  • celune/celune.py
  • celune/cevoice.py
  • celune/colors.py
  • celune/config.py
  • celune/constants.py
  • celune/dataclasses/__init__.py
  • celune/dataclasses/celune.py
  • celune/dataclasses/extensions.py
  • celune/dataclasses/persona.py
  • celune/dataclasses/pipeline.py
  • celune/dataclasses/properties.py
  • celune/entrypoint.py
  • celune/extensions/base.py
  • celune/persona/prompts.py
  • celune/persona/runtime.py
  • celune/pipeline.py
  • celune/terminal.py
  • celune/typing/__init__.py
  • celune/typing/analysis.py
  • celune/typing/backends.py
  • celune/typing/celune.py
  • celune/typing/cevoice.py
  • celune/typing/common.py
  • celune/typing/extensions.py
  • celune/typing/persona.py
  • celune/typing/pipeline.py
  • celune/typing/ui.py
  • celune/typing/utils.py
  • celune/ui/protocols.py
  • celune/utils.py
  • celune/vram.py
  • default_config.yaml
  • pyproject.toml
  • requirements.txt
  • tests/support.py
  • tests/test_backends_and_extensions.py
  • tests/test_celune_core.py
  • tests/test_pipeline.py
✅ Files skipped from review due to trivial changes (7)
  • celune/typing/cevoice.py
  • celune/typing/common.py
  • celune/typing/utils.py
  • celune/typing/pipeline.py
  • AGENTS.md
  • celune/colors.py
  • celune/backends/mini.py
🚧 Files skipped from review as they are similar to previous changes (11)
  • tests/support.py
  • celune/config.py
  • tests/test_celune_core.py
  • celune/backends/base.py
  • celune/entrypoint.py
  • celune/constants.py
  • celune/api.py
  • celune/cevoice.py
  • celune/celune.py
  • tests/test_pipeline.py
  • celune/pipeline.py

Comment thread celune/backends/dotstts.py Outdated
Comment thread celune/backends/dotstts.py
Comment on lines +150 to +307
CELUNE_FORWARDED_PROPERTIES = (
ForwardedPropertySpec("log_callback", "_callbacks", "log_callback"),
ForwardedPropertySpec("status_callback", "_callbacks", "status_callback"),
ForwardedPropertySpec("error_callback", "_callbacks", "error_callback"),
ForwardedPropertySpec("idle_callback", "_callbacks", "idle_callback"),
ForwardedPropertySpec("queue_avail_callback", "_callbacks", "queue_avail_callback"),
ForwardedPropertySpec(
"voice_changed_callback", "_callbacks", "voice_changed_callback"
),
ForwardedPropertySpec(
"change_input_state_callback",
"_callbacks",
"change_input_state_callback",
),
ForwardedPropertySpec(
"change_voice_lock_state_callback",
"_callbacks",
"change_voice_lock_state_callback",
),
ForwardedPropertySpec("progress_callback", "_callbacks", "progress_callback"),
ForwardedPropertySpec("config", "_backend_state", "config"),
ForwardedPropertySpec("_backend_spec", "_backend_state", "backend_spec"),
ForwardedPropertySpec("_backend_kwargs", "_backend_state", "backend_kwargs"),
ForwardedPropertySpec("backend", "_backend_state", "backend"),
ForwardedPropertySpec("tts_backend", "_backend_state", "tts_backend"),
ForwardedPropertySpec("chunk_size", "_backend_state", "chunk_size"),
ForwardedPropertySpec("language", "_backend_state", "language"),
ForwardedPropertySpec("dev", "_backend_state", "dev"),
ForwardedPropertySpec("use_normalization", "_backend_state", "use_normalization"),
ForwardedPropertySpec("model", "_model_state", "model"),
ForwardedPropertySpec("model_name", "_model_state", "model_name"),
ForwardedPropertySpec("llm", "_model_state", "llm"),
ForwardedPropertySpec("tokenizer", "_model_state", "tokenizer"),
ForwardedPropertySpec("_last_warmup_error", "_model_state", "last_warmup_error"),
ForwardedPropertySpec(
"_normalizer_load_epoch",
"_model_state",
"normalizer_load_epoch",
),
ForwardedPropertySpec("current_voice", "_voice_state", "current_voice"),
ForwardedPropertySpec("current_character", "_voice_state", "current_character"),
ForwardedPropertySpec(
"current_character_persona",
"_voice_state",
"current_character_persona",
),
ForwardedPropertySpec(
"voice_bundle_is_default",
"_voice_state",
"voice_bundle_is_default",
),
ForwardedPropertySpec("persona_history", "_voice_state", "persona_history"),
ForwardedPropertySpec("persona_attachments", "_voice_state", "persona_attachments"),
ForwardedPropertySpec("voices", "_voice_state", "voices"),
ForwardedPropertySpec("voice_prompt", "_voice_state", "voice_prompt"),
ForwardedPropertySpec("text_queue", "_pipeline_state", "text_queue"),
ForwardedPropertySpec("audio_queue", "_pipeline_state", "audio_queue"),
ForwardedPropertySpec("_playback_thread", "_pipeline_state", "playback_thread"),
ForwardedPropertySpec("_generation_thread", "_pipeline_state", "generation_thread"),
ForwardedPropertySpec("_api_thread", "_pipeline_state", "api_thread"),
ForwardedPropertySpec("_persona_thread", "_pipeline_state", "persona_thread"),
ForwardedPropertySpec("_queue_lock", "_pipeline_state", "queue_lock"),
ForwardedPropertySpec(
"_utterance_force_stop",
"_pipeline_state",
"utterance_force_stop",
),
ForwardedPropertySpec(
"_next_playback_source_id",
"_pipeline_state",
"next_playback_source_id",
),
ForwardedPropertySpec(
"_playback_source_statuses",
"_pipeline_state",
"playback_source_statuses",
),
ForwardedPropertySpec(
"_playback_source_meta", "_pipeline_state", "playback_source_meta"
),
ForwardedPropertySpec(
"_playback_progress_last_emit_at",
"_pipeline_state",
"playback_progress_last_emit_at",
),
ForwardedPropertySpec(
"_playback_progress_last_source_id",
"_pipeline_state",
"playback_progress_last_source_id",
),
ForwardedPropertySpec("_model_ready", "_pipeline_state", "model_ready"),
ForwardedPropertySpec("_playback_done", "_pipeline_state", "playback_done"),
ForwardedPropertySpec("_say_lock", "_pipeline_state", "say_lock"),
ForwardedPropertySpec("_wake_lock", "_pipeline_state", "wake_lock"),
ForwardedPropertySpec("_model_lock", "_pipeline_state", "model_lock"),
ForwardedPropertySpec("_exit_requested", "_pipeline_state", "exit_requested"),
ForwardedPropertySpec("_stream", "_audio_state", "stream"),
ForwardedPropertySpec("_current_sr", "_audio_state", "current_sr"),
ForwardedPropertySpec("_audio_unavailable", "_audio_state", "audio_unavailable"),
ForwardedPropertySpec("can_use_rubberband", "_audio_state", "can_use_rubberband"),
ForwardedPropertySpec("speed", "_audio_state", "speed"),
ForwardedPropertySpec("reverb", "_audio_state", "reverb"),
ForwardedPropertySpec("recently_saved", "_audio_state", "recently_saved"),
ForwardedPropertySpec("kept_sfx_audio", "_audio_state", "kept_sfx_audio"),
ForwardedPropertySpec("regenerate", "_runtime_state", "regenerate"),
ForwardedPropertySpec("locked", "_runtime_state", "locked"),
ForwardedPropertySpec("loaded", "_runtime_state", "loaded"),
ForwardedPropertySpec("sleeping", "_runtime_state", "sleeping"),
ForwardedPropertySpec("_last_flavor", "_runtime_state", "last_flavor"),
ForwardedPropertySpec("_ready_announced", "_runtime_state", "ready_announced"),
ForwardedPropertySpec("cur_state", "_runtime_state", "cur_state"),
ForwardedPropertySpec("is_in_tutorial", "_runtime_state", "is_in_tutorial"),
ForwardedPropertySpec("extension_manager", "_runtime_state", "extension_manager"),
ForwardedPropertySpec("glow", "_runtime_state", "glow"),
ForwardedPropertySpec("vision", "_runtime_state", "vision"),
ForwardedPropertySpec("stream", "_audio_state", "stream"),
ForwardedPropertySpec("say_lock", "_pipeline_state", "say_lock", read_only=True),
ForwardedPropertySpec(
"utterance_force_stop",
"_pipeline_state",
"utterance_force_stop",
read_only=True,
),
ForwardedPropertySpec(
"queue_lock", "_pipeline_state", "queue_lock", read_only=True
),
ForwardedPropertySpec(
"playback_done", "_pipeline_state", "playback_done", read_only=True
),
ForwardedPropertySpec(
"model_ready", "_pipeline_state", "model_ready", read_only=True
),
ForwardedPropertySpec(
"generation_thread",
"_pipeline_state",
"generation_thread",
read_only=True,
),
ForwardedPropertySpec(
"playback_thread",
"_pipeline_state",
"playback_thread",
read_only=True,
),
ForwardedPropertySpec(
"exit_requested", "_pipeline_state", "exit_requested", read_only=True
),
ForwardedPropertySpec(
"model_lock", "_pipeline_state", "model_lock", read_only=True
),
ForwardedPropertySpec(
"audio_unavailable",
"_audio_state",
"audio_unavailable",
read_only=True,
),
ForwardedPropertySpec("current_sr", "_audio_state", "current_sr"),
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Duplicate property definition for stream.

The property "stream" is defined twice in CELUNE_FORWARDED_PROPERTIES:

  • Line 246: ForwardedPropertySpec("_stream", "_audio_state", "stream")
  • Line 265: ForwardedPropertySpec("stream", "_audio_state", "stream")

This creates both a private _stream and a public stream property pointing to the same field. If this is intentional (to provide both private and public access), it's correct. If not, the duplicate should be removed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/dataclasses/celune.py` around lines 150 - 307, The
CELUNE_FORWARDED_PROPERTIES list contains a duplicate for the audio stream:
ForwardedPropertySpec("_stream", "_audio_state", "stream") and
ForwardedPropertySpec("stream", "_audio_state", "stream"); remove the unintended
duplicate (preferably drop the private "_stream" entry and keep
ForwardedPropertySpec("stream", "_audio_state", "stream") unless you
specifically need both private and public access) or, if both were intentional,
make the intent explicit by renaming one and documenting it; update the
CELUNE_FORWARDED_PROPERTIES list accordingly so only the intended spec(s) for
the stream property remain.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
celune/pipeline.py (1)

1655-1687: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid forcing idle state after non-readiness signals.

At Line 1684, release_pipeline_when_finished=True is applied to every signal type. That completion path releases the pipeline into idle, which can overwrite active states like sleeping/error/reloading after those cues finish.

Suggested minimal fix
 def play_signal(engine: Celune, signal_type: str) -> bool:
@@
-    if acquire_pipeline(engine, f"play {signal_type} signal"):
+    if acquire_pipeline(engine, f"play {signal_type} signal"):
+        release_to_idle = signal_type == "readiness"
         engine.cur_state = "speaking"
         source_id = _next_playback_source_id(engine)
         _register_playback_source(engine, source_id, kind="sfx")
         _queue_playback_chunk(engine, source_id, signal, BASE_SR)
         _queue_playback_done(
             engine,
             source_id,
-            release_pipeline_when_finished=True,
+            release_pipeline_when_finished=release_to_idle,
         )
+        if not release_to_idle:
+            release_pipeline(engine, playback_idle=False)
         return True
     return False
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/pipeline.py` around lines 1655 - 1687, The completion handler
currently always sets release_pipeline_when_finished=True in play_signal, which
forces the pipeline back to idle after any signal; change play_signal (and its
call to _queue_playback_done) so release_pipeline_when_finished is True only for
the "readiness" signal and False for other signals (e.g.,
"working","sleeping","error") to avoid overwriting active states; locate the
conditional that selects the signal in play_signal, compute a boolean like
release_when_finished = (signal_type == "readiness"), and pass that boolean into
_queue_playback_done instead of the hardcoded True.
♻️ Duplicate comments (1)
celune/backends/dotstts.py (1)

281-287: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use validated voice_names for fallback voice selection.

The fallback currently picks the first raw key from loader.bundle.voices, which can bypass the validated set returned by _require_compatible_bundle() and fail even when the pack is otherwise compatible. Pick from voice_names instead.

Suggested fix
-            loader, _ = self._require_compatible_bundle()
+            loader, voice_names = self._require_compatible_bundle()
             if voice not in loader.bundle.voices:
-                voice = next(iter(loader.bundle.voices), None)
-                if voice is None:
-                    raise ValueError(
-                        f"backend '{self.name}' requires at least one voice in the active pack"
-                    )
+                voice = voice_names[0]
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/backends/dotstts.py` around lines 281 - 287, The fallback voice
selection uses loader.bundle.voices directly and can bypass the validated set
returned by _require_compatible_bundle(); change the logic so that after calling
loader, _ = self._require_compatible_bundle() you use the validated voice_names
(the second value returned by _require_compatible_bundle() or otherwise obtain
the validated list) to pick a fallback (e.g., voice = next(iter(voice_names),
None)) instead of next(iter(loader.bundle.voices, None)), and keep the existing
ValueError if that yields None.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@celune/pipeline.py`:
- Around line 1655-1687: The completion handler currently always sets
release_pipeline_when_finished=True in play_signal, which forces the pipeline
back to idle after any signal; change play_signal (and its call to
_queue_playback_done) so release_pipeline_when_finished is True only for the
"readiness" signal and False for other signals (e.g.,
"working","sleeping","error") to avoid overwriting active states; locate the
conditional that selects the signal in play_signal, compute a boolean like
release_when_finished = (signal_type == "readiness"), and pass that boolean into
_queue_playback_done instead of the hardcoded True.

---

Duplicate comments:
In `@celune/backends/dotstts.py`:
- Around line 281-287: The fallback voice selection uses loader.bundle.voices
directly and can bypass the validated set returned by
_require_compatible_bundle(); change the logic so that after calling loader, _ =
self._require_compatible_bundle() you use the validated voice_names (the second
value returned by _require_compatible_bundle() or otherwise obtain the validated
list) to pick a fallback (e.g., voice = next(iter(voice_names), None)) instead
of next(iter(loader.bundle.voices, None)), and keep the existing ValueError if
that yields None.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31a54469-da0b-4799-b29d-72b7a22b7191

📥 Commits

Reviewing files that changed from the base of the PR and between a34fe01 and b61cda5.

⛔ Files ignored due to path filters (1)
  • celune/assets/chord.wav is excluded by !**/*.wav
📒 Files selected for processing (14)
  • celune/backends/base.py
  • celune/backends/dotstts.py
  • celune/backends/qwen3.py
  • celune/backends/voxcpm2.py
  • celune/celune.py
  • celune/dsp.py
  • celune/pipeline.py
  • celune/ui/app.py
  • scripts/cac.py
  • scripts/run_ci.py
  • tests/test_backends_and_extensions.py
  • tests/test_celune_core.py
  • tests/test_colors_and_dsp.py
  • tests/test_runtime_and_ui_commands.py
✅ Files skipped from review due to trivial changes (1)
  • scripts/cac.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/test_runtime_and_ui_commands.py
  • celune/ui/app.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@celune/pipeline.py`:
- Around line 1677-1688: The current code holds engine.locked during readiness
chime playback by setting release_to_idle = True only for readiness signals,
preventing other say()/play() calls from proceeding until playback finishes.
Instead, queue the playback signal for all signal types and immediately release
the pipeline by always calling release_pipeline(engine, playback_idle=False)
after _queue_playback_done, regardless of signal type. This allows the
playback_worker() to manage the idle transition when the mixer empties while
freeing the engine lock for incoming requests. Remove the conditional release
logic based on release_to_idle and ensure release_pipeline is called
unconditionally for all signals.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e18fa1dc-5dc2-486d-b4d8-e2381a528bd3

📥 Commits

Reviewing files that changed from the base of the PR and between b61cda5 and 2a03105.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (3)
  • celune/backends/base.py
  • celune/backends/dotstts.py
  • celune/pipeline.py
🚧 Files skipped from review as they are similar to previous changes (2)
  • celune/backends/dotstts.py
  • celune/backends/base.py

Comment thread celune/pipeline.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
celune/pipeline.py (2)

1664-1666: ⚡ Quick win

Docstring placeholder not filled in.

The docstring says "Raises: ValueError: If ValueError needs to be raised." which is not meaningful documentation. It should describe when ValueError is actually raised (line 1677: when signal_type is not one of the recognized types).

Suggested fix
     Returns:
         bool: Whether the readiness signal was processed successfully.
-
-    Raises:
-        ValueError: If `ValueError` needs to be raised.
+
+    Raises:
+        ValueError: The signal_type is not one of 'readiness', 'working', 'sleeping', or 'error'.
     """
Based on learnings: After each task, run `scripts/update_docstrings.py` and replace placeholders in docstrings with proper documentation while preserving the docstring format.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/pipeline.py` around lines 1664 - 1666, The Raises section docstring in
the function contains a placeholder statement "If `ValueError` needs to be
raised" which does not meaningfully document when the error occurs. Replace this
placeholder with actual documentation describing the specific condition that
triggers the ValueError, namely when the signal_type parameter is not one of the
recognized types (as validated around line 1677). After making this change, run
the scripts/update_docstrings.py script to ensure docstring formatting is
consistent with the rest of the codebase.

Source: Learnings


1492-1492: 💤 Low value

Volume parameter is silently halved before playback.

The play() function accepts a volume parameter but then halves it (volume * 0.5) before passing to queue_sfx_audio. This means callers passing volume=1.0 get 0.5 effective volume. Consider either:

  1. Documenting this behavior in the docstring
  2. Adjusting the default to 2.0 so volume=1.0 results in 0.5 effective
  3. Removing the halving and letting callers control the actual volume

This silent modification could lead to confusion when debugging volume issues.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@celune/pipeline.py` at line 1492, The play() function silently halves the
volume parameter before passing it to queue_sfx_audio (with `volume * 0.5`),
causing callers to get unexpected effective volume levels. Remove the `* 0.5`
multiplication in the volume assignment to pass the caller's volume directly to
queue_sfx_audio, making the behavior transparent. If the halving is intentional
for technical reasons, document this behavior in the play() function's docstring
to explain why the parameter value is modified, or adjust the function's default
volume parameter to 2.0 to make the scaling less surprising to callers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@celune/pipeline.py`:
- Around line 1664-1666: The Raises section docstring in the function contains a
placeholder statement "If `ValueError` needs to be raised" which does not
meaningfully document when the error occurs. Replace this placeholder with
actual documentation describing the specific condition that triggers the
ValueError, namely when the signal_type parameter is not one of the recognized
types (as validated around line 1677). After making this change, run the
scripts/update_docstrings.py script to ensure docstring formatting is consistent
with the rest of the codebase.
- Line 1492: The play() function silently halves the volume parameter before
passing it to queue_sfx_audio (with `volume * 0.5`), causing callers to get
unexpected effective volume levels. Remove the `* 0.5` multiplication in the
volume assignment to pass the caller's volume directly to queue_sfx_audio,
making the behavior transparent. If the halving is intentional for technical
reasons, document this behavior in the play() function's docstring to explain
why the parameter value is modified, or adjust the function's default volume
parameter to 2.0 to make the scaling less surprising to callers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9983d701-4f1b-4fd5-9814-5f6760d7bfbf

📥 Commits

Reviewing files that changed from the base of the PR and between b61cda5 and 927180e.

⛔ Files ignored due to path filters (9)
  • demos/balanced_dotstts_lc.wav is excluded by !**/*.wav
  • demos/balanced_dotstts_sc.wav is excluded by !**/*.wav
  • demos/bold_dotstts_lc.wav is excluded by !**/*.wav
  • demos/bold_dotstts_sc.wav is excluded by !**/*.wav
  • demos/calm_dotstts_lc.wav is excluded by !**/*.wav
  • demos/calm_dotstts_sc.wav is excluded by !**/*.wav
  • demos/upbeat_dotstts_lc.wav is excluded by !**/*.wav
  • demos/upbeat_dotstts_sc.wav is excluded by !**/*.wav
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (22)
  • README.md
  • celune/__init__.py
  • celune/api.py
  • celune/backends/base.py
  • celune/backends/dotstts.py
  • celune/backends/mini.py
  • celune/backends/qwen3.py
  • celune/backends/voxcpm2.py
  • celune/dataclasses/properties.py
  • celune/dsp.py
  • celune/persona/impl.py
  • celune/pipeline.py
  • celune/typing/analysis.py
  • celune/typing/backends.py
  • celune/typing/celune.py
  • celune/typing/persona.py
  • celune/updater.py
  • tests/support.py
  • tests/test_backends_and_extensions.py
  • tests/test_celune_core.py
  • tests/test_persona_api.py
  • tests/test_pipeline.py
🚧 Files skipped from review as they are similar to previous changes (16)
  • celune/init.py
  • celune/typing/backends.py
  • celune/dataclasses/properties.py
  • celune/typing/analysis.py
  • tests/test_persona_api.py
  • celune/backends/voxcpm2.py
  • README.md
  • celune/typing/persona.py
  • tests/support.py
  • celune/typing/celune.py
  • celune/persona/impl.py
  • celune/dsp.py
  • celune/updater.py
  • celune/api.py
  • tests/test_pipeline.py
  • tests/test_celune_core.py

@celunah celunah merged commit 8b34f53 into main Jun 15, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant