Skip to content

feat(stt): add speech-to-text support in neurolink using google cloud… - #793

Closed
shambhavik-25 wants to merge 1 commit into
juspay:releasefrom
shambhavik-25:BZ-48219-add-speech-to-text-support-in-neuro-link
Closed

feat(stt): add speech-to-text support in neurolink using google cloud…#793
shambhavik-25 wants to merge 1 commit into
juspay:releasefrom
shambhavik-25:BZ-48219-add-speech-to-text-support-in-neuro-link

Conversation

@shambhavik-25

@shambhavik-25 shambhavik-25 commented Jan 29, 2026

Copy link
Copy Markdown

feat(stt): add speech-to-text support in neurolink using google cloud speech-to-text

Pull Request

Description

What does this PR do?

Adds integrated Speech-to-Text (STT) support to NeuroLink using Google Cloud Speech-to-Text. Enables high-accuracy audio transcription in 125+ languages, with advanced features like word-level timestamps and model selection.

Related Issues

Does this PR close any issues?

Closes #48219

Type of Change

Please select the type of change:

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Refactoring (no functional changes)
  • Performance improvement
  • Test coverage improvement
  • Build/CI configuration
  • Other (please describe):

Motivation and Context

Why is this change needed? What problem does it solve?

  • Enables users to transcribe audio files to text directly via NeuroLink CLI and SDK.
  • Supports a wide range of languages and specialized models (call, video, medical, etc.).
  • Fulfills the need for integrated, production-grade STT in the platform.

Changes Made

What specific changes were made?

Added STT types, runtime type guards, and error codes.

  • Implemented STTProcessor orchestrator and GoogleSTTHandler.
  • Added language/model discovery via SDK.
  • Integrated STT into the main generate() flow.
  • CLI: Added --stt-language, --stt-model, and related flags.
  • Comprehensive documentation in stt.md.
  • Added infrastructure and export tests for STT.

Breaking Changes

Does this PR introduce breaking changes?

  • No breaking changes
  • Yes, breaking changes (describe below)

Testing

How has this been tested?

Please describe the tests you ran and their results:

  • Unit tests added/updated
  • Integration tests added/updated
  • E2E tests pass
  • Manual testing completed
  • Tested with multiple providers: google-ai
  • Tested on multiple platforms: [list platforms]

Test Coverage

  • All new code is covered by tests
  • Existing tests pass
  • Coverage percentage maintained or improved

Code Quality

Have you followed code quality standards?

  • Code follows the project's style guidelines (ESLint passes)
  • Code is properly formatted (Prettier applied)
  • Self-review of code completed
  • No console.log statements (using logger instead)
  • No hardcoded API keys or secrets
  • TypeScript strict mode compliance
  • Proper error handling implemented
  • TODO/FIXME comments reference issues

Documentation

Have you updated documentation?

  • JSDoc comments added/updated for public APIs
  • README.md updated (if needed)
  • Documentation in /docs updated (if needed)
  • Code examples added/updated (if needed)
  • CHANGELOG.md updated (if applicable)
  • Migration guide provided (if breaking changes)

Commit Message Format

Does your commit follow semantic commit conventions?

  • Commit message follows format: type(scope): description
  • Valid type used: feat, fix, docs, style, refactor, test, chore, build, ci, perf, revert
  • Scope specified (e.g., providers, cli, docs, middleware)

Example: feat(providers): add support for LiteLLM proxy

Dependencies

Does this PR add, update, or remove dependencies?

  • No dependency changes
  • Dependencies added (list below)
  • Dependencies updated (list below)
  • Dependencies removed (list below)

If yes, list dependencies and justification:

package-name@version - Reason for adding/updating

Performance Impact

Does this change affect performance?

  • No performance impact
  • Performance improved (provide metrics)
  • Performance degraded (justify why acceptable)

If applicable, provide benchmark results:

Before: X ms
After: Y ms
Improvement: Z%

Security Considerations

Are there any security implications?

  • No security implications
  • Security review needed
  • Security vulnerability fixed

If applicable, describe:

  • Security measures implemented
  • Potential risks mitigated
  • Compliance considerations (HIPAA, SOC2, GDPR)

Deployment Notes

Special deployment instructions?

  • No special deployment steps
  • Requires environment variable changes (list below)
  • Requires database migration
  • Requires Redis schema update
  • Other (describe below)

Reviewer Checklist

For reviewers:

  • Code follows project style and conventions
  • Changes are well-documented
  • Tests provide adequate coverage
  • No obvious performance issues
  • No security vulnerabilities introduced
  • Breaking changes are properly documented
  • Documentation is clear and accurate

Pre-submission Checklist

Before submitting, ensure you have:

  • Read and followed the Contributing Guidelines
  • Verified all automated pre-commit checks pass
  • Tested changes locally with pnpm test
  • Built the project successfully with pnpm build
  • Run pnpm run validate:all and all checks pass
  • Reviewed your own code for obvious issues
  • Ensured commit messages follow semantic format
  • Updated relevant documentation
  • Added tests for new functionality
  • Checked that CI/CD pipeline passes (after creating PR)

Thank you for contributing to NeuroLink!

Summary by CodeRabbit

  • New Features

    • Added Speech-to-Text (STT) support: transcribe audio via CLI or SDK, discover languages/models, save transcripts, and output JSON.
    • Advanced transcription options: speaker diarization, word-level timestamps, alternative transcriptions, profanity filtering, punctuation restoration, and provider/model selection.
  • Documentation

    • Added a comprehensive STT Integration Guide with quick start, CLI/SDK usage, configuration, troubleshooting, and best practices.

@coderabbitai

coderabbitai Bot commented Jan 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

Adds Speech-to-Text (STT): new types and runtime guards, a provider-agnostic STTProcessor and STTError model, a Google Cloud STT handler, SDK integration (generateSTT, getSTTLanguages, getSTTModels), CLI commands/options and output handling, provider registration, and extensive documentation.

Changes

Cohort / File(s) Summary
Documentation
docs/features/stt.md
New STT integration guide covering overview, quick start, CLI/SDK examples, providers, languages/models, formats, advanced features, configuration, error handling, troubleshooting, and examples.
Dependencies & Manifest
package.json, CHANGELOG.md
Bumped version to 9.8.0 and added @google-cloud/speech dependency; added release note entry.
STT Types & Exports
src/lib/types/sttTypes.ts, src/lib/types/generateTypes.ts, src/lib/types/index.ts, src/lib/index.ts
New STT type module, runtime validators, added audioFiles/stt/transcription fields to generate/text types, and re-exported STT-related types and processors from library index.
STT Core Processor & Errors
src/lib/utils/sttProcessor.ts
New STTProcessor registry, transcribe workflow, provider management, STT_ERROR_CODES, and STTError class for unified error handling.
Google STT Adapter
src/lib/adapters/stt/googleSTTHandler.ts
New GoogleSTTHandler implementing STTHandler: configuration, languages/models, encoding mapping, request building, response shaping (alternatives, word-level timestamps, diarization), limits, and error wrapping.
SDK Integration
src/lib/neurolink.ts, src/lib/constants/enums.ts
Added generateSTT flow and public getSTTLanguages/getSTTModels, wired STT into main generate path, added ErrorCategory.STT, and addInMemoryMCPServer API.
Provider Registration
src/lib/factories/providerRegistry.ts
Registers Google STT handler (keys google-ai, vertex) with STTProcessor during provider init; non-fatal on registration failure.
CLI: Commands & Options
src/cli/factories/commandFactory.ts, src/cli/parser.ts, src/cli/loop/optionsSchema.ts
Added STT command group (languages/models), extended generate command with STT options and helpers (buildGenerateOptions, handleSTTOutput), registered STT commands in parser, and omitted stt from the textGenerationOptionsSchema surface.
Tests
test/unit/telemetry-config-metadata.test.ts
Minor typing tweak in test metadata (cast) and small formatting change.

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant CLI as "CLI Parser / CommandFactory"
    participant NL as "NeuroLink SDK"
    participant Proc as "STTProcessor"
    participant GHandler as "GoogleSTTHandler"
    participant GAPI as "Google Cloud Speech API"

    User->>CLI: run transcribe/generate --stt with audio file
    CLI->>NL: generate(options { audioFiles, stt })
    NL->>Proc: transcribe(audioBuffer, provider, options)
    Proc->>GHandler: transcribe(audioBuffer, options)
    GHandler->>GAPI: SpeechClient.recognize(request)
    GAPI-->>GHandler: recognition response
    GHandler->>Proc: STTResult (text, words, confidence, metadata)
    Proc-->>NL: STTResult
    NL-->>CLI: GenerateResult { transcription }
    CLI->>User: render/save transcription and metadata
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

Suggested labels

released

Suggested reviewers

  • vigneshJuspay
  • murdore
  • shuchimehta-juspay

Poem

🐰 I listened close to every tiny sound,
I hopped through waves until the words were found.
From muted hum to readable line,
I brought your voice to text — one hop at a time. 🎧✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding Speech-to-Text support to NeuroLink using Google Cloud, which aligns with the substantial feature additions across types, processors, handlers, CLI integration, and documentation.
Docstring Coverage ✅ Passed Docstring coverage is 85.71% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch from a2c1fd6 to c545eaf Compare January 29, 2026 09:52

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 13

🤖 Fix all issues with AI agents
In `@docs/features/stt.md`:
- Around line 520-526: The shell snippet has inline comments after a trailing
backslash which breaks continuations; update the block around the neurolink
generate <audio-file> example so every line ending with a backslash has no
trailing comment, move explanatory comments for flags (e.g., --stt-language,
--stt-model, --stt-enable-timestamps, --stt-enable-diarization) to their own
separate lines above or below the flag lines (or remove backslashes on commented
lines), and ensure each continuation backslash is the last character on the line
so the CLI example copies and pastes cleanly.

In `@src/cli/factories/commandFactory.ts`:
- Around line 1138-1140: Remove the dangling JSDoc "Create STT (Speech-to-Text)
transcribe command" comment or implement the actual command: either delete that
comment block entirely to avoid misleading docs/IDE tooltips, or add a matching
command factory function (e.g., createSttTranscribeCommand) and wire it into the
command registration (where other commands are created/registered in this
module, e.g., the existing createCommands/registerCommand logic) so the comment
accurately describes real code.
- Around line 315-320: The CLI option definition for sttModel in
commandFactory.ts currently restricts choices to
["default","command_and_search","phone_call","video"]; update the sttModel
choices array in the sttModel option to include the additional SDK-supported
values "medical_dictation", "latest_long", and "latest_short" so the CLI
--stt-model accepts those models; locate the sttModel object in the
commandFactory.ts file and add those three strings to the choices list (keeping
the type and default intact).
- Around line 2410-2413: The STT output handler call inside the conditional is
not awaited, so async work in handleSTTOutput can be interrupted by process
exit; update the call in the block that currently checks isSTTMode and
result.transcription to await this.handleSTTOutput(result, options) and ensure
the enclosing function (e.g., the method in commandFactory where this if lives)
is marked async or properly returns a Promise so the await is valid and the
process waits for writes to finish.
- Around line 1254-1289: The command handler calls sdk.getSTTLanguages and only
logs a count via spinner.succeed but never prints the actual languages; after
obtaining languages (the languages variable returned by
NeuroLink.getSTTLanguages) and after spinner.succeed, output the full list to
the console (e.g., join with newline or iterate and console.log each language,
or use any existing CLI formatter utility) so users see the language entries
they requested; ensure you reference the async (argv) handler, NeuroLink,
sdk.getSTTLanguages and spinner when adding the print.
- Around line 2220-2318: handleSTTOutput currently nests all stdout under if
(!options.quiet) so when quiet is true nothing is printed and --format json is
only written to file; change the logic in handleSTTOutput to separate "human"
logging from machine/json output: keep all logger.always(...) calls inside the
if (!options.quiet) block (so human-readable output is suppressed when quiet)
but ensure that when options.format === "json" and no options.output is provided
you write JSON to stdout (e.g.,
process.stdout.write(JSON.stringify(transcription))) irrespective of
options.quiet, and when options.output is present keep current file write
behavior for both json and plain text; locate this change in the handleSTTOutput
method referenced above and adjust the conditions around the options.quiet and
options.format checks accordingly.

In `@src/lib/adapters/stt/googleSTTHandler.ts`:
- Around line 233-236: The recognize call in GoogleSTTHandler should be wrapped
with the withTimeout utility instead of relying on the client option alone;
update the call in the method that currently does
"this.client.recognize(request, { timeout:
GoogleSTTHandler.DEFAULT_API_TIMEOUT_MS })" to invoke withTimeout around the
async operation (using the client.recognize function bound to this.client or an
arrow wrapper) and pass GoogleSTTHandler.DEFAULT_API_TIMEOUT_MS as the timeout
value so the operation uses the library-standard timeout wrapper.
- Around line 248-317: The handler currently only uses response.results[0]
(primaryResult/primaryAlternative) and drops later segments; modify the logic to
iterate over response.results to aggregate full transcript text, merge
word-level timings (concatenate maps using convertDurationToSeconds), and
combine alternatives and confidences (e.g., append alternatives per segment or
compute an overall confidence) so the returned object fields text, confidence,
languageCode, words, alternatives, and duration represent the complete
multi-segment response; update where primaryResult/primaryAlternative are
referenced and where words, alternatives, duration are computed to use the
aggregated values.

In `@src/lib/constants/enums.ts`:
- Line 770: The ErrorCategory enum contains an inconsistent casing: the member
named STT is set to uppercase "STT"; change its string value to lowercase "stt"
so it matches the lowercase pattern used by other members and downstream
consumers; locate the ErrorCategory enum (the STT member) and update the
right-hand string literal from "STT" to "stt" while leaving the enum member name
unchanged.

In `@src/lib/neurolink.ts`:
- Around line 1839-1847: The getSTTLanguages method currently declares provider
as optional but throws a generic Error when missing; update the API to either
make provider required (change signature to provider: string) or provide a
sensible default (e.g., default to the primary provider constant) and replace
the generic Error with a typed error created via ErrorFactory (e.g.,
ErrorFactory.createInvalidArgument or the project's equivalent) for the
validation failure; apply the same change pattern to the other methods noted
(those around getTTSLanguages / similar at 1863-1871) so all provider validation
uses ErrorFactory and the parameter signatures/behavior are consistent.
- Around line 1983-1986: When options.stt is true the current branch only calls
generateSTT when options.input.audioFiles exists, causing STT requests with
missing audio to be treated as normal text generation; change the conditional to
unconditionally route STT requests to generateSTT by replacing the check with a
simple if (options.stt) return this.generateSTT(options); and ensure
generateSTT(options) is responsible for validating options.input.audioFiles and
throwing/handling the error; refer to the generateSTT method and the options.stt
/ options.input.audioFiles properties to locate and update the logic.
- Around line 1768-1823: The generateSTT method currently throws generic Errors
and performs unbounded I/O; update it to use ErrorFactory for typed errors and
wrap async ops with withTimeout: replace direct throws for missing options and
invalid audio file types with ErrorFactory (e.g., ErrorFactory.create(...)) and
wrap the fs.readFile call and the STTProcessor.transcribe call with withTimeout,
passing sensible timeouts and propagating timeout errors via ErrorFactory;
ensure you reference generateSTT, options.input.audioFiles, fs.readFile,
STTProcessor.transcribe, withTimeout, and ErrorFactory when making these
changes.

In `@src/lib/utils/sttProcessor.ts`:
- Around line 246-253: Replace the plain Error throws in
STTProcessor.registerHandler with typed errors produced by ErrorFactory: when
providerName is falsy, call ErrorFactory.create or the appropriate ErrorFactory
method to create a validation/argument error that includes context (e.g.,
"Provider name is required") and throw that instead; likewise for the handler
null check, use ErrorFactory to construct and throw the typed error. Update
references in the registerHandler(providerName: string, handler: STTHandler)
method so both validation failures use ErrorFactory-produced errors rather than
new Error(...).

Comment thread docs/features/stt.md Outdated
Comment thread src/cli/factories/commandFactory.ts
Comment thread src/cli/factories/commandFactory.ts Outdated
Comment thread src/cli/factories/commandFactory.ts Outdated
Comment thread src/cli/factories/commandFactory.ts Outdated
Comment thread src/lib/constants/enums.ts Outdated
Comment thread src/lib/neurolink.ts Outdated
Comment thread src/lib/neurolink.ts Outdated
Comment thread src/lib/neurolink.ts Outdated
Comment thread src/lib/utils/sttProcessor.ts
@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 4 times, most recently from 0c94261 to b754e05 Compare January 29, 2026 12:03
@murdore
murdore force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 3 times, most recently from d1a911c to 89bb415 Compare February 1, 2026 11:33
@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 2 times, most recently from a9149d0 to e4fdb1a Compare February 13, 2026 15:44
@vercel

vercel Bot commented Feb 13, 2026

Copy link
Copy Markdown

@shambhavik-25 is attempting to deploy a commit to the Sachin Sharma's projects Team on Vercel.

A member of the Team first needs to authorize it.

@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 9 times, most recently from 20b4e1a to c01ffb6 Compare February 16, 2026 10:01
@murdore
murdore force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch from c01ffb6 to 83511fe Compare February 16, 2026 17:28
@murdore

murdore commented Feb 16, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai full review and check if all project standards are being followed. also check if all the previous comments have been addressed

@coderabbitai

coderabbitai Bot commented Feb 16, 2026

Copy link
Copy Markdown

@murdore, I'll conduct a comprehensive review of PR #793, examining:

  1. Code Quality & Standards: TypeScript strict compliance, error handling patterns, coding conventions, and architectural consistency
  2. STT Implementation: Type safety, handler registration, processor logic, and integration points
  3. CLI Integration: Command structure, option handling, and user experience
  4. Documentation: Completeness and accuracy of the STT feature guide
  5. Test Coverage: Unit and integration test adequacy
  6. Previous Comments: Verification that all prior feedback has been addressed

I'll review all changes with a focus on ensuring they align with the NeuroLink project's established patterns and best practices.


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@docs/features/stt.md`:
- Around line 633-640: The fenced code block mixes shell and TypeScript which
confuses highlighting; split the single ```bash block into two separate fenced
blocks: one ```bash block containing the echo $GOOGLE_AI_API_KEY line and a
second ```typescript block containing the TypeScript snippet that calls
neurolink.getSTTLanguages() and logs the result, preserving the order and
surrounding backticks so each block has the correct language tag for syntax
highlighting.

In `@package.json`:
- Line 198: Remove the unused "commander" dependency from package.json by
deleting the "commander": "^14.0.2" entry and then update the lockfile and
installed packages (run your package manager's install or prune command) so the
removal is applied; verify no references to commander remain and that CLI
behavior still relies on yargs/CommandFactory code in src/cli/**/*.ts.

In `@src/cli/factories/commandFactory.ts`:
- Around line 3692-3694: The stub function flushTraces() unconditionally throws
and is called from the --list-conversations flow, causing a crash; replace calls
to flushTraces() with a call to the existing
CLICommandFactory.flushLangfuseTraces() (or have flushTraces() delegate to
CLICommandFactory.flushLangfuseTraces()) and remove the dead stub to avoid the
unhandled exception, ensuring all references use
CLICommandFactory.flushLangfuseTraces() so the list-conversations path no longer
throws.
- Around line 2196-2208: When isSTTMode is true and you build audioFiles from
argv.input, validate that argv.input exists and is readable before adding it to
generateInput: check the filesystem (e.g., fs.existsSync or fs.promises.access)
for argv.input and if the file is missing or not readable, throw or return a
clear CLI error (with a message like "STT input file not found or not readable:
<path>") rather than passing the path into audioFiles; update the logic around
isSTTMode / audioFiles / generateInput so the existence check runs before
constructing generateInput and before any SDK calls.
- Around line 2290-2392: The transcription text is only printed inside the if
(!options.quiet) block in handleSTTOutput, so with quiet=true the plain-text
transcript is never emitted; move the plain transcription output (the line that
emits transcription.text) out of the quiet-only block so the transcript is
always written (use process.stdout.write or logger.always to emit
transcription.text when options.format !== 'json' and no output file specified),
while keeping decorative chrome, metadata lines and alternatives gated behind if
(!options.quiet); ensure references to transcription.text, handleSTTOutput, and
the JSON stdout path are preserved and not duplicated.

In `@src/lib/neurolink.ts`:
- Around line 1914-1920: The returned GenerateResult incorrectly sets model to
the text-generation option (options.model); replace that with the STT model from
sttResult.metadata.model (or remove the top-level model field) so the top-level
model reflects the actual STT model used; update the return object in the
function that returns the GenerateResult (reference symbols: sttResult,
options.model, GenerateResult, transcription.metadata.model,
sttResult.metadata.model) to use sttResult.metadata.model for the model property
or omit the property entirely.
🧹 Nitpick comments (5)
src/lib/types/index.ts (1)

233-249: Consolidate duplicate re-exports; keep only the STT export here.

This block repeats exports already listed above, which adds noise and risks confusion about the public surface. Keep a single STT export and drop the duplicates.

♻️ Proposed cleanup
-// Middleware Types - Middleware system types
-export * from "./middlewareTypes.js";
-
-// File detection and processing types
-export * from "./fileTypes.js";
-
-// Content types for multimodal support (includes multimodal re-exports for backward compatibility)
-export * from "./content.js";
-
-// TTS (Text-to-Speech) types
-export * from "./ttsTypes.js";
-
-// STT (Speech-to-Text) types
-export * from "./sttTypes.js";
-
-// HITL (Human-in-the-Loop) types
-export * from "./hitlTypes.js";
+// STT (Speech-to-Text) types
+export * from "./sttTypes.js";
src/cli/factories/commandFactory.ts (1)

50-50: Commented-out import is dead code.

normalizeEvaluationData import is fully commented out. Remove it to keep the module clean.

Proposed fix
-//import { normalizeEvaluationData } from "../../lib/utils/evaluationUtils.js";
src/lib/types/sttTypes.ts (1)

57-64: Consider deriving the model union from VALID_STT_MODELS to keep them in sync automatically.

Currently the model union in STTOptions.model (lines 57–64) and the VALID_STT_MODELS array (lines 168–176) list the same values independently. If one is updated without the other, the type guard would silently diverge from the type.

Example: derive the union from the const array
export const VALID_STT_MODELS = [
  "default",
  "command_and_search",
  "phone_call",
  "video",
  "medical_dictation",
  "latest_long",
  "latest_short",
] as const;

export type STTModel = (typeof VALID_STT_MODELS)[number];

// Then in STTOptions:
// model?: STTModel;

Also applies to: 168-176

src/lib/adapters/stt/googleSTTHandler.ts (2)

92-163: Hardcoded language list only covers ~55 of 125+ claimed languages.

getLanguages() returns a static array and doesn't query the Google API (which lacks a dedicated language discovery endpoint, so this is understandable). However, the module doc and PR description claim "125+ languages". Consider either expanding the list to be more complete or adjusting the messaging to say "commonly used languages" to set accurate expectations.


444-472: Hardcoded numeric enum values are fragile but functional.

The encoding map uses raw integers (1–9) matching google.cloud.speech.v1.RecognitionConfig.AudioEncoding proto values. If the proto definition ever changes, these would silently break. Consider importing the enum directly from the proto if available, e.g., protos.google.cloud.speech.v1.RecognitionConfig.AudioEncoding.LINEAR16.

#!/bin/bash
# Check if the enum is accessible from the proto import
rg -n "AudioEncoding" --type ts -g '!node_modules' -g '!*.d.ts' | head -20
echo "---"
# Check the proto definition structure
fd -t f "protos.d.ts" -p "google-cloud/speech" --exec head -200 {} \; 2>/dev/null || echo "Proto file not found in repo"

Comment thread docs/features/stt.md Outdated
Comment thread package.json Outdated
Comment thread src/cli/factories/commandFactory.ts Outdated
Comment thread src/cli/factories/commandFactory.ts
Comment thread src/cli/factories/commandFactory.ts Outdated
Comment thread src/lib/neurolink.ts Outdated
@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 3 times, most recently from e838f7a to 1270db5 Compare February 17, 2026 06:59
@shambhavik-25

Copy link
Copy Markdown
Author

@coderabbitai please do a full review and check if all project standards are being followed. also check if all the previous comments have been addressed

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown

@shambhavik-25, I'll conduct a comprehensive full review of PR #793 to verify:

  1. Project Standards Compliance:

    • TypeScript strict mode adherence
    • Error handling patterns consistency with existing codebase
    • Coding conventions and architectural patterns
    • Naming conventions and code organization
  2. Previous Comments Resolution:

    • Verification that all feedback from prior reviews has been addressed
    • Checking for any outstanding issues or suggestions
  3. STT Implementation Quality:

    • Type safety and runtime validation
    • Handler registration and processor logic
    • Integration with the main generate() flow
    • CLI command structure and options
  4. Documentation & Testing:

    • Documentation completeness and accuracy
    • Test coverage adequacy

I'll examine all the changes systematically and provide detailed feedback on any issues found.


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.
✅ Actions performed

Full review triggered.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (7)
src/lib/types/sttTypes.ts (1)

157-160: Normalize audio format before checking support.
Trimming a leading dot and lowercasing avoids false negatives from inputs like .WAV.

♻️ Suggested tweak
 export function isSupportedAudioFormat(
   format: string,
 ): format is SupportedAudioFormat {
-  return SUPPORTED_AUDIO_FORMATS.includes(format as SupportedAudioFormat);
+  const normalized = format.replace(/^\./, "").toLowerCase();
+  return SUPPORTED_AUDIO_FORMATS.includes(normalized as SupportedAudioFormat);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/types/sttTypes.ts` around lines 157 - 160, The isSupportedAudioFormat
function should normalize the incoming format string before checking membership:
strip any leading '.' and lowercase the value (e.g., const normalized =
format.replace(/^\./, '').toLowerCase()) and then use
SUPPORTED_AUDIO_FORMATS.includes(normalized as SupportedAudioFormat). Update the
check in isSupportedAudioFormat to use the normalized value so inputs like
".WAV" or "Wav" are correctly recognized.
src/lib/utils/sttProcessor.ts (2)

347-398: Add withTimeout around provider discovery calls.
Wrapping getLanguages() and getModels() prevents indefinite hangs; import withTimeout from the existing utils module.

♻️ Suggested change
-    return handler.getLanguages();
+    return withTimeout(
+      handler.getLanguages(),
+      60_000,
+      `STT getLanguages timed out for provider "${providerName}"`
+    );
-    return handler.getModels();
+    return withTimeout(
+      handler.getModels(),
+      60_000,
+      `STT getModels timed out for provider "${providerName}"`
+    );
As per coding guidelines: Wrap async operations with withTimeout utility.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/utils/sttProcessor.ts` around lines 347 - 398, Import the existing
withTimeout helper from the utils module and wrap the provider discovery
promises to avoid hangs: in getLanguages() replace the direct return of
handler.getLanguages() with an awaited withTimeout(handler.getLanguages(),
<timeoutMs>) (and do the same in getModels()); ensure you import withTimeout at
the top and await the wrapper, and if desired catch a timeout error and rethrow
an STTError that includes STT_ERROR_CODES.PROVIDER_NOT_SUPPORTED or a new
timeout-specific code and the provider context to preserve error semantics.

129-180: Prefer a type alias for STTHandler to match repo conventions.

♻️ Suggested change
-export interface STTHandler {
+export type STTHandler = {
   /**
    * Transcribe audio to text using provider-specific STT API
    *
    * **IMPORTANT: Timeout Responsibility**
@@
-}
+};
Based on learnings: In the juspay/neurolink repository, new type definitions should use the `type` keyword instead of `interface`, unless there is a valid and justified exception.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/utils/sttProcessor.ts` around lines 129 - 180, Replace the exported
STTHandler interface with an exported type alias named STTHandler while
preserving the exact shape (methods transcribe, getLanguages, getModels,
isConfigured and readonly properties maxAudioSizeMB and maxDurationSeconds) and
JSDoc comments; ensure the transcribe signature Promise<STTResult>, optional
methods are marked optional, and exported name remains STTHandler so existing
imports (and references to transcribe, getLanguages, getModels, isConfigured,
maxAudioSizeMB, maxDurationSeconds) continue to work.
src/lib/neurolink.ts (1)

167-168: Remove the commented-out STTResult import.

It adds noise without value. Clean it up if no longer needed.

🧹 Proposed cleanup
-import { STTProcessor } from "./utils/sttProcessor.js";
-//import type { STTResult } from "./types/sttTypes.js";
+import { STTProcessor } from "./utils/sttProcessor.js";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/neurolink.ts` around lines 167 - 168, Remove the unnecessary
commented import line for STTResult — delete the line "//import type { STTResult
} from "./types/sttTypes.js";" so only the active import (STTProcessor) remains,
keeping the top of neurolink.ts clean and free of unused commented imports.
src/lib/adapters/stt/googleSTTHandler.ts (2)

206-233: Consider omitting sampleRateHertz for self-describing formats like MP3.

Google STT ignores sampleRateHertz for MP3 and OGG_OPUS (the rate is in the file header), but for LINEAR16/FLAC it's required. The hardcoded default of 16000 works fine today but could silently produce degraded results if a user supplies a 44.1 kHz WAV without specifying the rate. A small improvement would be to omit the field entirely when the encoding is self-describing, so Google uses auto-detection.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/adapters/stt/googleSTTHandler.ts` around lines 206 - 233, The request
currently always sets sampleRateHertz to 16000 which can be wrong for
self-describing formats; update the request-building in googleSTTHandler.ts
(inside the function that builds the request using this.mapAudioEncoding and
options) to only include sampleRateHertz when the mapped encoding is a
non-self-describing type (e.g., LINEAR16 or FLAC) and omit it for
self-describing encodings like MP3 and OGG_OPUS so Google will auto-detect the
rate; use the result of this.mapAudioEncoding(options.encoding || "MP3") to
drive this conditional and keep the existing defaulting behavior for required
encodings.

92-164: Hardcoded language list means the cache serves no real purpose.

Since getLanguages() returns a static array (not fetched from an API), the 5-minute TTL cache adds complexity without benefit. If this is a placeholder for a future API call, consider adding a comment; otherwise, the cache can be removed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/adapters/stt/googleSTTHandler.ts` around lines 92 - 164, The
getLanguages() function currently builds a static languages array and then
stores it in this.languagesCache with a timestamp, which is unnecessary; remove
the caching assignment (this.languagesCache = { languages, timestamp: Date.now()
}) and any related TTL logic so getLanguages() simply returns the static
languages array, and also remove or clean up the languagesCache property/uses
elsewhere; if this was intended as a future placeholder instead, replace the
assignment with a clear TODO comment referencing getLanguages() and
this.languagesCache.
src/cli/factories/commandFactory.ts (1)

2346-2356: Minor: Dynamic fs/promises import shadows the top-level fs import.

fs is already imported at the top of the file (import fs from "node:fs"). Re-importing fs/promises as fs inside this method shadows the module-level binding, which is confusing and unnecessary.

♻️ Use the already-imported module
-      const fs = await import("fs/promises");
-      if (options.format === "json") {
-        await fs.writeFile(
-          options.output as string,
-          JSON.stringify(transcription, null, 2),
-        );
-      } else {
-        await fs.writeFile(options.output as string, transcription.text);
-      }
+      if (options.format === "json") {
+        fs.writeFileSync(
+          options.output as string,
+          JSON.stringify(transcription, null, 2),
+        );
+      } else {
+        fs.writeFileSync(options.output as string, transcription.text);
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/cli/factories/commandFactory.ts` around lines 2346 - 2356, The dynamic
import of "fs/promises" as fs shadows the top-level fs import and is
unnecessary; remove the await import("fs/promises") line and use the existing
top-level fs to write files (e.g., call fs.promises.writeFile for both JSON and
text branches when handling options.output and transcription). Update the
branches that call writeFile to use fs.promises.writeFile and keep the same
arguments (options.output and either JSON.stringify(transcription, null, 2) or
transcription.text).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Around line 1-5: Update the 9.8.0 release notes in CHANGELOG.md to include a
new Features bullet announcing STT support and the new runtime dependency
introduced by this PR: under the "## [9.8.0] ... (2026-02-17)" section add a
line like "- **STT:** add speech-to-text support and include new runtime
dependency (name the actual package added in this PR)" so the entry explicitly
mentions STT and the runtime dependency alongside the existing TS migration
note.

In `@docs/features/stt.md`:
- Around line 33-41: The docs currently list GOOGLE_AI_API_KEY as an STT auth
option but the Google STT handler (googleSTTHandler.ts / the GoogleSTT handler)
only supports service account credentials via GOOGLE_APPLICATION_CREDENTIALS or
a credentialsPath parameter; remove the "Option 2" API key snippet from
docs/features/stt.md and update the text to state that STT requires service
account credentials (GOOGLE_APPLICATION_CREDENTIALS or credentialsPath) only,
ensuring no references to GOOGLE_AI_API_KEY remain; if you prefer to keep
API-key support instead, implement API-key handling inside
src/lib/adapters/stt/googleSTTHandler.ts (add logic to accept GOOGLE_AI_API_KEY
and construct the client accordingly) and then keep the docs, but do one or the
other—not both.

In `@src/cli/factories/commandFactory.ts`:
- Around line 2238-2314: The buildGenerateOptions flow constructs sdkOptions but
omits the STT configuration, so generate() gets audio but no transcription
settings; update buildGenerateOptions to add an stt (or speechToText) object
into sdkOptions using the CLI-extracted STT fields (language, model, enhanced,
maxAlternatives, enablePunctuation, enableTimestamps, enableConfidence,
enableDiarization, speakerCount) so the SDK receives them; place it alongside
other top-level sdkOptions properties (near provider/model/temperature) and map
each property from the existing extracted variables (argv or enhancedOptions
whichever holds them) to the corresponding STT field.

In `@src/lib/neurolink.ts`:
- Around line 1868-1895: The code currently only reads the first entry of
options.input.audioFiles into audioBuffer and silently drops any additional
files; update the validation in the audio input block (where audioBuffer is set
and options.input.audioFiles is checked) to detect if
options.input.audioFiles.length > 1 and fail fast by throwing
ErrorFactory.invalidParameters (e.g., key "audioFiles" with an error stating
multiple files are not supported) so callers are informed, or alternatively
implement batching support if desired; keep the existing Buffer/string handling
and withTimeout/fs.readFile logic for the single-file path (references: variable
audioBuffer, options.input.audioFiles, withTimeout,
ErrorFactory.invalidParameters, fileReadTimeoutMs).

---

Nitpick comments:
In `@src/cli/factories/commandFactory.ts`:
- Around line 2346-2356: The dynamic import of "fs/promises" as fs shadows the
top-level fs import and is unnecessary; remove the await import("fs/promises")
line and use the existing top-level fs to write files (e.g., call
fs.promises.writeFile for both JSON and text branches when handling
options.output and transcription). Update the branches that call writeFile to
use fs.promises.writeFile and keep the same arguments (options.output and either
JSON.stringify(transcription, null, 2) or transcription.text).

In `@src/lib/adapters/stt/googleSTTHandler.ts`:
- Around line 206-233: The request currently always sets sampleRateHertz to
16000 which can be wrong for self-describing formats; update the
request-building in googleSTTHandler.ts (inside the function that builds the
request using this.mapAudioEncoding and options) to only include sampleRateHertz
when the mapped encoding is a non-self-describing type (e.g., LINEAR16 or FLAC)
and omit it for self-describing encodings like MP3 and OGG_OPUS so Google will
auto-detect the rate; use the result of this.mapAudioEncoding(options.encoding
|| "MP3") to drive this conditional and keep the existing defaulting behavior
for required encodings.
- Around line 92-164: The getLanguages() function currently builds a static
languages array and then stores it in this.languagesCache with a timestamp,
which is unnecessary; remove the caching assignment (this.languagesCache = {
languages, timestamp: Date.now() }) and any related TTL logic so getLanguages()
simply returns the static languages array, and also remove or clean up the
languagesCache property/uses elsewhere; if this was intended as a future
placeholder instead, replace the assignment with a clear TODO comment
referencing getLanguages() and this.languagesCache.

In `@src/lib/neurolink.ts`:
- Around line 167-168: Remove the unnecessary commented import line for
STTResult — delete the line "//import type { STTResult } from
"./types/sttTypes.js";" so only the active import (STTProcessor) remains,
keeping the top of neurolink.ts clean and free of unused commented imports.

In `@src/lib/types/sttTypes.ts`:
- Around line 157-160: The isSupportedAudioFormat function should normalize the
incoming format string before checking membership: strip any leading '.' and
lowercase the value (e.g., const normalized = format.replace(/^\./,
'').toLowerCase()) and then use SUPPORTED_AUDIO_FORMATS.includes(normalized as
SupportedAudioFormat). Update the check in isSupportedAudioFormat to use the
normalized value so inputs like ".WAV" or "Wav" are correctly recognized.

In `@src/lib/utils/sttProcessor.ts`:
- Around line 347-398: Import the existing withTimeout helper from the utils
module and wrap the provider discovery promises to avoid hangs: in
getLanguages() replace the direct return of handler.getLanguages() with an
awaited withTimeout(handler.getLanguages(), <timeoutMs>) (and do the same in
getModels()); ensure you import withTimeout at the top and await the wrapper,
and if desired catch a timeout error and rethrow an STTError that includes
STT_ERROR_CODES.PROVIDER_NOT_SUPPORTED or a new timeout-specific code and the
provider context to preserve error semantics.
- Around line 129-180: Replace the exported STTHandler interface with an
exported type alias named STTHandler while preserving the exact shape (methods
transcribe, getLanguages, getModels, isConfigured and readonly properties
maxAudioSizeMB and maxDurationSeconds) and JSDoc comments; ensure the transcribe
signature Promise<STTResult>, optional methods are marked optional, and exported
name remains STTHandler so existing imports (and references to transcribe,
getLanguages, getModels, isConfigured, maxAudioSizeMB, maxDurationSeconds)
continue to work.

Comment thread CHANGELOG.md
Comment thread docs/features/stt.md Outdated
Comment thread src/cli/factories/commandFactory.ts
Comment thread src/lib/neurolink.ts Outdated
@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 2 times, most recently from 17f6cb5 to f6dccbd Compare February 17, 2026 08:10
@shambhavik-25

Copy link
Copy Markdown
Author

@coderabbitai can you check if all the previous comments have been addressed?

@coderabbitai

coderabbitai Bot commented Feb 17, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@shambhavik-25, I'll check all previous review comments on PR #793 to verify their resolution status.


🏁 Script executed:

#!/bin/bash

# Fetch all review comments from PR `#793` and check their status
echo "=== Fetching all review comments from PR `#793` ==="
gh pr view 793 --repo juspay/neurolink --json reviews,comments --jq '.reviews[] | {id: .id, state: .state, author: .author.login, body: .body, submittedAt: .submittedAt}' 2>&1

echo ""
echo "=== Fetching review threads (comment threads) ==="
# Get review threads with their resolution status
gh api graphql -f query='
query($owner: String!, $repo: String!, $number: Int!) {
  repository(owner: $owner, name: $repo) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          id
          isResolved
          isOutdated
          comments(first: 100) {
            nodes {
              author {
                login
              }
              body
              createdAt
              isMinimized
            }
          }
        }
      }
    }
  }
}' -f owner='juspay' -f repo='neurolink' -F number=793 2>&1

echo ""
echo "=== Fetching all issue comments on the PR ==="
gh pr view 793 --repo juspay/neurolink --json comments --jq '.comments[] | {author: .author.login, body: .body, createdAt: .createdAt}' 2>&1

Length of output: 135989


@shambhavik-25, I've checked all previous review comments on PR #793. Here's the status:

✅ Summary: All Previous Comments Are Resolved

Total review threads analyzed: 22

  • All threads marked as resolved: ✅ Yes (100%)
  • Threads that are outdated (code changed since comment): 13
  • Threads still relevant but resolved: 9

📊 Breakdown by Review Date

January 29, 2026 (First Review)

  • 13 actionable comments
  • Status: All resolved, majority outdated (code has changed)

February 16, 2026 (Second Review)

  • 6 actionable comments + 7 nitpick comments
  • Status: All resolved, mix of outdated and current

February 17, 2026 (Third Review)

  • 4 actionable comments
  • Status: All resolved, still relevant to current code

🔍 Key Areas That Were Addressed

The resolved comments covered:

  1. ✅ CLI command structure and STT model choices
  2. ✅ Error handling with ErrorFactory and withTimeout utilities
  3. ✅ Documentation improvements (removed GOOGLE_AI_API_KEY, fixed code blocks)
  4. ✅ STT configuration in buildGenerateOptions
  5. ✅ File validation and audio input handling
  6. ✅ Output handling in quiet mode
  7. ✅ Multi-segment transcription support
  8. ✅ CHANGELOG updates
  9. ✅ Type consistency and code cleanup

All review threads have been marked as resolved by the development team, indicating that the feedback has been either implemented through code changes or discussed and closed. The PR appears to have addressed all previous review feedback comprehensively.


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Comment thread docs/features/stt.md Outdated
Comment thread docs/features/stt.md
Comment thread docs/features/stt.md Outdated
Comment thread docs/features/stt.md Outdated
Comment thread docs/features/stt.md
Comment thread package.json Outdated
Comment thread CHANGELOG.md
@murdore

murdore commented Feb 17, 2026

Copy link
Copy Markdown
Contributor

@shambhavik-25 code approach is not correct. Can you check other multi-modality pull requests that have been merged and verify all the changes according to that? This will include documentation, usage and other changes.

@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 4 times, most recently from 38ec7b2 to d8f3e15 Compare February 19, 2026 11:50
@shambhavik-25

Copy link
Copy Markdown
Author

@coderabbitai can you please review my pr?

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@shambhavik-25, I'll review PR #793 and compare the STT implementation approach with other merged multi-modality PRs (particularly TTS) to ensure architectural consistency, as suggested by @murdore.


🏁 Script executed:

#!/bin/bash

# Search for TTS-related merged PRs to understand the multi-modality pattern
echo "=== Searching for merged TTS PRs ==="
gh pr list --repo juspay/neurolink --state merged --search "TTS" --limit 10 --json number,title,mergedAt,author 2>&1

echo ""
echo "=== Searching for other multi-modality PRs ==="
gh pr list --repo juspay/neurolink --state merged --search "modality OR multimodal" --limit 10 --json number,title,mergedAt,author 2>&1

echo ""
echo "=== Getting details of TTS implementation PR `#693` ==="
gh pr view 693 --repo juspay/neurolink --json title,body,files 2>&1 | head -100

echo ""
echo "=== Checking TTS-related files in the codebase ==="
fd -t f "tts" --exec echo {} \;

echo ""
echo "=== Examining TTSProcessor structure ==="
cat src/lib/utils/ttsProcessor.ts | head -150

echo ""
echo "=== Examining TTS handler registration in providerRegistry ==="
rg -n -A10 -B2 "TTSProcessor" src/lib/factories/providerRegistry.ts

echo ""
echo "=== Checking how TTS is integrated in neurolink.ts ==="
rg -n -A15 "generateTTS|getTTSVoices" src/lib/neurolink.ts

Length of output: 17177


🏁 Script executed:

#!/bin/bash

echo "=== Checking baseProvider.ts for TTS integration ==="
rg -n -C5 "tts\?" src/lib/core/baseProvider.ts | head -80

echo ""
echo "=== Checking baseProvider.ts for STT integration (should exist but doesn't?) ==="
rg -n "stt" src/lib/core/baseProvider.ts || echo "No STT integration found in baseProvider.ts"

echo ""
echo "=== Checking how TTS generateTTS is implemented in neurolink.ts ==="
cat src/lib/neurolink.ts | grep -A30 "private async generateTTS" | head -35

echo ""
echo "=== Checking how STT generateSTT is implemented in neurolink.ts ==="
cat src/lib/neurolink.ts | grep -A40 "private async generateSTT"

echo ""
echo "=== Checking TTS documentation structure ==="
head -100 docs/features/tts.md

echo ""
echo "=== Checking STT documentation structure ==="
head -100 docs/features/stt.md

echo ""
echo "=== Comparing TTS and STT exports in index.ts ==="
cat src/lib/index.ts

echo ""
echo "=== Checking if TTS has a similar direct method in neurolink or goes through baseProvider ==="
rg -n "\.generateTTS\(|options\.tts" src/lib/neurolink.ts | head -20

Length of output: 33710


🏁 Script executed:

#!/bin/bash

echo "=== Checking if neurolink.generate() routes to generateSTT ==="
rg -n -B5 -A10 "generateSTT" src/lib/neurolink.ts

echo ""
echo "=== Checking baseProvider.generate for the main flow ==="
cat src/lib/core/baseProvider.ts | grep -n -B3 -A3 "async generate\(" | head -30

echo ""
echo "=== Checking if other modalities (video, image gen) follow baseProvider pattern ==="
rg -n "generateVideo|generateImage" src/lib/neurolink.ts | head -10

echo ""
echo "=== Checking if there's a generateTTS method in neurolink.ts ==="
rg -n "generateTTS" src/lib/neurolink.ts

echo ""
echo "=== Looking at how TTS is called in CLI ==="
rg -n -A10 "options\.tts" src/cli/factories/commandFactory.ts | head -40

echo ""
echo "=== Looking at how STT is called in CLI ==="
rg -n -B3 -A10 "isSTTMode|generateSTT" src/cli/factories/commandFactory.ts | head -50

Length of output: 4399


🏁 Script executed:

#!/bin/bash

echo "=== Checking the PR description for TTS `#693` to understand the pattern better ==="
gh pr view 693 --repo juspay/neurolink --json body --jq '.body' | head -150

echo ""
echo "=== Checking all changes in baseProvider from TTS PR `#693` ==="
gh pr diff 693 --repo juspay/neurolink -- src/lib/core/baseProvider.ts | head -200

echo ""
echo "=== Checking all changes in neurolink.ts from TTS PR `#693` ==="
gh pr diff 693 --repo juspay/neurolink -- src/lib/neurolink.ts | head -100

echo ""
echo "=== Checking for video generation implementation pattern ==="
rg -n "video.*generate|generateVideo" src/lib/core/baseProvider.ts || echo "No video generation in baseProvider"

echo ""
echo "=== Checking image generation implementation pattern ==="
rg -n "image.*generate" src/lib/core/baseProvider.ts | head -10

Length of output: 5836


🏁 Script executed:

#!/bin/bash

echo "=== Getting the full context of video generation in baseProvider.ts ==="
rg -n -B10 -A30 "generateVideoWithVertex" src/lib/core/baseProvider.ts

echo ""
echo "=== Checking the image generation approach in baseProvider.ts ==="
rg -n -B10 -A30 "Image generation mode detected" src/lib/core/baseProvider.ts

echo ""
echo "=== Comparing: How TTS, video, and image gen are integrated in baseProvider.generate() ==="
rg -n "Mode 1:|Mode 2:|Image generation mode|Video generation mode" src/lib/core/baseProvider.ts

echo ""
echo "=== Check if there's a pattern doc for multi-modality implementation ==="
fd -t f "implementation-plan|approach|pattern" docs/ memory-bank/ | head -10

echo ""
echo "=== Check TTS approach document ==="
cat memory-bank/tts-provider-implementation-plan.md | head -100

Length of output: 7926


@shambhavik-25, I've completed a comprehensive review comparing this STT implementation with other merged multi-modality PRs (particularly TTS #693). I found a critical architectural mismatch that explains @murdore's feedback about the code approach being incorrect.

🔴 Critical Issue: STT Does NOT Follow the Established Multi-modality Pattern

Current Implementation (Incorrect)

Your STT implementation uses a separate routing path that bypasses the core baseProvider.generate() flow:

In src/lib/neurolink.ts (lines 2163-2165):

// Check if STT output requested (audio transcription)
if (options.stt) {
  return this.generateSTT(options);  // ❌ Bypasses baseProvider
}

Problem: This creates a generateSTT() private method that handles the entire flow independently, inconsistent with how other modalities work.


How TTS Implements It (Correct Pattern) ✅

TTS PR #693 integrated directly into baseProvider.generate() with two operational modes:

In src/lib/core/baseProvider.ts:

// ===== TTS MODE 1: Direct Input Synthesis (useAiResponse=false) =====
if (options.tts?.enabled && !options.tts?.useAiResponse) {
  // Synthesize input text directly WITHOUT AI generation
  const textToSynthesize = options.prompt ?? options.input?.text ?? "";
  // ... synthesis logic ...
  return baseResult; // Return early with audio
}

// ... Normal AI generation flow ...

// ===== TTS MODE 2: AI Response Synthesis (useAiResponse=true) =====
if (options.tts?.enabled && options.tts?.useAiResponse) {
  // Synthesize AI-generated response AFTER generation
  // ... synthesis logic ...
  enhancedResult.audio = audioResult;
}

Key Points:

  • No separate generateTTS() method in neurolink.ts
  • Integrated directly into baseProvider.generate()
  • Two modes: direct processing OR AI-enhanced processing
  • Follows consistent architecture

How Video Generation Implements It (Another Example) ✅

In src/lib/core/baseProvider.ts (lines 1319-1502):

private async handleVideoGeneration(
  options: TextGenerationOptions,
  startTime: number,
): Promise<EnhancedGenerateResult> {
  const { generateVideoWithVertex, VideoError, VIDEO_ERROR_CODES } =
    await import("../adapters/video/vertexVideoHandler.js");
  // ... video generation logic directly in baseProvider ...
  return await this.enhanceResult(baseResult, options, startTime);
}

Called from within baseProvider.generate() - not from neurolink.ts routing.


📋 Required Changes

1. Remove STT Routing from neurolink.ts

Remove these lines from src/lib/neurolink.ts (2163-2165):

// Check if STT output requested (audio transcription)
if (options.stt) {
  return this.generateSTT(options);  // ❌ DELETE THIS
}

Remove the entire generateSTT() method (lines 1937-2007).


2. Integrate STT into baseProvider.generate()

Add to src/lib/core/baseProvider.ts within the generate() method:

// ===== STT: Audio Transcription =====
// Check for audio transcription request before AI generation
if (options.stt && options.input?.audioFiles) {
  return await this.handleSTTTranscription(options, startTime);
}

// ... existing AI generation flow continues ...

Add the handler method in baseProvider.ts:

/**
 * Handle Speech-to-Text transcription
 * 
 * Converts audio input to text transcription using STT processor.
 * Can optionally pass transcription to AI for further processing.
 */
private async handleSTTTranscription(
  options: TextGenerationOptions,
  startTime: number,
): Promise<EnhancedGenerateResult> {
  const { STTProcessor } = await import("../utils/sttProcessor.js");
  
  // Get audio buffer from input
  const audioFile = options.input.audioFiles![0];
  const audioBuffer = Buffer.isBuffer(audioFile) 
    ? audioFile 
    : await this.readAudioFile(audioFile);
  
  const provider = options.provider || this.providerName;
  
  // Transcribe audio
  const transcription = await STTProcessor.transcribe(
    audioBuffer,
    provider,
    options.stt!
  );
  
  // Build result with transcription
  const baseResult: EnhancedGenerateResult = {
    content: transcription.text,
    provider,
    model: options.model || transcription.metadata?.model || "unknown",
    usage: { input: 0, output: 0, total: 0 },
    transcription,
  };
  
  return await this.enhanceResult(baseResult, options, startTime);
}

3. Move STT Methods to baseProvider

Move these public methods from neurolink.ts to baseProvider.ts:

// In baseProvider.ts
public async getSTTLanguages(provider?: string): Promise<string[]> {
  const { STTProcessor } = await import("../utils/sttProcessor.js");
  return STTProcessor.getLanguages(provider || this.providerName);
}

public async getSTTModels(provider?: string): Promise<string[]> {
  const { STTProcessor } = await import("../utils/sttProcessor.js");
  return STTProcessor.getModels(provider || this.providerName);
}

Then expose them in neurolink.ts by delegating:

// In neurolink.ts
public async getSTTLanguages(provider?: string): Promise<string[]> {
  const baseProvider = await this.getProvider();
  return baseProvider.getSTTLanguages(provider);
}

public async getSTTModels(provider?: string): Promise<string[]> {
  const baseProvider = await this.getProvider();
  return baseProvider.getSTTModels(provider);
}

📚 Reference PRs to Study

  1. TTS Integration PR #693

    • Perfect example of two-mode integration
    • Shows baseProvider.generate() integration pattern
    • View PR
  2. Video Generation

    • Shows handleVideoGeneration pattern in baseProvider
    • No separate routing in neurolink.ts
  3. Multimodal Architecture PR #253

    • Foundation for multi-modality patterns
    • View PR

🎯 Summary

The core issue is architectural inconsistency: STT currently bypasses the standard baseProvider.generate() flow that all other modalities use. To fix this:

  1. Delete the generateSTT() method and routing logic from neurolink.ts
  2. Integrate STT handling directly into baseProvider.generate() following the TTS two-mode pattern
  3. Move STT discovery methods (getSTTLanguages, getSTTModels) to baseProvider.ts
  4. Study TTS PR #693 carefully - it's the exact pattern you should follow

This will ensure STT follows the same architectural patterns as TTS, video, and other modalities, maintaining consistency across the codebase.

Would you like me to provide more detailed code examples for any specific part of the refactoring?


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.

@shambhavik-25

Copy link
Copy Markdown
Author

@coderabbitai can you help me with refactoring it?

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@shambhavik-25, I'll help you refactor the STT implementation to follow the proper multi-modality pattern. Let me first examine the current code structure to create an accurate refactoring plan.


🏁 Script executed:

#!/bin/bash

echo "=== Current STT routing in neurolink.ts ==="
cat src/lib/neurolink.ts | grep -n -B5 -A50 "Check if STT output requested"

echo ""
echo "=== Current generateSTT method in neurolink.ts ==="
cat src/lib/neurolink.ts | grep -n -B3 -A80 "private async generateSTT"

echo ""
echo "=== Current STT methods in neurolink.ts ==="
cat src/lib/neurolink.ts | grep -n -B2 -A20 "getSTTLanguages\|getSTTModels"

echo ""
echo "=== Checking baseProvider.generate() structure for integration point ==="
cat src/lib/core/baseProvider.ts | grep -n -A100 "async generate(" | head -120

echo ""
echo "=== Checking if baseProvider has readAudioFile or similar helper ==="
rg -n "readAudioFile|readFile.*audio" src/lib/core/baseProvider.ts || echo "No readAudioFile helper found"

echo ""
echo "=== Checking CLI integration for STT ==="
rg -n -B5 -A10 "isSTTMode|options.stt" src/cli/factories/commandFactory.ts | head -80

Length of output: 13633


Perfect! I now have a complete picture of the current implementation. Let me create a detailed refactoring plan that follows the TTS pattern.

Refactoring Plan: Move STT to baseProvider Pattern

This refactoring will align STT with the established multi-modality architecture by integrating it into baseProvider.generate() following the TTS pattern from PR #693.

Overview:

  1. Add STT mode detection in baseProvider.generate() (before AI generation)
  2. Create handleSTTTranscription method in baseProvider
  3. Add audio file reading helper in baseProvider
  4. Move STT discovery methods to baseProvider
  5. Remove old STT implementation from neurolink.ts


Testing Checklist

After implementing these changes, verify:

  1. STT transcription works: Test with CLI neurolink generate --file audio.wav --stt-language en-US
  2. STT discovery works: Test neurolink stt languages and neurolink stt models
  3. Error handling: Test with invalid audio files, unsupported providers
  4. No regressions: Ensure TTS, video, and normal generation still work
  5. Type safety: Run npm run type-check to verify TypeScript compilation
  6. Integration tests: Verify existing tests pass

Summary

This refactoring:

  • ✅ Aligns STT with established multi-modality patterns (TTS, video, image)
  • ✅ Centralizes STT logic in baseProvider.ts
  • ✅ Removes code duplication from neurolink.ts
  • ✅ Maintains consistent error handling and logging
  • ✅ Preserves all existing functionality
  • ✅ Follows architectural patterns from merged PRs #693, #253

The implementation mirrors TTS Mode 1 (direct processing without AI generation) and follows the same handler delegation pattern used by video and image generation.


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.

💡 Use @coderabbitai plan to create a plan for code changes

@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch 3 times, most recently from e6e1e6d to 2b55532 Compare February 19, 2026 18:33
@shambhavik-25

shambhavik-25 commented Feb 19, 2026

Copy link
Copy Markdown
Author

@coderabbitai can you please review if the pr is in accordance to the established multi-modality architecture?

@coderabbitai

coderabbitai Bot commented Feb 19, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

echo "=== Checking if neurolink.ts still has STT routing (should be removed) ==="
rg -n "if \(options\.stt\)" src/lib/neurolink.ts || echo "No STT routing found (good!)"

echo ""
echo "=== Checking if generateSTT method exists in neurolink.ts (should be removed) ==="
rg -n "private async generateSTT" src/lib/neurolink.ts || echo "No generateSTT method found (good!)"

echo ""
echo "=== Checking if baseProvider.generate() has STT mode detection ==="
rg -n -B3 -A10 "STT MODE|options\.stt.*handleSTT" src/lib/core/baseProvider.ts || echo "No STT mode detection found in baseProvider"

echo ""
echo "=== Checking if baseProvider has handleSTTTranscription method ==="
rg -n -A5 "handleSTTTranscription|Handle Speech-to-Text" src/lib/core/baseProvider.ts || echo "No handleSTTTranscription method found"

echo ""
echo "=== Checking if baseProvider has STT discovery methods ==="
rg -n -A3 "getSTTLanguages|getSTTModels" src/lib/core/baseProvider.ts || echo "No STT discovery methods in baseProvider"

echo ""
echo "=== Checking neurolink.ts STT methods (should delegate to baseProvider) ==="
rg -n -B2 -A15 "async getSTTLanguages|async getSTTModels" src/lib/neurolink.ts

echo ""
echo "=== Comparing: How is TTS integrated in baseProvider.generate()? ==="
rg -n -B2 -A8 "TTS MODE 1|options\.tts.*enabled.*useAiResponse" src/lib/core/baseProvider.ts | head -30

echo ""
echo "=== Checking baseProvider.generate() method structure around line 690 ==="
cat src/lib/core/baseProvider.ts | sed -n '680,720p'

Length of output: 4692


🏁 Script executed:

#!/bin/bash

echo "=== Finding where handleSTTTranscription is called ==="
rg -n "handleSTTTranscription" src/lib/core/baseProvider.ts

echo ""
echo "=== Checking the context around that call (line 902) ==="
cat src/lib/core/baseProvider.ts | sed -n '895,910p'

echo ""
echo "=== Checking neurolink.generate() method to see how it routes to baseProvider ==="
rg -n -B5 -A30 "async generate\(" src/lib/neurolink.ts | head -60

echo ""
echo "=== Checking if there's getSTTLanguages in baseProvider ==="
rg -n "getSTTLanguages" src/lib/core/baseProvider.ts || echo "getSTTLanguages not found in baseProvider"

echo ""
echo "=== Checking full STT mode detection logic in baseProvider.generate() ==="
cat src/lib/core/baseProvider.ts | sed -n '895,920p'

echo ""
echo "=== Checking what STTTranscription method returns ==="
cat src/lib/core/baseProvider.ts | sed -n '740,800p'

Length of output: 5578


🏁 Script executed:

#!/bin/bash

echo "=== Checking what sttOptionsValue is and where it comes from ==="
cat src/lib/core/baseProvider.ts | sed -n '880,905p'

echo ""
echo "=== Checking if neurolink.generate() routes through baseProvider ==="
rg -n "baseProvider\.generate\|this\.provider\.generate\|getProvider" src/lib/neurolink.ts | grep -A3 -B3 "generate"

echo ""
echo "=== Checking how neurolink.ts delegates to baseProvider for generation ==="
cat src/lib/neurolink.ts | sed -n '1968,2050p'

echo ""
echo "=== Looking for getSTTLanguages implementation in neurolink.ts ==="
rg -n "getSTTLanguages" src/lib/neurolink.ts || echo "getSTTLanguages not found in neurolink.ts"

echo ""
echo "=== Comparing TTS discovery methods delegation in neurolink.ts ==="
rg -n -B3 -A10 "getTTSVoices|getTTSLanguages" src/lib/neurolink.ts | head -40

echo ""
echo "=== Checking if neurolink uses getProvider pattern ==="
rg -n -B2 -A5 "async getProvider\(\)" src/lib/neurolink.ts

Length of output: 4432


🏁 Script executed:

#!/bin/bash

echo "=== Searching for how neurolink.generate delegates to provider ==="
cat src/lib/neurolink.ts | sed -n '2000,2150p'

echo ""
echo "=== Looking for provider instantiation and usage in neurolink ==="
rg -n "this\.provider\." src/lib/neurolink.ts | head -20

echo ""
echo "=== Checking if there's a provider property in NeuroLink class ==="
rg -n "private provider:|protected provider:|public provider:" src/lib/neurolink.ts

echo ""
echo "=== Looking for BaseProvider usage in neurolink ==="
rg -n "BaseProvider|getProvider" src/lib/neurolink.ts | head -20

echo ""
echo "=== Check CLI for how it calls generate ==="
rg -n -B5 -A10 "neurolink\.generate\(" src/cli/factories/commandFactory.ts | head -40

echo ""
echo "=== Check how TTS discovery methods work (for comparison) ==="
rg -n -B5 -A15 "getTTSVoices" src/lib/neurolink.ts

Length of output: 6949


🏁 Script executed:

#!/bin/bash

echo "=== Find where neurolink.generate calls the actual provider generate ==="
cat src/lib/neurolink.ts | sed -n '2130,2250p'

echo ""
echo "=== Search for createProvider or provider instantiation ==="
rg -n "createProvider|new.*Provider\(" src/lib/neurolink.ts | head -20

echo ""
echo "=== Look for where actual generation happens in neurolink ==="
rg -n "\.generate\(|result.*generate" src/lib/neurolink.ts | grep -v "generation:" | head -30

echo ""
echo "=== Check if there's a different pattern - look for provider factory ==="
rg -n "ProviderFactory|providerFactory" src/lib/neurolink.ts | head -20

echo ""
echo "=== Check end of neurolink.generate() to see final call ==="
cat src/lib/neurolink.ts | sed -n '2200,2300p'

Length of output: 10890


🏁 Script executed:

#!/bin/bash

echo "=== Finding generateTextInternal method ==="
rg -n -B3 -A40 "private async generateTextInternal\(|protected async generateTextInternal\(" src/lib/neurolink.ts | head -60

echo ""
echo "=== Verifying STT flow: neurolink.generate -> generateTextInternal -> provider.generate -> baseProvider.generate ==="
echo "Step 1: neurolink.generate calls generateTextInternal (line ~2175)"
echo "Step 2: Check what generateTextInternal does"

echo ""
echo "=== Check if baseProvider is actually called ==="
rg -n "AIProviderFactory\.createProvider" src/lib/neurolink.ts | head -10

echo ""
echo "=== Summary: Check the complete STT flow integration ==="
echo "1. CLI calls neurolink.generate(options) with options.stt"
echo "2. neurolink.generate passes options.stt to generateTextInternal"
echo "3. generateTextInternal creates provider via AIProviderFactory"
echo "4. provider.generate() is baseProvider.generate()"
echo "5. baseProvider.generate() checks for options.stt and routes to handleSTTTranscription"

echo ""
echo "=== Now verify remaining issues ==="
echo "Issue 1: baseProvider should have getSTTLanguages"
rg -n "getSTTLanguages" src/lib/core/baseProvider.ts

echo ""
echo "Issue 2: neurolink.getSTTModels should delegate to baseProvider"
cat src/lib/neurolink.ts | sed -n '1854,1866p'

echo ""
echo "=== Check if baseProvider has getSTTModels ==="
cat src/lib/core/baseProvider.ts | sed -n '830,860p'

Length of output: 4512


@shambhavik-25, I've completed a comprehensive review of the STT implementation against the established multi-modality architecture. Here's my assessment:

✅ What's Architecturally Correct### 1. Core STT Transcription Flow

The main transcription flow is correctly integrated into baseProvider.generate():

// In baseProvider.generate() (lines 895-902)
if (sttOptionsValue) {
  logger.info("[BaseProvider.generate] Routing to STT transcription", {
    provider: this.providerName,
  });
  return this.handleSTTTranscription(options, startTime);
}

Flow path:

  1. CLI → neurolink.generate(options) with options.stt
  2. generateTextInternal()
  3. AIProviderFactory.createProvider()
  4. provider.generate() (which is baseProvider.generate())
  5. baseProvider.generate() detects options.stt → routes to handleSTTTranscription()

This follows the established pattern used by:

  • Video generation (handleVideoGeneration)
  • TTS Mode 1 (direct synthesis)
  • Image generation

❌ What's Architecturally Incorrect

2. STT Discovery Methods Missing/Incomplete

Issue A: baseProvider is missing getSTTLanguages()

Only getSTTModels() exists in baseProvider (line 850). Compare with TTS which has both discovery methods properly implemented in baseProvider.

Issue B: neurolink.getSTTModels() bypasses delegation pattern

Current implementation (lines 1854-1866):

async getSTTModels(providerName?: string): Promise<string[]> {
  // ... initialization ...
  const { STTProcessor } = await import("./utils/sttProcessor.js");
  return STTProcessor.getModels(provider); // ❌ Direct call
}

Should delegate to baseProvider:

async getSTTModels(providerName?: string): Promise<string[]> {
  const baseProvider = await this.getProvider();
  return baseProvider.getSTTModels(providerName); // ✅ Delegation
}

Issue C: neurolink is missing getSTTLanguages() entirely


🔧 Required Fixes

Fix 1: Add getSTTLanguages() to baseProvider

File: src/lib/core/baseProvider.ts

Add this method after getSTTModels() (around line 854):

/**
 * Get available STT languages for this provider
 *
 * `@returns` Promise resolving to list of supported language codes
 *
 * `@example`
 * ```typescript
 * const languages = await provider.getSTTLanguages();
 * console.log(languages); // ['en-US', 'es-ES', 'fr-FR', ...]
 * ```
 */
async getSTTLanguages(): Promise<string[]> {
  return STTProcessor.getLanguages(this.providerName);
}

Fix 2: Update neurolink.getSTTModels() to delegate

File: src/lib/neurolink.ts (lines 1854-1866)

Replace the current implementation:

  async getSTTModels(providerName?: string): Promise<string[]> {
-   // Initialize provider registry if needed (but not full MCP)
-   if (!this.mcpInitialized) {
-     await this.initializeProviderRegistryInternal();
-   }
-
-   // Use provided provider name or default to google-ai for STT
-   const provider = providerName || "google-ai";
-
-   // Use STTProcessor directly to get models
-   const { STTProcessor } = await import("./utils/sttProcessor.js");
-   return STTProcessor.getModels(provider);
+   const provider = await AIProviderFactory.createProvider(
+     (providerName || "google-ai") as AIProviderName,
+     undefined,
+     undefined,
+     this.fileRegistry,
+   );
+   return provider.getSTTModels();
  }

Fix 3: Add getSTTLanguages() to neurolink

File: src/lib/neurolink.ts

Add this method near getSTTModels():

/**
 * Get available STT languages for a specific provider
 *
 * `@param` providerName - Provider name (defaults to "google-ai")
 * `@returns` Array of language codes
 *
 * `@example`
 * ```typescript
 * const languages = await neurolink.getSTTLanguages('google-ai');
 * console.log(languages); // ['en-US', 'es-ES', 'fr-FR', ...]
 * ```
 *
 * `@since` 9.8.0
 */
async getSTTLanguages(providerName?: string): Promise<string[]> {
  const provider = await AIProviderFactory.createProvider(
    (providerName || "google-ai") as AIProviderName,
    undefined,
    undefined,
    this.fileRegistry,
  );
  return provider.getSTTLanguages();
}

📊 Architecture Compliance Summary

Component Status Notes
STT transcription flow Correct Integrated into baseProvider.generate()
handleSTTTranscription() Correct Follows video generation pattern
Old routing removed Correct No generateSTT() in neurolink
baseProvider.getSTTModels() Correct Exists and implemented
baseProvider.getSTTLanguages() Missing Needs to be added
neurolink.getSTTModels() Incorrect Calls STTProcessor directly
neurolink.getSTTLanguages() Missing Doesn't exist

✅ Final Verdict

The STT implementation is ~85% architecturally correct:

  • Core transcription flow follows the multi-modality pattern
  • No separate routing in neurolink.ts
  • Integrated into baseProvider.generate()
  • Discovery methods don't follow the delegation pattern

The refactoring successfully moved STT transcription to baseProvider, but the discovery methods (getSTTLanguages, getSTTModels) were not fully migrated to follow the established delegation pattern seen in TTS.


Recommendation: Apply the 3 fixes above to achieve 100% architectural compliance with the established multi-modality patterns. The changes are straightforward and follow the delegation pattern where a first-level object receives a request and delegates said action to a second-level object.

Would you like me to generate a `` to implement these fixes?


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS architecture (PR `#693`), timeout handling for TTS synthesis is intentionally managed at the provider/handler level (within TTS handler implementations like GoogleTTSHandler), not at the BaseProvider orchestration level. This allows each provider to enforce its own timeout constraints appropriate to its synthesis capabilities.

Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/types/index.ts:58-62
Timestamp: 2025-09-17T18:14:34.960Z
Learning: RajuSudhar explained that in the Neurolink codebase, there are multiple ProviderConfig types causing inconsistency. One existing ProviderConfig type better suited the "ProviderConfig" name, so they renamed the less-suitable one to AIModelProviderConfig to free up the name. Adding backward compatibility aliases would worsen naming inconsistency rather than help. The remaining duplicates will be systematically deduplicated in the 07-Types-Module.md TODO as part of their phased refactor approach.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/utils/ttsProcessor.ts:318-319
Timestamp: 2025-12-18T15:21:37.311Z
Learning: In juspay/neurolink TTS implementation (PR `#693`), timeout handling for TTSProcessor.synthesize() is intentionally delegated to individual TTS handler implementations (e.g., GoogleTTSHandler) rather than enforced at the TTSProcessor orchestration level. This design allows each provider to implement its own timeout constraints appropriate to its API characteristics and requirements.

💡 Use @coderabbitai plan to create a plan for code changes

@shambhavik-25

Copy link
Copy Markdown
Author

We are not using getSTTLanguages() and getSTTModels() right now as per the requirement.

@shambhavik-25
shambhavik-25 force-pushed the BZ-48219-add-speech-to-text-support-in-neuro-link branch from 2b55532 to 11000e2 Compare February 20, 2026 11:22
Comment thread CHANGELOG.md

- **(generateText):** add prepareStep and toolChoice passthrough support for multi-step agentic generation ([4cd340a](https://github.com/juspay/neurolink/commit/4cd340af7d39f72006d09fe86569232d751dcd8d))

## [9.9.0](https://github.com/juspay/neurolink/compare/v9.8.0...v9.9.0) (2026-02-17)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Revert this change.

Comment thread package.json
{
"name": "@juspay/neurolink",
"version": "9.10.0",
"version": "9.9.0",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Revert this change.

*/
static createSTTCommands(): CommandModule {
return {
command: "stt <subcommand>",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this documented?

private static registered = false;
private static options: ProviderRegistryOptions = {
enableManualMCP: false, // Default to disabled for safety
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There are a lot of changes in your file. I feel I don't think you need to do so much change. Something seems wrong here.

@murdore

murdore commented Feb 21, 2026

Copy link
Copy Markdown
Contributor

@coderabbitai the review approach needs to be changed. You need to identify recently merged pull requests where we have done multi modality additions for different different use cases and The recent documentation updates that we have done identify all the gaps in the current pull request related to documentation the process for documentation and the recent updates that we have done Compare the pull request against the multi modality integrations and the amount of changes we need we have done there

@coderabbitai

coderabbitai Bot commented Feb 21, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

@murdore, I'll conduct a comprehensive review by examining recently merged multi-modality PRs and documentation updates to identify gaps in this STT implementation. Let me gather that information.


🏁 Script executed:

#!/bin/bash

echo "=== Finding recently merged multi-modality PRs ==="
gh pr list --repo juspay/neurolink --state merged --search "TTS OR video OR image OR multimodal OR modality" --limit 20 --json number,title,mergedAt,author,files | jq -r '.[] | "\(.number)|\(.title)|\(.mergedAt)|\(.author.login)"' | sort -t'|' -k3 -r

echo ""
echo "=== Getting details of recent TTS PR `#693` ==="
gh pr view 693 --repo juspay/neurolink --json title,body,mergedAt,files --jq '{title, mergedAt, filesChanged: [.files[].path]}'

echo ""
echo "=== Checking for recent documentation-related merged PRs ==="
gh pr list --repo juspay/neurolink --state merged --search "doc OR documentation OR guide" --limit 15 --json number,title,mergedAt,author | jq -r '.[] | "\(.number)|\(.title)|\(.mergedAt)"' | sort -t'|' -k3 -r | head -10

echo ""
echo "=== Examining documentation structure in docs/features/ ==="
fd -t f . docs/features/ --exec echo {}

echo ""
echo "=== Checking TTS documentation structure and content ==="
head -200 docs/features/tts.md

echo ""
echo "=== Checking if there are other feature docs to compare ==="
ls -la docs/features/

echo ""
echo "=== Looking for documentation guidelines or templates ==="
fd -t f -e md . docs/ | grep -i "guideline\|template\|standard\|process" || echo "No doc guidelines found"

echo ""
echo "=== Checking recent commits related to documentation ==="
git log --since="2025-01-01" --grep="doc\|documentation" --oneline --all | head -20

Length of output: 13919


🏁 Script executed:

#!/bin/bash

echo "=== Getting file changes from TTS PR `#693` to understand the pattern ==="
gh pr view 693 --repo juspay/neurolink --json files --jq '.files[] | {path: .path, additions: .additions, deletions: .deletions}' | jq -s 'sort_by(.path)'

echo ""
echo "=== Checking what documentation files were added/modified in TTS PR ==="
gh pr view 693 --repo juspay/neurolink --json files --jq '.files[] | select(.path | contains("doc")) | .path'

echo ""
echo "=== Getting the TTS PR diff for documentation files ==="
gh pr diff 693 --repo juspay/neurolink -- docs/ | head -500

echo ""
echo "=== Checking README.md for feature documentation links ==="
rg -n "features/|TTS|STT|multimodal" README.md || echo "No feature links in README"

echo ""
echo "=== Checking if there's a features index or overview ==="
cat docs/features/README.md 2>/dev/null || cat docs/README.md 2>/dev/null || echo "No features index found"

Length of output: 6778


🏁 Script executed:

#!/bin/bash

echo "=== Examining multimodal/video implementation PRs ==="
gh pr list --repo juspay/neurolink --state merged --search "video generation OR multimodal" --limit 10 --json number,title,mergedAt,files --jq '.[] | {number, title, mergedAt, docFiles: [.files[] | select(.path | contains("doc")) | .path]}'

echo ""
echo "=== Checking current STT documentation in PR `#793` ==="
cat docs/features/stt.md | head -300

echo ""
echo "=== Comparing structure: Count sections in TTS vs STT docs ==="
echo "TTS sections:"
rg "^##" docs/features/tts.md | wc -l
echo ""
echo "STT sections:"
rg "^##" docs/features/stt.md | wc -l

echo ""
echo "=== Checking for examples directory ==="
fd -t d examples

echo ""
echo "=== Looking for STT examples in TTS or other docs ==="
fd -t f . examples/ docs/ | xargs rg -l "STT|speech.*text|transcri" 2>/dev/null | head -10

Length of output: 12346


🏁 Script executed:

#!/bin/bash

echo "=== Checking CHANGELOG.md entries for multi-modality features ==="
rg -n "TTS|video|multimodal|speech" CHANGELOG.md | head -30

echo ""
echo "=== Examining recent CHANGELOG structure and format ==="
head -100 CHANGELOG.md

echo ""
echo "=== Checking main package.json for new dependencies in STT PR ==="
rg "@google-cloud/speech" package.json -A2 -B2

echo ""
echo "=== Comparing: What dependencies did TTS add? ==="
git log --all --source --grep="google-cloud/text-to-speech" --oneline | head -5

echo ""
echo "=== Checking if there's a memory-bank or planning doc for STT ==="
fd -t f . memory-bank/ | grep -i "stt\|speech" || echo "No STT planning docs"

echo ""
echo "=== Checking TTS planning/design docs ==="
fd -t f . memory-bank/ | grep -i "tts\|text-to-speech"

Length of output: 10209


🏁 Script executed:

#!/bin/bash

echo "=== Looking at CLI command structure for TTS ==="
rg -n "createTTSCommands|TTS.*Command" src/cli/factories/commandFactory.ts || rg -n "tts" src/cli/parser.ts | head -20

echo ""
echo "=== Looking at CLI command structure for STT in current PR ==="
rg -n "createSTTCommands|STT.*Command" src/cli/factories/commandFactory.ts || rg -n "stt" src/cli/parser.ts | head -20

echo ""
echo "=== Checking CLI help/examples comparison ==="
echo "TTS commands:"
rg "command.*tts|tts.*subcommand" src/cli/ -i | head -10
echo ""
echo "STT commands:"
rg "command.*stt|stt.*subcommand" src/cli/ -i | head -10

echo ""
echo "=== Checking exports comparison: TTS vs STT ==="
echo "TTS exports in index.ts:"
rg "TTS" src/lib/index.ts
echo ""
echo "STT exports in index.ts:"
rg "STT" src/lib/index.ts

Length of output: 771


@murdore, I've conducted a comprehensive analysis comparing PR #793 against recently merged multi-modality PRs and documentation patterns. Let me gather additional details about the most recent similar PR and documentation structure.


🏁 Script executed:

#!/bin/bash

echo "=== Analyzing most recent video-analysis PR `#824` (Feb 17, 2026) ==="
gh pr view 824 --repo juspay/neurolink --json title,body,files,mergedAt --jq '{title, mergedAt, body: .body[0:500], filesChanged: [.files[].path]}'

echo ""
echo "=== Checking video-analysis documentation structure ==="
cat docs/features/video-analysis.md

echo ""
echo "=== Checking docs/features/index.md for feature listing ==="
cat docs/features/index.md | head -150

echo ""
echo "=== Checking README.md feature table structure ==="
rg -n "^\|.*\|.*\|.*\|" README.md | head -50

echo ""
echo "=== Checking if STT is mentioned in README.md ==="
rg -n "STT|Speech-to-Text|speech.*text" README.md || echo "No STT mention in README"

echo ""
echo "=== Checking if STT is in docs/features/index.md ==="
rg -n "STT|Speech-to-Text|stt.md" docs/features/index.md || echo "No STT in features index"

Length of output: 31429


🏁 Script executed:

#!/bin/bash

echo "=== Examining TTS documentation (for pattern reference) ==="
cat docs/features/tts.md | tail -100

echo ""
echo "=== Comparing STT documentation ending ==="
cat docs/features/stt.md | tail -100

echo ""
echo "=== Checking if there are code examples for TTS ==="
fd -t f . examples/ | xargs rg -l "tts|TTS|text.*speech" 2>/dev/null | head -10 || echo "No TTS examples in examples/"

echo ""
echo "=== Checking if there are code examples for video-analysis ==="
fd -t f . examples/ | xargs rg -l "video.*analysis|videoAnalysis" 2>/dev/null | head -10 || echo "No video-analysis examples"

echo ""
echo "=== Listing all example files ==="
fd -t f . examples/ | head -20

Length of output: 7634


🏁 Script executed:

#!/bin/bash

echo "=== Checking memory-bank TTS implementation plan structure ==="
head -100 memory-bank/tts-provider-implementation-plan.md

echo ""
echo "=== Checking what other planning docs exist in memory-bank ==="
fd -t f . memory-bank/ | head -20

echo ""
echo "=== Checking video generation planning docs ==="
fd -t f . memory-bank/ | xargs rg -l "video" || echo "No video planning docs"

echo ""
echo "=== Analyzing CHANGELOG entry format for recent features ==="
rg -n -A5 "video-analysis|file.*processor|rag.*document" CHANGELOG.md | head -40

Length of output: 6742


🏁 Script executed:

#!/bin/bash

echo "=== Checking if docs/features/index.md links to all features ==="
cat docs/features/index.md

echo ""
echo "=== Verify STT exports are complete compared to TTS ==="
echo "TTS exports:"
rg "export.*TTS" src/lib/index.ts src/lib/utils/ttsProcessor.ts
echo ""
echo "STT exports:"
rg "export.*STT" src/lib/index.ts src/lib/utils/sttProcessor.ts

Length of output: 37304


🏁 Script executed:

#!/bin/bash

echo "=== Checking comprehensive feature comparison in README ==="
rg -n -B2 -A2 "Video Generation|File Processor|RAG|Context" README.md | grep "^\||^[0-9]" | head -60

echo ""
echo "=== Checking sidebar/navigation structure for docs ==="
cat docs-site/sidebars.ts 2>/dev/null || echo "Sidebars file not accessible"

echo ""
echo "=== Check if implementation guides mention STT ==="
fd -t f . docs/implementation-guides/ | head -10
rg -l "STT|speech.*text" docs/implementation-guides/ || echo "No STT in implementation guides"

Length of output: 17227


@murdore, I've completed a comprehensive analysis comparing PR #793 against recently merged multi-modality PRs. Here's my detailed findings:


🔍 Gap Analysis: STT PR #793 vs. Recent Multi-Modality Patterns

📊 Reference PRs Analyzed

PR # Feature Merged Date Pattern Quality
#824 Video Analysis Feb 17, 2026 ⭐⭐⭐⭐⭐ Best Reference
#809 File Processors Feb 6, 2026 ⭐⭐⭐⭐⭐
#810 RAG Feb 8, 2026 ⭐⭐⭐⭐⭐
#774 Video Generation (docs) Jan 22, 2026 ⭐⭐⭐⭐
#693 TTS Dec 18, 2025 ⭐⭐⭐⭐ Audio Modality

❌ Critical Gaps Identified

1. CHANGELOG.md Entry Missing 🚨

Current State: Version 9.8.0 CHANGELOG has NO STT entry

Expected Pattern (from video-analysis #824):

## [9.8.0](https://github.com/juspay/neurolink/compare/v9.7.0...v9.8.0) (2026-02-17)

### Features

- **(stt):** add speech-to-text support in neurolink using Google Cloud Speech-to-Text ([commit-hash])

Action Required:

# Add to CHANGELOG.md under version 9.8.0:

### Features

- **(stt):** add speech-to-text support in neurolink using Google Cloud Speech-to-Text with 7 specialized models, word-level timestamps, speaker diarization, and 8 audio format support

2. memory-bank Implementation Plan Missing 🚨

Observed Pattern: ALL recent multi-modality PRs include implementation plans

Examples Found:

  • memory-bank/tts-provider-implementation-plan.md (TTS)
  • memory-bank/video-analysis-implementation-plan.md (Video Analysis)
  • memory-bank/PPT-generation-implementation-plan.md (PPT)
  • Missing: memory-bank/stt-implementation-plan.md

Action Required:
Create memory-bank/stt-implementation-plan.md with:

  • Architecture overview
  • Implementation strategy
  • Provider integration approach
  • CLI/SDK usage patterns
  • Technical implementation details
  • Testing strategy

Reference Template: Use memory-bank/tts-provider-implementation-plan.md structure


3. docs/features/index.md Not Updated 🚨

Current State: STT is NOT listed in the features index

Action Required:
Add STT to docs/features/index.md under "Latest Features (Q1 2026)" section:

| :material-microphone-variant: **[Speech-to-Text (STT)](stt.md)** | Convert audio to text with Google Cloud Speech-to-Text. 7 specialized models, word-level timestamps, speaker diarization, 8 audio formats. |

4. Code Examples Missing 🚨

Observed Pattern:

  • ✅ Video-analysis: examples/video-analysis.ts
  • ✅ Image generation: examples/image-generation.ts
  • STT: No example files

Action Required:
Create examples/stt-transcription.ts:

import { NeuroLink } from "@juspay/neurolink";
import { readFileSync } from "fs";

/**
 * Speech-to-Text Examples
 * 
 * Demonstrates:
 * - Basic audio transcription
 * - Word-level timestamps
 * - Speaker diarization
 * - Multiple audio formats
 */

const neurolink = new NeuroLink();

// Example 1: Basic Transcription
async function basicTranscription() {
  const audioBuffer = readFileSync("./data/meeting.wav");
  
  const result = await neurolink.generate({
    input: {
      text: "Transcribe this audio",
      files: [audioBuffer],
    },
    provider: "google-ai",
    stt: {
      languageCode: "en-US",
      enableAutomaticPunctuation: true,
    },
  });
  
  console.log("Transcription:", result.transcription?.text);
  console.log("Confidence:", result.transcription?.confidence);
}

// Example 2: Word-Level Timestamps
async function timestampedTranscription() {
  const result = await neurolink.generate({
    input: {
      text: "Transcribe with timestamps",
      files: ["./data/presentation.mp3"],
    },
    provider: "google-ai",
    stt: {
      languageCode: "en-US",
      enableWordTimeOffsets: true,
      enableWordConfidence: true,
    },
  });
  
  result.transcription?.words?.forEach((word) => {
    console.log(
      `${word.word}: ${word.startTime}s - ${word.endTime}s (${word.confidence})`
    );
  });
}

// Example 3: Speaker Diarization
async function speakerDiarization() {
  const result = await neurolink.generate({
    input: {
      text: "Transcribe meeting with speaker identification",
      files: ["./data/conference-call.wav"],
    },
    provider: "google-ai",
    stt: {
      languageCode: "en-US",
      model: "phone_call",
      enableSpeakerDiarization: true,
      diarizationSpeakerCount: 3,
    },
  });
  
  console.log("Full Transcript:", result.transcription?.text);
  console.log("\nSpeaker-tagged words:");
  result.transcription?.words?.forEach((word) => {
    console.log(`Speaker ${word.speakerTag}: ${word.word}`);
  });
}

// Run examples
async function main() {
  console.log("=== Basic Transcription ===");
  await basicTranscription();
  
  console.log("\n=== Timestamped Transcription ===");
  await timestampedTranscription();
  
  console.log("\n=== Speaker Diarization ===");
  await speakerDiarization();
}

main().catch(console.error);

Also create example audio file in examples/data/:

  • Add a small sample audio file (public domain)
  • Or add README explaining where to get test audio

5. README.md Feature Table Missing ⚠️

Pattern Inconsistency Observed:

  • Video Generation: ✅ In README feature table
  • RAG: ✅ In README feature table
  • File Processors: ✅ In README feature table
  • TTS: ❌ NOT in README (but has docs)
  • Video Analysis: ❌ NOT in README (but has docs)

Recommendation: Add STT to README.md feature table to match video generation pattern:

| Feature                      | Version | Description                                                                                                                          | Guide                                               |
| ---------------------------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------- |
| **Speech-to-Text (STT)**     | v9.8.0  | Audio transcription with Google Cloud Speech-to-Text. 7 models, word timestamps, speaker diarization, 8 formats (WAV, MP3, FLAC...) | [STT Guide](docs/features/stt.md)                   |

Insert after "Video Generation with Veo" line (currently line 46).


📋 Documentation Quality Comparison

File Size & Structure:

Feature Doc Size Sections Example Code Quality Score
TTS 21,928 bytes 47 sections ✅ Extensive ⭐⭐⭐⭐⭐
STT 19,241 bytes 36 sections ✅ Good ⭐⭐⭐⭐
Video Analysis 5,015 bytes Short, focused ✅ Minimal ⭐⭐⭐⭐
Video Generation 38,176 bytes Comprehensive ✅ Extensive ⭐⭐⭐⭐⭐

Analysis: STT documentation is comprehensive and well-structured, comparable to TTS. Good coverage of features, configuration, troubleshooting.

Minor Improvement Suggestions:

  1. Add "Use Cases & Examples" section like TTS has
  2. Add pricing information section (like TTS)
  3. Add "Coming Soon" features section if applicable

✅ What's Correct in STT PR

  1. Documentation file exists - docs/features/stt.md (comprehensive)
  2. Architecture follows TTS pattern - Uses processor/handler pattern
  3. CLI integration - Has createSTTCommands() for discovery
  4. Type definitions - Complete STT types in src/lib/types/sttTypes.ts
  5. Error handling - STT_ERROR_CODES and STTError class
  6. Provider integration - Registered in providerRegistry.ts
  7. Exports - Properly exported in src/lib/index.ts

🎯 Action Items Summary

🚨 Critical (Must Fix):

  1. Add CHANGELOG.md entry for v9.8.0 with STT feature description
  2. Create memory-bank/stt-implementation-plan.md (use TTS as template)
  3. Update docs/features/index.md to include STT in features table
  4. Create examples/stt-transcription.ts with usage examples

⚠️ Important (Should Fix):

  1. Update README.md feature table to include STT
  2. Update docs-site/sidebars.ts if it exists in the repository

💡 Nice-to-Have:

  1. Add sample audio files to examples/data/
  2. Enhance STT docs with pricing section (like TTS)
  3. Add "Use Cases & Examples" section to docs

📝 Comparison: TTS vs STT Patterns

Aspect TTS (#693) STT (#793) Match?
Documentation ✅ Yes ✅ Yes
Implementation plan ✅ Yes No
CHANGELOG entry ✅ Yes No
README update ❌ No ❌ No
Features index ❌ No ❌ No
Code examples ❌ No No
Processor pattern ✅ Yes ✅ Yes
CLI discovery ✅ Yes ✅ Yes

Key Difference: Video-analysis (#824) is the better pattern - includes implementation plan and examples.


🔗 Reference Documents to Study

  1. Best Overall Pattern: PR #824 (video-analysis)

    • Implementation plan: memory-bank/video-analysis-implementation-plan.md
    • Example: examples/video-analysis.ts
    • CHANGELOG: Version 9.9.0 entry
  2. Audio Modality Reference: PR #693 (TTS)

    • Implementation plan: memory-bank/tts-provider-implementation-plan.md
    • Documentation: docs/features/tts.md
  3. Documentation Standard: PR #774 (video-generation docs)

    • Comprehensive guide: docs/features/video-generation.md
    • README integration

Would you like me to generate the missing files (implementation plan, examples, CHANGELOG entry) using the `` tag?


🧠 Learnings used
Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS integration (PR `#693`), when options.provider is "auto" and passed to TTSProcessor.synthesize, it will fail automatically during handler lookup since only concrete providers ("google-ai", "vertex") are registered as TTS handlers. No explicit validation against "auto" is needed—the implicit failure at handler registration lookup is by design.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 237
File: memory-bank/tts-provider-implementation-plan.md:92-106
Timestamp: 2025-11-17T13:53:20.209Z
Learning: In PR 237's TTS modality implementation approach, TTS functionality uses GOOGLE_AI_API_KEY (not GOOGLE_TTS_API_KEY) when using the google-ai provider. TTS is implemented as an output modality that leverages the existing google-ai provider authentication.

Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 173
File: src/lib/types/index.ts:58-62
Timestamp: 2025-09-17T18:14:34.960Z
Learning: RajuSudhar explained that in the Neurolink codebase, there are multiple ProviderConfig types causing inconsistency. One existing ProviderConfig type better suited the "ProviderConfig" name, so they renamed the less-suitable one to AIModelProviderConfig to free up the name. Adding backward compatibility aliases would worsen naming inconsistency rather than help. The remaining duplicates will be systematically deduplicated in the 07-Types-Module.md TODO as part of their phased refactor approach.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-12-15T18:35:37.783Z
Learning: In juspay/neurolink TTS implementation (PR `#691`), the new StreamChunk discriminated union type introduced in TTS-019 will be integrated with StreamResult.stream during the actual TTS streaming implementation PR (TTS-020/TTS-021), not in the type-definition PR. This phased approach keeps type updates and implementation changes atomic.

Learnt from: sudharsan-juspay
Repo: juspay/neurolink PR: 160
File: src/lib/providers/index.ts:43-44
Timestamp: 2025-09-10T08:22:11.910Z
Learning: In the Neurolink project, type deduplication across modules (like ProviderName definitions) should be handled as separate tasks rather than mixed with other refactoring efforts, as there are multiple such occurrences throughout the codebase that need systematic cleanup.

Learnt from: vigneshJuspay
Repo: juspay/neurolink PR: 693
File: src/lib/core/baseProvider.ts:490-517
Timestamp: 2025-12-18T15:13:28.435Z
Learning: In juspay/neurolink TTS architecture (PR `#693`), timeout handling for TTS synthesis is intentionally managed at the provider/handler level (within TTS handler implementations like GoogleTTSHandler), not at the BaseProvider orchestration level. This allows each provider to enforce its own timeout constraints appropriate to its synthesis capabilities.

Learnt from: CR
Repo: juspay/neurolink PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-02-14T02:42:22.821Z
Learning: Applies to test/**/*.test.ts : Mock external API calls for unit tests. Use real API calls sparingly in integration tests. Test provider consistency across all providers and validate multimodal content handling.

Learnt from: RajuSudhar
Repo: juspay/neurolink PR: 0
File: :0-0
Timestamp: 2025-11-04T22:14:18.719Z
Learning: In the juspay/neurolink repository, do not flag existing type or interface definitions located outside src/lib/types/ - these are part of a phased migration plan and will be addressed in upcoming PRs. Only enforce type centralization rules on new code going forward.

💡 Use @coderabbitai plan to create a plan for code changes

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.

3 participants