AI-103 Part 4: Text Analysis Solutions
Part 4 of 5 — 10–15% of the AI-103 exam. It covers Azure AI Language Service (sentiment, NER, PII, key phrases, language detection), Conversational Language Understanding (CLU), Custom NER, Azure AI Speech (STT/TTS, speaker diarization), and Azure AI Translator.
Text and Speech Services Landscape
Azure AI Language Service
The Azure AI Language service is a managed NLP service that provides pre-trained analysis
capabilities accessible through the TextAnalyticsClient in the
azure-ai-textanalytics SDK. Each capability is invoked as a separate method
call on the same client, and you can batch multiple documents in a single request.
Built-in Language Capabilities
| Feature | SDK method | Output | Typical use case |
|---|---|---|---|
| Sentiment Analysis |
analyze_sentiment() |
positive/neutral/negative + confidence scores at document and sentence level | Product reviews, support ticket triage |
| Named Entity Recognition |
recognize_entities() |
Entity text, category (Person, Location, Organization, Date, Quantity, URL) | Metadata extraction, document tagging |
| Key Phrase Extraction |
extract_key_phrases() |
List of significant noun phrases | Topic summarization, search indexing |
| PII Detection |
recognize_pii_entities() |
PII entities detected; redacted text with *** masking | GDPR compliance, log sanitization |
| Linked Entities |
recognize_linked_entities() |
Entity + Wikipedia URL + confidence | Knowledge graph enrichment |
| Language Detection |
detect_language() |
ISO 639-1 language code + confidence | Route multilingual content to the right pipeline |
| Text Summarization |
begin_abstract_summary() / begin_extract_summary()
|
Abstractive: generated summary; Extractive: selected key sentences with ranking scores | Document summaries, news digests, meeting notes |
| Question Answering | Custom Question Answering (Language Studio project) | Answer + confidence score from a curated Q&A knowledge base | FAQ bots, support knowledge bases |
Python Example: Sentiment, Key Phrases, and Entities
from azure.ai.textanalytics import TextAnalyticsClient
from azure.core.credentials import AzureKeyCredential
client = TextAnalyticsClient(
endpoint="https://my-language.cognitiveservices.azure.com/",
credential=AzureKeyCredential("YOUR_KEY")
)
documents = [
"The Azure AI Language service is incredibly powerful and easy to use.",
"The documentation was confusing and the setup took too long.",
]
# Sentiment — document-level AND sentence-level scores
sentiment_results = client.analyze_sentiment(documents, show_opinion_mining=True)
for doc in sentiment_results:
print(f"Document sentiment: {doc.sentiment}")
print(f" Positive: {doc.confidence_scores.positive:.2f}, "
f"Neutral: {doc.confidence_scores.neutral:.2f}, "
f"Negative: {doc.confidence_scores.negative:.2f}")
for sentence in doc.sentences:
print(f" Sentence '{sentence.text}' → {sentence.sentiment}")
# Key phrases
kp_results = client.extract_key_phrases(documents)
for doc in kp_results:
print(f"Key phrases: {', '.join(doc.key_phrases)}")
# Named Entity Recognition
ner_results = client.recognize_entities(
["Satya Nadella announced Azure AI at Microsoft Build in Seattle."]
)
for doc in ner_results:
for entity in doc.entities:
print(f" {entity.text} ({entity.category}, confidence: {entity.confidence_score:.2f})")
# PII detection — also returns redacted text
pii_results = client.recognize_pii_entities(
["Call John Smith at 425-555-1234 or john@example.com"]
)
for doc in pii_results:
print(f" Redacted: {doc.redacted_text}")
for entity in doc.entities:
print(f" PII: {entity.text} ({entity.category})")
Custom NLP — CLU and Custom NER
Conversational Language Understanding (CLU)
CLU is the successor to LUIS (Language Understanding Intelligent Service). It classifies user utterances into intents and extracts entities, making it the foundation for chatbots and voice assistants. CLU projects are created and trained in Language Studio. The model learns from labeled examples that pair utterances with their intent and entity annotations.
Intents represent the user's goal — what they want to do. For example:
BookFlight, GetWeather, CancelOrder.
Entities are the specific values extracted from the utterance that
parameterize the action — for example the destination city and departure date in a
BookFlight intent.
CLU differs from the built-in NER feature: NER identifies and categorizes named entities (persons, locations, organizations) without any notion of user intent. CLU is specifically for intent classification plus entity extraction in a conversational context, where you define your own set of intents and entity types for your domain.
from azure.ai.language.conversations import ConversationAnalysisClient
from azure.core.credentials import AzureKeyCredential
client = ConversationAnalysisClient(
endpoint="https://my-language.cognitiveservices.azure.com/",
credential=AzureKeyCredential("YOUR_KEY")
)
result = client.analyze_conversation(
task={
"kind": "Conversation",
"analysisInput": {
"conversationItem": {
"text": "Book a flight to Helsinki next Friday",
"id": "1",
"participantId": "user1"
}
},
"parameters": {
"projectName": "travel-assistant",
"deploymentName": "production",
"verbose": True
}
}
)
prediction = result["result"]["prediction"]
print(f"Top intent: {prediction['topIntent']}")
print(f"Confidence: {prediction['intents'][0]['confidence']:.2f}")
for entity in prediction.get("entities", []):
print(f" Entity: {entity['text']} → {entity['category']}")
Custom NER
Custom NER lets you train a model to extract domain-specific entities that the built-in NER does not cover — for example, extracting legal clause references from contracts, or extracting drug names and dosages from medical notes. The workflow is the same as CLU: label your training documents in Language Studio, train the model, evaluate F1 score per entity type, then deploy and call via the same Conversations API endpoint.
Microsoft recommends a minimum of 10 labeled examples per entity type for training, though more is always better. After training you review precision, recall, and F1 score per entity type and add more examples where the model is underperforming.
Exam tip: CLU replaces LUIS. LUIS was retired on March 31, 2026 (the LUIS portal became unavailable on October 31, 2025). If an exam scenario mentions LUIS, it is referring to the legacy service — the correct modern answer is CLU. Both CLU and Custom NER are trained through Language Studio and deployed to the same Azure AI Language endpoint.
Azure AI Speech
The Azure AI Speech service handles all audio-to-text and text-to-audio scenarios. It
uses the azure-cognitiveservices-speech SDK (also called the Speech SDK).
Unlike the Language service's REST-friendly batch model, the Speech SDK is typically
used for real-time streaming scenarios where you need continuous recognition or
low-latency synthesis.
Speech-to-Text (STT)
There are two recognition modes. Single-utterance recognition
(recognize_once_async()) listens until a pause is detected and returns one
result — suitable for command-and-control scenarios. Continuous
recognition streams audio and fires callbacks for each recognized segment —
suitable for transcribing meetings, interviews, or phone calls.
import azure.cognitiveservices.speech as speechsdk
speech_config = speechsdk.SpeechConfig(
subscription="YOUR_KEY",
region="eastus"
)
speech_config.speech_recognition_language = "en-US"
# Single utterance from microphone
audio_config = speechsdk.audio.AudioConfig(use_default_microphone=True)
recognizer = speechsdk.SpeechRecognizer(
speech_config=speech_config,
audio_config=audio_config
)
result = recognizer.recognize_once_async().get()
if result.reason == speechsdk.ResultReason.RecognizedSpeech:
print(f"Recognized: {result.text}")
elif result.reason == speechsdk.ResultReason.NoMatch:
print("No speech could be recognized.")
elif result.reason == speechsdk.ResultReason.Canceled:
cancellation = result.cancellation_details
print(f"Canceled: {cancellation.reason}, {cancellation.error_details}")
# From audio file
file_config = speechsdk.audio.AudioConfig(filename="recording.wav")
file_recognizer = speechsdk.SpeechRecognizer(
speech_config=speech_config,
audio_config=file_config
)
result2 = file_recognizer.recognize_once_async().get()
print(result2.text)
Text-to-Speech (TTS)
TTS converts text to spoken audio using neural voices. Azure has over 400 neural voices across 140+ languages. You can use SSML (Speech Synthesis Markup Language) to control prosody — pauses, rate, pitch, emphasis, and voice style (cheerful, sad, newscast, etc.). Custom Neural Voice lets you train a voice model on recordings of a specific speaker, subject to access approval.
import azure.cognitiveservices.speech as speechsdk
speech_config = speechsdk.SpeechConfig(subscription="YOUR_KEY", region="eastus")
speech_config.speech_synthesis_voice_name = "en-US-JennyNeural"
# Synthesize to speaker
synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config)
result = synthesizer.speak_text_async("Hello from Azure AI Speech!").get()
# SSML for prosody control
ssml = """
Welcome to the Azure AI certification study guide.
"""
result2 = synthesizer.speak_ssml_async(ssml).get()
Speaker Diarization
Speaker diarization identifies which speaker is talking at each point in a multi-speaker
recording. It is configured through the SpeakerDiarizationConfig on the
AutoDetectSourceLanguageConfig or through the
ConversationTranscriber. The result includes a speaker ID for each
recognized segment. Note that diarization is only available through the Speech SDK — the
REST batch transcription API also supports it for audio files.
Speech Translation
The Speech translation feature converts spoken audio directly to text in a different
language in real time. It uses a TranslationRecognizer configured with
source language and one or more target translation languages. This is distinct from
using STT followed by Translator — the combined speech translation is optimized for
conversational latency.
Exam tip: Speaker diarization requires the Speech SDK — it is not available through the simple REST API. For batch audio file transcription with diarization, use the batch transcription REST API with
diarizationsettings in the JSON body.
Azure AI Translator
Azure AI Translator is a separate cognitive service for text and document translation. It
supports over 100 languages and handles auto-detection of the source language when you
omit it from the request. The REST API is straightforward and does not require an SDK,
though the azure-ai-translation-text package is available.
Translator Capabilities
- Text translation: Translate text strings in a single request; supports multiple target languages in one call
- Document translation: Translate entire documents (Word, PDF, HTML, etc.) while preserving the original formatting; runs as an asynchronous batch job
- Auto-language detection: If you omit the
fromparameter, the service detects the source language automatically - Transliteration: Convert text between scripts without translating the meaning — for example, convert Arabic text to Latin characters (romanization)
- Custom Translator: Train a custom translation model on domain-specific parallel corpus (e.g., medical or legal texts) to improve accuracy for specialized vocabulary
import requests, uuid
key = "YOUR_TRANSLATOR_KEY"
endpoint = "https://api.cognitive.microsofttranslator.com"
location = "eastus"
headers = {
"Ocp-Apim-Subscription-Key": key,
"Ocp-Apim-Subscription-Region": location,
"Content-type": "application/json",
"X-ClientTraceId": str(uuid.uuid4())
}
# Translate to multiple target languages in one call
body = [{"text": "Hello, how are you today?"}]
params = {
"api-version": "3.0",
# "from": "en", # omit to use auto-detection
"to": ["fi", "de", "ja"]
}
response = requests.post(
f"{endpoint}/translate",
params=params,
headers=headers,
json=body
)
translations = response.json()
for translation in translations[0]["translations"]:
print(f"{translation['to']}: {translation['text']}")
# Transliteration (Arabic → Latin)
body2 = [{"text": "مرحبا"}]
params2 = {
"api-version": "3.0",
"language": "ar",
"fromScript": "Arab",
"toScript": "Latn"
}
response2 = requests.post(f"{endpoint}/transliterate", params=params2, headers=headers, json=body2)
print(response2.json()[0]["text"]) # → "mrhba"
Exam tip: When you know the source language, specify it in the
fromparameter rather than relying on auto-detection. Auto-detection adds a small latency and costs a minor additional detection call. For high-volume production workloads, always specify the source language explicitly.
LLM-Powered Text Analysis
The updated AI-103 study guide explicitly covers using generative AI for text analysis tasks — not just the classical Azure AI Language endpoints. For many scenarios, prompting GPT-4o or Phi-4 with structured output instructions is more flexible than training a custom NER or CLU model, especially for domain-specific or low-volume tasks.
Structured Entity Extraction with JSON Mode
Use response_format={"type": "json_object"} with a clear schema in the
system prompt to extract structured entities from text without a custom NER model. This
is practical for domain-specific fields — contract clause types, medical terminology,
financial line items — where the Azure AI Language prebuilt models do not have
sufficient coverage.
from openai import AzureOpenAI
client = AzureOpenAI(
azure_endpoint="https://<resource>.openai.azure.com/",
api_key="<key>",
api_version="2024-08-01-preview"
)
system_prompt = """Extract the following fields from the contract clause and return as JSON:
{
"clause_type": string,
"parties": [string],
"effective_date": string or null,
"obligation": string
}"""
response = client.chat.completions.create(
model="gpt-4o",
response_format={"type": "json_object"},
messages=[
{"role": "system", "content": system_prompt},
{"role": "user", "content": clause_text}
]
)
import json
extracted = json.loads(response.choices[0].message.content)
print(extracted)
When to Use Azure AI Language vs. LLM Prompting
| Factor | Azure AI Language | LLM Prompting (GPT-4o/Phi-4) |
|---|---|---|
| Cost per call | Low (fixed per text record) | Higher (token-based) |
| Latency | Low (dedicated endpoint) | Higher (LLM generation time) |
| Domain coverage | General + custom training required for specialist terms | Broad — handles domain-specific fields via prompt description |
| Output predictability | Deterministic structured response | Variable unless JSON mode is enforced |
| Best for | High-volume, standard NLP tasks (sentiment, generic NER, PII) | Low-volume, complex, or novel extraction tasks |
Speech as an Agent Modality
The updated study guide covers integrating Speech into agentic pipelines — not just standalone STT/TTS. When an agent interacts with a user via voice, the speech pipeline feeds directly into the agent's reasoning loop.
STT → Agent → TTS Pipeline
import azure.cognitiveservices.speech as speechsdk
speech_config = speechsdk.SpeechConfig(
subscription="<key>",
region="eastus"
)
speech_config.speech_synthesis_voice_name = "en-US-AvaMultilingualNeural"
# Step 1: Transcribe user speech
recognizer = speechsdk.SpeechRecognizer(speech_config=speech_config)
result = recognizer.recognize_once()
user_text = result.text # "What are today's sales figures?"
# Step 2: Pass to agent (Azure AI Agent Service or custom)
agent_response = agent.run(user_text) # returns text
# Step 3: Synthesise response as speech
synthesizer = speechsdk.SpeechSynthesizer(speech_config=speech_config)
synthesizer.speak_text_async(agent_response).get()
Batch Transcription for Agent Inputs
For agents that process historical call recordings — customer service QA, compliance review — use the batch transcription REST API rather than the real-time Speech SDK. Batch transcription submits audio files stored in Azure Blob Storage and returns transcript files asynchronously. Enable speaker diarization in the batch job to tag each segment with a speaker label, then feed the labelled transcript as structured context to the LLM.
Exam note: Real-time streaming STT uses the Speech SDK's
SpeechRecognizer. Batch transcription for stored audio files uses the REST API endpoint/speechtotext/v3.1/transcriptions. Speaker diarization is configured differently for each: it's a property in the SDK'sSpeechConfigvs. adiarizationfield in the batch job JSON body.
Exam Tips & Key Takeaways
- CLU replaces LUIS. Any exam question referencing LUIS is about a deprecated service. The current service for intent classification and entity extraction in conversational scenarios is Conversational Language Understanding (CLU), accessed through the Azure AI Language endpoint.
- PII detection has two modes.
recognize_pii_entities()returns both the detected PII entities (for auditing) andredacted_text(with PII replaced by asterisks or category labels). Choose based on whether you need to inspect the PII or just remove it. - Speaker diarization requires the Speech SDK. It is not available
through the simple one-shot REST API. Use the Speech SDK with a
ConversationTranscriber, or the batch transcription REST API for file-based scenarios. - Custom NER: minimum 10 examples per entity type. Below this threshold the model training may succeed but precision will be unreliable. Aim for 50+ examples per entity type for production quality.
- Translator auto-detect adds cost and latency. Specify the source
language when known to reduce both. For multi-language input where you genuinely do
not know the language, combine the Language service's
detect_language()with Translator. - Batch document translation is asynchronous. Unlike text translation which is synchronous, document translation submits a job and you poll for completion — the output is written to an Azure Blob Storage container you specify in the request.