# Deepgram Nova-2 für deutsche Spracherkennung: Production Guide **Meta-Description:** Optimierung von Deepgram Nova-2 für deutsche Sprache. Dialekterkennung, Fachvokabular-Boosting, Streaming-Integration und Produktions-Konfiguration. **Keywords:** Deepgram, Nova-2, German ASR, Speech-to-Text, Deutsche Spracherkennung, STT API, Voice Recognition Germany --- ## Einführung Deutsch ist eine **Tier-1-Sprache** bei Deepgram mit 5-10% Word Error Rate (WER). Doch für Production-Qualität braucht es Feintuning: Dialekte, Fachbegriffe, Komposita – die deutsche Sprache hat ihre Eigenheiten. --- ## Baseline Performance | Metrik | Nova-2 (Deutsch) | Whisper Large | Google STT | |--------|------------------|---------------|------------| | **WER** | 8-10% | 12-15% | 10-12% | | **Latenz** | ~150ms | ~2000ms | ~300ms | | **Preis/min** | $0.0043 | $0.006 | $0.016 | | **Streaming** | Ja | Nein | Ja | --- ## Basis-Setup für Deutsch ```typescript // src/services/deepgram-german.ts import { createClient, LiveTranscriptionEvents } from '@deepgram/sdk'; interface GermanASRConfig { model: 'nova-2' | 'nova-3'; language: 'de' | 'de-DE' | 'de-AT' | 'de-CH'; smartFormat: boolean; punctuate: boolean; diarize: boolean; keywords: string[]; endpointing: number; } const defaultGermanConfig: GermanASRConfig = { model: 'nova-2', language: 'de', smartFormat: true, punctuate: true, diarize: false, keywords: [], endpointing: 500 }; export class GermanASR { private client = createClient(process.env.DEEPGRAM_API_KEY!); async transcribeStream( config: Partial = {} ) { const finalConfig = { ...defaultGermanConfig, ...config }; const connection = this.client.listen.live({ model: finalConfig.model, language: finalConfig.language, smart_format: finalConfig.smartFormat, punctuate: finalConfig.punctuate, diarize: finalConfig.diarize, keywords: finalConfig.keywords, endpointing: finalConfig.endpointing, // Deutsche Spezialoptionen numerals: true, // "dreiundzwanzig" → "23" profanity_filter: false, // Für vollständige Transkription redact: false, replace: [], search: [], utterance_end_ms: 1000, interim_results: true }); return connection; } async transcribeFile( audioBuffer: Buffer, config: Partial = {} ) { const finalConfig = { ...defaultGermanConfig, ...config }; const result = await this.client.listen.prerecorded.transcribeFile( audioBuffer, { model: finalConfig.model, language: finalConfig.language, smart_format: finalConfig.smartFormat, punctuate: finalConfig.punctuate, diarize: finalConfig.diarize, keywords: finalConfig.keywords, // Für Batch: Zusätzliche Optionen paragraphs: true, summarize: 'v2', topics: true, intents: true, sentiment: true } ); return result; } } ``` --- ## Keyword Boosting für Fachvokabular ### Das Problem mit deutschen Fachbegriffen ``` Standard ASR: "Der Patient hat Rücken Syndrom" Mit Boosting: "Der Patient hat Rückensyndrom" Standard ASR: "Wir nutzen Kühn a tees" Mit Boosting: "Wir nutzen Kubernetes" ``` ### Implementation ```typescript // src/config/german-keywords.ts // Medizinische Begriffe const medicalKeywords = [ 'Rückensyndrom', 'Bandscheibenvorfall', 'Computertomografie', 'Magnetresonanztomografie', 'Blutdruckmessung', 'Cholesterinspiegel', 'Elektrokardiogramm', // ... weitere ]; // Tech-Begriffe const techKeywords = [ 'Kubernetes', 'TypeScript', 'PostgreSQL', 'WebSocket', 'Microservices', 'Containerisierung', 'Deployment', 'Repository', // ... weitere ]; // E-Commerce const ecommerceKeywords = [ 'Mehrwertsteuer', 'Rechnungsstellung', 'Gewährleistung', 'Widerrufsrecht', 'Versandkosten', 'Zahlungsabwicklung', // ... weitere ]; // Domain-spezifische Keywords zusammenstellen export function getKeywordsForDomain(domain: string): string[] { switch (domain) { case 'medical': return [...medicalKeywords, ...germanBaseKeywords]; case 'tech': return [...techKeywords, ...germanBaseKeywords]; case 'ecommerce': return [...ecommerceKeywords, ...germanBaseKeywords]; default: return germanBaseKeywords; } } // Basis-Keywords für alle Domains const germanBaseKeywords = [ // Zahlen (für bessere Erkennung) 'einundzwanzig', 'zweiunddreißig', 'fünfundvierzig', // Häufige Firmennamen 'Deutsche Bahn', 'Volkswagen', 'Siemens', 'Bosch', // Abkürzungen 'GmbH', 'AG', 'KG', 'e.V.' ]; ``` ### Keyword Boosting mit Intensitäten ```typescript // Deepgram unterstützt Keyword-Intensifier const boostedKeywords = [ 'Kubernetes:2', // Stark boosten 'PostgreSQL:2', 'Deployment:1', // Normal boosten 'Repository:1', 'GmbH:3' // Sehr stark boosten ]; const connection = deepgram.listen.live({ model: 'nova-2', language: 'de', keywords: boostedKeywords }); ``` --- ## Deutsche Dialekte ### Regionale Anpassungen ```typescript // src/config/german-dialects.ts type GermanDialect = | 'hochdeutsch' // Standard | 'bayerisch' | 'schwäbisch' | 'sächsisch' | 'plattdeutsch' | 'österreichisch' | 'schweizerdeutsch'; interface DialectConfig { languageCode: string; additionalKeywords: string[]; postProcessing: (text: string) => string; } const dialectConfigs: Record = { hochdeutsch: { languageCode: 'de-DE', additionalKeywords: [], postProcessing: (text) => text }, bayerisch: { languageCode: 'de-DE', additionalKeywords: [ 'Servus', 'Grüß Gott', 'Pfiat di', 'Brezn', 'Semmel', 'Weißwurst' ], postProcessing: (text) => { // Bayrische Ausdrücke normalisieren wenn gewünscht return text .replace(/\bfei\b/g, 'wirklich') .replace(/\bgell\b/g, 'nicht wahr'); } }, österreichisch: { languageCode: 'de-AT', additionalKeywords: [ 'Servus', 'Grüß Gott', 'Baba', 'Paradeiser', 'Erdapfel', 'Sackerl', 'Jänner', 'Feber' ], postProcessing: (text) => text }, schweizerdeutsch: { languageCode: 'de-CH', additionalKeywords: [ 'Grüezi', 'Merci', 'Ade', 'Velo', 'Natel', 'Trottoir', 'Rüebli', 'Zmorge' ], postProcessing: (text) => text }, // ... weitere Dialekte }; export function getDialectConfig(dialect: GermanDialect): DialectConfig { return dialectConfigs[dialect] || dialectConfigs.hochdeutsch; } ``` --- ## Komposita-Handling Deutsche Komposita sind eine Herausforderung: ```typescript // src/processing/composita-handler.ts // Problem: "Kraft fahrzeug haft pflicht versicherung" // Gewünscht: "Kraftfahrzeughaftpflichtversicherung" class CompositaProcessor { // Häufige Komposita-Teile private prefixes = [ 'Kraft', 'Fahrzeug', 'Haft', 'Pflicht', 'Versicherung', 'Daten', 'Schutz', 'Verarbeitung', 'Einwilligung', 'Geschäfts', 'Führung', 'Bericht', 'Erstattung' ]; // Bekannte vollständige Komposita private knownComposita = new Set([ 'Kraftfahrzeughaftpflichtversicherung', 'Datenschutzgrundverordnung', 'Bundesausbildungsförderungsgesetz', 'Geschäftsführer', 'Einwilligungserklärung' ]); process(text: string): string { // Versuche aufeinanderfolgende Wörter zu verbinden const words = text.split(' '); const result: string[] = []; let i = 0; while (i < words.length) { let combined = words[i]; let j = i + 1; // Versuche mit nächsten Wörtern zu kombinieren while (j < words.length) { const potential = combined + words[j]; if (this.isLikelyCompositum(potential)) { combined = potential; j++; } else { break; } } result.push(combined); i = j; } return result.join(' '); } private isLikelyCompositum(word: string): boolean { // Bekannt? if (this.knownComposita.has(word)) return true; // Beginnt mit bekanntem Prefix und ist lang genug? const hasKnownPrefix = this.prefixes.some(p => word.startsWith(p) && word.length > p.length + 3 ); return hasKnownPrefix; } } ``` --- ## Post-Processing Pipeline ```typescript // src/processing/german-postprocessor.ts import { CompositaProcessor } from './composita-handler'; interface PostProcessorConfig { normalizeNumbers: boolean; fixComposita: boolean; correctCommonErrors: boolean; dialect: GermanDialect; } class GermanPostProcessor { private compositaProcessor = new CompositaProcessor(); process(text: string, config: PostProcessorConfig): string { let result = text; // 1. Häufige Fehler korrigieren if (config.correctCommonErrors) { result = this.correctCommonErrors(result); } // 2. Komposita zusammenfügen if (config.fixComposita) { result = this.compositaProcessor.process(result); } // 3. Zahlen normalisieren if (config.normalizeNumbers) { result = this.normalizeNumbers(result); } // 4. Dialekt-spezifische Anpassungen const dialectConfig = getDialectConfig(config.dialect); result = dialectConfig.postProcessing(result); return result; } private correctCommonErrors(text: string): string { const corrections: [RegExp, string][] = [ [/\beine mail\b/gi, 'eine E-Mail'], [/\bwhats app\b/gi, 'WhatsApp'], [/\bwifi\b/gi, 'WLAN'], [/\bapp\b/gi, 'App'], [/\bcloud\b/gi, 'Cloud'], [/\bsmart phone\b/gi, 'Smartphone'], [/\bhandy\b/gi, 'Handy'], [/\bwebsite\b/gi, 'Webseite'], [/\bhome office\b/gi, 'Homeoffice'], ]; let result = text; for (const [pattern, replacement] of corrections) { result = result.replace(pattern, replacement); } return result; } private normalizeNumbers(text: string): string { // "drei komma fünf prozent" → "3,5 Prozent" const numberWords: Record = { 'null': '0', 'eins': '1', 'zwei': '2', 'drei': '3', 'vier': '4', 'fünf': '5', 'sechs': '6', 'sieben': '7', 'acht': '8', 'neun': '9', 'zehn': '10', 'elf': '11', 'zwölf': '12', 'dreizehn': '13', 'zwanzig': '20', 'dreißig': '30', 'vierzig': '40', 'fünfzig': '50', 'hundert': '100', 'tausend': '1000' }; let result = text; // Komma-Zahlen result = result.replace( /(\w+)\s+komma\s+(\w+)/gi, (_, before, after) => { const num1 = numberWords[before.toLowerCase()] || before; const num2 = numberWords[after.toLowerCase()] || after; return `${num1},${num2}`; } ); return result; } } ``` --- ## Production-Konfiguration ```typescript // src/config/production-german-asr.ts export const productionConfig = { // Deepgram Settings deepgram: { model: 'nova-2', language: 'de', smart_format: true, punctuate: true, diarize: false, // Nur wenn nötig (kostet extra) endpointing: 500, interim_results: true, utterance_end_ms: 1000, vad_events: true, // Keywords für Domain keywords: getKeywordsForDomain('tech') }, // Post-Processing postProcessing: { normalizeNumbers: true, fixComposita: true, correctCommonErrors: true, dialect: 'hochdeutsch' as GermanDialect }, // Retry Logic retry: { maxRetries: 3, backoffMs: 1000 }, // Monitoring monitoring: { logTranscripts: false, // DSGVO! logLatency: true, logErrors: true } }; ``` --- ## Metriken & Monitoring ```typescript // src/monitoring/asr-metrics.ts interface ASRMetrics { requestId: string; timestamp: Date; // Performance latencyMs: number; audioLengthMs: number; processingRatio: number; // audioLength / latency // Quality wordCount: number; confidenceScore: number; alternativesCount: number; // Errors errorType?: string; errorMessage?: string; } class ASRMonitor { async track(metrics: ASRMetrics) { // Latenz-Anomalien erkennen if (metrics.latencyMs > 500) { console.warn(`High ASR latency: ${metrics.latencyMs}ms`); } // Niedrige Konfidenz flaggen if (metrics.confidenceScore < 0.7) { console.warn(`Low confidence: ${metrics.confidenceScore}`); } // Metriken speichern (für Dashboards) await this.store(metrics); } } ``` --- ## Fazit Deutsche Spracherkennung mit Deepgram Nova-2 erfordert: 1. **Keyword Boosting**: Für Fachvokabular und Eigennamen 2. **Dialekt-Awareness**: de-DE, de-AT, de-CH unterscheiden 3. **Komposita-Handling**: Post-Processing für zusammengesetzte Wörter 4. **Domänen-Anpassung**: Keywords je nach Use Case Mit diesen Optimierungen ist 5-8% WER auch für komplexe deutsche Fachsprache erreichbar. --- ## Bildprompts 1. "German language sound waves transforming into text, blue and gold colors, technical illustration" 2. "Map of Germany, Austria, Switzerland with different speech bubbles, dialect visualization" 3. "Long German compound word being assembled like building blocks, playful tech illustration" --- ## Quellen - [Deepgram Speech Recognition Accuracy Guide](https://deepgram.com/learn/speech-recognition-accuracy-production-metrics) - [Deepgram Multilingual STT Guide](https://deepgram.com/learn/multilingual-speech-to-text-guide) - [Deepgram vs OpenAI vs Google Comparison](https://deepgram.com/learn/deepgram-vs-openai-vs-google-stt-accuracy-latency-price-compared) - [Deepgram Nova-3 German Support](https://deepgram.com/learn/aura-2-now-speaks-dutch-french-german-italian-japanese)