Skip to content

Implement silero-based audio chunker(#857) & introducing adaptive VAD & fix compilations on Windows(#66)/Linux(#67)#989

Closed
metaphorics wants to merge 39 commits intomainfrom
enhance-audio-chunking-#857
Closed

Implement silero-based audio chunker(#857) & introducing adaptive VAD & fix compilations on Windows(#66)/Linux(#67)#989
metaphorics wants to merge 39 commits intomainfrom
enhance-audio-chunking-#857

Conversation

@metaphorics
Copy link

No description provided.

…es`, `.code_indexer`, `.idea`)

- Add comprehensive guidelines for project development and architecture in `.junie/guidelines.md`
- Introduce dedicated instructions for Claude code contribution in `CLAUDE.md`
…essing

- Added `ChunkConfig` for flexible chunking behavior.
- Implemented adaptive VAD with `SileroConfig`, allowing dynamic threshold adjustments.
- Introduced new tests covering RMS chunking, Silero chunking, and configuration scenarios.
- Improved silence handling to enhance accuracy and prevent empty chunks.
- Enabled `Box<dyn Predictor>` usage for flexible predictor implementations.
- Added support for dynamic VAD selection (Silero or RMS) based on environment variable.
- Integrated configurable max duration for audio chunking.
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jun 21, 2025

📝 Walkthrough

Walkthrough

This update introduces new documentation files outlining project guidelines and AI assistant instructions, updates ignore files for Git and AI assistants, and enhances the audio chunking system. The chunker now supports configurable parameters, adaptive Silero VAD-based chunking with a new SmartPredictor, improved silence trimming with multi-stage and spectral analysis, and dynamic predictor selection in the local STT plugin.

Changes

File(s) Change Summary
.aiignore Added new ignore file for AI assistants, specifying files/directories requiring explicit approval before access, with exceptions for Brave Mode and allowlisted commands.
.gitignore Expanded ignore patterns: added recursive **/node_modules/, .code_indexer/, .idea/, and .serena/cache/ directories.
.junie/guidelines.md
CLAUDE.md
Added detailed project guidelines and AI assistant instructions, covering architecture, development workflow, code conventions, testing, performance, security, and platform-specific considerations for contributors and automated tools.
AGENTS.md Added comprehensive project overview and development guide for Hyprnote, detailing architecture, workflows, Rust codebase structure, code conventions, and important considerations for contributors and automated code assistants.
.cursor/rules/audio-processing.mdc
.cursor/rules/code-style.mdc
.cursor/rules/database-patterns.mdc
.cursor/rules/dev-commands.mdc
.cursor/rules/plugin-development.mdc
.cursor/rules/project-overview.mdc
.cursor/rules/project-structure.mdc
.cursor/rules/task-completion.mdc
Added multiple new documentation files under .cursor/rules/ describing audio processing pipeline architecture and error handling, code style and conventions for TypeScript and Rust, database patterns with libsql/Turso and Drizzle ORM, essential development commands, plugin development patterns, project overview, project structure, and task completion checklist for consistent development practices.
.serena/memories/code_style_conventions.md
.serena/memories/codebase_structure.md
.serena/memories/project_overview.md
.serena/memories/rust_style_guide.md
.serena/memories/suggested_commands.md
.serena/memories/task_completion_checklist.md
Added new markdown documentation files under .serena/memories/ providing detailed code style conventions for TypeScript/React and Rust, codebase structure overview, project overview, Rust style guide compliance, recommended development commands, and a task completion checklist enforcing mandatory formatting, linting, testing, and build verification steps.
.serena/project.yml Added new project configuration file specifying Rust project settings, ignoring .gitignore files, writable mode, and available tools descriptions.
crates/chunker/src/lib.rs Added new audio_analysis module; extended ChunkerExt trait with chunks_with_config method accepting a ChunkConfig; renamed existing test test_chunker to test_rms_chunker with updated output directory; added multiple async tests for Silero chunker with and without custom config; added tests for ChunkConfig defaults and variants; added helper function to_f32 converting raw bytes to normalized f32 samples; added tests verifying trimming behavior under hallucination prevention levels.
crates/chunker/src/predictor.rs Implemented Predictor trait for boxed predictors; added Default for RMS; introduced configurable SileroConfig struct; refactored Silero struct with thread-safe internals and confidence history; implemented adaptive thresholding and confidence decay profiling; fully implemented Silero's predict method using mutex-protected state; added SmartPredictor struct combining Silero VAD with noise profile, onset detection, and spectral features; implemented fused multi-feature speech detection with hysteresis and dynamic thresholds; implemented Predictor for SmartPredictor.
crates/chunker/src/stream.rs Introduced ChunkConfig struct encapsulating chunk duration, silence window, trimming parameters, and hallucination prevention levels (Normal, Aggressive, Paranoid); replaced ChunkStream's max duration with full config; added ChunkContext for adaptive chunking state tracking; enhanced silence trimming with multi-stage process including VAD-based trimming, energy-based validation, hallucination trigger removal, and fade-out; added advanced smart_trim_with_spectral_features method using spectral analysis, pitch continuity, onset detection, and speech quality metrics; updated poll_next to use config parameters, skip empty trimmed chunks, and adapt chunking parameters dynamically; refactored constructors to support config.
crates/chunker/src/audio_analysis.rs Added new module with audio analysis utilities: RMS and peak RMS calculation; energy decay profiling; repetitive pattern detection via autocorrelation; low-frequency energy ratio estimation; fade-in/out effects; spectral feature extraction (centroid, spread, flux, rolloff, pitch, harmonicity) using simple DFT and autocorrelation pitch detection; onset detection with adaptive thresholding; multi-resolution speech quality analysis; extensive unit tests validating these features on synthetic and noise signals.
crates/chunker/README.md Added comprehensive README for chunker crate detailing functionality for intelligent audio chunking optimized for real-time speech and Whisper STT; describes Silero VAD, SmartPredictor fusion, and RMS chunking methods; explains adaptive thresholding and configurable chunk durations; details multi-stage silence trimming and hallucination prevention levels; provides usage examples; documents advanced smart features combining spectral, pitch, onset, and contextual analysis; discusses performance considerations and thread safety.
crates/chunker/Cargo.toml Added rand crate version 0.8 as a new development dependency under [dev-dependencies]; added rustfft crate version 6.4 as a new dependency for performance optimizations.
plugins/local-stt/src/server.rs Modified WebSocket server to select audio chunking predictor dynamically based on USE_SMART_PREDICTOR and HALLUCINATION_PREVENTION environment variables (default true and aggressive respectively); attempts to initialize SmartPredictor for real-time use with fallback to Silero and then RMS predictor; creates ChunkConfig with selected hallucination prevention level; updated chunking logic to use selected predictor and config; added logging for chosen predictor and config; noted potential for lower thresholds with SmartPredictor.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant WebSocketServer
    participant Chunker
    participant SmartPredictor
    participant SileroVAD
    participant RMSPredictor

    User->>WebSocketServer: Connects and sends audio
    WebSocketServer->>WebSocketServer: Check USE_SMART_PREDICTOR env
    alt USE_SMART_PREDICTOR == "true"
        WebSocketServer->>SmartPredictor: Try to initialize (realtime)
        alt SmartPredictor init success
            WebSocketServer->>Chunker: Use SmartPredictor with config
        else SmartPredictor init fails
            WebSocketServer->>SileroVAD: Try to initialize
            alt SileroVAD init success
                WebSocketServer->>Chunker: Use SileroVAD with config
            else SileroVAD init fails
                WebSocketServer->>RMSPredictor: Use RMS with config
            end
        end
    else
        WebSocketServer->>SileroVAD: Try to initialize
        alt SileroVAD init success
            WebSocketServer->>Chunker: Use SileroVAD with config
        else SileroVAD init fails
            WebSocketServer->>RMSPredictor: Use RMS with config
        end
    end
    WebSocketServer->>Chunker: Stream audio chunks using selected predictor and hallucination prevention config
    Chunker->>SmartPredictor/SileroVAD/RMSPredictor: Predict speech/silence per chunk
    Chunker->>WebSocketServer: Emit trimmed, non-empty audio chunks
    WebSocketServer->>User: Sends transcriptions/results
Loading
sequenceDiagram
    participant ChunkStream
    participant Predictor
    participant AudioSource

    loop For each audio buffer
        AudioSource->>ChunkStream: Provide audio samples
        ChunkStream->>Predictor: Check for silence using window
        alt Silence detected or max duration reached
            ChunkStream->>Predictor: Trim silence using multi-stage and spectral methods
            alt Chunk is non-empty after trimming
                ChunkStream->>Caller: Emit chunk
            else
                ChunkStream->>Caller: Skip empty chunk, continue polling
            end
        else
            ChunkStream->>AudioSource: Wait for more data
        end
    end
Loading
sequenceDiagram
    participant Silero
    participant Vad
    participant ConfidenceBuffer

    Silero->>Vad: Predict speech probability for frame
    Vad-->>Silero: Probability value
    Silero->>ConfidenceBuffer: Update with new probability
    Silero->>Silero: Calculate adaptive threshold based on confidence history
    Silero->>Silero: Decide speech/silence using adaptive threshold
    Silero->>Silero: Reset state if no speech for N frames
Loading
sequenceDiagram
    participant SmartPredictor
    participant Silero
    participant NoiseProfile
    participant OnsetDetector
    participant SpectrumAnalyzer

    SmartPredictor->>Silero: Get VAD confidence
    SmartPredictor->>NoiseProfile: Update noise floor and profile during silence
    SmartPredictor->>OnsetDetector: Detect onsets in audio
    SmartPredictor->>SpectrumAnalyzer: Extract spectral features (centroid, spread, harmonicity)
    SmartPredictor->>SmartPredictor: Fuse features with weights and hysteresis
    SmartPredictor->>SmartPredictor: Adjust thresholds based on confidence decay and SNR
    SmartPredictor-->>ChunkStream: Return fused speech detection result
Loading
✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

‼️ IMPORTANT
Auto-reply has been disabled for this repository in the CodeRabbit settings. The CodeRabbit bot will not respond to your replies unless it is explicitly tagged.

  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@metaphorics metaphorics requested review from Copilot and yujonglee June 21, 2025 13:16

This comment was marked as outdated.

@metaphorics metaphorics changed the title Implement silero-based audio chunker & Introducing adaptive VAD Implement silero-based audio chunker & introducing adaptive VAD Jun 21, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (9)
.junie/guidelines.md (2)

29-29: Fix code block language specification.

The code block is missing a language identifier, which is flagged by markdownlint.

-```
+```bash

83-90: Minor grammatical improvements suggested.

Static analysis suggests small preposition fixes for better readability.

-1. If it needs native access, create a new plugin in `plugins/`
+1. If it needs native access, create a new plugin to `plugins/`
 2. Implement Rust logic and expose commands
 3. Run `cargo test export_types` to generate TypeScript bindings
-4. Import and use in React components
+4. Import and use them in React components
CLAUDE.md (1)

87-90: Minor grammatical improvements suggested.

Same issues as in guidelines.md - small preposition fixes for better readability.

-1. If it needs native access, create a new plugin in `plugins/`
+1. If it needs native access, create a new plugin to `plugins/`
 2. Implement Rust logic and expose commands
 3. Run `cargo test export_types` to generate TypeScript bindings
-4. Import and use in React components
+4. Import and use them in React components
plugins/local-stt/src/server.rs (1)

148-149: Consider using a more robust configuration approach.

While environment variables work, consider moving this to a proper configuration system for better maintainability and testability.

// Consider a configuration struct approach:
struct ChunkerConfig {
    use_silero_vad: bool,
    silero_max_duration: Duration,
    rms_max_duration: Duration,
}

impl Default for ChunkerConfig {
    fn default() -> Self {
        Self {
            use_silero_vad: true,
            silero_max_duration: Duration::from_secs(30),
            rms_max_duration: Duration::from_secs(15),
        }
    }
}
crates/chunker/src/lib.rs (1)

136-143: Document or make endianness configurable.

The function assumes little-endian byte order which may not be portable. Consider documenting this assumption or using target-specific byte order.

 fn to_f32(bytes: &[u8]) -> Vec<f32> {
+    // Note: Assumes little-endian PCM data
     let mut samples = Vec::with_capacity(bytes.len() / 2);
     for chunk in bytes.chunks_exact(2) {
         let sample = i16::from_le_bytes([chunk[0], chunk[1]]) as f32 / 32768.0;
         samples.push(sample);
     }
     samples
 }
crates/chunker/src/stream.rs (1)

73-109: Improved silence trimming logic.

The bidirectional trimming is a great improvement. However, the condition check on lines 92-94 appears unnecessary.

         for start_idx in (0..data.len()).rev().step_by(window_size) {
             let end_idx = (start_idx + window_size).min(data.len());
-            if start_idx >= end_idx {
-                continue;
-            }
             let window = &data[start_idx..end_idx];

The condition start_idx >= end_idx can only be true when start_idx equals data.len() and window_size is 0, which shouldn't happen given the function's context.

crates/chunker/src/predictor.rs (3)

5-10: Good addition for dynamic dispatch support.

The implementation correctly enables Box<dyn Predictor> usage. Minor note: the comment could be more precise.

-// Allow Box<dyn Predictor> to be used as a Predictor
+// Implement Predictor for Box<P> where P: Predictor

64-84: Consider optimizing mutex usage for performance.

The implementation is thread-safe but uses many separate mutex lock/unlock operations in the hot path (predict method). This could impact performance in high-throughput scenarios.

Consider combining related state into a single mutex-protected struct to reduce lock contention:

struct SileroState {
    vad: hypr_vad::Vad,
    confidence_history: VecDeque<f32>,
    frames_since_speech: usize,
}

pub struct Silero {
    state: Mutex<SileroState>,
    config: SileroConfig, // Config is read-only, no mutex needed
}

This would reduce the number of lock operations per predict() call from 4+ to 1-2.

Also applies to: 117-147


87-95: Optimize mutex usage in reset logic.

The method locks frames_since_speech twice unnecessarily.

 fn maybe_reset_state(&self) {
-    let frames = *self.frames_since_speech.lock().unwrap();
+    let mut frames = self.frames_since_speech.lock().unwrap();
     // Reset after ~3 seconds of no speech (assuming 30ms chunks)
-    if frames > 100 {
+    if *frames > 100 {
         self.inner.lock().unwrap().reset();
         self.confidence_history.lock().unwrap().clear();
-        *self.frames_since_speech.lock().unwrap() = 0;
+        *frames = 0;
     }
 }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1e70f59 and 3ab770b.

📒 Files selected for processing (8)
  • .aiignore (1 hunks)
  • .gitignore (1 hunks)
  • .junie/guidelines.md (1 hunks)
  • CLAUDE.md (1 hunks)
  • crates/chunker/src/lib.rs (2 hunks)
  • crates/chunker/src/predictor.rs (2 hunks)
  • crates/chunker/src/stream.rs (3 hunks)
  • plugins/local-stt/src/server.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • plugins/local-stt/src/server.rs
  • crates/chunker/src/lib.rs
  • crates/chunker/src/stream.rs
  • crates/chunker/src/predictor.rs
🪛 GitHub Actions: .github/workflows/fmt.yaml
plugins/local-stt/src/server.rs

[error] 143-179: dprint formatting check failed. The file is not properly formatted according to dprint rules. Run 'dprint fmt' to fix code style issues.

🪛 LanguageTool
CLAUDE.md

[uncategorized] ~87-~87: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~90-~90: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~92-~92: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

.junie/guidelines.md

[uncategorized] ~83-~83: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~86-~86: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~88-~88: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

🪛 markdownlint-cli2 (0.17.2)
.junie/guidelines.md

29-29: Fenced code blocks should have a language specified
null

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (6)
.gitignore (1)

10-10: LGTM! Good additions to .gitignore.

The recursive **/node_modules/ pattern and tool-specific directory ignores (.code_indexer/, .idea/, .serena/) are appropriate additions that will help maintain a cleaner repository.

Also applies to: 18-21

.aiignore (1)

1-8: Well-documented AI ignore configuration.

The file clearly explains its purpose and functionality, including important exceptions. The documentation strikes a good balance between being informative and concise.

.junie/guidelines.md (1)

1-197: Excellent comprehensive documentation.

This is a thorough and well-structured guide that covers all essential aspects of the project architecture, development workflow, and conventions. It will be invaluable for onboarding new contributors.

CLAUDE.md (1)

1-201: Excellent AI-focused documentation.

This comprehensive guide provides excellent context for automated code assistants working with the Hyprnote codebase. The detailed architecture overview and development patterns will be invaluable for AI-assisted development.

plugins/local-stt/src/server.rs (1)

147-168: Well-implemented dynamic predictor selection.

The logic for choosing between Silero VAD and RMS predictors is sound:

  • Environment variable configuration provides flexibility
  • Graceful fallback when Silero initialization fails
  • Appropriate different max durations (30s for Silero, 15s for RMS)
  • Good logging for observability
crates/chunker/src/stream.rs (1)

13-35: Well-structured configuration with sensible defaults.

The ChunkConfig struct provides good configurability for chunking behavior. The default values appear reasonable for audio processing.

- Introduced a detailed `README.md` for the `chunker` crate, outlining features, usage, and configuration.
- Enhanced dynamic VAD selection logic in `local-stt` to improve error handling and fallback mechanism.
- Refactored code for better readability and maintainability in chunking implementations.
@metaphorics
Copy link
Author

metaphorics commented Jun 21, 2025

Workarounds for a little issue:

2025-06-21T13:21:37.383176Z  WARN ort::environment: Non-zero status code returned while running Conv node. Name:'Conv_132' Status Message: Invalid input shape: {1}
2025-06-21T13:21:37.383182Z  WARN ort::environment: Non-zero status code returned while running If node. Name:'If_25' Status Message: Non-zero status code returned while running Conv node. Name:'Conv_132' Status Message: Invalid input shape: {1}

The Silero VAD model expects audio chunks of at least 30ms (480 samples at 16kHz), but the chunker's silence trimming is using 100-sample windows, which is only about 6ms. This is causing the invalid input shape error.

- Refactored temporary directory handling with better error handling and clearer expectations.
- Adjusted `trim_window_size` to match Silero's minimum sample requirement (480 samples for 30ms at 16kHz).
- Updated test cases to verify speech detection within the first 600ms of audio.
- Added zero-padding logic in Silero predictor for small chunks to improve robustness.
- Improved handling for prolonged silences to prevent busy looping in audio streaming.
@metaphorics metaphorics requested a review from Copilot June 21, 2025 13:36

This comment was marked as outdated.

@metaphorics metaphorics requested a review from Copilot June 21, 2025 13:37

This comment was marked as outdated.

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@metaphorics metaphorics requested a review from Copilot June 21, 2025 13:39
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
crates/chunker/src/predictor.rs (1)

132-132: Consider error handling for VAD prediction.

The hypr_vad::Vad::run() call could potentially fail. While the current error propagation is correct, consider logging VAD failures for debugging purposes in production environments.

- let probability = self.inner.lock().unwrap().run(samples)?;
+ let probability = self.inner.lock().unwrap().run(samples)
+     .map_err(|e| {
+         log::warn!("VAD prediction failed: {}", e);
+         e
+     })?;
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3ab770b and ca37e76.

📒 Files selected for processing (5)
  • crates/chunker/README.md (1 hunks)
  • crates/chunker/src/lib.rs (2 hunks)
  • crates/chunker/src/predictor.rs (2 hunks)
  • crates/chunker/src/stream.rs (3 hunks)
  • plugins/local-stt/src/server.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • plugins/local-stt/src/server.rs
  • crates/chunker/src/lib.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • crates/chunker/src/predictor.rs
  • crates/chunker/src/stream.rs
🪛 LanguageTool
crates/chunker/README.md

[uncategorized] ~51-~51: Loose punctuation mark.
Context: ...ation ### ChunkConfig - max_duration: Maximum chunk duration (default: 30s) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...s) ### SileroConfig - base_threshold: Default VAD threshold (0.0-1.0) - `conf...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci
🔇 Additional comments (8)
crates/chunker/src/predictor.rs (4)

5-10: LGTM! Clean trait object implementation.

This enables using Box<dyn Predictor> seamlessly, which is essential for dynamic predictor selection mentioned in the PR objectives.


37-62: Well-structured adaptive configuration.

The configuration parameters provide good control over the adaptive thresholding behavior. The default values appear reasonable for general use cases.


118-126: Excellent fix for the core PR issue.

This directly addresses the ONNX Runtime warnings mentioned in the PR objectives by enforcing the 480-sample minimum (30ms at 16kHz) required by Silero VAD. Returning false for small chunks during silence trimming is appropriate.


88-94: ```shell
#!/bin/bash

Display context around chunk_size in crates/chunker/src/lib.rs

rg -n -A10 -B10 "chunk_size" crates/chunker/src/lib.rs


</details>
<details>
<summary>crates/chunker/src/stream.rs (3)</summary>

`32-32`: **Perfect alignment with Silero VAD requirements.**

The default `trim_window_size: 480` (30ms at 16kHz) matches exactly with the minimum input size required by Silero VAD, preventing the ONNX Runtime warnings mentioned in the PR objectives.

---

`73-109`: **Robust bidirectional silence trimming.**

The enhanced trimming logic now removes silence from both ends of the audio buffer. The implementation correctly handles edge cases and uses the predictor for accurate silence detection.

---

`174-177`: **Good resolution of the busy loop issue.**

This addresses the past review comment about potential busy loops. By returning `Poll::Pending` without calling `wake_by_ref()` when chunks are trimmed to empty, the code avoids immediate rescheduling and allows more data to accumulate naturally.

</details>
<details>
<summary>crates/chunker/README.md (1)</summary>

`1-70`: **Excellent comprehensive documentation.**

The README provides clear usage examples, detailed configuration options, and helpful implementation details. The structure makes it easy for developers to understand both basic and advanced usage patterns.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

This comment was marked as outdated.

- Updated default `trim_window_size` in `README.md` to 480 samples for better alignment with Silero requirements.
- Optimized silence trimming loop in `stream.rs` to improve efficiency and maintainability.
@metaphorics metaphorics requested a review from Copilot June 21, 2025 13:52

This comment was marked as outdated.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (6)
crates/chunker/README.md (6)

1-4: Standardize the crate title header
It’s more conventional to use the crate name as the primary header.

Apply this diff if you’d like to align with typical Rust crate READMEs:

-# Audio Chunker
+# chunker
+
+Audio Chunker: intelligent, real-time audio segmentation for Whisper STT integration.

5-13: Singularize “neural networks” for accuracy
The Silero VAD predictor uses a single neural network under the hood.

- - **Silero VAD-based chunking**: Advanced voice activity detection using neural networks
+ - **Silero VAD-based chunking**: Advanced voice activity detection using a neural network

16-24: Clarify return type of chunks
It’s helpful to note that chunks(...) returns an iterator/stream of audio buffers.

 let chunked = audio_source.chunks(RMS::new(), Duration::from_secs(15));
+
+// `chunked` implements Iterator<Item = AudioChunk> (or Stream in async contexts)

49-55: Unify duration units for clarity
Spell out seconds for consistency across all defaults.

- - `max_duration`: Maximum chunk duration (default: 30s)
+ - `max_duration`: Maximum chunk duration (default: 30 seconds)
- - `min_buffer_duration`: Minimum buffer before considering splits (default: 6s)
+ - `min_buffer_duration`: Minimum buffer before considering splits (default: 6 seconds)

56-63: Enhance SileroConfig field descriptions
Consider listing valid ranges or expected units for all thresholds to guide users.

For example:

- `confidence_window_size`: History window in frames (default: 10, must be ≥1)
- `high_confidence_threshold`: Clear-speech detection (0.0–1.0)

66-70: Capitalize “Runtime” in ONNX Runtime
Use the official product name for consistency.

- - Uses ONNX runtime for efficient neural network inference
+ - Uses ONNX Runtime for efficient neural network inference
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ca37e76 and 92229df.

📒 Files selected for processing (2)
  • crates/chunker/README.md (1 hunks)
  • crates/chunker/src/stream.rs (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/chunker/src/stream.rs
🧰 Additional context used
🪛 LanguageTool
crates/chunker/README.md

[uncategorized] ~51-~51: Loose punctuation mark.
Context: ...ation ### ChunkConfig - max_duration: Maximum chunk duration (default: 30s) -...

(UNLIKELY_OPENING_PUNCTUATION)


[uncategorized] ~58-~58: Loose punctuation mark.
Context: ...s) ### SileroConfig - base_threshold: Default VAD threshold (0.0-1.0) - `conf...

(UNLIKELY_OPENING_PUNCTUATION)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-latest)

…es`, `.code_indexer`, `.idea`)

- Add comprehensive guidelines for project development and architecture in `.junie/guidelines.md`
- Introduce dedicated instructions for Claude code contribution in `CLAUDE.md`
…essing

- Added `ChunkConfig` for flexible chunking behavior.
- Implemented adaptive VAD with `SileroConfig`, allowing dynamic threshold adjustments.
- Introduced new tests covering RMS chunking, Silero chunking, and configuration scenarios.
- Improved silence handling to enhance accuracy and prevent empty chunks.
- Enabled `Box<dyn Predictor>` usage for flexible predictor implementations.
- Added support for dynamic VAD selection (Silero or RMS) based on environment variable.
- Integrated configurable max duration for audio chunking.
- Introduced a detailed `README.md` for the `chunker` crate, outlining features, usage, and configuration.
- Enhanced dynamic VAD selection logic in `local-stt` to improve error handling and fallback mechanism.
- Refactored code for better readability and maintainability in chunking implementations.
- Refactored temporary directory handling with better error handling and clearer expectations.
- Adjusted `trim_window_size` to match Silero's minimum sample requirement (480 samples for 30ms at 16kHz).
- Updated test cases to verify speech detection within the first 600ms of audio.
- Added zero-padding logic in Silero predictor for small chunks to improve robustness.
- Improved handling for prolonged silences to prevent busy looping in audio streaming.
- Enhanced clarity of small chunk rejection logic with detailed explanations for ONNX model assumptions and trimming safety margins.
- Simplified VAD speech likelihood computation by removing fallback prediction and relying on default average confidence.
- Added explicit formatting with `dprint fmt` for consistency with `cargo fmt`.
@metaphorics metaphorics requested a review from Copilot June 22, 2025 01:15

This comment was marked as outdated.

…elopment patterns

- Introduced standardized `.cursor/rules/` files detailing audio processing pipelines, code style conventions, database patterns, and plugin development recommendations.
- Added comprehensive guides for essential development commands, project overview, structure, and task completion checklists.
- Improved maintainability through centralized documentation of architecture and best practices.
- Updated `.gitignore` and `.serena` for cache management and memory updates.
- Enhanced `.cursor/rules/` with detailed Rust style conventions aligned with the official Rust Style Guide.
- Expanded audio processing guidelines to emphasize local-first privacy and backend options.
- Introduced comprehensive code style, testing patterns, and performance best practices.
- Added `rustfmt` compliance details and standardized project documentation structure.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (9)
crates/chunker/src/predictor.rs (3)

351-351: Handle potential prediction errors gracefully.

The VAD prediction result is ignored, which could mask errors that might affect the confidence history.

Consider handling the prediction result:

-        let _ = self.silero.predict(samples);
+        if let Err(e) = self.silero.predict(samples) {
+            tracing::warn!("VAD prediction failed: {}", e);
+            // Continue with default confidence or return early
+        }

373-378: Improve readability of SNR calculation.

The SNR calculation could be clearer with intermediate variables.

Consider extracting intermediate variables:

-        let snr = if noise_floor > 0.0 {
-            rms / noise_floor
-        } else {
-            10.0
-        };
+        let snr = if noise_floor > 0.0 { 
+            rms / noise_floor 
+        } else { 
+            10.0 // Default high SNR when noise floor is zero
+        };

380-394: Consider extracting confidence calculation logic.

The multi-feature fusion calculation is complex and could benefit from clearer variable names and structure.

Consider refactoring for clarity:

-        // Weighted feature fusion
-        let mut confidence = 0.0;
-        confidence += speech_likelihood * VAD_WEIGHT; // VAD is primary
-        confidence += speech_quality * SPEECH_QUALITY_WEIGHT; // Spectral quality
-        confidence += (snr.min(10.0) / 10.0) * SNR_WEIGHT; // SNR contribution
-
-        // Boost confidence if onset detected
-        if is_onset {
-            confidence = (confidence + ONSET_BOOST).min(1.0);
-        }
-
-        // Hysteresis for temporal stability
-        let prev_confidence = self.silero.get_recent_confidence_avg(3).unwrap_or(0.5);
-        confidence =
-            confidence * HYSTERESIS_CURRENT_WEIGHT + prev_confidence * HYSTERESIS_PREVIOUS_WEIGHT;
+        // Weighted feature fusion
+        let vad_contribution = speech_likelihood * VAD_WEIGHT;
+        let quality_contribution = speech_quality * SPEECH_QUALITY_WEIGHT;
+        let snr_contribution = (snr.min(10.0) / 10.0) * SNR_WEIGHT;
+        
+        let mut base_confidence = vad_contribution + quality_contribution + snr_contribution;
+        
+        // Boost confidence if onset detected
+        if is_onset {
+            base_confidence = (base_confidence + ONSET_BOOST).min(1.0);
+        }
+        
+        // Apply hysteresis for temporal stability
+        let prev_confidence = self.silero.get_recent_confidence_avg(3).unwrap_or(0.5);
+        let confidence = base_confidence * HYSTERESIS_CURRENT_WEIGHT + prev_confidence * HYSTERESIS_PREVIOUS_WEIGHT;
CLAUDE.md (2)

88-88: Minor grammatical improvement suggested.

Static analysis suggests using "to" instead of "in" for better readability.

-1. If it needs native access, create a new plugin in `plugins/`
+1. If it needs native access, create a new plugin to `plugins/`

91-91: Missing preposition in step 4.

The sentence appears to be missing a preposition for proper grammar.

-4. Import and use in React components
+4. Import and use in React components

Note: The sentence could be improved as "Import and use them in React components" for clarity.

AGENTS.md (2)

1-198: Consider reducing duplication with CLAUDE.md.

This documentation largely duplicates content from CLAUDE.md. While having comprehensive documentation is valuable, the significant overlap creates maintenance burden and potential for inconsistencies.

Consider:

  1. Creating a shared base document with common content
  2. Having agent-specific sections that reference the base
  3. Or clearly differentiating the target audiences and use cases

84-84: Minor grammatical improvement suggested.

Same issue as in CLAUDE.md - static analysis suggests using "to" instead of "in".

-1. If it needs native access, create a new plugin in `plugins/`
+1. If it needs native access, create a new plugin to `plugins/`
.serena/memories/code_style_conventions.md (1)

104-104: Correct macOS capitalization.

The operating system should be capitalized as "macOS" according to Apple's official branding.

-- Platform modules (e.g., `audio::macos`, `audio::windows`)
+- Platform modules (e.g., `audio::macOS`, `audio::windows`)
.cursor/rules/code-style.mdc (1)

341-341: Correct macOS capitalization for consistency.

Same issue as in the other style guide - macOS should be properly capitalized.

-- Platform modules (e.g., `audio::macos`, `audio::windows`)
+- Platform modules (e.g., `audio::macOS`, `audio::windows`)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d40425 and eae0e9c.

📒 Files selected for processing (19)
  • .cursor/rules/audio-processing.mdc (1 hunks)
  • .cursor/rules/code-style.mdc (1 hunks)
  • .cursor/rules/database-patterns.mdc (1 hunks)
  • .cursor/rules/dev-commands.mdc (1 hunks)
  • .cursor/rules/plugin-development.mdc (1 hunks)
  • .cursor/rules/project-overview.mdc (1 hunks)
  • .cursor/rules/project-structure.mdc (1 hunks)
  • .cursor/rules/task-completion.mdc (1 hunks)
  • .gitignore (1 hunks)
  • .serena/memories/code_style_conventions.md (1 hunks)
  • .serena/memories/codebase_structure.md (1 hunks)
  • .serena/memories/project_overview.md (1 hunks)
  • .serena/memories/rust_style_guide.md (1 hunks)
  • .serena/memories/suggested_commands.md (1 hunks)
  • .serena/memories/task_completion_checklist.md (1 hunks)
  • .serena/project.yml (1 hunks)
  • AGENTS.md (1 hunks)
  • CLAUDE.md (1 hunks)
  • crates/chunker/src/predictor.rs (3 hunks)
✅ Files skipped from review due to trivial changes (12)
  • .serena/project.yml
  • .serena/memories/project_overview.md
  • .cursor/rules/task-completion.mdc
  • .serena/memories/codebase_structure.md
  • .cursor/rules/project-overview.mdc
  • .cursor/rules/dev-commands.mdc
  • .cursor/rules/audio-processing.mdc
  • .cursor/rules/database-patterns.mdc
  • .serena/memories/task_completion_checklist.md
  • .serena/memories/suggested_commands.md
  • .serena/memories/rust_style_guide.md
  • .cursor/rules/project-structure.mdc
🚧 Files skipped from review as they are similar to previous changes (1)
  • .gitignore
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.{js,ts,tsx,rs}`: 1. No error handling. 2. No unused imports, variables, or functions. 3. For comments, keep it minimal. It should be about "Why", not "What".

**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".

  • crates/chunker/src/predictor.rs
🪛 LanguageTool
AGENTS.md

[uncategorized] ~84-~84: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~87-~87: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~89-~89: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

.serena/memories/code_style_conventions.md

[grammar] ~104-~104: The operating system from Apple is written “macOS”.
Context: ...in Cargo.toml - Platform modules (e.g., audio::macos, audio::windows) - Clear abstraction...

(MAC_OS)

CLAUDE.md

[uncategorized] ~88-~88: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~91-~91: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~93-~93: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (13)
crates/chunker/src/predictor.rs (9)

5-10: LGTM! Clean trait implementation for boxed predictors.

The implementation correctly delegates to the inner predictor, enabling ergonomic use of boxed trait objects.


21-25: LGTM! Standard Default implementation.

Properly delegates to the existing constructor.


43-68: LGTM! Well-structured configuration with sensible defaults.

The configuration parameters are clearly documented and the default values appear reasonable for speech detection scenarios.


90-99: LGTM! Robust mutex error handling.

The helper function provides consistent error recovery across the codebase, addressing the previous review concern about mutex poisoning.


101-108: LGTM! Constants extracted as suggested in previous reviews.

The magic numbers have been properly extracted into named constants, improving maintainability.


213-220: LGTM! Well-reasoned approach to minimum sample handling.

The decision to return false for small chunks is well-justified by the detailed comments explaining why padding would be problematic for the ONNX model.


226-229: LGTM! Proper mutex scope management.

The explicit scope block ensures the lock is dropped immediately after the VAD prediction, preventing lock contention.


419-452: LGTM! Well-documented speech quality calculation.

The hard-coded thresholds are properly justified with detailed comments explaining the physiological basis for the ranges. The decision not to make these configurable is well-reasoned.


465-465: LGTM! Conservative threshold for noise profile updates.

The 0.3 threshold is well-explained and appropriately conservative to prevent contaminating the noise profile with speech.

CLAUDE.md (1)

1-269: Excellent comprehensive documentation for Claude Code integration.

This documentation provides thorough coverage of the Hyprnote project architecture, development workflows, and coding conventions. The structure is logical and the content is detailed enough to be valuable for onboarding.

A few minor grammatical improvements are suggested by static analysis tools, but these don't significantly impact readability.

.cursor/rules/plugin-development.mdc (1)

1-67: Well-structured plugin development guide.

This documentation provides clear, actionable guidance for Tauri plugin development. The progression from creation to usage is logical, and the code examples are helpful for developers.

The integration with the broader project architecture (as described in other documentation files) is consistent and well-explained.

.serena/memories/code_style_conventions.md (1)

1-105: Comprehensive and well-organized style guide.

This documentation provides excellent coverage of coding conventions for both TypeScript/React and Rust. The examples are practical and the organization makes it easy to find specific guidance.

.cursor/rules/code-style.mdc (1)

1-342: Outstanding comprehensive style guide.

This is an exceptionally well-structured and comprehensive code style guide. The detailed examples, formatting tables, and coverage of advanced topics like async patterns make this an excellent reference for developers.

The integration of both TypeScript/React and Rust conventions in a single document with clear organization is particularly valuable for a polyglot codebase like Hyprnote.

- Added specific TypeScript/React and Rust review guidelines for structured code checks.
- Introduced detailed instructions for audio processing and Tauri plugin development.
- Updated development commands with `dprint fmt` for formatting consistency.
- Adjusted dependencies for macOS-specific `apple-calendar` plugin features.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
.coderabbit.yaml (1)

9-22: Validate TypeScript/React path_instructions block.
The new entry under path_instructions conforms to the schema and covers .js, .ts, and .tsx files with clear guidelines. Consider whether you need to include other extensions (e.g., .jsx) or adjust the glob to match your full React codebase.

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between eae0e9c and 8e3b2c9.

📒 Files selected for processing (3)
  • .coderabbit.yaml (1 hunks)
  • .cursor/rules/dev-commands.mdc (1 hunks)
  • plugins/apple-calendar/Cargo.toml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • plugins/apple-calendar/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (1)
  • .cursor/rules/dev-commands.mdc
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (3)
.coderabbit.yaml (3)

23-38: Rust review guidelines block is well-formed.
This segment correctly follows the schema for Rust files, with comprehensive checks and proper indentation. No issues found.


39-47: Audio processing instructions are accurate.
The real-time and buffer management checks align with the project’s audio crate requirements. Formatting and schema usage look correct.


48-56: Tauri plugin instructions look good.
The plugin-specific guidelines are clear, follow the schema, and cover command exposure, error serialization, and async handling.

@metaphorics metaphorics requested a review from Copilot June 22, 2025 02:43
@metaphorics metaphorics changed the title Implement silero-based audio chunker & introducing adaptive VAD Implement silero-based audio chunker & introducing adaptive VAD & fix compilations on Windows(#66)/Linux Jun 22, 2025

This comment was marked as outdated.

@metaphorics metaphorics changed the title Implement silero-based audio chunker & introducing adaptive VAD & fix compilations on Windows(#66)/Linux Implement silero-based audio chunker & introducing adaptive VAD & fix compilations on Windows(#66)/Linux(#67) Jun 22, 2025
@metaphorics metaphorics changed the title Implement silero-based audio chunker & introducing adaptive VAD & fix compilations on Windows(#66)/Linux(#67) Implement silero-based audio chunker(#857) & introducing adaptive VAD & fix compilations on Windows(#66)/Linux(#67) Jun 22, 2025
- Updated `list_system_events` and `monitor` function signatures for alignment with updated imports and configurations.
- Included `CalendarSource` in imports for enhanced feature compatibility.
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

♻️ Duplicate comments (1)
plugins/apple-calendar/src/sync.rs (1)

189-209: Avoid creating a new Tokio runtime inside spawn_blocking.

Same issue as list_system_calendars - creating a new runtime is inefficient.

🧹 Nitpick comments (10)
crates/tcc/src/lib.rs (2)

7-11: Consider consistent error handling across platforms.

The non-macOS implementation always returns true, which may not reflect reality. Consider whether this should return a Result type for consistency with potential macOS error cases, or at least document why permissions are assumed to be granted on non-macOS platforms.

For consistency with potential macOS error handling:

#[cfg(not(target_os = "macos"))]
-pub fn _audio_capture_permission_granted() -> bool {
+pub fn audio_capture_permission_granted() -> Result<bool, String> {
     // On non-macOS platforms, assume permission is granted
-    true
+    Ok(true)
 }

Or add documentation explaining the assumption:

#[cfg(not(target_os = "macos"))]
+/// On non-macOS platforms, we assume audio capture permission is always granted
+/// as these platforms typically don't require explicit permission requests
pub fn _audio_capture_permission_granted() -> bool {
    // On non-macOS platforms, assume permission is granted
    true
}

18-22: Review unsafe usage and test reliability.

The unsafe call to the Swift FFI function is necessary, but the test always assumes the result will be true. In real scenarios, permission might be denied. Consider testing both scenarios or at least documenting why we expect true.

Consider making the test more robust:

 #[test]
 #[cfg(target_os = "macos")]
 fn test_audio_capture_permission_granted() {
     let result = unsafe { _audio_capture_permission_granted() };
-    assert!(result);
+    // Note: This test may fail if audio capture permission is not granted
+    // In CI/testing environments, this should typically be true
+    assert!(result, "Audio capture permission should be granted in test environment");
 }
AGENTS.md (2)

84-84: Minor grammatical correction needed.

The preposition should be "to" instead of "in" for better clarity.

-1. If it needs native access, create a new plugin in `plugins/`
+1. If it needs native access, create a new plugin to `plugins/`

87-87: Add missing preposition for clarity.

The sentence is missing a preposition "to" before "use".

-4. Import and use in React components
+4. Import and use to React components
crates/calendar-apple/src/stub.rs (2)

5-12: Consider implementing the Default trait.

Since Handle has a simple new() method that takes no parameters, implementing Default would make it more idiomatic.

+#[derive(Default)]
 pub struct Handle;
 
 impl Handle {
     pub fn new() -> Self {
-        Handle
+        Self::default()
     }

14-22: ```shell
#!/bin/bash

Display the calendar-interface crate's lib.rs to locate the Error definition

echo "=== calendar-interface/src/lib.rs (first 200 lines) ==="
sed -n '1,200p' crates/calendar-interface/src/lib.rs || true


</blockquote></details>
<details>
<summary>plugins/apple-calendar/src/ext.rs (2)</summary><blockquote>

`125-129`: **Maintain consistent commenting style for no-op blocks.**

Some non-macOS blocks have comments while others don't. Consider being consistent - either add comments to all no-op blocks or remove them.



Also applies to: 139-143, 186-189

---

`43-46`: **Consider using the Error enum instead of String errors.**

Multiple methods return `String` errors when they could use the more specific `crate::Error::NotSupported` for consistency.

For example:
```diff
-        Err("Apple Calendar is only supported on macOS".to_string())
+        Err(crate::Error::NotSupported.to_string())

Also applies to: 63-66, 83-86, 168-171

crates/calendar-apple/src/macos.rs (2)

99-133: Add safety documentation for unsafe blocks.

The unsafe blocks interact with Objective-C APIs. Consider adding safety comments explaining why these operations are safe.

For example:

+        // Safety: calendars() returns a retained NSArray that is memory-safe
         let calendars: Retained<NSArray<EKCalendar>> = unsafe { self.event_store.calendars() }

135-170: Consider refactoring the nested logic for clarity.

The transform_participant method has deeply nested logic that could be simplified for better readability.

     fn transform_participant(&self, participant: &EKParticipant) -> Participant {
         let name = unsafe { participant.name() }
             .unwrap_or_default()
             .to_string();
 
-        let email = {
-            if !self.contacts_access_granted {
-                None
-            } else {
-                // ... complex nested logic
-            }
-        };
+        let email = if self.contacts_access_granted {
+            self.fetch_participant_email(participant)
+        } else {
+            None
+        };
 
         Participant { name, email }
     }
+
+    fn fetch_participant_email(&self, participant: &EKParticipant) -> Option<String> {
+        // Extract the email fetching logic here
+    }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8e3b2c9 and 7d9898f.

📒 Files selected for processing (20)
  • .junie/guidelines.md (1 hunks)
  • AGENTS.md (1 hunks)
  • crates/calendar-apple/Cargo.toml (1 hunks)
  • crates/calendar-apple/src/lib.rs (1 hunks)
  • crates/calendar-apple/src/macos.rs (1 hunks)
  • crates/calendar-apple/src/stub.rs (1 hunks)
  • crates/detect/src/app/linux.rs (1 hunks)
  • crates/detect/src/app/mod.rs (1 hunks)
  • crates/detect/src/browser/linux.rs (1 hunks)
  • crates/detect/src/browser/mod.rs (1 hunks)
  • crates/detect/src/mic/linux.rs (1 hunks)
  • crates/detect/src/mic/mod.rs (1 hunks)
  • crates/tcc/Cargo.toml (1 hunks)
  • crates/tcc/build.rs (1 hunks)
  • crates/tcc/src/lib.rs (1 hunks)
  • plugins/apple-calendar/Cargo.toml (1 hunks)
  • plugins/apple-calendar/src/error.rs (1 hunks)
  • plugins/apple-calendar/src/ext.rs (1 hunks)
  • plugins/apple-calendar/src/sync.rs (3 hunks)
  • plugins/apple-calendar/src/worker.rs (2 hunks)
✅ Files skipped from review due to trivial changes (4)
  • plugins/apple-calendar/src/error.rs
  • crates/tcc/build.rs
  • crates/tcc/Cargo.toml
  • plugins/apple-calendar/src/worker.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • plugins/apple-calendar/Cargo.toml
🧰 Additional context used
📓 Path-based instructions (2)
`**/*.rs`: Rust Review Guidelines: 1. Ensure proper error handling with Result/Option types 2. Check for clippy warnings and suggest fixes 3. Verify memory safety and absence of un...

**/*.rs: Rust Review Guidelines:

  1. Ensure proper error handling with Result/Option types
  2. Check for clippy warnings and suggest fixes
  3. Verify memory safety and absence of unnecessary unsafe blocks
  4. Check for proper use of lifetimes and borrowing
  5. Ensure efficient use of iterators over manual loops
  6. Verify proper async/await usage with Tokio
  7. Check for appropriate use of Arc/Mutex in concurrent code
  8. Ensure consistent error types using thiserror
  9. Verify proper use of tracing for logging
  10. Comments should explain "why" not "what"
  11. Check adherence to Rust Style Guide (enforced by rustfmt)
  12. Verify performance-critical paths use appropriate optimizations
  • crates/detect/src/browser/mod.rs
  • crates/detect/src/app/mod.rs
  • crates/detect/src/app/linux.rs
  • crates/detect/src/mic/mod.rs
  • crates/detect/src/browser/linux.rs
  • crates/detect/src/mic/linux.rs
  • crates/tcc/src/lib.rs
  • crates/calendar-apple/src/stub.rs
  • crates/calendar-apple/src/lib.rs
  • plugins/apple-calendar/src/sync.rs
  • plugins/apple-calendar/src/ext.rs
  • crates/calendar-apple/src/macos.rs
`**/plugins/**/*.rs`: Tauri Plugin Specific: 1. Ensure commands are properly exposed with #[tauri::command] 2. Verify error types are serializable for IPC 3. Check for proper permi...

**/plugins/**/*.rs: Tauri Plugin Specific:

  1. Ensure commands are properly exposed with #[tauri::command]
  2. Verify error types are serializable for IPC
  3. Check for proper permission handling
  4. Ensure TypeScript bindings will generate correctly
  5. Verify async commands use proper runtime handling
  • plugins/apple-calendar/src/sync.rs
  • plugins/apple-calendar/src/ext.rs
🪛 GitHub Actions: .github/workflows/fmt.yaml
plugins/apple-calendar/src/sync.rs

[error] 188-191: dprint formatting check failed. File is not properly formatted according to dprint rules.

🪛 LanguageTool
AGENTS.md

[uncategorized] ~84-~84: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~87-~87: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~89-~89: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

.junie/guidelines.md

[uncategorized] ~84-~84: The preposition ‘to’ seems more likely in this position.
Context: ...eeds native access, create a new plugin in plugins/ 2. Implement Rust logic and ...

(AI_HYDRA_LEO_REPLACE_IN_TO)


[uncategorized] ~87-~87: Possible missing preposition found.
Context: ...pes` to generate TypeScript bindings 4. Import and use in React components ### Workin...

(AI_HYDRA_LEO_MISSING_TO)


[duplication] ~89-~89: Possible typo: you repeated a word.
Context: ...e in React components ### Working with Audio - Audio processing logic is in crates/audio/ ...

(ENGLISH_WORD_REPEAT_RULE)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (11)
crates/tcc/src/lib.rs (1)

24-29: Test implementation looks good.

The non-macOS test correctly calls the safe Rust function and verifies the expected behavior. The implementation is straightforward and appropriate for the fallback case.

AGENTS.md (2)

89-89: Remove duplicate word.

The word "with" appears to be duplicated.

-### Working with Audio
+### Working Audio

Wait, actually looking at this more carefully, "Working with Audio" is correct and not a duplication. The static analysis tool seems to have a false positive here.


1-265: Excellent comprehensive documentation!

This is a well-structured and thorough documentation file that provides excellent onboarding material for the Hyprnote project. It covers all the essential aspects including architecture, development workflow, coding conventions, and important considerations. The inclusion of specific examples and detailed explanations will be very valuable for new contributors.

crates/detect/src/browser/mod.rs (2)

11-14: Well-implemented platform abstraction for Linux support.

The conditional compilation logic correctly adds Linux support by using a catch-all condition for non-macOS/non-Windows targets. This follows the established pattern and maintains consistency with the existing platform abstraction.


11-14: Verify Linux implementation exists.

Ensure that the corresponding linux.rs module has been implemented with appropriate detection logic for Linux platforms.

#!/bin/bash
# Description: Check if the Linux implementation file exists and examine its contents
# Expected: Find linux.rs with Detector implementation

find crates/detect/src -name "linux.rs" -exec echo "Found: {}" \; -exec cat {} \;
crates/calendar-apple/Cargo.toml (1)

7-10: Inappropriate dependency scoping for cross-platform dependencies.

Moving anyhow, chrono, and itertools to the macOS-specific section may cause compilation issues if these dependencies are used in platform-agnostic code or stub implementations for other platforms.

These common utility crates are typically safe to include in the general [dependencies] section unless they're exclusively used in macOS-specific code paths.

#!/bin/bash
# Description: Check if the moved dependencies are used in non-macOS code
# Expected: Find usage patterns to determine appropriate scoping

echo "Checking usage of moved dependencies in calendar-apple crate..."
echo "=== anyhow usage ==="
rg "anyhow" crates/calendar-apple/src/

echo "=== chrono usage ==="
rg "chrono" crates/calendar-apple/src/

echo "=== itertools usage ==="
rg "itertools" crates/calendar-apple/src/

echo "=== File structure ==="
find crates/calendar-apple/src -name "*.rs" -exec echo "Found: {}" \;
crates/detect/src/app/mod.rs (2)

11-14: Consistent platform abstraction implementation.

Excellent consistency with the browser detection module's approach to Linux support. The conditional compilation logic is correct and maintains the established platform abstraction pattern.


11-14: Verify corresponding Linux implementation.

Ensure the linux.rs module for app detection has been implemented with appropriate detection logic.

#!/bin/bash
# Description: Check for Linux app detection implementation
# Expected: Find app/linux.rs with Detector implementation

echo "Checking for app detection Linux implementation..."
find crates/detect/src/app -name "linux.rs" -exec echo "Found: {}" \; -exec cat {} \;
crates/detect/src/mic/mod.rs (1)

11-14: Platform abstraction looks good!

The Linux platform support follows the established pattern and correctly handles all non-macOS/non-Windows targets.

crates/calendar-apple/src/lib.rs (1)

1-9: Excellent platform abstraction pattern!

The refactoring to platform-specific modules with conditional exports provides clean separation of concerns and follows Rust best practices for cross-platform code.

plugins/apple-calendar/src/sync.rs (1)

287-308: LGTM!

The platform-specific implementation correctly returns NotSupported error on non-macOS platforms and properly checks calendar access on macOS.

@metaphorics metaphorics requested a review from Copilot June 22, 2025 02:53

This comment was marked as outdated.

metaphorics and others added 2 commits June 22, 2025 12:05
…andling

- Replaced `tauri::async_runtime::spawn_blocking` in macOS-specific calendar functions with direct calls for cleaner async handling.
- Renamed and updated `_audio_capture_permission_granted` to `_macos_audio_capture_permission` with a unified interface for permission checks.
- Improved test structure for `audio_capture_permission_granted` to ensure function compatibility across platforms.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@metaphorics metaphorics requested a review from Copilot June 22, 2025 03:06

This comment was marked as outdated.

…ync handling

- Replaced direct async calls with `tauri::async_runtime::spawn_blocking` to better handle blocking operations in macOS-specific calendar functions.
- Updated `list_system_calendars` and `list_system_events` for cleaner and more robust execution.
@metaphorics metaphorics requested a review from Copilot June 22, 2025 03:11
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Adds extensive configuration and guideline files for AI assistants, project tooling, and code review processes alongside setup adjustments supporting the new Silero-based audio chunker and adaptive VAD.

  • Introduce CLAUDE.md and AGENTS.md with detailed AI assistant usage guidelines
  • Add Serena and Cursor configurations and memory artifacts for onboarding, task completion, and project structure
  • Update coderabbit.yaml and .aiignore to refine automated review patterns

Reviewed Changes

Copilot reviewed 20 out of 48 changed files in this pull request and generated no comments.

Show a summary per file
File Description
CLAUDE.md New guidelines for Claude Code assistant
AGENTS.md New guidelines for generic AI agents
.serena/project.yml Serena project configuration
.serena/memories/task_completion_checklist.md Task completion checklist memory
.serena/memories/suggested_commands.md Suggested commands memory
.serena/memories/rust_style_guide.md Rust style guide memory
.serena/memories/project_overview.md Project overview memory
.serena/memories/codebase_structure.md Codebase structure memory
.serena/memories/code_style_conventions.md Code style conventions memory
.junie/guidelines.md Duplicate AI assistant guidelines
.cursor/rules/task-completion.mdc Task completion rule for Cursor
.cursor/rules/project-structure.mdc Project structure rule for Cursor
.cursor/rules/project-overview.mdc Project overview rule for Cursor
.cursor/rules/plugin-development.mdc Plugin development rule for Cursor
.cursor/rules/dev-commands.mdc Development commands rule for Cursor
.cursor/rules/database-patterns.mdc Database patterns rule for Cursor
.cursor/rules/code-style.mdc Code style rule for Cursor
.cursor/rules/audio-processing.mdc Audio processing rule for Cursor
.coderabbit.yaml Update code review instruction patterns
.aiignore Add .aiignore file
Comments suppressed due to low confidence (4)

AGENTS.md:1

  • [nitpick] Consider adding a top-level H1 (e.g., "# AGENTS.md") for consistency with other assistant guideline files.
## Project Overview

.coderabbit.yaml:9

  • This entry’s indentation appears off and no longer includes .rs. Verify the path patterns and indentation to ensure tool configs are applied correctly.
    - path: "**/*.{js,ts,tsx}"

.serena/memories/suggested_commands.md:39

  • [nitpick] Content here overlaps heavily with .serena/memories/task_completion_checklist.md and cursor rules. Consider deduplicating or referencing a single source of truth.
# Generate TypeScript bindings from Rust plugins (CRITICAL after modifying plugin commands)

CLAUDE.md:1

  • The content in CLAUDE.md largely duplicates AGENTS.md and .junie/guidelines.md. Consider consolidating shared guidelines to reduce duplication.
# CLAUDE.md

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
crates/whisper/src/local/types.rs (3)

1-6: Consider using std::sync::OnceLock instead of lazy_static.

The lazy_static crate is no longer necessary in modern Rust. You can use std::sync::OnceLock which is part of the standard library since Rust 1.70.

-use lazy_static::lazy_static;
-use regex::Regex;
-
-lazy_static! {
-    static ref TRAILING_DOTS: Regex = Regex::new(r"\.{2,}$").unwrap();
-}
+use regex::Regex;
+use std::sync::OnceLock;
+
+static TRAILING_DOTS: OnceLock<Regex> = OnceLock::new();
+
+fn trailing_dots_regex() -> &'static Regex {
+    TRAILING_DOTS.get_or_init(|| Regex::new(r"\.{2,}$").unwrap())
+}

18-36: Consider removing redundant accessor methods for public fields.

Since the struct fields are already public, the getter methods are redundant and add unnecessary boilerplate. Direct field access is more idiomatic in Rust when fields are public.

-    pub fn text(&self) -> &str {
-        &self.text
-    }
-
-    pub fn start(&self) -> f32 {
-        self.start
-    }
-
-    pub fn end(&self) -> f32 {
-        self.end
-    }
-
-    pub fn confidence(&self) -> f32 {
-        self.confidence
-    }

Keep the duration() method as it provides computed functionality.


38-41: Update trim method to use modern regex pattern if refactored.

If you adopt the OnceLock approach, update this method accordingly:

     pub fn trim(&mut self) {
-        self.text = TRAILING_DOTS.replace(&self.text, "").to_string();
+        self.text = trailing_dots_regex().replace(&self.text, "").to_string();
     }
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e25c1d2 and c0adb27.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (11)
  • .serena/project.yml (1 hunks)
  • crates/tcc/src/lib.rs (1 hunks)
  • crates/tcc/swift-lib/src/lib.swift (1 hunks)
  • crates/whisper/.gitignore (1 hunks)
  • crates/whisper/Cargo.toml (1 hunks)
  • crates/whisper/src/local/mod.rs (1 hunks)
  • crates/whisper/src/local/model.rs (4 hunks)
  • crates/whisper/src/local/reporter.rs (1 hunks)
  • crates/whisper/src/local/types.rs (1 hunks)
  • plugins/apple-calendar/src/sync.rs (3 hunks)
  • plugins/local-stt/src/server.rs (3 hunks)
✅ Files skipped from review due to trivial changes (3)
  • crates/whisper/.gitignore
  • crates/whisper/src/local/mod.rs
  • crates/whisper/Cargo.toml
🚧 Files skipped from review as they are similar to previous changes (4)
  • .serena/project.yml
  • crates/tcc/src/lib.rs
  • plugins/local-stt/src/server.rs
  • plugins/apple-calendar/src/sync.rs
🧰 Additional context used
📓 Path-based instructions (1)
`**/*.rs`: Rust Review Guidelines: 1. Ensure proper error handling with Result/Option types 2. Check for clippy warnings and suggest fixes 3. Verify memory safety and absence of un...

**/*.rs: Rust Review Guidelines:

  1. Ensure proper error handling with Result/Option types
  2. Check for clippy warnings and suggest fixes
  3. Verify memory safety and absence of unnecessary unsafe blocks
  4. Check for proper use of lifetimes and borrowing
  5. Ensure efficient use of iterators over manual loops
  6. Verify proper async/await usage with Tokio
  7. Check for appropriate use of Arc/Mutex in concurrent code
  8. Ensure consistent error types using thiserror
  9. Verify proper use of tracing for logging
  10. Comments should explain "why" not "what"
  11. Check adherence to Rust Style Guide (enforced by rustfmt)
  12. Verify performance-critical paths use appropriate optimizations
  • crates/whisper/src/local/types.rs
  • crates/whisper/src/local/reporter.rs
  • crates/whisper/src/local/model.rs
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: ci (windows, windows-latest)
  • GitHub Check: ci (macos, macos-latest)
  • GitHub Check: ci
🔇 Additional comments (6)
crates/tcc/swift-lib/src/lib.swift (1)

13-14: LGTM! Platform-specific naming improves clarity.

The function rename from _audio_capture_permission_granted to _macos_audio_capture_permission makes the platform-specific nature of this function explicit, which aligns well with the PR objectives of fixing compilation issues across different platforms. The internal logic remains unchanged, preserving the existing functionality.

crates/whisper/src/local/types.rs (1)

9-15: LGTM! Well-structured Segment definition.

The struct follows Rust conventions with proper derive macros for serialization and debugging. The public fields and reference to external source documentation are good practices.

crates/whisper/src/local/model.rs (4)

3-4: LGTM! Clean module imports.

The imports are well-organized and follow Rust conventions.


56-60: LGTM! Proper conditional compilation pattern.

The debug-only initialization of the reporter is handled correctly using cfg! macro.


84-87: Clever use of conditional compilation for the reporter field.

The approach of using different types for debug vs release builds while maintaining the same field name is elegant and avoids runtime overhead in release builds.


161-164: Add error handling for reporter save operation.

If the WhisperReporter::save method is updated to return a Result (as suggested in the reporter review), this code should handle potential errors gracefully to avoid breaking the transcription process.

         if let Some(reporter) = &mut self.reporter {
-            reporter.save(audio, &segments);
+            if let Err(e) = reporter.save(audio, &segments) {
+                tracing::warn!("Failed to save reporter data: {}", e);
+            }
         }

This change depends on updating the save method signature in WhisperReporter.

Comment on lines +32 to +51
pub fn save(&mut self, audio: &[f32], segments: &[Segment]) {
let file_path = self
.base_dir
.join(format!("{}_{}.json", self.uid, self.counter));
let audio_path = self
.base_dir
.join(format!("{}_{}.wav", self.uid, self.counter));

let mut audio_writer = hound::WavWriter::create(audio_path, self.audio_spec).unwrap();
for sample in audio {
audio_writer.write_sample(*sample).unwrap();
}
audio_writer.finalize().unwrap();

let mut json_writer = std::fs::File::create(file_path).unwrap();
serde_json::to_writer(&mut json_writer, &segments).unwrap();

self.counter += 1;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add proper error handling to the save method.

The method uses multiple unwrap() calls which can cause the application to panic. This is especially problematic for a debugging/reporting feature that shouldn't crash the main application.

-    pub fn save(&mut self, audio: &[f32], segments: &[Segment]) {
+    pub fn save(&mut self, audio: &[f32], segments: &[Segment]) -> Result<(), Box<dyn std::error::Error>> {
         let file_path = self
             .base_dir
             .join(format!("{}_{}.json", self.uid, self.counter));
         let audio_path = self
             .base_dir
             .join(format!("{}_{}.wav", self.uid, self.counter));
 
-        let mut audio_writer = hound::WavWriter::create(audio_path, self.audio_spec).unwrap();
+        let mut audio_writer = hound::WavWriter::create(audio_path, self.audio_spec)?;
         for sample in audio {
-            audio_writer.write_sample(*sample).unwrap();
+            audio_writer.write_sample(*sample)?;
         }
-        audio_writer.finalize().unwrap();
+        audio_writer.finalize()?;
 
-        let mut json_writer = std::fs::File::create(file_path).unwrap();
-        serde_json::to_writer(&mut json_writer, &segments).unwrap();
+        let json_writer = std::fs::File::create(file_path)?;
+        serde_json::to_writer(json_writer, segments)?;
 
         self.counter += 1;
+        Ok(())
     }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In crates/whisper/src/local/reporter.rs around lines 32 to 51, the save method
uses multiple unwrap() calls that can cause panics. Refactor the method to
return a Result type and replace unwrap() calls with proper error handling using
the ? operator or match statements. This will propagate errors instead of
panicking, making the method safer and preventing the application from crashing
during save failures.

Comment on lines +10 to +29
impl Default for WhisperReporter {
fn default() -> Self {
let base_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("data");
std::fs::create_dir_all(&base_dir).unwrap();

let audio_spec = hound::WavSpec {
channels: 1,
sample_rate: 16000,
bits_per_sample: 32,
sample_format: hound::SampleFormat::Float,
};

Self {
base_dir,
uid: uuid::Uuid::new_v4().to_string(),
counter: 0,
audio_spec,
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Improve error handling and avoid using CARGO_MANIFEST_DIR at runtime.

The current implementation has several issues:

  1. Multiple unwrap() calls that can cause panics
  2. CARGO_MANIFEST_DIR may not be available in production builds
  3. No error propagation mechanism
 impl Default for WhisperReporter {
-    fn default() -> Self {
-        let base_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("data");
-        std::fs::create_dir_all(&base_dir).unwrap();
+    fn default() -> Self {
+        Self::new().expect("Failed to create WhisperReporter")
+    }
+}
+
+impl WhisperReporter {
+    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
+        let base_dir = dirs::data_dir()
+            .or_else(|| dirs::home_dir().map(|p| p.join(".local/share")))
+            .unwrap_or_else(|| std::path::PathBuf::from("./data"))
+            .join("hyprnote")
+            .join("whisper_reports");
+        
+        std::fs::create_dir_all(&base_dir)?;
 
         let audio_spec = hound::WavSpec {
             channels: 1,
             sample_rate: 16000,
             bits_per_sample: 32,
             sample_format: hound::SampleFormat::Float,
         };
 
-        Self {
+        Ok(Self {
             base_dir,
             uid: uuid::Uuid::new_v4().to_string(),
             counter: 0,
             audio_spec,
-        }
-    }
+        })
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
impl Default for WhisperReporter {
fn default() -> Self {
let base_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("data");
std::fs::create_dir_all(&base_dir).unwrap();
let audio_spec = hound::WavSpec {
channels: 1,
sample_rate: 16000,
bits_per_sample: 32,
sample_format: hound::SampleFormat::Float,
};
Self {
base_dir,
uid: uuid::Uuid::new_v4().to_string(),
counter: 0,
audio_spec,
}
}
}
impl Default for WhisperReporter {
fn default() -> Self {
Self::new().expect("Failed to create WhisperReporter")
}
}
impl WhisperReporter {
pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
let base_dir = dirs::data_dir()
.or_else(|| dirs::home_dir().map(|p| p.join(".local/share")))
.unwrap_or_else(|| std::path::PathBuf::from("./data"))
.join("hyprnote")
.join("whisper_reports");
std::fs::create_dir_all(&base_dir)?;
let audio_spec = hound::WavSpec {
channels: 1,
sample_rate: 16000,
bits_per_sample: 32,
sample_format: hound::SampleFormat::Float,
};
Ok(Self {
base_dir,
uid: uuid::Uuid::new_v4().to_string(),
counter: 0,
audio_spec,
})
}
}
🤖 Prompt for AI Agents
In crates/whisper/src/local/reporter.rs around lines 10 to 29, replace the use
of env!("CARGO_MANIFEST_DIR") with a runtime-available directory path, such as a
configurable or standard data directory. Remove all unwrap() calls by handling
errors gracefully, returning a Result from the default or initialization
function instead of panicking. Implement proper error propagation to allow
callers to handle failures in directory creation or other setup steps.

@yujonglee
Copy link
Contributor

Closing due to inactivity

@yujonglee yujonglee closed this Jul 3, 2025
@yujonglee yujonglee deleted the enhance-audio-chunking-#857 branch July 3, 2025 22:00
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.

2 participants