feat(ultraplan-local): v1.6.0 — /ultraresearch-local deep research command
Add /ultraresearch-local for structured research combining local codebase analysis with external knowledge via parallel agent swarms. Produces research briefs with triangulation, confidence ratings, and source quality assessment. New command: /ultraresearch-local with modes --quick, --local, --external, --fg. New agents: research-orchestrator (opus), docs-researcher, community-researcher, security-researcher, contrarian-researcher, gemini-bridge (all sonnet). New template: research-brief-template.md. Integration: --research flag in /ultraplan-local accepts pre-built research briefs (up to 3), enriches the interview and exploration phases. Planning orchestrator cross-references brief findings during synthesis. Design principle: Context Engineering — right information to right agent at right time. Research briefs are structured artifacts in the pipeline: ultraresearch → brief → ultraplan --research → plan → ultraexecute. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
commit
baa2d0220b
488 changed files with 213221 additions and 0 deletions
|
|
@ -0,0 +1,520 @@
|
|||
# Speech-to-AI Integration Pipelines
|
||||
|
||||
**Last updated:** 2026-02
|
||||
**Status:** GA
|
||||
**Category:** Multi-Modal AI
|
||||
|
||||
---
|
||||
|
||||
## Introduksjon
|
||||
|
||||
Speech-to-AI-integrasjon handlar om å kople talegjenkjenning med downstream AI-tenester for å skape ende-til-ende-pipelines som konverterer tale til handlingsorienterte innsikter. Azure Speech Service dannar grunnlaget, med støtte for sanntids talegjenkjenning, batchtranskribering, språkdeteksjon, talardiarisering og tilpassa talemodular.
|
||||
|
||||
For norsk offentleg sektor er tale-til-AI-pipelines avgjerande for tilgjengelegheit (automatisk teksting), møtetranskribering (kommunestyre, utval), klageblandling per telefon, og innbyggardialog via talebaserte brukargrensesnitt. Azure Speech Service støttar norsk bokmål (nb-NO) og kan kombinerast med Azure OpenAI for intelligente samtaleagenter.
|
||||
|
||||
Denne referansefila dekkjer arkitekturmønster for sanntidsstreaming, batchprosessering, språkdeteksjon og feilhandtering — med fokus på robuste produksjonsklare implementeringar.
|
||||
|
||||
---
|
||||
|
||||
## Speech Recognition og Language Detection
|
||||
|
||||
### Azure Speech Service oversikt
|
||||
|
||||
| Funksjon | Tilgjengelegheit | Brukstilfelle |
|
||||
|----------|-----------------|--------------|
|
||||
| **Real-time STT** | GA | Samtaleagenter, live teksting |
|
||||
| **Batch transcription** | GA | Arkivprosessering, møtereferat |
|
||||
| **Fast transcription** | GA | Rask transkribering av filer |
|
||||
| **Language identification** | GA | Fleirspråklege samtalar |
|
||||
| **Speaker diarization** | GA | Møtetranskribering |
|
||||
| **Custom speech** | GA | Bransjespecifikk terminologi |
|
||||
| **Real-time TTS** | GA | Talebaserte assistentar |
|
||||
| **Text streaming** | GA | Sanntids TTS frå GPT-output |
|
||||
| **gpt-4o-realtime** | Preview | Direkte tale-til-tale |
|
||||
|
||||
### Språkgjenkjenning
|
||||
|
||||
Azure Speech Service tilbyr to typar språkdeteksjon:
|
||||
|
||||
**At-Start Language Identification:**
|
||||
- Detekterer språk i starten av audiostraumen
|
||||
- Støtta i C#, C++, Python, Java, JavaScript, Objective-C
|
||||
- Best for scenario med eitt hovudspråk per sesjon
|
||||
|
||||
**Continuous Language Identification:**
|
||||
- Detekterer språkbytter undervegs i samtalen
|
||||
- Støtta i C#, C++, Java, JavaScript, Python
|
||||
- Kritisk for fleirspråklege norske kommunar
|
||||
|
||||
```python
|
||||
import azure.cognitiveservices.speech as speechsdk
|
||||
|
||||
speech_config = speechsdk.SpeechConfig(
|
||||
subscription=os.environ["SPEECH_KEY"],
|
||||
region=os.environ["SPEECH_REGION"]
|
||||
)
|
||||
|
||||
# Konfigurer automatisk språkdeteksjon
|
||||
auto_detect_config = speechsdk.languageconfig.AutoDetectSourceLanguageConfig(
|
||||
languages=["nb-NO", "nn-NO", "en-US", "se-NO"] # Bokmål, nynorsk, engelsk, nordsamisk
|
||||
)
|
||||
|
||||
speech_recognizer = speechsdk.SpeechRecognizer(
|
||||
speech_config=speech_config,
|
||||
auto_detect_source_language_config=auto_detect_config,
|
||||
audio_config=audio_config
|
||||
)
|
||||
|
||||
def recognized_handler(evt):
|
||||
result = evt.result
|
||||
auto_detect_result = speechsdk.AutoDetectSourceLanguageResult(result)
|
||||
detected_language = auto_detect_result.language
|
||||
print(f"[{detected_language}] {result.text}")
|
||||
|
||||
speech_recognizer.recognized.connect(recognized_handler)
|
||||
speech_recognizer.start_continuous_recognition()
|
||||
```
|
||||
|
||||
### Tilpassa talemodular (Custom Speech)
|
||||
|
||||
For norsk offentleg sektor med spesialisert terminologi:
|
||||
|
||||
| Tilpasning | Brukstilfelle | Eksempel |
|
||||
|-----------|--------------|---------|
|
||||
| **Phrase list** | Forbetra gjenkjenning av spesifikke ord | Stadnamn, fagtermar |
|
||||
| **Custom model** | Trenar ny modell med eigne data | Vegsektoren, helsesektor |
|
||||
| **Display format** | Tilpass visning av gjenkjend tekst | Tal-til-siffer, dato-format |
|
||||
|
||||
```python
|
||||
# Phrase list for forbetra norsk gjenkjenning
|
||||
phrase_list = speechsdk.PhraseListGrammar.from_recognizer(speech_recognizer)
|
||||
phrase_list.addPhrase("Statens vegvesen")
|
||||
phrase_list.addPhrase("E6 Megården-Mørsvikbotn")
|
||||
phrase_list.addPhrase("Utredningsinstruksen")
|
||||
phrase_list.addPhrase("Forvaltningsloven")
|
||||
phrase_list.addPhrase("personvernforordningen")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Audio Preprocessing og Quality Assessment
|
||||
|
||||
### Audioformat og kvalitetskrav
|
||||
|
||||
| Parameter | Tilrådde verdi | Minimum | Kommentar |
|
||||
|-----------|---------------|---------|-----------|
|
||||
| **Samplingsrate** | 16 kHz | 8 kHz | 16 kHz gir best nøyaktigheit |
|
||||
| **Bit depth** | 16-bit | 8-bit | Mono PCM tilrådde |
|
||||
| **Kanalar** | Mono | Mono | Stereo splittar automatisk |
|
||||
| **Format** | WAV (PCM) | WAV, MP3, OGG | WAV gir minst komprimeringstap |
|
||||
| **SNR** | >20 dB | >10 dB | Signal-to-noise ratio |
|
||||
|
||||
### Audio preprocessing pipeline
|
||||
|
||||
```python
|
||||
import numpy as np
|
||||
from scipy.io import wavfile
|
||||
from scipy.signal import butter, lfilter
|
||||
|
||||
class AudioPreprocessor:
|
||||
"""Preprosessering av audio for optimal talegjenkjenning."""
|
||||
|
||||
def __init__(self, target_sample_rate=16000):
|
||||
self.target_sample_rate = target_sample_rate
|
||||
|
||||
def assess_quality(self, audio_data: np.ndarray, sample_rate: int) -> dict:
|
||||
"""Vurder audiokvalitet før talegjenkjenning."""
|
||||
# Berekn SNR
|
||||
signal_power = np.mean(audio_data ** 2)
|
||||
noise_floor = np.percentile(np.abs(audio_data), 5) ** 2
|
||||
snr = 10 * np.log10(signal_power / max(noise_floor, 1e-10))
|
||||
|
||||
# Berekn varigheit
|
||||
duration = len(audio_data) / sample_rate
|
||||
|
||||
# Detekter stille
|
||||
silence_threshold = np.percentile(np.abs(audio_data), 10)
|
||||
silence_ratio = np.sum(np.abs(audio_data) < silence_threshold) / len(audio_data)
|
||||
|
||||
# Berekn peak level
|
||||
peak_level = 20 * np.log10(np.max(np.abs(audio_data)) / 32768)
|
||||
|
||||
return {
|
||||
"snr_db": round(snr, 1),
|
||||
"duration_seconds": round(duration, 1),
|
||||
"silence_ratio": round(silence_ratio, 3),
|
||||
"peak_level_db": round(peak_level, 1),
|
||||
"sample_rate": sample_rate,
|
||||
"quality_score": self._calculate_quality_score(snr, silence_ratio, peak_level),
|
||||
"recommendation": self._get_recommendation(snr, silence_ratio)
|
||||
}
|
||||
|
||||
def _calculate_quality_score(self, snr, silence_ratio, peak_level):
|
||||
score = 0
|
||||
if snr > 20: score += 40
|
||||
elif snr > 15: score += 30
|
||||
elif snr > 10: score += 20
|
||||
else: score += 10
|
||||
|
||||
if silence_ratio < 0.3: score += 30
|
||||
elif silence_ratio < 0.5: score += 20
|
||||
else: score += 10
|
||||
|
||||
if -6 < peak_level < -1: score += 30
|
||||
elif -12 < peak_level < 0: score += 20
|
||||
else: score += 10
|
||||
|
||||
return min(score, 100)
|
||||
|
||||
def _get_recommendation(self, snr, silence_ratio):
|
||||
if snr < 10:
|
||||
return "Låg SNR — vurder støyreduksjon eller betre mikrofon"
|
||||
if silence_ratio > 0.7:
|
||||
return "Mykje stille — sjekk at audio faktisk inneheld tale"
|
||||
return "Kvaliteten er akseptabel for talegjenkjenning"
|
||||
|
||||
def apply_noise_reduction(self, audio_data: np.ndarray, sample_rate: int) -> np.ndarray:
|
||||
"""Enkel bandpassfiltrering for å redusere støy."""
|
||||
low_freq = 80 # Hz — under menneskeleg tale
|
||||
high_freq = 8000 # Hz — over dei fleste talefrekvensane
|
||||
|
||||
nyquist = sample_rate / 2
|
||||
low = low_freq / nyquist
|
||||
high = high_freq / nyquist
|
||||
|
||||
b, a = butter(4, [low, high], btype='band')
|
||||
return lfilter(b, a, audio_data).astype(np.int16)
|
||||
```
|
||||
|
||||
### Quality gates for produksjon
|
||||
|
||||
| Gate | Terskel | Handling |
|
||||
|------|---------|---------|
|
||||
| **SNR-sjekk** | < 10 dB | Avvis, be om ny innspeling |
|
||||
| **Varighetssjekk** | < 1 sekund | Avvis, for kort |
|
||||
| **Stillesjekk** | > 80% stille | Åtvar, be om verifikasjon |
|
||||
| **Peak clipping** | > -0.5 dB | Åtvar, mogleg klipping |
|
||||
| **Format-validering** | Støtta format | Konverter automatisk |
|
||||
|
||||
---
|
||||
|
||||
## Low-Latency Streaming Architectures
|
||||
|
||||
### Sanntids talegjenkjenning
|
||||
|
||||
```
|
||||
Mikrofon → Audio stream → Azure Speech SDK
|
||||
↓
|
||||
┌── Recognizing event (interim)
|
||||
│ "Eg trur at veg..."
|
||||
├── Recognized event (final)
|
||||
│ "Eg trur at vegsektoren bør investere meir."
|
||||
│ Offset: 1800000 ticks
|
||||
│ Duration: 30500000 ticks
|
||||
└── SessionStopped event
|
||||
```
|
||||
|
||||
### Speech SDK streaming-arkitektur
|
||||
|
||||
```python
|
||||
import azure.cognitiveservices.speech as speechsdk
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
class StreamingSpeechPipeline:
|
||||
"""Sanntids tale-til-AI pipeline med låg latency."""
|
||||
|
||||
def __init__(self, speech_key, speech_region, openai_client):
|
||||
self.speech_config = speechsdk.SpeechConfig(
|
||||
subscription=speech_key,
|
||||
region=speech_region
|
||||
)
|
||||
self.speech_config.speech_recognition_language = "nb-NO"
|
||||
self.speech_config.request_word_level_timestamps()
|
||||
self.speech_config.set_property(
|
||||
speechsdk.PropertyId.SpeechServiceResponse_StablePartialResultThreshold,
|
||||
"3" # Reduser flimring i delresultat
|
||||
)
|
||||
|
||||
self.openai_client = openai_client
|
||||
self.transcript_buffer = []
|
||||
|
||||
async def start_streaming(self, audio_config=None):
|
||||
"""Start sanntids talegjenkjenning med AI-prosessering."""
|
||||
if audio_config is None:
|
||||
audio_config = speechsdk.audio.AudioConfig(use_default_microphone=True)
|
||||
|
||||
recognizer = speechsdk.SpeechRecognizer(
|
||||
speech_config=self.speech_config,
|
||||
audio_config=audio_config
|
||||
)
|
||||
|
||||
# Interim-resultat for live visning
|
||||
recognizer.recognizing.connect(self._on_recognizing)
|
||||
|
||||
# Endelege resultat for AI-prosessering
|
||||
recognizer.recognized.connect(self._on_recognized)
|
||||
|
||||
# Start gjenkjenning
|
||||
recognizer.start_continuous_recognition()
|
||||
return recognizer
|
||||
|
||||
def _on_recognizing(self, evt):
|
||||
"""Handter interim-resultat (vis til brukar)."""
|
||||
print(f"\r [interim] {evt.result.text}", end="", flush=True)
|
||||
|
||||
def _on_recognized(self, evt):
|
||||
"""Handter endeleg resultat (send til AI)."""
|
||||
if evt.result.reason == speechsdk.ResultReason.RecognizedSpeech:
|
||||
text = evt.result.text
|
||||
offset = evt.result.offset
|
||||
duration = evt.result.duration
|
||||
|
||||
self.transcript_buffer.append({
|
||||
"text": text,
|
||||
"offset_ticks": offset,
|
||||
"duration_ticks": duration,
|
||||
"timestamp": offset / 10_000_000 # Konverter til sekund
|
||||
})
|
||||
|
||||
print(f"\n[{offset/10_000_000:.1f}s] {text}")
|
||||
```
|
||||
|
||||
### Speech-to-Speech med Azure OpenAI
|
||||
|
||||
For samtaleagenter med direkte tale-til-tale:
|
||||
|
||||
```
|
||||
Brukar tale → Speech SDK (STT) → Tekst
|
||||
↓
|
||||
Azure OpenAI (GPT-4o)
|
||||
↓
|
||||
Svar-tekst
|
||||
↓
|
||||
Speech SDK (TTS) med text streaming
|
||||
↓
|
||||
Syntetisert tale → Brukar
|
||||
```
|
||||
|
||||
```python
|
||||
# Text streaming for låg-latency TTS
|
||||
speech_config.set_speech_synthesis_output_format(
|
||||
speechsdk.SpeechSynthesisOutputFormat.Raw24Khz16BitMonoPcm
|
||||
)
|
||||
|
||||
tts_endpoint = (
|
||||
f"wss://{region}.tts.speech.microsoft.com"
|
||||
f"/cognitiveservices/websocket/v2"
|
||||
)
|
||||
|
||||
# Stream GPT-output direkte til TTS
|
||||
async def stream_response_to_speech(gpt_stream, synthesizer):
|
||||
"""Stream GPT-4o tokens direkte til TTS for minimal latency."""
|
||||
request = speechsdk.SpeechSynthesisRequest(
|
||||
input_type=speechsdk.SpeechSynthesisRequestInputType.TextStream
|
||||
)
|
||||
|
||||
# Start TTS-syntese
|
||||
result_future = synthesizer.speak_async(request)
|
||||
|
||||
# Stream tekst-chunks frå GPT
|
||||
async for chunk in gpt_stream:
|
||||
if chunk.choices[0].delta.content:
|
||||
request.input_stream.write(chunk.choices[0].delta.content)
|
||||
|
||||
# Steng straumen
|
||||
request.input_stream.close()
|
||||
result = await result_future
|
||||
```
|
||||
|
||||
### GPT-4o Realtime API for direkte tale-til-tale
|
||||
|
||||
```
|
||||
Brukar tale → WebSocket → GPT-4o Realtime API → Syntetisert tale
|
||||
(bidireksjonell audiostraum)
|
||||
```
|
||||
|
||||
| Eigenskap | Verdi |
|
||||
|-----------|-------|
|
||||
| **Latency** | < 500ms |
|
||||
| **Protokoll** | WebSocket |
|
||||
| **Audio input** | PCM 24kHz 16-bit mono |
|
||||
| **Audio output** | PCM 24kHz 16-bit mono |
|
||||
| **Innhaldsmoderering** | Ja, innebygd |
|
||||
| **Norsk støtte** | Ja (nb-NO) |
|
||||
|
||||
---
|
||||
|
||||
## Error Handling og Confidence Scoring
|
||||
|
||||
### Confidence scoring i talegjenkjenning
|
||||
|
||||
Azure Speech Service rapporterer confidence på fleire nivå:
|
||||
|
||||
| Nivå | Tilgjengeleg | Brukstilfelle |
|
||||
|------|-------------|--------------|
|
||||
| **Ytring-nivå** | Recognized event | Filtrering av låg-kvalitets resultat |
|
||||
| **Ord-nivå** | Med word timestamps aktivert | Identifisere usikre ord |
|
||||
|
||||
```python
|
||||
speech_config.request_word_level_timestamps()
|
||||
speech_config.output_format = speechsdk.OutputFormat.Detailed
|
||||
|
||||
def handle_detailed_result(evt):
|
||||
result = evt.result
|
||||
detailed = json.loads(result.json)
|
||||
|
||||
# N-best alternatives
|
||||
for nbest in detailed.get("NBest", []):
|
||||
confidence = nbest.get("Confidence", 0)
|
||||
text = nbest.get("Display", "")
|
||||
|
||||
if confidence < 0.6:
|
||||
print(f" [LAV CONFIDENCE {confidence:.2f}] {text}")
|
||||
else:
|
||||
print(f" [OK {confidence:.2f}] {text}")
|
||||
|
||||
# Ord-nivå confidence
|
||||
for word in nbest.get("Words", []):
|
||||
word_confidence = word.get("Confidence", 0)
|
||||
if word_confidence < 0.5:
|
||||
print(f" Usikkert ord: '{word['Word']}' ({word_confidence:.2f})")
|
||||
```
|
||||
|
||||
### Robuste feilhandteringsmønster
|
||||
|
||||
```python
|
||||
class ResilientSpeechPipeline:
|
||||
"""Robust tale-pipeline med retry og fallback."""
|
||||
|
||||
MAX_RETRIES = 3
|
||||
RETRY_DELAY = 1.0 # sekund
|
||||
|
||||
def __init__(self, primary_config, fallback_config=None):
|
||||
self.primary_config = primary_config
|
||||
self.fallback_config = fallback_config
|
||||
self.error_counts = {"no_match": 0, "canceled": 0, "timeout": 0}
|
||||
|
||||
async def recognize_with_retry(self, audio_data):
|
||||
"""Gjenkjenn tale med retry-logikk."""
|
||||
for attempt in range(self.MAX_RETRIES):
|
||||
try:
|
||||
result = await self._attempt_recognition(audio_data, self.primary_config)
|
||||
|
||||
if result.reason == speechsdk.ResultReason.RecognizedSpeech:
|
||||
self.error_counts = {"no_match": 0, "canceled": 0, "timeout": 0}
|
||||
return {"status": "success", "text": result.text, "confidence": self._get_confidence(result)}
|
||||
|
||||
elif result.reason == speechsdk.ResultReason.NoMatch:
|
||||
self.error_counts["no_match"] += 1
|
||||
details = result.no_match_details
|
||||
return {
|
||||
"status": "no_match",
|
||||
"reason": str(details.reason),
|
||||
"recommendation": self._no_match_recommendation(details)
|
||||
}
|
||||
|
||||
elif result.reason == speechsdk.ResultReason.Canceled:
|
||||
cancellation = result.cancellation_details
|
||||
if cancellation.reason == speechsdk.CancellationReason.Error:
|
||||
if "timeout" in str(cancellation.error_details).lower():
|
||||
self.error_counts["timeout"] += 1
|
||||
await asyncio.sleep(self.RETRY_DELAY * (attempt + 1))
|
||||
continue
|
||||
raise SpeechServiceError(cancellation.error_details)
|
||||
|
||||
except Exception as e:
|
||||
if attempt == self.MAX_RETRIES - 1:
|
||||
if self.fallback_config:
|
||||
return await self._attempt_recognition(audio_data, self.fallback_config)
|
||||
raise
|
||||
await asyncio.sleep(self.RETRY_DELAY * (attempt + 1))
|
||||
|
||||
def _no_match_recommendation(self, details):
|
||||
if details.reason == speechsdk.NoMatchReason.InitialSilenceTimeout:
|
||||
return "Ingen tale detektert — sjekk mikrofon eller audiokjelde"
|
||||
elif details.reason == speechsdk.NoMatchReason.InitialBabbleTimeout:
|
||||
return "For mykje bakgrunnsstøy — forbetra audiokvalitet"
|
||||
return "Ukjend årsak — prøv på nytt"
|
||||
```
|
||||
|
||||
### Feilkategoriar og handtering
|
||||
|
||||
| Feiltype | Årsak | Handling | Retry? |
|
||||
|---------|-------|---------|--------|
|
||||
| **NoMatch - InitialSilenceTimeout** | Ingen tale i starten | Sjekk mikrofon, auk timeout | Nei |
|
||||
| **NoMatch - InitialBabbleTimeout** | For mykje støy | Forbetra audiokvalitet | Nei |
|
||||
| **Canceled - AuthenticationError** | Ugyldig nøkkel/token | Forny token | Ja (etter fornyelse) |
|
||||
| **Canceled - ConnectionError** | Nettverksproblem | Retry med exponential backoff | Ja |
|
||||
| **Canceled - ServiceTimeout** | Tenesta overbelasta | Retry med delay | Ja |
|
||||
| **Canceled - RuntimeError** | Intern feil | Retry | Ja |
|
||||
|
||||
### Monitoring og observability
|
||||
|
||||
```python
|
||||
from azure.monitor.opentelemetry import configure_azure_monitor
|
||||
from opentelemetry import metrics
|
||||
|
||||
# Konfigurer Azure Monitor
|
||||
configure_azure_monitor(connection_string=os.environ["APPLICATIONINSIGHTS_CONNECTION_STRING"])
|
||||
|
||||
meter = metrics.get_meter("speech-pipeline")
|
||||
recognition_counter = meter.create_counter("speech.recognition.count")
|
||||
confidence_histogram = meter.create_histogram("speech.recognition.confidence")
|
||||
latency_histogram = meter.create_histogram("speech.recognition.latency_ms")
|
||||
|
||||
def track_recognition(result, latency_ms):
|
||||
recognition_counter.add(1, {"status": result["status"], "language": "nb-NO"})
|
||||
if result.get("confidence"):
|
||||
confidence_histogram.record(result["confidence"])
|
||||
latency_histogram.record(latency_ms)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Pipeline-arkitekturar for norsk offentleg sektor
|
||||
|
||||
### Møtetranskribering med diarisering
|
||||
|
||||
```
|
||||
Møtelyd → Audio preprocessing → Quality gate
|
||||
↓
|
||||
Speaker diarization
|
||||
"Talar 1: ..." | "Talar 2: ..."
|
||||
↓
|
||||
Continuous recognition
|
||||
(nb-NO med phrase list)
|
||||
↓
|
||||
Strukturert transkripsjon
|
||||
[tidskode, talar, tekst]
|
||||
↓
|
||||
GPT-4o: Oppsummering + handlingspunkt
|
||||
↓
|
||||
Dokument: Møtereferat + opptak
|
||||
```
|
||||
|
||||
### Innbyggardialog via telefon
|
||||
|
||||
```
|
||||
Innringar → Azure Communication Services
|
||||
↓
|
||||
Real-time transcription
|
||||
+ Language detection
|
||||
↓
|
||||
GPT-4o: Klassifisering
|
||||
+ Intentdeteksjon
|
||||
↓
|
||||
Routing til rett etat/saksbehandlar
|
||||
ELLER
|
||||
Automatisk svar via TTS
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## For Cosmo
|
||||
|
||||
- **Azure Speech Service støttar norsk bokmål (nb-NO) fullt ut** for STT og TTS. Nynorsk (nn-NO) og nordsamisk (se-NO) har meir avgrensa støtte. Bruk language identification for fleirspråklege scenario.
|
||||
- **Word-level timestamps og confidence scoring** er avgjerande for produksjonsbruk — aktiver `request_word_level_timestamps()` og filtrer resultat med confidence under 0.6 for kvalitetssikring.
|
||||
- **Text streaming for TTS** (websocket v2) reduserer opplevd latency dramatisk når du kombinerer GPT-4o med Speech Service. Stream GPT-tokens direkte til TTS i staden for å vente på fullstendig svar.
|
||||
- **Custom Speech med phrase lists** er eit låg-innsats, høg-verdi tiltak for norske offentlege scenario. Legg til stadnamn, fagtermar og organisasjonsnamn for vesentleg forbetra gjenkjenning.
|
||||
- **Implementer quality gates før talegjenkjenning** — sjekk SNR, varigheit og støynivå. Det reduserer feilrate og unødvendige API-kall mot Speech Service.
|
||||
Loading…
Add table
Add a link
Reference in a new issue