Skip to content

added 60DB services#14

Open
Dev-develope wants to merge 1 commit into
XimilalaXiang:mainfrom
Dev-develope:main
Open

added 60DB services#14
Dev-develope wants to merge 1 commit into
XimilalaXiang:mainfrom
Dev-develope:main

Conversation

@Dev-develope

@Dev-develope Dev-develope commented Jun 9, 2026

Copy link
Copy Markdown

Summary by CodeRabbit

  • New Features
    • Integrated Sixtydb as a new real-time speech-to-text provider with support for multiple languages.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This pull request integrates 60db Speech-to-Text as a new ASR provider into DeLive. It adds vendor types, a WebSocket proxy that bridges client requests to 60db's upstream API, a frontend provider implementation, registration infrastructure, and a UI logo component.

Changes

60db Speech-to-Text Provider

Layer / File(s) Summary
Type definitions for 60db vendor
frontend/src/types/asr/common.ts, frontend/src/types/asr/vendors/sixtydb.ts
ASRVendor enum adds Sixtydb entry; vendor types define default model, supported languages (multi for auto-detect), and server event shapes (transcription, session started, errors).
Backend WebSocket proxy core
shared/sixtydbProxyCore.ts
Proxy connects client WebSocket to wss://api.60db.ai/ws/stt upstream using API key from query params, forwards upstream connection_established + session_started handshake as ready message, translates transcription events to partial/final based on speech_final flag, passes binary audio frames through, converts audio_end/terminate control messages to upstream stop, and handles connection errors with user-friendly formatting.
Backend proxy server integration
server/src/index.ts, server/src/sixtydbProxy.ts
Express server creates WebSocketServer for proxy, handles /ws/sixtydb HTTP upgrade requests, and registers proxy connection handler via createSixtydbProxyServer(wss).
Frontend SixtydbProvider implementation
frontend/src/providers/implementations/SixtydbProvider.ts
Provider class connects to ws://localhost:23456/ws/sixtydb with API key and optional language params, waits for ready message, handles partial/final/error events by emitting provider events, supports audio via sendAudio() with Blob-to-ArrayBuffer conversion, and gracefully disconnects with optional audio_end message.
Provider registration and exports
frontend/src/providers/index.ts, frontend/src/providers/registry.ts
Export SixtydbProvider and register in default provider registry with capabilities, required apiKey config field, and supported languages.
Provider UI logo component
frontend/src/components/icons/ProviderLogos.tsx
Add SixtydbLogo SVG with stroked circle and "60db" text; register in PROVIDER_LOGO_MAP for UI rendering.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 A proxy hops to bridge the way,
From client calls to 60db's say,
With types and logos shining bright,
The STT provider takes its flight!
Whiskers twitch with joy,

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'added 60DB services' accurately reflects the main change: adding integration for 60db (Sixtydb) speech-to-text service across frontend types, providers, UI components, and a server-side WebSocket proxy.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@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: 3

🧹 Nitpick comments (1)
frontend/src/providers/implementations/SixtydbProvider.ts (1)

199-202: 💤 Low value

Guard against race condition in async Blob conversion.

If the WebSocket closes during the async arrayBuffer() call, this.ws could become null, causing the optional chaining to silently drop audio. Consider checking readiness after the await.

Proposed fix
    if (data instanceof Blob) {
      data.arrayBuffer().then(buffer => {
-       this.ws?.send(buffer)
+       if (this.ws && this.wsReady) {
+         this.ws.send(buffer)
+       }
      })
    } else {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/providers/implementations/SixtydbProvider.ts` around lines 199 -
202, In SixtydbProvider (the method sending audio blobs), avoid the race by
awaiting the Blob.arrayBuffer() call instead of using .then, then re-check that
this.ws exists and is open (WebSocket.readyState === WebSocket.OPEN) before
calling this.ws.send; also wrap the await/send in try/catch to handle errors and
avoid silently dropping audio when the socket closes during conversion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/src/providers/implementations/SixtydbProvider.ts`:
- Around line 92-98: The connect method in SixtydbProvider (connect(config:
ProviderConfig)) calls this.emitError(this.createError(...)) when apiKey is
missing but never rejects or throws, leaving the caller hanging; after emitting
the error you should reject the Promise by throwing the created error (or
returning Promise.reject) so callers receive the failure. Update the connect
implementation to create the error via this.createError('MISSING_API_KEY', '60db
API key is required'), call this.emitError(error), then throw that error (or
return Promise.reject(error)) so the Promise is settled.
- Around line 138-142: In the 'final' switch branch inside SixtydbProvider (the
case handling final messages) remove the call to this.emitFinished() so that
emitFinal(msg.text || '') is emitted without signaling session end; instead
ensure emitFinished() is only invoked from real session-termination paths (e.g.,
the session_stopped/disconnect handler or wherever session lifecycle is
explicitly closed) so multiple 'final' transcripts during continuous
transcription don't trigger end-of-session callbacks.

In `@shared/sixtydbProxyCore.ts`:
- Around line 197-201: The clientWs 'error' handler closes the upstream without
checking its WebSocket state, which can attempt to close an already-closed
connection; update the clientWs.on('error', ...) handler (the same handler that
sets clientClosed) to first check upstream.readyState (or upstream.readyState
=== WebSocket.OPEN/CONNECTING depending on your desired behavior) before calling
upstream.close(1000, 'Client error'), mirroring the readiness check used in the
clientWs.on('close') handler so upstream.close is only invoked when appropriate.

---

Nitpick comments:
In `@frontend/src/providers/implementations/SixtydbProvider.ts`:
- Around line 199-202: In SixtydbProvider (the method sending audio blobs),
avoid the race by awaiting the Blob.arrayBuffer() call instead of using .then,
then re-check that this.ws exists and is open (WebSocket.readyState ===
WebSocket.OPEN) before calling this.ws.send; also wrap the await/send in
try/catch to handle errors and avoid silently dropping audio when the socket
closes during conversion.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4c0f63f0-1419-4e8a-8aad-049a0b347ee7

📥 Commits

Reviewing files that changed from the base of the PR and between a982636 and 497a3e7.

📒 Files selected for processing (9)
  • frontend/src/components/icons/ProviderLogos.tsx
  • frontend/src/providers/implementations/SixtydbProvider.ts
  • frontend/src/providers/index.ts
  • frontend/src/providers/registry.ts
  • frontend/src/types/asr/common.ts
  • frontend/src/types/asr/vendors/sixtydb.ts
  • server/src/index.ts
  • server/src/sixtydbProxy.ts
  • shared/sixtydbProxyCore.ts

Comment on lines +92 to +98
async connect(config: ProviderConfig): Promise<void> {
const apiKey = config.apiKey as string

if (!apiKey) {
this.emitError(this.createError('MISSING_API_KEY', '60db API key is required'))
return
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject promise when API key is missing.

When apiKey is missing, emitError is called but the Promise returned by connect() is never resolved or rejected. This leaves the caller hanging indefinitely.

Proposed fix
  async connect(config: ProviderConfig): Promise<void> {
    const apiKey = config.apiKey as string

    if (!apiKey) {
-     this.emitError(this.createError('MISSING_API_KEY', '60db API key is required'))
-     return
+     const error = this.createError('MISSING_API_KEY', '60db API key is required')
+     this.emitError(error)
+     throw new Error(error.message)
    }
📝 Committable suggestion

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

Suggested change
async connect(config: ProviderConfig): Promise<void> {
const apiKey = config.apiKey as string
if (!apiKey) {
this.emitError(this.createError('MISSING_API_KEY', '60db API key is required'))
return
}
async connect(config: ProviderConfig): Promise<void> {
const apiKey = config.apiKey as string
if (!apiKey) {
const error = this.createError('MISSING_API_KEY', '60db API key is required')
this.emitError(error)
throw new Error(error.message)
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/providers/implementations/SixtydbProvider.ts` around lines 92 -
98, The connect method in SixtydbProvider (connect(config: ProviderConfig))
calls this.emitError(this.createError(...)) when apiKey is missing but never
rejects or throws, leaving the caller hanging; after emitting the error you
should reject the Promise by throwing the created error (or returning
Promise.reject) so callers receive the failure. Update the connect
implementation to create the error via this.createError('MISSING_API_KEY', '60db
API key is required'), call this.emitError(error), then throw that error (or
return Promise.reject(error)) so the Promise is settled.

Comment on lines +138 to +142
case 'final':
console.log('[SixtydbProvider] final:', msg.text)
this.emitFinal(msg.text || '')
this.emitFinished()
break

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Remove emitFinished() call on each final transcript.

Calling emitFinished() after every final message signals end of session repeatedly. In continuous transcription, multiple finals occur during a single session. emitFinished() should only be called when the session truly ends (e.g., on intentional disconnect or session_stopped).

Based on the downstream behavior in providerSession.ts, this could trigger unintended session-end callbacks multiple times.

Proposed fix
              case 'final':
                console.log('[SixtydbProvider] final:', msg.text)
                this.emitFinal(msg.text || '')
-               this.emitFinished()
                break
📝 Committable suggestion

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

Suggested change
case 'final':
console.log('[SixtydbProvider] final:', msg.text)
this.emitFinal(msg.text || '')
this.emitFinished()
break
case 'final':
console.log('[SixtydbProvider] final:', msg.text)
this.emitFinal(msg.text || '')
break
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/src/providers/implementations/SixtydbProvider.ts` around lines 138 -
142, In the 'final' switch branch inside SixtydbProvider (the case handling
final messages) remove the call to this.emitFinished() so that
emitFinal(msg.text || '') is emitted without signaling session end; instead
ensure emitFinished() is only invoked from real session-termination paths (e.g.,
the session_stopped/disconnect handler or wherever session lifecycle is
explicitly closed) so multiple 'final' transcripts during continuous
transcription don't trigger end-of-session callbacks.

Comment on lines +197 to +201
clientWs.on('error', (error) => {
console.error('[SixtydbProxy] client WebSocket error:', error)
clientClosed = true
upstream.close(1000, 'Client error')
})

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add readyState check before closing upstream on client error.

The clientWs.on('error') handler closes upstream without checking readyState, unlike the clientWs.on('close') handler on line 191. This could cause issues if the upstream is already closed.

Proposed fix
  clientWs.on('error', (error) => {
    console.error('[SixtydbProxy] client WebSocket error:', error)
    clientClosed = true
-   upstream.close(1000, 'Client error')
+   if (upstream.readyState === NodeWebSocket.OPEN) {
+     try { upstream.send(JSON.stringify({ type: 'stop' })) } catch { /* ignore */ }
+     upstream.close(1000, 'Client error')
+   }
  })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@shared/sixtydbProxyCore.ts` around lines 197 - 201, The clientWs 'error'
handler closes the upstream without checking its WebSocket state, which can
attempt to close an already-closed connection; update the clientWs.on('error',
...) handler (the same handler that sets clientClosed) to first check
upstream.readyState (or upstream.readyState === WebSocket.OPEN/CONNECTING
depending on your desired behavior) before calling upstream.close(1000, 'Client
error'), mirroring the readiness check used in the clientWs.on('close') handler
so upstream.close is only invoked when appropriate.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant