ms-ai-architect/skills/ms-ai-engineering/references/multi-modal/audio-video-transcription-workflow.md
Kjell Tore Guttormsen baa2d0220b 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>
2026-04-08 08:58:35 +02:00

17 KiB

Audio and Video Transcription Workflow Architecture

Last updated: 2026-02 Status: GA Category: Multi-Modal AI


Introduksjon

Azure Speech Services tilbyr omfattande kapabilitetar for transkribering og oversettelse av audio- og videoinnhald. Tenesta støttar sanntids- og batch-transkribering med funksjonar som taleridentifisering (diarization), automatisk språkdeteksjon, ordnivå-tidsstempel og tilpassa talemodeller. For norsk offentleg sektor er dette relevant for møtetranskribering, arkivering av telefonsamtalar, tekstforming av video, og tilgjengeleggjering av audioinnnhald.

Batch Transcription API er designa for å transkribere store mengder lydfilar lagra i Azure Blob Storage eller tilgjengelege via URL. Prosesseringa skjer asynkront og er optimal for arkivtranskribering, callcenter-analyse og untertekstproduksjon. Fast Transcription API (preview) tilbyr synkron prosessering med lågare latency for kortare lydfiler. Sanntidstranskribering via Speech SDK er eigna for live-scenario.

Azure Video Indexer (tidlegare Azure Media Services Video Indexer) tilbyr AI-driven analyse av videoinnhald, inkludert automatisk transkribering, omsetjing, emnedeteksjon, ansiktsdeteksjon og scene-segmentering. For heilskaplege audio/video-transkripsjonsworkflowar bør ein vurdere å kombinere Speech Services, Video Indexer og Azure OpenAI for oppsummering og innsikt.


Kjernekomponentar

Komponent Formål Teknologi
Real-time STT Sanntids tale-til-tekst Azure Speech SDK
Batch Transcription Volumbasert asynkron transkribering Speech to text REST API v3.1+
Fast Transcription Synkron rask transkribering Speech REST API (preview)
Diarization Taleridentifisering og -separering Speech Services
Speech Translation Sanntids taleoversettelse Translation SDK
Custom Speech Tilpassa talegjenkjenning Azure Speech Studio
Video Indexer AI-driven videoanalyse Azure Video Indexer
Batch Processing Kit Open-source container for volum-transkribering GitHub/Docker Hub

Batch Transcription at Scale

Batch Transcription API

import requests
import json
import time

speech_key = os.environ["SPEECH_KEY"]
speech_region = os.environ["SPEECH_REGION"]

base_url = (f"https://{speech_region}.api.cognitive.microsoft.com"
            "/speechtotext/v3.1")

headers = {
    "Ocp-Apim-Subscription-Key": speech_key,
    "Content-Type": "application/json"
}

# Opprett batch-transkribering
transcription_payload = {
    "contentUrls": [
        "https://storage.blob.core.windows.net/audio/meeting1.wav",
        "https://storage.blob.core.windows.net/audio/meeting2.wav",
        "https://storage.blob.core.windows.net/audio/meeting3.wav"
    ],
    "locale": "nb-NO",
    "displayName": "Kommunestyremøte Q4 2025",
    "properties": {
        "wordLevelTimestampsEnabled": True,
        "diarizationEnabled": True,
        "diarization": {
            "speakers": {
                "minCount": 2,
                "maxCount": 15
            }
        },
        "punctuationMode": "DictatedAndAutomatic",
        "profanityFilterMode": "Masked",
        "destinationContainerUrl": (
            "https://mystorage.blob.core.windows.net/transcripts"
            "?sp=rwl&st=...&sig=..."
        )
    }
}

# Start transkribering
response = requests.post(
    f"{base_url}/transcriptions",
    headers=headers,
    data=json.dumps(transcription_payload)
)

transcription_url = response.headers["Location"]
print(f"Transkribering starta: {transcription_url}")

# Poll for ferdigstilling
while True:
    status = requests.get(transcription_url, headers=headers).json()
    if status["status"] in ["Succeeded", "Failed"]:
        break
    print(f"Status: {status['status']}")
    time.sleep(30)

# Hent resultat
if status["status"] == "Succeeded":
    files_url = f"{transcription_url}/files"
    files = requests.get(files_url, headers=headers).json()
    for file in files["values"]:
        if file["kind"] == "Transcription":
            result = requests.get(
                file["links"]["contentUrl"], headers=headers
            ).json()
            for phrase in result["recognizedPhrases"]:
                speaker = phrase.get("speaker", "Ukjent")
                text = phrase["nBest"][0]["display"]
                offset = phrase["offsetInTicks"] / 10_000_000
                print(f"[{offset:.1f}s] Taler {speaker}: {text}")

Batch Processing Kit (open-source)

For store volum med fleire Speech-containers:

# docker-compose.yml for batch processing kit
version: "3"
services:
  batch-kit:
    image: batchkit/speech-batch-kit:latest
    environment:
      - SPEECH_ENDPOINT=http://speech-container:5000
      - INPUT_FOLDER=/input
      - OUTPUT_FOLDER=/output
      - DIARIZATION=true
      - LANGUAGE=nb-NO
    volumes:
      - ./audio-files:/input
      - ./transcripts:/output

  speech-container:
    image: mcr.microsoft.com/azure-cognitive-services/speechservices/speech-to-text
    environment:
      - EULA=accept
      - Billing=https://northeurope.api.cognitive.microsoft.com
      - ApiKey=${SPEECH_KEY}
    ports:
      - "5000:5000"

Skaleringsstrategiar

Volum Strategi Gjennomstrøyming
< 100 filer/dag Batch Transcription API direkte Standard quota
100-1000 filer/dag Batch API med auka quota Kontakt Microsoft
> 1000 filer/dag Batch Processing Kit + fleire containers Lineær skalering
Sanntid + batch Hybrid: SDK for live, API for arkiv Ulike endpoints

Speaker Attribution og Diarization

Sanntids diarization

import azure.cognitiveservices.speech as speechsdk

speech_config = speechsdk.SpeechConfig(
    subscription=os.environ["SPEECH_KEY"],
    region=os.environ["SPEECH_REGION"]
)

# Konfigurer for diarization
speech_config.speech_recognition_language = "nb-NO"
speech_config.set_property(
    speechsdk.PropertyId.SpeechServiceConnection_LanguageIdMode,
    "Continuous"
)

audio_config = speechsdk.audio.AudioConfig(
    filename="meeting_recording.wav"
)

# Opprett conversation transcriber
conversation_transcriber = speechsdk.transcription.ConversationTranscriber(
    speech_config=speech_config,
    audio_config=audio_config
)

transcript = []
done = False

def transcribed_cb(evt):
    if evt.result.reason == speechsdk.ResultReason.RecognizedSpeech:
        transcript.append({
            "speaker": evt.result.speaker_id,
            "text": evt.result.text,
            "offset": evt.result.offset,
            "duration": evt.result.duration
        })
        print(f"Taler {evt.result.speaker_id}: {evt.result.text}")

def canceled_cb(evt):
    nonlocal done
    done = True

def stopped_cb(evt):
    nonlocal done
    done = True

conversation_transcriber.transcribed.connect(transcribed_cb)
conversation_transcriber.canceled.connect(canceled_cb)
conversation_transcriber.session_stopped.connect(stopped_cb)

# Start transkribering
conversation_transcriber.start_transcribing_async()

while not done:
    time.sleep(0.5)

conversation_transcriber.stop_transcribing_async()

Diarization i batch-modus

Batch Transcription API støttar opp til 35 talarar:

{
    "locale": "nb-NO",
    "properties": {
        "diarizationEnabled": true,
        "diarization": {
            "speakers": {
                "minCount": 2,
                "maxCount": 35
            }
        },
        "wordLevelTimestampsEnabled": true
    }
}

Resultatformat med talarinformasjon

{
    "recognizedPhrases": [
        {
            "speaker": 1,
            "offsetInTicks": 15000000,
            "durationInTicks": 35000000,
            "nBest": [{
                "confidence": 0.92,
                "display": "Eg vil starte med å gå gjennom sakslista.",
                "words": [
                    {"word": "Eg", "offset": "PT1.5S", "duration": "PT0.2S"},
                    {"word": "vil", "offset": "PT1.7S", "duration": "PT0.15S"}
                ]
            }]
        },
        {
            "speaker": 2,
            "offsetInTicks": 52000000,
            "durationInTicks": 28000000,
            "nBest": [{
                "confidence": 0.88,
                "display": "Takk. Eg har eit spørsmål til sak nummer tre.",
                "words": []
            }]
        }
    ]
}

Automatic Translation with Context Preservation

Sanntids taleoversettelse

import azure.cognitiveservices.speech as speechsdk

translation_config = speechsdk.translation.SpeechTranslationConfig(
    subscription=os.environ["SPEECH_KEY"],
    region=os.environ["SPEECH_REGION"]
)

# Gjenkjenn norsk, omset til fleire språk
translation_config.speech_recognition_language = "nb-NO"
translation_config.add_target_language("en")   # Engelsk
translation_config.add_target_language("ar")   # Arabisk
translation_config.add_target_language("so")   # Somali
translation_config.add_target_language("pl")   # Polsk

audio_config = speechsdk.audio.AudioConfig(
    filename="info_meeting.wav"
)

recognizer = speechsdk.translation.TranslationRecognizer(
    translation_config=translation_config,
    audio_config=audio_config
)

def recognized_cb(evt):
    if evt.result.reason == speechsdk.ResultReason.TranslatedSpeech:
        print(f"NORSK: {evt.result.text}")
        for lang, translation in evt.result.translations.items():
            print(f"  → {lang}: {translation}")

recognizer.recognized.connect(recognized_cb)
recognizer.start_continuous_recognition()

import time
time.sleep(300)  # Køyr i 5 minutt
recognizer.stop_continuous_recognition()

Post-transkribering AI-powered oversettelse

For betre kontekstuell kvalitet, kombiner transkribering + Azure OpenAI:

def translate_transcript_with_context(
    transcript: list[dict],
    target_language: str
) -> list[dict]:
    """Omset transkripsjon med kontekst via GPT-4o."""

    # Samle heile transkripsjonen for kontekst
    full_text = "\n".join(
        f"[Taler {t['speaker']}]: {t['text']}"
        for t in transcript
    )

    response = openai_client.chat.completions.create(
        model="gpt-4o",
        messages=[
            {
                "role": "system",
                "content": f"""Omset følgjande møtereferat frå norsk
                til {target_language}. Bevar:
                - Talaridentifikasjon ([Taler X])
                - Fagterminologi (omset korrekt eller behold)
                - Formell tone (dette er offentleg forvaltning)
                - Kontekst mellom ytringane"""
            },
            {"role": "user", "content": full_text}
        ],
        max_tokens=4000
    )

    return response.choices[0].message.content

Quality Assurance og Human-in-the-Loop Workflows

Confidence-basert QA

def qa_transcript(transcript_result: dict,
                  confidence_threshold: float = 0.7) -> dict:
    """QA av transkriberingsresultat med flagging."""

    qa_report = {
        "total_phrases": 0,
        "high_confidence": 0,
        "low_confidence": 0,
        "flagged_phrases": [],
        "average_confidence": 0.0
    }

    confidences = []

    for phrase in transcript_result["recognizedPhrases"]:
        qa_report["total_phrases"] += 1
        conf = phrase["nBest"][0]["confidence"]
        confidences.append(conf)

        if conf >= confidence_threshold:
            qa_report["high_confidence"] += 1
        else:
            qa_report["low_confidence"] += 1
            qa_report["flagged_phrases"].append({
                "text": phrase["nBest"][0]["display"],
                "confidence": conf,
                "offset": phrase["offsetInTicks"] / 10_000_000,
                "speaker": phrase.get("speaker", "?"),
                "alternatives": [
                    n["display"] for n in phrase["nBest"][1:3]
                ]
            })

    qa_report["average_confidence"] = (
        sum(confidences) / len(confidences) if confidences else 0
    )

    return qa_report

Human-in-the-Loop workflow med Power Automate

Batch Transcription API → Azure Blob Storage (transcript.json)
    → Azure Function: QA-analyse
        → IF avg_confidence >= 0.85:
            → Automatisk godkjenning → Arkivsystem
        → IF avg_confidence 0.6-0.85:
            → Power Automate: Send flagga segment til korrekturles
            → Teams Adaptive Card til saksbehandlar
            → Manuell korrigering → Arkivsystem
        → IF avg_confidence < 0.6:
            → Varsling: Lydkvalitet for låg
            → Anbefal ny innspeling eller manuell transkribering

Custom Speech for betre norsk gjenkjenning

# Tren tilpassa modell med norsk fagterminologi
# Steg 1: Førebu treningsdata
training_data = {
    "plain_text": [
        "Reguleringsplan for Stortorvet",
        "Detaljreguleringsplan med konsekvensutgreiing",
        "Klage på vedtak etter plan- og bygningslova"
    ],
    "structured_text": [
        {"phrase": "bygningslova", "pronunciation": "BYG-NINGS-LO-VA"},
        {"phrase": "detaljreguleringsplan",
         "pronunciation": "DE-TALJ-RE-GU-LE-RINGS-PLAN"}
    ]
}

# Steg 2: Opplasting via Speech Studio eller REST API
# Steg 3: Tren modell
# Steg 4: Deploy som custom endpoint
# Steg 5: Bruk endpoint-ID i transkribering

Implementeringsmønstre

Mønster 1: Møtetranskribering for kommunestyre

Teams-møte → Opptak (MP4/WAV)
    → Azure Blob Storage
    → Batch Transcription API (diarization ON)
    → QA-funksjon (confidence check)
    → Azure OpenAI: Oppsummering + vedtaksliste
    → Power Automate: Distribusjon
        → Saksbehandlingssystem (møteprotokoll)
        → Offentleg nettside (med tidskoda tekst)
        → Arkiv (eInnsyn-kompatibelt)

Mønster 2: Callcenter-analyse

Telefonopptak → Event Grid trigger
    → Azure Function → Batch Transcription
    → Cosmos DB (transcript + metadata)
    → Azure OpenAI: Sentiment + kategorisering
    → Power BI: Dashboard med KPI-ar
        → Gjennomsnittleg behandlingstid
        → Innbyggjartilfredsheit (sentiment)
        → Hyppigaste henvendelsestypar

Mønster 3: Untertekstproduksjon for offentleg video

Video → Azure Media Services (encode)
    → Speech Services: Transkribering (nb-NO)
    → Speech Translation: Omsetjing (en, ar, so)
    → VTT/SRT-filgenerering per språk
    → Azure CDN: Distribusjon
    → Videospelar med fleirspråklege untertekstar

Norsk offentleg sektor

Lovkrav

  • Offentlegheitslova: Møteprotokoll skal vere tilgjengelege
  • Likestillings- og diskrimineringslova: Lydopptak må tekstast for tilgjengelegheit
  • Arkivlova: Transkripsjoner er arkivverdig materiale
  • WCAG 2.1 AA: Video skal ha teksting/untertekstar

Språkstøtte for norsk

  • Norsk bokmål (nb-NO) fullt støtta for STT og TTS
  • Custom Speech med fagterminologi for betre resultat
  • Speech Translation frå norsk til 30+ målspråk
  • Diarization fungerer med norsk tale (opp til 35 talarar)

Personvern

  • Lydopptak er personopplysingar — krev rettsleg grunnlag
  • Batch Transcription: Resultat kan lagrast i eigen Azure Storage
  • Ikkje lagring hos Microsoft etter prosessering (stateless)
  • Custom Speech-treningsdata: Kontroller plassering og tilgang
  • Anbefaling: Sletting av lydfilar etter transkribering om ikkje arkivpliktig

DPIA-vurdering

  • Transkribering av møte/telefonar krev DPIA
  • Vurder: Samtykke, informasjonsplikt, lagringsbegrensing
  • Diarization identifiserer talarar med generisk ID — ikkje biometrisk identifikasjon
  • Container-deployment for ekstra datakontroll

Beslutningsrammeverk

Scenario Anbefaling Grunngjeving
Live møtetranskribering Speech SDK med ConversationTranscriber Sanntid + diarization
Arkiv-transkribering (100+ filer) Batch Transcription API Asynkron, skalerbar
Kort lydfil (< 5 min) Fast Transcription API Synkron, låg latency
Fleirspråkleg teneste Speech Translation SDK Sanntid omsetjing
Kontekstuell omsetjing Transkribering + GPT-4o Betre kvalitet
Callcenter-analyse Batch + sentiment + oppsummering End-to-end innsikt
Video-untertekstar Batch + VTT-generering WCAG-kompatibelt
On-premises krav Speech containers + Batch Kit Ingen data ut av nettverk

For Cosmo

  • Batch Transcription API er standard for volumbasert transkribering — asynkron prosessering av store lydarkiv med diarization (opp til 35 talarar), ordnivå-tidsstempel og automatisk interpunksjon, resultat til eigen Azure Storage.
  • Diarization er tilgjengeleg i både sanntid og batch — ConversationTranscriber (SDK) for live-møte, og diarizationEnabled + diarization.speakers i Batch API for opptak, med speaker-ID per frase i output.
  • Norsk bokmål (nb-NO) er fullt støtta for STT — Custom Speech med plain text og structured text-treningsdata forbetrar gjenkjenning av fagterminologi (t.d. "detaljreguleringsplan", "konsekvensutgreiing").
  • Kombiner transkribering med Azure OpenAI for verdiskaping — GPT-4o kan oppsummere møtereferat, trekke ut vedtakspunkt, kategorisere henvendelsestypar og utføre kontekstuell omsetjing med betre kvalitet enn direkte taleoversetting.
  • Human-in-the-loop basert på confidence scores er påkravd for juridisk bindande transkripsjoner — automatisk godkjenning over 0.85, manuell korrekturlesing for 0.6-0.85, og re-innspeling under 0.6.