Skip to content

Commit de20f64

Browse files
Merge pull request #674 from openlayer-ai/stlc/promote
Promote staging to production (44acff9)
2 parents 27c60e0 + 44acff9 commit de20f64

7 files changed

Lines changed: 1645 additions & 2 deletions

File tree

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"metadata": {},
6+
"source": [
7+
"[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/openlayer-ai/openlayer-python/blob/main/examples/tracing/azure-speech/azure_speech_tracing.ipynb)\n",
8+
"\n",
9+
"\n",
10+
"# <a id=\"top\">Azure AI Speech tracing quickstart</a>\n",
11+
"\n",
12+
"This notebook illustrates how to monitor Azure AI Speech (speech-to-text, speech translation and text-to-speech) with Openlayer.\n",
13+
"\n",
14+
"The Speech SDK and the Openlayer tracer both run in your backend: the Azure key stays in your server-side configuration and is never sent to Openlayer. Only non-secret settings (region, language, voice, custom endpoint ID, output format), the recognized text or synthesized-audio stats, latency and failure details are traced. Do not ship either the Azure key or the Openlayer API key in browser or mobile code."
15+
]
16+
},
17+
{
18+
"cell_type": "code",
19+
"execution_count": null,
20+
"metadata": {},
21+
"outputs": [],
22+
"source": [
23+
"!pip install openlayer azure-cognitiveservices-speech"
24+
]
25+
},
26+
{
27+
"cell_type": "markdown",
28+
"metadata": {},
29+
"source": [
30+
"## 1. Set the environment variables"
31+
]
32+
},
33+
{
34+
"cell_type": "code",
35+
"execution_count": null,
36+
"metadata": {},
37+
"outputs": [],
38+
"source": [
39+
"import os\n",
40+
"\n",
41+
"# Azure AI Speech env variables (load these from your secret store in production)\n",
42+
"os.environ[\"AZURE_SPEECH_KEY\"] = \"YOUR_AZURE_SPEECH_KEY_HERE\"\n",
43+
"os.environ[\"AZURE_SPEECH_REGION\"] = \"YOUR_AZURE_SPEECH_REGION_HERE\"\n",
44+
"\n",
45+
"# Openlayer env variables\n",
46+
"os.environ[\"OPENLAYER_API_KEY\"] = \"YOUR_OPENLAYER_API_KEY_HERE\"\n",
47+
"os.environ[\"OPENLAYER_INFERENCE_PIPELINE_ID\"] = \"YOUR_OPENLAYER_INFERENCE_PIPELINE_ID_HERE\""
48+
]
49+
},
50+
{
51+
"cell_type": "markdown",
52+
"metadata": {},
53+
"source": [
54+
"## 2. Initialize Openlayer and create the Speech clients\n",
55+
"\n",
56+
"`init()` auto-instruments every `SpeechRecognizer`, `TranslationRecognizer` and `SpeechSynthesizer` created afterwards. You can also trace a single client explicitly with `trace_azure_speech(client)`.\n",
57+
"\n",
58+
"Audio is **not** sent to Openlayer by default. Set `attachment_upload_enabled=True` only if your security and privacy requirements allow storing audio in Openlayer; synthesized audio and any input audio you pass as `openlayer_audio` are then uploaded alongside the trace."
59+
]
60+
},
61+
{
62+
"cell_type": "code",
63+
"execution_count": null,
64+
"metadata": {},
65+
"outputs": [],
66+
"source": [
67+
"import azure.cognitiveservices.speech as speechsdk\n",
68+
"\n",
69+
"from openlayer.lib import init\n",
70+
"\n",
71+
"init(\n",
72+
" attachment_upload_enabled=False, # set to True to upload audio to Openlayer\n",
73+
")\n",
74+
"\n",
75+
"speech_config = speechsdk.SpeechConfig(\n",
76+
" subscription=os.environ[\"AZURE_SPEECH_KEY\"],\n",
77+
" region=os.environ[\"AZURE_SPEECH_REGION\"],\n",
78+
")\n",
79+
"speech_config.speech_recognition_language = \"en-US\"\n",
80+
"speech_config.speech_synthesis_voice_name = \"en-US-JennyNeural\""
81+
]
82+
},
83+
{
84+
"cell_type": "markdown",
85+
"metadata": {},
86+
"source": [
87+
"## 3. Use your traced clients normally\n",
88+
"\n",
89+
"### Text-to-speech"
90+
]
91+
},
92+
{
93+
"cell_type": "code",
94+
"execution_count": null,
95+
"metadata": {},
96+
"outputs": [],
97+
"source": [
98+
"synthesizer = speechsdk.SpeechSynthesizer( # auto-traced by Openlayer\n",
99+
" speech_config=speech_config,\n",
100+
" audio_config=speechsdk.audio.AudioOutputConfig(filename=\"greeting.wav\"),\n",
101+
")\n",
102+
"\n",
103+
"result = synthesizer.speak_text(\"Hello! Thanks for calling. How can I help you today?\")\n",
104+
"result.reason"
105+
]
106+
},
107+
{
108+
"cell_type": "markdown",
109+
"metadata": {},
110+
"source": [
111+
"### Speech-to-text\n",
112+
"\n",
113+
"The Speech SDK does not expose the audio behind an `AudioConfig`, so pass the same file as `openlayer_audio` if you want it attached to the trace (only used when attachment uploads are enabled)."
114+
]
115+
},
116+
{
117+
"cell_type": "code",
118+
"execution_count": null,
119+
"metadata": {},
120+
"outputs": [],
121+
"source": [
122+
"recognizer = speechsdk.SpeechRecognizer( # auto-traced by Openlayer\n",
123+
" speech_config=speech_config,\n",
124+
" audio_config=speechsdk.audio.AudioConfig(filename=\"greeting.wav\"),\n",
125+
")\n",
126+
"\n",
127+
"result = recognizer.recognize_once(openlayer_audio=\"greeting.wav\")\n",
128+
"result.reason, result.text"
129+
]
130+
},
131+
{
132+
"cell_type": "markdown",
133+
"metadata": {},
134+
"source": [
135+
"### Grouping calls into one trace\n",
136+
"\n",
137+
"Wrap a conversational turn in `@trace` to see recognition and synthesis as steps of the same trace."
138+
]
139+
},
140+
{
141+
"cell_type": "code",
142+
"execution_count": null,
143+
"metadata": {},
144+
"outputs": [],
145+
"source": [
146+
"from openlayer.lib import trace\n",
147+
"\n",
148+
"\n",
149+
"@trace()\n",
150+
"def voice_turn(audio_path: str) -> str:\n",
151+
" recognizer = speechsdk.SpeechRecognizer(\n",
152+
" speech_config=speech_config,\n",
153+
" audio_config=speechsdk.audio.AudioConfig(filename=audio_path),\n",
154+
" )\n",
155+
" heard = recognizer.recognize_once(openlayer_audio=audio_path).text\n",
156+
"\n",
157+
" reply = f\"You said: {heard}\"\n",
158+
" speechsdk.SpeechSynthesizer(speech_config=speech_config, audio_config=None).speak_text(reply)\n",
159+
" return reply\n",
160+
"\n",
161+
"\n",
162+
"voice_turn(\"greeting.wav\")"
163+
]
164+
},
165+
{
166+
"cell_type": "markdown",
167+
"metadata": {},
168+
"source": [
169+
"That's it! The Speech calls are published to Openlayer and you can start creating tests around them."
170+
]
171+
}
172+
],
173+
"metadata": {
174+
"kernelspec": {
175+
"display_name": "Python 3",
176+
"language": "python",
177+
"name": "python3"
178+
},
179+
"language_info": {
180+
"name": "python",
181+
"version": "3.12"
182+
}
183+
},
184+
"nbformat": 4,
185+
"nbformat_minor": 5
186+
}

‎src/openlayer/lib/__init__.py‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
"trace_async",
1717
"trace_bedrock",
1818
"trace_azure_content_understanding",
19+
"trace_azure_speech",
1920
"trace_oci_genai",
2021
"trace_oci", # Alias for backward compatibility
2122
"trace_litellm",
@@ -167,6 +168,22 @@ def trace_azure_content_understanding(client):
167168
return azure_content_understanding_tracer.trace_azure_content_understanding(client)
168169

169170

171+
def trace_azure_speech(client):
172+
"""Trace Azure AI Speech recognition, translation and synthesis calls."""
173+
# pylint: disable=import-outside-toplevel
174+
try:
175+
import azure.cognitiveservices.speech # noqa: F401
176+
except ImportError:
177+
raise ImportError(
178+
"azure-cognitiveservices-speech is required for Azure Speech tracing. "
179+
"Install with: pip install azure-cognitiveservices-speech"
180+
)
181+
182+
from .integrations import azure_speech_tracer
183+
184+
return azure_speech_tracer.trace_azure_speech(client)
185+
186+
170187
def trace_oci_genai(client, estimate_tokens: bool = True):
171188
"""Trace OCI GenAI chat completions.
172189

‎src/openlayer/lib/integrations/_auto.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,12 @@ def _do_patch() -> None:
169169
_patch_via("azure_content_understanding_tracer", "_patch_acu"),
170170
_patch_via("azure_content_understanding_tracer", "_unpatch_acu"),
171171
),
172+
IntegrationSpec(
173+
"azure_speech",
174+
"azure.cognitiveservices.speech",
175+
_patch_via("azure_speech_tracer", "_patch_azure_speech"),
176+
_patch_via("azure_speech_tracer", "_unpatch_azure_speech"),
177+
),
172178
IntegrationSpec(
173179
"litellm",
174180
"litellm",

0 commit comments

Comments
 (0)