chore: remove parakeet service and configuration, switch completely to OpenRouter Whisper
This commit is contained in:
@@ -6,10 +6,6 @@ OpenRouterAPIKey=
|
|||||||
# Valid examples: anthropic/claude-3.5-haiku, anthropic/claude-3-haiku, anthropic/claude-haiku-4.5
|
# Valid examples: anthropic/claude-3.5-haiku, anthropic/claude-3-haiku, anthropic/claude-haiku-4.5
|
||||||
# OpenRouterModel=anthropic/claude-3.5-haiku
|
# OpenRouterModel=anthropic/claude-3.5-haiku
|
||||||
|
|
||||||
# Speech-to-Text Transcription Service (local Parakeet container endpoint)
|
|
||||||
# Defaults to: http://localhost:5092/v1/audio/transcriptions (or http://parakeet:5092/v1/audio/transcriptions in Docker)
|
|
||||||
# PARAKEET_URL=http://localhost:5092/v1/audio/transcriptions
|
|
||||||
|
|
||||||
# DeepL API (for scripts/translate-locales.mjs and scripts/translate-flyer.mjs)
|
# DeepL API (for scripts/translate-locales.mjs and scripts/translate-flyer.mjs)
|
||||||
# Free plan keys use api-free.deepl.com automatically (suffix :fx)
|
# Free plan keys use api-free.deepl.com automatically (suffix :fx)
|
||||||
DeepLAPIKey=
|
DeepLAPIKey=
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ services:
|
|||||||
OpenWeatherMapAPIKey: ${OpenWeatherMapAPIKey:-}
|
OpenWeatherMapAPIKey: ${OpenWeatherMapAPIKey:-}
|
||||||
OpenRouterAPIKey: ${OpenRouterAPIKey:-}
|
OpenRouterAPIKey: ${OpenRouterAPIKey:-}
|
||||||
OpenRouterModel: ${OpenRouterModel:-anthropic/claude-3.5-haiku}
|
OpenRouterModel: ${OpenRouterModel:-anthropic/claude-3.5-haiku}
|
||||||
PARAKEET_URL: ${PARAKEET_URL:-http://parakeet:5092/v1/audio/transcriptions}
|
|
||||||
SESSION_SECRET: ${SESSION_SECRET:-}
|
SESSION_SECRET: ${SESSION_SECRET:-}
|
||||||
ADMIN_USER_IDS: ${ADMIN_USER_IDS:-}
|
ADMIN_USER_IDS: ${ADMIN_USER_IDS:-}
|
||||||
NTFY_SERVER: ${NTFY_SERVER:-https://ntfy.sh}
|
NTFY_SERVER: ${NTFY_SERVER:-https://ntfy.sh}
|
||||||
@@ -67,14 +66,6 @@ services:
|
|||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
parakeet:
|
|
||||||
image: ghcr.io/achetronic/parakeet:latest
|
|
||||||
container_name: daagbox-staging-parakeet
|
|
||||||
restart: always
|
|
||||||
command: ["/app/parakeet", "-workers", "1"]
|
|
||||||
ports:
|
|
||||||
- "5092:5092"
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
name: daagbox-staging-pgdata
|
name: daagbox-staging-pgdata
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ services:
|
|||||||
OpenWeatherMapAPIKey: ${OpenWeatherMapAPIKey:-}
|
OpenWeatherMapAPIKey: ${OpenWeatherMapAPIKey:-}
|
||||||
OpenRouterAPIKey: ${OpenRouterAPIKey:-}
|
OpenRouterAPIKey: ${OpenRouterAPIKey:-}
|
||||||
OpenRouterModel: ${OpenRouterModel:-anthropic/claude-3.5-haiku}
|
OpenRouterModel: ${OpenRouterModel:-anthropic/claude-3.5-haiku}
|
||||||
PARAKEET_URL: ${PARAKEET_URL:-http://parakeet:5092/v1/audio/transcriptions}
|
|
||||||
SESSION_SECRET: ${SESSION_SECRET:-}
|
SESSION_SECRET: ${SESSION_SECRET:-}
|
||||||
ADMIN_USER_IDS: ${ADMIN_USER_IDS:-}
|
ADMIN_USER_IDS: ${ADMIN_USER_IDS:-}
|
||||||
NTFY_SERVER: ${NTFY_SERVER:-https://ntfy.sh}
|
NTFY_SERVER: ${NTFY_SERVER:-https://ntfy.sh}
|
||||||
@@ -68,14 +67,6 @@ services:
|
|||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
|
||||||
parakeet:
|
|
||||||
image: ghcr.io/achetronic/parakeet:latest
|
|
||||||
container_name: daagbox-prod-parakeet
|
|
||||||
restart: always
|
|
||||||
command: ["/app/parakeet", "-workers", "1"]
|
|
||||||
ports:
|
|
||||||
- "5092:5092"
|
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
pgdata:
|
pgdata:
|
||||||
name: daagbox-prod-pgdata
|
name: daagbox-prod-pgdata
|
||||||
|
|||||||
+28
-20
@@ -3,8 +3,6 @@ import { prisma } from '../db.js'
|
|||||||
import { requireUser } from '../middleware/auth.js'
|
import { requireUser } from '../middleware/auth.js'
|
||||||
|
|
||||||
const router = Router()
|
const router = Router()
|
||||||
|
|
||||||
const PARAKEET_URL = process.env.PARAKEET_URL || 'http://localhost:5092/v1/audio/transcriptions'
|
|
||||||
const MAX_ATTEMPTS_PER_ENTRY = 3
|
const MAX_ATTEMPTS_PER_ENTRY = 3
|
||||||
const DEFAULT_MODEL = 'anthropic/claude-3.5-haiku'
|
const DEFAULT_MODEL = 'anthropic/claude-3.5-haiku'
|
||||||
const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'
|
const OPENROUTER_URL = 'https://openrouter.ai/api/v1/chat/completions'
|
||||||
@@ -243,46 +241,56 @@ router.post('/transcribe', async (req: any, res) => {
|
|||||||
return res.status(400).json({ error: 'Invalid audio data URL format' })
|
return res.status(400).json({ error: 'Invalid audio data URL format' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const [, mimeType, base64Data] = match
|
const [, fullMimeType, base64Data] = match
|
||||||
const buffer = Buffer.from(base64Data, 'base64')
|
const mimeType = fullMimeType.split(';')[0]
|
||||||
|
|
||||||
let ext = 'webm'
|
let ext = 'webm'
|
||||||
if (mimeType.includes('mp4')) ext = 'mp4'
|
if (mimeType.includes('mp4')) ext = 'mp4'
|
||||||
else if (mimeType.includes('ogg')) ext = 'ogg'
|
else if (mimeType.includes('ogg')) ext = 'ogg'
|
||||||
else if (mimeType.includes('wav')) ext = 'wav'
|
else if (mimeType.includes('wav')) ext = 'wav'
|
||||||
|
|
||||||
const filename = `audio.${ext}`
|
const apiKey = resolveOpenRouterApiKey()
|
||||||
const file = new File([buffer], filename, { type: mimeType })
|
if (!apiKey) {
|
||||||
|
console.warn('[server] OpenRouter API key not configured, transcription unavailable')
|
||||||
|
return res.status(503).json({ error: 'Transcription service not configured' })
|
||||||
|
}
|
||||||
|
|
||||||
const formData = new FormData()
|
console.log(`[server] Forwarding ASR request to OpenRouter (${ext}, ${base64Data.length} chars)`)
|
||||||
formData.append('file', file)
|
|
||||||
|
|
||||||
console.log(`[server] Forwarding ASR request to ${PARAKEET_URL} (${filename}, ${buffer.length} bytes)`)
|
|
||||||
|
|
||||||
const controller = new AbortController()
|
const controller = new AbortController()
|
||||||
const timeoutId = setTimeout(() => controller.abort(), 15000)
|
const timeoutId = setTimeout(() => controller.abort(), 30000)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parakeetRes = await fetch(PARAKEET_URL, {
|
const openRouterRes = await fetch('https://openrouter.ai/api/v1/audio/transcriptions', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: formData,
|
headers: {
|
||||||
|
'Authorization': `Bearer ${apiKey}`,
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify({
|
||||||
|
model: 'openai/whisper-large-v3',
|
||||||
|
input_audio: {
|
||||||
|
data: base64Data,
|
||||||
|
format: ext
|
||||||
|
}
|
||||||
|
}),
|
||||||
signal: controller.signal
|
signal: controller.signal
|
||||||
})
|
})
|
||||||
|
|
||||||
if (!parakeetRes.ok) {
|
if (!openRouterRes.ok) {
|
||||||
const errorText = await parakeetRes.text().catch(() => '')
|
const errorText = await openRouterRes.text().catch(() => '')
|
||||||
console.error(`[server] Parakeet ASR error response (status=${parakeetRes.status}):`, errorText)
|
console.error(`[server] OpenRouter ASR error response (status=${openRouterRes.status}):`, errorText)
|
||||||
throw new Error(`Parakeet returned status ${parakeetRes.status}`)
|
throw new Error(`OpenRouter returned status ${openRouterRes.status}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: any = await parakeetRes.json()
|
const data: any = await openRouterRes.json()
|
||||||
const text = (data?.text || '').trim()
|
const text = (data?.text || '').trim()
|
||||||
|
|
||||||
console.log(`[server] ASR completed successfully: "${text}"`)
|
console.log(`[server] OpenRouter ASR completed successfully: "${text}"`)
|
||||||
return res.json({ text })
|
return res.json({ text })
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
if (error instanceof Error && error.name === 'AbortError') {
|
if (error instanceof Error && error.name === 'AbortError') {
|
||||||
console.error('[server] Parakeet ASR request timed out')
|
console.error('[server] OpenRouter ASR request timed out')
|
||||||
return res.status(504).json({ error: 'Transcription request timed out' })
|
return res.status(504).json({ error: 'Transcription request timed out' })
|
||||||
}
|
}
|
||||||
throw error
|
throw error
|
||||||
|
|||||||
Reference in New Issue
Block a user