Skip to content

Conversation

@shubhraMurf
Copy link

@shubhraMurf shubhraMurf commented Oct 30, 2025

feat: Add Murf Text-to-Speech Component

Description

This PR adds a new Langflow component that integrates with Murf AI's Text-to-Speech API, allowing users to convert text to high-quality speech audio with customizable voice parameters.

Changes

  • Added MurfTextToSpeech component (src/lfx/src/lfx/components/Murf/text_to_speech.py)
    • Supports dynamic voice selection based on locale and voice ID
    • Configurable audio parameters (format, sample rate, channel type, speed, pitch)
    • Base64 encoding option for audio output
    • Dynamic dropdown menus that update based on API key and selected locale
    • Multi-native locale support for voices

Features

  • Text Input: Multiline text input for speech generation
  • Dynamic Voice Selection:
    • Locale dropdown that populates from Murf API
    • Voice ID dropdown filtered by precedent locale selection
    • Multi-native locale support for selected voices
  • Audio Configuration:
    • Output formats: mp3, wav, flac, alaw, ulaw, pcm, ogg
    • Sample rates: 8000, 24000, 44100, 48000 Hz
    • Channel types: Mono, Stereo
    • Speed and pitch adjustment (-50 to +50)
  • Error Handling: Comprehensive error handling with specific exception types for better debugging

Testing

  • Component includes proper error handling and logging
  • Dynamic field updates based on API responses

Documentation


Note: This PR adds a new component that requires the murf Python package to be installed and a valid Murf API key to use.

Summary by CodeRabbit

  • New Features

    • Murf Text-to-Speech added — generate speech with configurable voice, locale, format, rate, pitch, and output options.
  • UI / UX

    • Murf bundle added to sidebar and icon set with eager and lazy loading support.
  • Documentation

    • New Murf bundle docs covering setup, parameters, examples, and troubleshooting.
  • Tests

    • Comprehensive unit tests for Murf TTS behavior, initialization, config updates, and error handling.
  • Chores

    • Murf dependency added to project configuration.

@github-actions github-actions bot added the community Pull Request from an external contributor label Oct 30, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 30, 2025

Walkthrough

Adds Murf Text-to-Speech integration: new backend component with dynamic voice/listing and TTS generation, frontend UI/icon/sidebar registration, documentation, tests, and murf dependency updates; also updates secrets metadata timestamps/line numbers.

Changes

Cohort / File(s) Summary
Documentation
docs/docs/Components/bundles-murf.mdx, docs/sidebars.js
New Murf bundle docs page and sidebar entry for the Murf component.
Dependencies
pyproject.toml, src/backend/base/pyproject.toml, src/lfx/pyproject.toml
Added murf>=2.1.0 to dev/runtime dependency lists.
Frontend Constants
src/frontend/src/constants/constants.ts
Added "Murf" to BUNDLES_SIDEBAR_FOLDER_NAMES.
Frontend Icons
src/frontend/src/icons/Murf/MurfSVG.jsx, src/frontend/src/icons/Murf/index.tsx
New Murf SVG component and forwardRef-wrapped MurfIcon export.
Icon Mappings
src/frontend/src/icons/eagerIconImports.ts, src/frontend/src/icons/lazyIconImports.ts
Registered MurfIcon in eager and lazy icon import mappings.
Frontend Bundle Configuration
src/frontend/src/utils/styleUtils.ts
Added Murf entry to SIDEBAR_BUNDLES and nodeIconToDisplayIconMap.
Backend Component
src/lfx/src/lfx/components/Murf/__init__.py, src/lfx/src/lfx/components/Murf/text_to_speech.py
New MurfTextToSpeech component with lazy import support, dynamic voice/locale fetching, build_config update methods, and generate_speech runtime logic.
Component Exports
src/lfx/src/lfx/components/__init__.py
Exported Murf in public __all__ and dynamic import map.
Tests
src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
Comprehensive unit tests for initialization, build_config updates, voice-list parsing, and generate_speech behavior (success/error cases).
Secrets Metadata
.secrets.baseline
Updated line_number entries and generated_at timestamp (metadata-only changes).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Frontend UI
    participant Component as MurfTextToSpeech
    participant MurfAPI as Murf API

    User->>UI: Open Murf TTS node / provide API key
    UI->>Component: initialize_voice_list_data()
    Component->>MurfAPI: GET voices/list
    MurfAPI-->>Component: voices with locales
    Component->>UI: populate locale/voice options

    User->>UI: Submit text + options
    UI->>Component: generate_speech()
    Component->>MurfAPI: POST TTS request (voice, locale, params)
    alt Success
        MurfAPI-->>Component: audio URL / data
        Component-->>UI: Data(response=audio metadata)
    else Error
        MurfAPI-->>Component: error
        Component-->>UI: Data(error details)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Areas to review closely:
    • MurfTextToSpeech.generate_speech — API request/response handling and error paths
    • Dynamic build_config methods in text_to_speech.py — correctness of option population and field interdependencies
    • Lazy-loading behavior in Murf/__init__.py__getattr__, __dir__, and import error messages
    • Unit tests — ensure mocks accurately reflect Murf client behavior and cover edge cases

Possibly related PRs

Suggested labels

enhancement, size:L, lgtm

Suggested reviewers

  • ogabrielluiz
  • edwinjosechittilappilly
  • Cristhianzl

Pre-merge checks and finishing touches

❌ Failed checks (1 error, 1 warning)
Check name Status Explanation Resolution
Test Coverage For New Implementations ❌ Error The PR includes comprehensive backend unit tests for the new MurfTextToSpeech component at src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py, following Langflow's naming conventions with test class TestMurfTextToSpeechComponent using snake_case file naming test_murf_text_to_speech_component.py. The test file includes fixtures for component_class and default_kwargs as required by Langflow's component testing base classes, and covers extensive functionality including component initialization, display properties, speech generation with various scenarios, voice data handling, and dynamic build-config updates with error handling. However, the PR does not include frontend unit tests for the new React icon components (MurfSVG.jsx and MurfIcon) that were added to src/frontend/src/icons/Murf/. While frontend tests typically use .test.ts or .test.tsx suffixes and icon React components are commonly created in TypeScript, no corresponding test files exist for these visual components to verify their rendering and behavior. To address this gap, frontend unit tests should be added for the Murf icon components at src/frontend/src/icons/Murf/MurfIcon.test.tsx (or similar) to verify that the MurfIcon component correctly wraps MurfSVG, properly forwards refs, and renders the SVG with expected props. Additionally, tests for MurfSVG.jsx should verify that the SVG renders correctly with different isDark prop values and that gradient/clip-path definitions are present. These frontend tests would follow the project's testing conventions and ensure the icon components function as expected in the UI layer alongside the comprehensive backend component testing already included.
Test File Naming And Structure ⚠️ Warning The backend test file test_murf_text_to_speech_component.py properly adheres to pytest naming and structural conventions with the test_ prefix, is organized in the appropriate directory structure (src/backend/tests/unit/components/bundles/murf/), extends a proper test base class, uses pytest fixtures correctly, and includes 35 comprehensive test methods with descriptive names that cover positive scenarios (successful generation, voice list initialization), negative scenarios (API errors, missing keys, exception handling), and edge cases (empty data, malformed data). The test methods follow the Arrange-Act-Assert pattern appropriate for unit testing. However, the PR introduces new frontend React components (MurfSVG.jsx, MurfIcon, icon mappings in eagerIconImports and lazyIconImports) but includes no corresponding frontend tests using Jest/React Testing Library with .test.tsx or .spec.tsx naming conventions, which are the standard patterns for React component testing as evidenced by industry practices. To meet the full check requirements, add frontend unit tests for the Murf icon components using Jest and React Testing Library with .spec.tsx file extension in an appropriate tests directory. Test files should verify component rendering with and without the isDark prop, SVG structure, ref forwarding for MurfIcon, proper exports, and integration with eagerIconImports and lazyIconImports mappings. These tests should follow the same organizational pattern and naming conventions as other frontend tests in the codebase.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "Feat: Add Murf TextToSpeech Support" is directly and fully related to the main objective of the changeset. The primary change is the addition of a new MurfTextToSpeech component with associated frontend UI support, documentation, dependencies, and comprehensive tests. The title accurately captures this core objective with specific, meaningful terminology ("Murf" and "TextToSpeech") rather than vague or generic phrasing. A teammate scanning the repository history would immediately understand that this PR introduces a new Murf text-to-speech integration without requiring additional context.
Docstring Coverage ✅ Passed Docstring coverage is 94.12% which is sufficient. The required threshold is 80.00%.
Test Quality And Coverage ✅ Passed The Murf TextToSpeech component has a comprehensive test suite with 35 well-structured tests covering the main functionality. Tests validate successful speech generation with proper Data object returns and API client instantiation; error handling for missing API keys, API failures, and malformed data; and complex dynamic field update logic for locale, voice_id, and multi-native locale dropdowns. The test suite includes 83 meaningful assertions that verify data structures, API call parameters, and error messages rather than just checking that methods don't crash. Tests follow pytest best practices with proper fixtures, MagicMock usage, patch.dict for module mocking, and a reusable _mock_murf_client() helper method. Edge cases are covered including empty voice lists, malformed data, and various exception types (KeyError, AttributeError, ValueError, RuntimeError). However, logging calls within error handlers are not explicitly tested, and test parameterization could reduce code duplication in some scenarios.
Excessive Mock Usage Warning ✅ Passed The test suite demonstrates excellent mock design and minimal excessive mock usage. Analysis shows 31 focused test methods using just 5 MagicMock instances total, with all mocking centralized through a single _mock_murf_client() helper method called 29 times (0.94 per test). The 57 patch_context usages represent standard context manager overhead, not excessive mocking. The 6 fixtures are appropriately structured (component_class, default_kwargs, dummy_voice_list, mock_voice_objects, mock_voice_dict, file_names_mapping) and reused across tests to avoid duplication. Only one patch.dict() call handles sys.modules patching within the helper, isolating external Murf SDK dependencies. Internal component logic—voice list parsing, build configuration updates, parameter mapping, error handling—is tested directly without mocks. Each test verifies specific behavior with focused assertions, testing real interactions and transformations rather than just mock behavior. The design isolates external API concerns from unit test logic effectively.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5427cf and 640178a.

⛔ Files ignored due to path filters (2)
  • src/frontend/src/icons/Murf/Murf-logo.svg is excluded by !**/*.svg
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (16)
  • .secrets.baseline (2 hunks)
  • docs/docs/Components/bundles-murf.mdx (1 hunks)
  • docs/sidebars.js (2 hunks)
  • pyproject.toml (1 hunks)
  • src/backend/base/pyproject.toml (1 hunks)
  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py (1 hunks)
  • src/frontend/src/constants/constants.ts (1 hunks)
  • src/frontend/src/icons/Murf/MurfSVG.jsx (1 hunks)
  • src/frontend/src/icons/Murf/index.tsx (1 hunks)
  • src/frontend/src/icons/eagerIconImports.ts (2 hunks)
  • src/frontend/src/icons/lazyIconImports.ts (1 hunks)
  • src/frontend/src/utils/styleUtils.ts (2 hunks)
  • src/lfx/pyproject.toml (1 hunks)
  • src/lfx/src/lfx/components/Murf/__init__.py (1 hunks)
  • src/lfx/src/lfx/components/Murf/text_to_speech.py (1 hunks)
  • src/lfx/src/lfx/components/__init__.py (3 hunks)
✅ Files skipped from review due to trivial changes (1)
  • pyproject.toml
🚧 Files skipped from review as they are similar to previous changes (10)
  • src/backend/base/pyproject.toml
  • src/frontend/src/icons/lazyIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/eagerIconImports.ts
  • src/lfx/src/lfx/components/Murf/init.py
  • src/lfx/src/lfx/components/init.py
  • src/frontend/src/icons/Murf/MurfSVG.jsx
  • src/frontend/src/constants/constants.ts
  • src/frontend/src/utils/styleUtils.ts
  • docs/sidebars.js
🧰 Additional context used
📓 Path-based instructions (10)
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/docs_development.mdc)

docs/**/*.{md,mdx}: All Markdown/MDX pages must start with front matter including at least title and description; include sidebar_position for docs pages when applicable
Code blocks must specify a language and may include a title (```lang title="…")
Use sentence case for headings and keep paragraphs short and scannable
Write in second person, present tense, with a professional but approachable tone
Use inline code with backticks for code terms; use bold for UI elements and italics for emphasis; keep lists in parallel structure
Ensure internal links are functional and navigation works (update cross-references as needed)
Verify all code examples in docs and blog actually run as shown
Use correct terminology capitalization: Langflow, Component, Flow, API, JSON
Reference images with absolute paths under /img/... and provide descriptive alt text

Files:

  • docs/docs/Components/bundles-murf.mdx
docs/docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/docs_development.mdc)

Use Docusaurus admonitions (:::+tip|warning|danger) instead of custom callouts in docs pages

Files:

  • docs/docs/Components/bundles-murf.mdx
src/backend/tests/unit/components/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

src/backend/tests/unit/components/**/*.py: Mirror the component directory structure for unit tests in src/backend/tests/unit/components/
Use ComponentTestBaseWithClient or ComponentTestBaseWithoutClient as base classes for component unit tests
Provide file_names_mapping for backward compatibility in component tests
Create comprehensive unit tests for all new components

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
{src/backend/**/*.py,tests/**/*.py,Makefile}

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

{src/backend/**/*.py,tests/**/*.py,Makefile}: Run make format_backend to format Python code before linting or committing changes
Run make lint to perform linting checks on backend Python code

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
src/backend/tests/unit/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/backend_development.mdc)

Test component integration within flows using create_flow, build_flow, and get_build_events utilities

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
src/backend/tests/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/testing.mdc)

src/backend/tests/**/*.py: Unit tests for backend code must be located in the 'src/backend/tests/' directory, with component tests organized by component subdirectory under 'src/backend/tests/unit/components/'.
Test files should use the same filename as the component under test, with an appropriate test prefix or suffix (e.g., 'my_component.py' → 'test_my_component.py').
Use the 'client' fixture (an async httpx.AsyncClient) for API tests in backend Python tests, as defined in 'src/backend/tests/conftest.py'.
When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.
Each test in backend Python test files should have a clear docstring explaining its purpose, and complex setups or mocks should be well-commented.
Test both sync and async code paths in backend Python tests, using '@pytest.mark.asyncio' for async tests.
Mock external dependencies appropriately in backend Python tests to isolate unit tests from external services.
Test error handling and edge cases in backend Python tests, including using 'pytest.raises' and asserting error messages.
Validate input/output behavior and test component initialization and configuration in backend Python tests.
Use the 'no_blockbuster' pytest marker to skip the blockbuster plugin in tests when necessary.
Be aware of ContextVar propagation in async tests; test both direct event loop execution and 'asyncio.to_thread' scenarios to ensure proper context isolation.
Test error handling by mocking internal functions using monkeypatch in backend Python tests.
Test resource cleanup in backend Python tests by using fixtures that ensure proper initialization and cleanup of resources.
Test timeout and performance constraints in backend Python tests using 'asyncio.wait_for' and timing assertions.
Test Langflow's Messag...

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
src/backend/**/*component*.py

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

In your Python component class, set the icon attribute to a string matching the frontend icon mapping exactly (case-sensitive).

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
src/backend/**/components/**/*.py

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

In your Python component class, set the icon attribute to a string matching the frontend icon mapping exactly (case-sensitive).

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
**/{test_*.py,*.test.ts,*.test.tsx}

📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)

**/{test_*.py,*.test.ts,*.test.tsx}: Check if tests have too many mock objects that obscure what’s actually being tested
Warn when mocks are used instead of testing real behavior and interactions
Suggest using real objects or simpler test doubles when mocks become excessive
Ensure mocks are used only for external dependencies, not core business logic
Recommend integration tests when unit tests become overly mocked
Check that test files follow the project’s naming conventions (backend: test_*.py; frontend: *.test.ts/tsx)
Verify that tests actually exercise the new or changed functionality, not placeholder assertions
Test files should have descriptive test function names explaining what is being tested
Organize tests logically with proper setup and teardown
Include edge cases and error conditions for comprehensive coverage
Verify tests cover both positive (success) and negative (failure) scenarios
Ensure tests are not mere smoke tests; they should validate behavior thoroughly
Ensure tests follow the project’s testing frameworks (pytest for backend, Playwright for frontend)

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
**/test_*.py

📄 CodeRabbit inference engine (coderabbit-custom-pre-merge-checks-unique-id-file-non-traceable-F7F2B60C-1728-4C9A-8889-4F2235E186CA.txt)

**/test_*.py: Backend tests must be named test_*.py and use proper pytest structure (fixtures, assertions)
For async backend code, use proper pytest async patterns (e.g., pytest-asyncio)
For API endpoints, include tests for both success and error responses

Files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
🧠 Learnings (11)
📚 Learning: 2025-09-07T05:44:46.715Z
Learnt from: TensorNull
Repo: langflow-ai/langflow PR: 9735
File: docs/docs/Components/bundles-cometapi.mdx:9-9
Timestamp: 2025-09-07T05:44:46.715Z
Learning: In Langflow bundle documentation files (docs/docs/Components/bundles-*.mdx), the standard link pattern for referencing the main Bundles page is [Bundles](/components-bundle-components), not /components-bundles. This pattern is used consistently across all 37+ bundle documentation files.

Applied to files:

  • docs/docs/Components/bundles-murf.mdx
📚 Learning: 2025-07-18T18:25:54.486Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.486Z
Learning: Applies to src/backend/tests/unit/components/**/*.py : Create comprehensive unit tests for all new components

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Test component configuration updates in backend Python tests by asserting correct updates to build configuration objects.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.md : Create comprehensive unit tests for all new components. If unit tests are incomplete, create a Markdown file with manual testing steps in the same directory as the unit tests, using the same filename as the component but with a '.md' extension.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-18T18:25:54.486Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.486Z
Learning: Applies to src/backend/tests/unit/components/**/*.py : Mirror the component directory structure for unit tests in src/backend/tests/unit/components/

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : When writing component tests, inherit from the appropriate base class in 'src/backend/tests/base.py' (ComponentTestBase, ComponentTestBaseWithClient, or ComponentTestBaseWithoutClient) and provide the required fixtures: 'component_class', 'default_kwargs', and 'file_names_mapping'.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-08-05T22:51:27.961Z
Learnt from: edwinjosechittilappilly
Repo: langflow-ai/langflow PR: 0
File: :0-0
Timestamp: 2025-08-05T22:51:27.961Z
Learning: The TestComposioComponentAuth test in src/backend/tests/unit/components/bundles/composio/test_base_composio.py demonstrates proper integration testing patterns for external API components, including real API calls with mocking for OAuth completion, comprehensive resource cleanup, and proper environment variable handling with pytest.skip() fallbacks.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Test backward compatibility across Langflow versions in backend Python tests by mapping component files to supported versions using 'VersionComponentMapping'.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Validate input/output behavior and test component initialization and configuration in backend Python tests.

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-18T18:25:54.487Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.487Z
Learning: Applies to src/backend/tests/unit/**/*.py : Test component integration within flows using create_flow, build_flow, and get_build_events utilities

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
📚 Learning: 2025-07-21T14:16:14.125Z
Learnt from: CR
Repo: langflow-ai/langflow PR: 0
File: .cursor/rules/testing.mdc:0-0
Timestamp: 2025-07-21T14:16:14.125Z
Learning: Applies to src/backend/tests/**/*.py : Test files should use the same filename as the component under test, with an appropriate test prefix or suffix (e.g., 'my_component.py' → 'test_my_component.py').

Applied to files:

  • src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py
🪛 Gitleaks (8.28.0)
.secrets.baseline

[high] 1296-1296: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 1304-1304: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
docs/docs/Components/bundles-murf.mdx

[grammar] ~35-~35: Use a hyphen to join words.
Context: ..., and other audio formats ### Murf Text to Speech Parameters You can inspect th...

(QB_NEW_EN_HYPHEN)


[grammar] ~35-~35: Use a hyphen to join words.
Context: ...nd other audio formats ### Murf Text to Speech Parameters You can inspect the c...

(QB_NEW_EN_HYPHEN)

🔇 Additional comments (21)
src/lfx/pyproject.toml (1)

42-42: LGTM!

The Murf dependency addition is correct and aligns with the new MurfTextToSpeech component implementation.

.secrets.baseline (1)

1290-1306: LGTM!

The line number updates in the secrets baseline reflect the addition of new code to src/frontend/src/constants/constants.ts. These are expected automated tool updates.

docs/docs/Components/bundles-murf.mdx (1)

1-88: LGTM!

The documentation is comprehensive and well-structured. It follows Langflow's standard bundle documentation patterns, includes proper setup instructions, detailed parameter tables, usage examples, and troubleshooting guidance. The link pattern on line 10 correctly uses /components-bundle-components as per the established convention.

Note: The static analysis suggestion to hyphenate "Text to Speech" can be safely ignored—this is the correct product terminology.

Based on learnings

src/lfx/src/lfx/components/Murf/text_to_speech.py (8)

9-102: LGTM!

The component definition is well-structured with appropriate input types, proper field configuration for dynamic updates, and correct icon mapping. The documentation URL provides helpful reference to the Murf API.


104-135: LGTM!

The API key validation has been correctly moved before client initialization, and the method now consistently returns Data objects for both success and error cases. The conditional handling of multi_native_locale is appropriate.


137-166: LGTM!

The method now consistently returns a dictionary in both success and error cases, resolving the previous return type inconsistency. The error handling appropriately catches the relevant exception types.


168-192: LGTM!

The method properly handles dictionary access with safe .get() calls and correctly manages both the presence and absence of voice data.


194-236: LGTM!

The method now includes comprehensive safety checks for dictionary access. The use of .get() with defaults, early returns for missing data, and validation of non-empty options before calling next(iter(...)) properly guard against runtime errors.


238-280: LGTM!

The critical type checking bug has been fixed (now using isinstance(locale, dict) on line 271), and comprehensive error handling with try-except wraps the nested dictionary access. The method safely handles missing or malformed voice data.


282-299: LGTM!

The method efficiently initializes voice data only when needed (API key present and no existing voices) and properly delegates to the locale update method.


301-332: LGTM!

The method properly handles field-specific updates with appropriate cascading updates to dependent fields. The conditional logic correctly manages the interdependencies between api_key, locale, and voice_id fields.

src/backend/tests/unit/components/bundles/murf/test_murf_text_to_speech_component.py (10)

1-106: LGTM!

The test class properly inherits from ComponentTestBaseWithoutClient and provides all required fixtures. The test data fixtures are comprehensive and well-organized, providing realistic mock data for voice lists and API responses.

As per coding guidelines


107-166: LGTM!

The helper method provides an excellent abstraction for mocking the Murf client. The conversion of dictionary responses to objects with __dict__ attributes accurately simulates the real API behavior, making tests more realistic.


169-257: LGTM!

The tests comprehensively cover component initialization, display properties, and all paths through the generate_speech method including success, missing API key, API errors, and parameter handling. The assertions properly verify both return values and mock call arguments.


260-320: LGTM!

The tests thoroughly cover the initialize_voice_list_data method, including successful voice list parsing and proper error handling for KeyError, AttributeError, and ValueError. The assertions verify both the data structure and error message formatting.


324-436: LGTM!

The tests comprehensively verify the build config update methods for locale and voice_id, covering success cases with proper data, missing data scenarios, invalid inputs, and empty data. The assertions properly check the show flag toggling and option population.


440-522: LGTM!

The tests thoroughly cover the _update_build_config_multi_native_locale method, including successful option population and proper handling of missing voices, invalid voice IDs, and voices without supported locales.


526-568: LGTM!

The tests properly verify the build_config method's conditional initialization logic, ensuring voice data is fetched only when needed (API key present and no existing voices) and that existing voice data isn't unnecessarily re-initialized.


572-631: LGTM!

The tests thoroughly verify the update_build_config method's handling of API key and locale field changes, including both populated and empty values. The assertions properly check cascading updates to dependent fields.


632-701: LGTM!

The tests comprehensively cover voice_id field updates (including multiple test cases with different voices), empty field values, unknown fields, and missing field names. The edge case handling is properly verified.


705-761: LGTM!

The additional edge case tests provide excellent coverage of error scenarios (empty voice list, malformed data) and verify that all component parameters are correctly passed to the API, including proper case transformations (e.g., "Stereo" → "stereo").


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

Comment @coderabbitai help to get the list of available commands and usage tips.

@autofix-ci
Copy link
Contributor

autofix-ci bot commented Oct 30, 2025

Hi! I'm autofix logoautofix.ci, a bot that automatically fixes trivial issues such as code formatting in pull requests.

I would like to apply some automated changes to this pull request, but it looks like I don't have the necessary permissions to do so. To get this pull request into a mergeable state, please do one of the following two things:

  1. Allow edits by maintainers for your pull request, and then re-trigger CI (for example by pushing a new commit).
  2. Manually fix the issues identified for your pull request (see the GitHub Actions output for details on what I would like to change).

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: 5

🧹 Nitpick comments (3)
src/lfx/pyproject.toml (1)

42-42: Consider alphabetical ordering for consistency.

The murf>=2.1.0 dependency should appear before validators>=0.34.0,<1.0.0 (line 41) to maintain alphabetical order, which is a common practice in dependency lists.

Apply this diff to reorder:

     "langchain~=0.3.23",
-    "validators>=0.34.0,<1.0.0",
-    "murf>=2.1.0"
+    "murf>=2.1.0",
+    "validators>=0.34.0,<1.0.0"
docs/docs/Components/bundles-murf.mdx (1)

24-24: Consider hyphenating "Text-to-Speech" for consistency.

The component name "Text to Speech" should be "Text-to-Speech" to match:

  • Murf's official branding
  • Standard terminology in the industry
  • Static analysis recommendations

This applies to lines 24, 35, and throughout the document where the component name appears.

src/lfx/src/lfx/components/Murf/text_to_speech.py (1)

228-245: Add type safety and simplify dict length check.

  1. Line 229: Assumes field_value is always a string without validation. If a non-string type is passed, len(field_value) will raise TypeError.

  2. Line 231: Using len(voices.keys()) is unnecessary when len(voices) achieves the same result more efficiently.

Apply this diff:

 def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict:
-    if field_name == "api_key" and len(field_value) > 0:
+    if field_name == "api_key" and field_value:
         voices = build_config.get("murf_voice_list")
-        if voices is None or len(voices.keys()) == 0:
+        if not voices:
             voices = self.initialize_voice_list_data()
             build_config["murf_voice_list"] = voices
         build_config = self._update_build_config_locale(build_config)
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d16a2e and f5427cf.

⛔ Files ignored due to path filters (2)
  • src/frontend/src/icons/Murf/Murf-logo.svg is excluded by !**/*.svg
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (15)
  • .secrets.baseline (2 hunks)
  • docs/docs/Components/bundles-murf.mdx (1 hunks)
  • docs/sidebars.js (2 hunks)
  • pyproject.toml (1 hunks)
  • src/backend/base/pyproject.toml (1 hunks)
  • src/frontend/src/constants/constants.ts (1 hunks)
  • src/frontend/src/icons/Murf/MurfSVG.jsx (1 hunks)
  • src/frontend/src/icons/Murf/index.tsx (1 hunks)
  • src/frontend/src/icons/eagerIconImports.ts (2 hunks)
  • src/frontend/src/icons/lazyIconImports.ts (1 hunks)
  • src/frontend/src/utils/styleUtils.ts (2 hunks)
  • src/lfx/pyproject.toml (1 hunks)
  • src/lfx/src/lfx/components/Murf/__init__.py (1 hunks)
  • src/lfx/src/lfx/components/Murf/text_to_speech.py (1 hunks)
  • src/lfx/src/lfx/components/__init__.py (3 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
src/frontend/src/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)

src/frontend/src/**/*.{ts,tsx,js,jsx}: All frontend TypeScript and JavaScript code should be located under src/frontend/src/ and organized into components, pages, icons, stores, types, utils, hooks, services, and assets directories as per the specified directory layout.
Use React 18 with TypeScript for all UI components in the frontend.
Format all TypeScript and JavaScript code using the make format_frontend command.
Lint all TypeScript and JavaScript code using the make lint command.

Files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/utils/styleUtils.ts
  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/Murf/MurfSVG.jsx
  • src/frontend/src/constants/constants.ts
  • src/frontend/src/icons/lazyIconImports.ts
src/frontend/src/icons/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)

Use Lucide React for icons in the frontend.

Files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/Murf/MurfSVG.jsx
  • src/frontend/src/icons/lazyIconImports.ts
src/frontend/src/utils/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/frontend_development.mdc)

All utility functions should be placed in the utils directory.

Files:

  • src/frontend/src/utils/styleUtils.ts
docs/sidebars.js

📄 CodeRabbit inference engine (.cursor/rules/docs_development.mdc)

Keep sidebars.js updated to include new/changed docs sections and items using Docusaurus category structure

Files:

  • docs/sidebars.js
src/frontend/src/icons/*/*.@(js|jsx|ts|tsx)

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

Create a new directory for your icon in src/frontend/src/icons/YourIconName/ and add your SVG as a React component (e.g., YourIconName.jsx). The SVG component must use the isDark prop to support both light and dark mode.

Files:

  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/Murf/MurfSVG.jsx
src/frontend/src/icons/*/index.tsx

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

Create an index.tsx in your icon directory that exports your icon using forwardRef and passes the isDark prop.

Files:

  • src/frontend/src/icons/Murf/index.tsx
docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/docs_development.mdc)

docs/**/*.{md,mdx}: All Markdown/MDX pages must start with front matter including at least title and description; include sidebar_position for docs pages when applicable
Code blocks must specify a language and may include a title (```lang title="…")
Use sentence case for headings and keep paragraphs short and scannable
Write in second person, present tense, with a professional but approachable tone
Use inline code with backticks for code terms; use bold for UI elements and italics for emphasis; keep lists in parallel structure
Ensure internal links are functional and navigation works (update cross-references as needed)
Verify all code examples in docs and blog actually run as shown
Use correct terminology capitalization: Langflow, Component, Flow, API, JSON
Reference images with absolute paths under /img/... and provide descriptive alt text

Files:

  • docs/docs/Components/bundles-murf.mdx
docs/docs/**/*.{md,mdx}

📄 CodeRabbit inference engine (.cursor/rules/docs_development.mdc)

Use Docusaurus admonitions (:::+tip|warning|danger) instead of custom callouts in docs pages

Files:

  • docs/docs/Components/bundles-murf.mdx
src/frontend/src/icons/lazyIconImports.ts

📄 CodeRabbit inference engine (.cursor/rules/icons.mdc)

Add your icon to the lazyIconsMapping object in src/frontend/src/icons/lazyIconImports.ts with a key that matches the backend icon string exactly.

Files:

  • src/frontend/src/icons/lazyIconImports.ts
🧠 Learnings (14)
📚 Learning: 2025-07-28T15:56:47.865Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-07-28T15:56:47.865Z
Learning: Applies to src/frontend/src/icons/lazyIconImports.ts : Add your icon to the `lazyIconsMapping` object in `src/frontend/src/icons/lazyIconImports.ts` with a key that matches the backend icon string exactly.

Applied to files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/lazyIconImports.ts
📚 Learning: 2025-07-18T18:27:12.609Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/frontend_development.mdc:0-0
Timestamp: 2025-07-18T18:27:12.609Z
Learning: Applies to src/frontend/src/icons/**/*.{ts,tsx,js,jsx} : Use Lucide React for icons in the frontend.

Applied to files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
📚 Learning: 2025-07-28T15:56:47.865Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-07-28T15:56:47.865Z
Learning: Applies to src/frontend/src/icons/*/index.tsx : Create an `index.tsx` in your icon directory that exports your icon using `forwardRef` and passes the `isDark` prop.

Applied to files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
📚 Learning: 2025-07-28T15:56:47.865Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-07-28T15:56:47.865Z
Learning: Applies to src/frontend/src/icons/*/*.@(js|jsx|ts|tsx) : Create a new directory for your icon in `src/frontend/src/icons/YourIconName/` and add your SVG as a React component (e.g., `YourIconName.jsx`). The SVG component must use the `isDark` prop to support both light and dark mode.

Applied to files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/Murf/MurfSVG.jsx
📚 Learning: 2025-07-28T15:56:47.865Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-07-28T15:56:47.865Z
Learning: Always use clear, recognizable, and consistent icon names for both backend and frontend (e.g., "AstraDB", "Postgres", "OpenAI").

Applied to files:

  • src/frontend/src/icons/eagerIconImports.ts
  • src/frontend/src/utils/styleUtils.ts
📚 Learning: 2025-09-30T00:09:51.631Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/docs_development.mdc:0-0
Timestamp: 2025-09-30T00:09:51.631Z
Learning: Applies to docs/sidebars.js : Keep sidebars.js updated to include new/changed docs sections and items using Docusaurus category structure

Applied to files:

  • docs/sidebars.js
📚 Learning: 2025-09-07T05:44:46.715Z
Learnt from: TensorNull
PR: langflow-ai/langflow#9735
File: docs/docs/Components/bundles-cometapi.mdx:9-9
Timestamp: 2025-09-07T05:44:46.715Z
Learning: In Langflow bundle documentation files (docs/docs/Components/bundles-*.mdx), the standard link pattern for referencing the main Bundles page is [Bundles](/components-bundle-components), not /components-bundles. This pattern is used consistently across all 37+ bundle documentation files.

Applied to files:

  • docs/sidebars.js
  • docs/docs/Components/bundles-murf.mdx
📚 Learning: 2025-09-30T00:09:51.631Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/docs_development.mdc:0-0
Timestamp: 2025-09-30T00:09:51.631Z
Learning: Applies to docs/**/*.{md,mdx} : Use correct terminology capitalization: Langflow, Component, Flow, API, JSON

Applied to files:

  • docs/sidebars.js
📚 Learning: 2025-06-23T12:46:52.420Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-06-23T12:46:52.420Z
Learning: Export custom icon components in React using React.forwardRef to ensure proper ref forwarding and compatibility with parent components.

Applied to files:

  • src/frontend/src/icons/Murf/index.tsx
📚 Learning: 2025-06-16T11:14:04.200Z
Learnt from: dolfim-ibm
PR: langflow-ai/langflow#8394
File: src/frontend/src/icons/Docling/index.tsx:4-6
Timestamp: 2025-06-16T11:14:04.200Z
Learning: The Langflow codebase consistently uses `React.PropsWithChildren<{}>` as the prop type for all icon components using forwardRef, rather than `React.SVGProps<SVGSVGElement>`. This is an established pattern across hundreds of icon files in src/frontend/src/icons/.

Applied to files:

  • src/frontend/src/icons/Murf/index.tsx
  • src/frontend/src/icons/Murf/MurfSVG.jsx
📚 Learning: 2025-06-23T12:46:52.420Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-06-23T12:46:52.420Z
Learning: When implementing a new component icon in Langflow, ensure the icon name is clear, recognizable, and used consistently across both backend (Python 'icon' attribute) and frontend (React/TypeScript mapping).

Applied to files:

  • src/frontend/src/icons/Murf/index.tsx
📚 Learning: 2025-06-23T12:46:52.420Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/icons.mdc:0-0
Timestamp: 2025-06-23T12:46:52.420Z
Learning: Custom SVG icon components in React should always support both light and dark mode by accepting an 'isdark' prop and adjusting colors accordingly.

Applied to files:

  • src/frontend/src/icons/Murf/index.tsx
📚 Learning: 2025-07-18T18:27:12.609Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/frontend_development.mdc:0-0
Timestamp: 2025-07-18T18:27:12.609Z
Learning: Applies to src/frontend/src/components/**/@(FlowGraph|nodes)/**/*.{ts,tsx,js,jsx} : Use React Flow for flow graph visualization components.

Applied to files:

  • src/frontend/src/icons/Murf/MurfSVG.jsx
📚 Learning: 2025-07-18T18:25:54.486Z
Learnt from: CR
PR: langflow-ai/langflow#0
File: .cursor/rules/backend_development.mdc:0-0
Timestamp: 2025-07-18T18:25:54.486Z
Learning: Applies to src/backend/base/langflow/components/**/__init__.py : Update __init__.py with alphabetical imports when adding new components

Applied to files:

  • src/lfx/src/lfx/components/__init__.py
🧬 Code graph analysis (4)
src/frontend/src/icons/eagerIconImports.ts (1)
src/frontend/src/icons/Murf/index.tsx (1)
  • MurfIcon (4-8)
src/lfx/src/lfx/components/Murf/text_to_speech.py (3)
src/lfx/src/lfx/schema/data.py (1)
  • Data (26-288)
src/lfx/src/lfx/schema/message.py (1)
  • Message (34-299)
src/lfx/src/lfx/custom/custom_component/component.py (1)
  • log (1480-1497)
src/lfx/src/lfx/components/Murf/__init__.py (1)
src/lfx/src/lfx/components/Murf/text_to_speech.py (1)
  • MurfTextToSpeech (10-245)
src/frontend/src/icons/Murf/index.tsx (1)
src/frontend/src/icons/Murf/MurfSVG.jsx (1)
  • MurfSVG (1-150)
🪛 Gitleaks (8.28.0)
.secrets.baseline

[high] 1296-1296: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)


[high] 1304-1304: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🪛 LanguageTool
docs/docs/Components/bundles-murf.mdx

[grammar] ~35-~35: Use a hyphen to join words.
Context: ..., and other audio formats ### Murf Text to Speech Parameters You can inspect th...

(QB_NEW_EN_HYPHEN)


[grammar] ~35-~35: Use a hyphen to join words.
Context: ...nd other audio formats ### Murf Text to Speech Parameters You can inspect the c...

(QB_NEW_EN_HYPHEN)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (18)
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 7/13
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 3/13
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 8/13
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 11/13
  • GitHub Check: Run Frontend Tests / Playwright Tests - Shard 1/13
  • GitHub Check: Lint Backend / Run Mypy (3.12)
  • GitHub Check: Lint Backend / Run Mypy (3.10)
  • GitHub Check: Test Docker Images / Test docker images
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 2
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 1
  • GitHub Check: Test Docs Build / Test Docs Build
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 5
  • GitHub Check: Lint Backend / Run Mypy (3.11)
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 3
  • GitHub Check: Run Backend Tests / Unit Tests - Python 3.10 - Group 4
  • GitHub Check: Run Backend Tests / Integration Tests - Python 3.10
  • GitHub Check: Run Frontend Unit Tests / Frontend Jest Unit Tests
  • GitHub Check: Test Starter Templates
🔇 Additional comments (19)
src/backend/base/pyproject.toml (1)

131-132: LGTM!

The Murf dependency is correctly added to the dev dependencies with an appropriate version constraint.

.secrets.baseline (1)

1290-1307: LGTM! Expected metadata update.

The line number adjustments and timestamp update are expected when new code is added to the repository. These changes reflect the secrets baseline being regenerated after adding the Murf integration.

Also applies to: 1405-1405

docs/sidebars.js (2)

170-170: LGTM! Formatting improvement.

The added space after the colon improves consistency with JavaScript/JSON formatting conventions.


329-329: LGTM!

The Murf bundle entry is correctly positioned alphabetically between MongoDB and Notion, following the established pattern for bundle documentation. Based on learnings

pyproject.toml (1)

191-191: LGTM!

The Murf dependency is correctly added to the dev dependencies with an appropriate version constraint.

src/frontend/src/utils/styleUtils.ts (2)

303-303: LGTM!

The Murf bundle entry is correctly added with consistent naming and proper alphabetical positioning. The naming follows the pattern for clear, recognizable icon names. Based on learnings


461-461: LGTM!

The icon mapping is correctly added and maintains alphabetical order in the nodeIconToDisplayIconMap.

src/lfx/src/lfx/components/__init__.py (3)

11-11: LGTM!

The Murf import is correctly added to the TYPE_CHECKING block with proper alphabetical ordering. Based on learnings


171-171: LGTM!

The Murf entry is correctly added to the dynamic imports mapping with proper alphabetical ordering and the appropriate "__module__" value for lazy loading.


245-245: LGTM!

The Murf export is correctly added to __all__ with proper alphabetical ordering, consistent with the TYPE_CHECKING and dynamic imports entries. Based on learnings

docs/docs/Components/bundles-murf.mdx (4)

1-4: LGTM!

The front matter includes the required title and slug fields, following Docusaurus conventions.


6-13: LGTM!

The imports and introduction follow the established patterns. The Bundles link correctly uses /components-bundle-components as per the standard pattern for bundle documentation. Based on learnings


14-23: LGTM!

The setup section provides clear instructions with appropriate links to official Murf documentation.


57-88: LGTM!

The outputs, usage examples, and troubleshooting sections are well-structured and provide practical guidance for users.

src/frontend/src/constants/constants.ts (1)

799-799: LGTM!

The addition of "Murf" to the bundle sidebar folder names is consistent with the existing pattern.

src/frontend/src/icons/lazyIconImports.ts (1)

290-290: LGTM!

The lazy icon import entry for Murf follows the established pattern and is correctly placed alphabetically.

src/frontend/src/icons/eagerIconImports.ts (1)

68-68: LGTM!

The import statement and eager icon mapping for Murf are correctly implemented and alphabetically ordered.

Also applies to: 189-189

src/frontend/src/icons/Murf/index.tsx (1)

1-8: LGTM!

The MurfIcon wrapper component correctly uses forwardRef with the established React.PropsWithChildren<{}> prop type pattern and properly forwards the ref and props to MurfSVG.

src/lfx/src/lfx/components/Murf/__init__.py (1)

1-32: LGTM!

The lazy loading implementation is well-structured with proper error handling, TYPE_CHECKING guards, and module caching. The __getattr__ and __dir__ implementations follow Python best practices.

Comment on lines 1 to 150
const MurfSVG = (props) => (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 256 256"
{...props}
>
<g clipPath="url(#clip0_338_416)">
<path
fill="url(#paint0_linear_338_416)"
d="M166.716 166.136c-32.005 37.493-75.573 58.871-113.04 68.844l-.04.014c-.938.244-1.867.489-2.791.72a30.4 30.4 0 0 1-6.231.644c-16.76 0-30.342-13.582-30.342-30.342V32.394c.004 38.55 8.226 97.604 29.39 128.577 5.552 8.125 11.863 14.965 18.703 20.445.009 0 .022.009.03.022.565.458 1.139.902 1.712 1.333 30.04 22.756 70.613 17.592 101.72-17.08z"
></path>
<path
fill="url(#paint1_radial_338_416)"
d="m166.366 165.78-.143.169-.022.026-.986 1.169c-10.374 11.276-21.916 19.587-33.974 24.631a44 44 0 0 1-.644.263c-8.667 3.457-17.609 5.24-26.596 5.24q-2.239 0-4.47-.147c-22.432-1.48-42.819-14.053-57.405-35.409-9.676-14.16-17.067-35.013-21.96-61.982-.09-.498-.183-.996-.271-1.494a349.946 349.946 0 0 1-1.453-8.973c-.094-.627-.183-1.249-.276-1.867a445 445 0 0 1-.778-5.777l-.307-2.498q-.075-.654-.155-1.307-.136-1.173-.262-2.333c0-.018-.005-.036-.005-.05q-.252-2.293-.471-4.532l-.027-.28-.186-1.96a410.493 410.493 0 0 1-.427-4.982c-.089-1.13-.169-2.24-.249-3.338-.009-.098-.013-.2-.022-.298q-.101-1.493-.196-2.938-.032-.567-.07-1.133-.058-.994-.116-1.97c.004-.008 0-.017 0-.026-.036-.64-.067-1.271-.103-1.898v-.124c-.049-.929-.088-1.84-.128-2.733a318 318 0 0 1-.107-2.632l-.014-.377q-.034-.921-.062-1.8l-.013-.387-.04-1.356c-.009-.284-.013-.569-.022-.844-.01-.276-.014-.547-.023-.813q.001-.12-.004-.24-.015-.58-.022-1.138c-.018-.885-.031-1.734-.045-2.556l-.013-1.302v-.213c0-.396-.009-.782-.009-1.16q-.002-.32-.004-.64-.006-.734-.005-1.414v-.444a7.584 7.584 0 0 1 12.37-5.853l1.097 1.097L166.37 165.78z"
></path>
<path fill="url(#paint2_radial_338_416)" d="M19.098 93.563"></path>
<path
fill="url(#paint3_linear_338_416)"
fillRule="evenodd"
d="M22.787 99.264c4.247 23.402 11.109 45.696 21.532 60.955 14.846 21.725 35.302 33.368 56.744 34.328 21.449.96 44.099-8.761 63.327-30.191l1.985 1.781c-19.66 21.912-43.044 32.076-65.431 31.074-22.393-1.003-43.575-13.168-58.827-35.488-10.741-15.724-17.685-38.46-21.954-61.982-4.275-23.554-5.892-48.043-5.892-67.384h2.667c0 19.212 1.608 43.538 5.849 66.907"
clipRule="evenodd"
></path>
<path
fill="url(#paint4_linear_338_416)"
d="M89.383 89.69c32.004-37.493 75.573-58.871 113.04-68.844l.04-.014c.938-.244 1.866-.489 2.791-.72a30.3 30.3 0 0 1 6.231-.644c16.76 0 30.342 13.582 30.342 30.342v173.622c-.004-38.551-8.226-97.604-29.391-128.577-5.551-8.125-11.862-14.965-18.702-20.445q-.015-.001-.031-.022a60 60 0 0 0-1.711-1.334c-30.04-22.755-70.614-17.59-101.72 17.08z"
></path>
<path
fill="url(#paint5_radial_338_416)"
d="m89.74 90.047.142-.17.023-.026.986-1.169c10.374-11.275 21.916-19.586 33.974-24.63.213-.09.431-.179.644-.263 8.667-3.458 17.609-5.24 26.596-5.24q2.238 0 4.471.147c22.431 1.48 42.818 14.053 57.404 35.408 9.676 14.16 17.067 35.014 21.96 61.983q.135.746.271 1.493.001.029.009.058.408 2.326.782 4.627.028.2.063.395.314 1.96.6 3.893.137.94.275 1.867.413 2.919.778 5.778l.307 2.498q.075.653.155 1.306.135 1.174.262 2.334c0 .017.005.035.005.049q.252 2.293.471 4.533l.027.28.186 1.96q.015.199.036.391.133 1.472.253 2.911.066.847.138 1.68c.089 1.129.169 2.24.249 3.338.009.098.013.2.022.298q.101 1.492.196 2.937.032.567.071 1.134c.04.662.075 1.32.115 1.969-.004.009 0 .017 0 .026.036.64.067 1.271.103 1.898v.125c.048.928.088 1.84.128 2.733a314 314 0 0 1 .12 3.009q.035.92.063 1.8l.013.386.04 1.356c.009.284.013.569.022.844q.012.414.022.814-.001.12.005.24.015.578.022 1.138.025 1.324.045 2.555l.013 1.302v.214c0 .395.009.782.009 1.16 0 .213.004.426.004.64q.006.733.005 1.413v.444a7.585 7.585 0 0 1-12.369 5.854l-1.098-1.098z"
></path>
<path fill="url(#paint6_radial_338_416)" d="M237.005 162.263"></path>
<path
fill="url(#paint7_linear_338_416)"
fillRule="evenodd"
d="M155.038 61.28c-21.448-.96-44.098 8.76-63.327 30.19l-1.984-1.78c19.66-21.912 43.043-32.076 65.43-31.074 22.393 1.003 43.575 13.168 58.827 35.488 10.744 15.721 17.688 38.458 21.956 61.981 4.274 23.554 5.89 48.044 5.89 67.384h-2.667c0-19.211-1.606-43.538-5.846-66.908-4.247-23.402-11.109-45.697-21.534-60.953l1.1-.752-1.1.752c-14.846-21.725-35.302-33.368-56.745-34.328"
clipRule="evenodd"
></path>
<path
fill="#fff"
d="M127.999 182.361c30.022 0 54.36-24.338 54.36-54.36 0-30.023-24.338-54.36-54.36-54.36-30.023 0-54.36 24.337-54.36 54.36 0 30.022 24.337 54.36 54.36 54.36"
></path>
</g>
<defs>
<radialGradient
id="paint1_radial_338_416"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(-152.007 0 0 -154.231 121.623 142.275)"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.28" stopColor="#DAABFF"></stop>
<stop offset="0.87" stopColor="#735DFF"></stop>
</radialGradient>
<radialGradient
id="paint2_radial_338_416"
cx="0"
cy="0"
r="1"
gradientTransform="translate(19.706 96.318)scale(3.13778)"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.3" stopColor="#DAABFF"></stop>
<stop offset="0.87" stopColor="#735DFF"></stop>
</radialGradient>
<radialGradient
id="paint5_radial_338_416"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(152.003 0 0 154.231 134.486 113.539)"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.22" stopColor="#FFD522"></stop>
<stop offset="0.27" stopColor="#FFCA27"></stop>
<stop offset="0.34" stopColor="#FFAC37"></stop>
<stop offset="0.45" stopColor="#FF7D50"></stop>
<stop offset="0.54" stopColor="#FF4B6C"></stop>
<stop offset="1" stopColor="#C81395"></stop>
</radialGradient>
<radialGradient
id="paint6_radial_338_416"
cx="0"
cy="0"
r="1"
gradientTransform="matrix(-3.13777 0 0 -3.13778 236.396 159.508)"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.3" stopColor="#DAABFF"></stop>
<stop offset="0.87" stopColor="#735DFF"></stop>
</radialGradient>
<linearGradient
id="paint0_linear_338_416"
x1="-29.273"
x2="123.447"
y1="103.961"
y2="187.663"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.42" stopColor="#C6B2FF"></stop>
<stop offset="0.84" stopColor="#735DFF"></stop>
</linearGradient>
<linearGradient
id="paint3_linear_338_416"
x1="63.123"
x2="112.042"
y1="19.004"
y2="197.948"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#fff" stopOpacity="0"></stop>
<stop offset="0.1" stopColor="#fff" stopOpacity="0.01"></stop>
<stop offset="0.3" stopColor="#fff" stopOpacity="0.073"></stop>
<stop offset="0.59" stopColor="#fff" stopOpacity="0.348"></stop>
<stop offset="0.94" stopColor="#fff"></stop>
</linearGradient>
<linearGradient
id="paint4_linear_338_416"
x1="122.821"
x2="259.519"
y1="137.555"
y2="116.348"
gradientUnits="userSpaceOnUse"
>
<stop offset="0.35" stopColor="#F02173"></stop>
<stop offset="0.61" stopColor="#E81DB8"></stop>
<stop offset="0.76" stopColor="#C516E1"></stop>
<stop offset="1" stopColor="#735DFF"></stop>
</linearGradient>
<linearGradient
id="paint7_linear_338_416"
x1="193.079"
x2="144.177"
y1="236.788"
y2="57.871"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#fff" stopOpacity="0"></stop>
<stop offset="0.1" stopColor="#fff" stopOpacity="0.01"></stop>
<stop offset="0.3" stopColor="#fff" stopOpacity="0.073"></stop>
<stop offset="0.59" stopColor="#fff" stopOpacity="0.348"></stop>
<stop offset="0.94" stopColor="#fff"></stop>
</linearGradient>
<clipPath id="clip0_338_416">
<path fill="#fff" d="M14.22 14.223h227.557v227.556H14.22z"></path>
</clipPath>
</defs>
</svg>
);
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add theme support with isDark prop.

The SVG component should accept and use an isDark prop to support both light and dark themes. Currently, all colors are hardcoded, which doesn't align with Langflow's theming system.

Based on coding guidelines.

Consider adding the isDark prop and adjusting fill colors accordingly:

-const MurfSVG = (props) => (
+const MurfSVG = ({ isDark, ...props }) => (
   <svg
     xmlns="http://www.w3.org/2000/svg"
     fill="none"
     viewBox="0 0 256 256"
     {...props}
   >

Then adjust gradient and fill definitions based on the isDark value to ensure proper contrast in both light and dark modes.

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

🤖 Prompt for AI Agents
In src/frontend/src/icons/Murf/MurfSVG.jsx around lines 1-150, the component
currently hardcodes gradient and fill colors and does not accept an isDark prop;
add an isDark boolean prop (default false) to the component signature and use it
to conditionally select alternate gradient stopColor values and fill attributes
(e.g., swap lighter stopColors/white highlights for darker variants or
higher-contrast colors when isDark is true) by computing gradient/fill color
variables before returning the SVG; update gradient definitions and any
hardcoded white/opacity stops to reference those variables (or alternate
gradient IDs) so the SVG renders appropriate contrast in both light and dark
themes, and ensure existing props are still spread onto the <svg> element.

Comment on lines 97 to 123
def generate_speech(self) -> Data:
try:
from murf import Murf

# Initialize Murf client
client = Murf(api_key=self.api_key)

if not self.api_key:
msg = "Set your MURF_API_KEY as environment variable."
raise ValueError(msg)

# Generate speech
res = client.text_to_speech.generate(
text=self.text,
voice_id=self.voice_id,
encode_as_base_64=self.encode_as_base_64,
channel_type=self.channel_type.lower(),
format=self.format,
rate=self.rate,
pitch=self.pitch,
sample_rate=int(self.sample_rate),
**({"multi_native_locale": self.multi_native_locale} if self.multi_native_locale is not None else {}),
)
return Data(data=res)
except Exception as e: # noqa: BLE001
self.log(f"Error generating speech: {e!s}")
return Output(name="error", message=Message(text=f"API error: {e}"), error=True)
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 | 🔴 Critical

Critical: Fix return type inconsistency and API key validation order.

  1. Return type mismatch: Line 123 returns Output(...) but the method signature specifies -> Data. The Output class is meant for defining component outputs in the outputs list, not for returning error data from methods.

  2. Redundant API key validation: Lines 104-106 check if self.api_key is empty after already using it to initialize the Murf client on line 102. If the key is invalid, the client initialization would fail first.

Apply this diff to fix both issues:

 def generate_speech(self) -> Data:
     try:
         from murf import Murf
 
+        if not self.api_key:
+            msg = "Set your MURF_API_KEY as environment variable."
+            raise ValueError(msg)
+
         # Initialize Murf client
         client = Murf(api_key=self.api_key)
 
-        if not self.api_key:
-            msg = "Set your MURF_API_KEY as environment variable."
-            raise ValueError(msg)
-
         # Generate speech
         res = client.text_to_speech.generate(
             text=self.text,
             voice_id=self.voice_id,
             encode_as_base_64=self.encode_as_base_64,
             channel_type=self.channel_type.lower(),
             format=self.format,
             rate=self.rate,
             pitch=self.pitch,
             sample_rate=int(self.sample_rate),
             **({"multi_native_locale": self.multi_native_locale} if self.multi_native_locale is not None else {}),
         )
         return Data(data=res)
     except Exception as e:  # noqa: BLE001
         self.log(f"Error generating speech: {e!s}")
-        return Output(name="error", message=Message(text=f"API error: {e}"), error=True)
+        return Data(data={"error": f"API error: {e}"})
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/Murf/text_to_speech.py around lines 97 to 123, the
method validates the API key after initializing the Murf client and returns an
Output on error even though the signature declares -> Data; move the API key
presence check to before creating the Murf client so you never call
Murf(api_key=...) with a missing key, and on exception return a Data instance
representing the error (e.g., Data containing error details or None payload and
an error flag/message) instead of Output while keeping the logging of the
exception.

Comment on lines 125 to 145
def initialize_voice_list_data(self) -> dict:
try:
from murf import Murf

client = Murf(api_key=self.api_key)
voice_list = client.text_to_speech.get_voices()
voice_list_dict = [voice.__dict__ for voice in voice_list]
locales_to_voices = {}
for voice in voice_list_dict:
locale = voice["locale"]
if locale not in locales_to_voices:
locales_to_voices[locale] = {
"display_name": f"{voice['display_language']}({voice['accent']})",
"voice_list": {},
}
locales_to_voices[locale]["voice_list"][voice["voice_id"]] = voice
return locales_to_voices # noqa: TRY300
except (KeyError, AttributeError, ValueError) as e:
self.log(f"Error initializing Murf Voice List: {e}")
msg = f"Error initializing Murf Voice List: {e}"
return Data(data={"error": msg})
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 | 🟠 Major

Fix return type inconsistency in error handling.

The method signature specifies -> dict but line 145 returns Data(data={"error": msg}) on error. This type inconsistency can cause issues for callers expecting a dictionary.

Apply this diff to maintain consistent return types:

     except (KeyError, AttributeError, ValueError) as e:
         self.log(f"Error initializing Murf Voice List: {e}")
-        msg = f"Error initializing Murf Voice List: {e}"
-        return Data(data={"error": msg})
+        return {"error": f"Error initializing Murf Voice List: {e}"}
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/Murf/text_to_speech.py around lines 125 to 145,
the method initialize_voice_list_data is declared to return a dict but on
exception returns a Data(...) object; change the error branch to return a plain
dict with the error message (e.g., {"error": msg}) instead of Data(...), keeping
the existing self.log call intact so callers always receive a dict as the return
type.

Comment on lines 161 to 236
def _update_build_config_voice_id(self, build_config: dict) -> dict:
selected_locale = build_config["locale"]["value"]
voices = build_config.get("murf_voice_list")
if voices and selected_locale in voices:
options = voices.get(selected_locale).get("voice_list")
build_config["voice_id"]["options"] = list(options.keys())
build_config["voice_id"]["options_metadata"] = [
{
"Name": voice.get("display_name"),
"Voice ID": voice.get("voice_id"),
"Description": voice.get("description"),
"Gender": voice.get("gender"),
"Locale": voice.get("locale"),
"Accent": voice.get("accent"),
"Styles": voice.get("available_styles"),
"Supported Locales": list(voice.get("supported_locales").keys()),
}
for voice in options.values()
]
build_config["voice_id"]["value"] = next(iter(options.keys()))
build_config["voice_id"]["show"] = True
build_config = self._update_build_config_multi_native_locale(
build_config, build_config["voice_id"]["value"], voices
)
else:
build_config["voice_id"]["show"] = False
return build_config
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 | 🟠 Major

Add safety checks for dictionary access.

Two potential runtime errors:

  1. Line 162: Direct access to build_config["locale"]["value"] without checking if keys exist could raise KeyError.

  2. Line 180: Using next(iter(options.keys())) without verifying options is non-empty could raise StopIteration.

Apply this diff to add safety checks:

 def _update_build_config_voice_id(self, build_config: dict) -> dict:
-    selected_locale = build_config["locale"]["value"]
+    selected_locale = build_config.get("locale", {}).get("value")
+    if not selected_locale:
+        build_config["voice_id"]["show"] = False
+        return build_config
+        
     voices = build_config.get("murf_voice_list")
     if voices and selected_locale in voices:
         options = voices.get(selected_locale).get("voice_list")
+        if not options:
+            build_config["voice_id"]["show"] = False
+            return build_config
+            
         build_config["voice_id"]["options"] = list(options.keys())
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/Murf/text_to_speech.py around lines 161 to 187,
the code assumes build_config and nested keys exist and that options is
non-empty; add defensive checks: verify build_config.get("locale") and
build_config["locale"].get("value") exist (use .get and default fallback) before
using selected_locale, handle missing voices or missing selected_locale by
setting voice_id.show=False and returning early, and ensure options is a
non-empty dict before calling next(iter(...))—if options is empty, skip setting
voice_id.value (or set to None/default) and keep show=False; also guard accesses
like voices.get(selected_locale).get("voice_list") with safe .get calls to avoid
KeyError.

Comment on lines 189 to 280
def _update_build_config_multi_native_locale(
self, build_config: dict, field_value: str, voices: dict | None = None
) -> dict:
if voices is None:
voices = build_config["murf_voice_list"]
if voices is None or len(voices) == 0:
voices = self.initialize_voice_list_data()
build_config["murf_voice_list"] = voices
selected_locale = build_config["locale"]["value"]
selected_voice_id = field_value

selected_voice = voices[selected_locale]["voice_list"][selected_voice_id]
if selected_voice and selected_voice["supported_locales"]:
locale_options = selected_voice["supported_locales"].keys()
build_config["multi_native_locale"]["options"] = list(locale_options)
options_metadata = []
for locale in selected_voice["supported_locales"].values():
if locale is dict:
options_metadata.append({"locale": locale.get("detail")})
else:
options_metadata.append({"locale": locale.__dict__.get("detail")})
build_config["multi_native_locale"]["options_metadata"] = options_metadata
build_config["multi_native_locale"]["value"] = selected_voice.get("locale")
build_config["multi_native_locale"]["show"] = True
else:
build_config["multi_native_locale"]["show"] = False
return build_config
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 | 🔴 Critical

Critical: Fix type checking bug and add safety checks.

  1. Line 206 - Logic bug: Uses locale is dict which checks if locale is the dict class itself, not if it's an instance of dict. This condition will always be False. Should use isinstance(locale, dict).

  2. Line 200: Direct nested dictionary access without safety checks could raise KeyError if any key doesn't exist.

Apply this diff to fix both issues:

     selected_locale = build_config["locale"]["value"]
     selected_voice_id = field_value
 
-    selected_voice = voices[selected_locale]["voice_list"][selected_voice_id]
+    try:
+        selected_voice = voices[selected_locale]["voice_list"][selected_voice_id]
+    except (KeyError, TypeError):
+        build_config["multi_native_locale"]["show"] = False
+        return build_config
+        
     if selected_voice and selected_voice["supported_locales"]:
         locale_options = selected_voice["supported_locales"].keys()
         build_config["multi_native_locale"]["options"] = list(locale_options)
         options_metadata = []
         for locale in selected_voice["supported_locales"].values():
-            if locale is dict:
+            if isinstance(locale, dict):
                 options_metadata.append({"locale": locale.get("detail")})
             else:
                 options_metadata.append({"locale": locale.__dict__.get("detail")})
📝 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
def _update_build_config_multi_native_locale(
self, build_config: dict, field_value: str, voices: dict | None = None
) -> dict:
if voices is None:
voices = build_config["murf_voice_list"]
if voices is None or len(voices) == 0:
voices = self.initialize_voice_list_data()
build_config["murf_voice_list"] = voices
selected_locale = build_config["locale"]["value"]
selected_voice_id = field_value
selected_voice = voices[selected_locale]["voice_list"][selected_voice_id]
if selected_voice and selected_voice["supported_locales"]:
locale_options = selected_voice["supported_locales"].keys()
build_config["multi_native_locale"]["options"] = list(locale_options)
options_metadata = []
for locale in selected_voice["supported_locales"].values():
if locale is dict:
options_metadata.append({"locale": locale.get("detail")})
else:
options_metadata.append({"locale": locale.__dict__.get("detail")})
build_config["multi_native_locale"]["options_metadata"] = options_metadata
build_config["multi_native_locale"]["value"] = selected_voice.get("locale")
build_config["multi_native_locale"]["show"] = True
else:
build_config["multi_native_locale"]["show"] = False
return build_config
def _update_build_config_multi_native_locale(
self, build_config: dict, field_value: str, voices: dict | None = None
) -> dict:
if voices is None:
voices = build_config["murf_voice_list"]
if voices is None or len(voices) == 0:
voices = self.initialize_voice_list_data()
build_config["murf_voice_list"] = voices
selected_locale = build_config["locale"]["value"]
selected_voice_id = field_value
try:
selected_voice = voices[selected_locale]["voice_list"][selected_voice_id]
except (KeyError, TypeError):
build_config["multi_native_locale"]["show"] = False
return build_config
if selected_voice and selected_voice["supported_locales"]:
locale_options = selected_voice["supported_locales"].keys()
build_config["multi_native_locale"]["options"] = list(locale_options)
options_metadata = []
for locale in selected_voice["supported_locales"].values():
if isinstance(locale, dict):
options_metadata.append({"locale": locale.get("detail")})
else:
options_metadata.append({"locale": locale.__dict__.get("detail")})
build_config["multi_native_locale"]["options_metadata"] = options_metadata
build_config["multi_native_locale"]["value"] = selected_voice.get("locale")
build_config["multi_native_locale"]["show"] = True
else:
build_config["multi_native_locale"]["show"] = False
return build_config
🤖 Prompt for AI Agents
In src/lfx/src/lfx/components/Murf/text_to_speech.py around lines 189 to 215,
the function _update_build_config_multi_native_locale has two problems: it uses
“locale is dict” (should be isinstance(locale, dict)) and it performs unsafe
nested dict access that can raise KeyError; fix by replacing the identity check
with isinstance(locale, dict) and add defensive checks and .get() usage for
build_config keys (e.g., use build_config.get("murf_voice_list") and
build_config.get("locale", {}).get("value")), verify selected_locale exists in
voices, verify selected_voice and its "supported_locales" are present and are a
dict before iterating, and fallback safely (e.g., set show=False or empty lists)
when any required piece is missing so no KeyError occurs.

@shubhraMurf shubhraMurf marked this pull request as draft October 30, 2025 13:10
@shubhraMurf shubhraMurf marked this pull request as ready for review October 31, 2025 08:04
@shubhraMurf
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 31, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Pull Request from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant