Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 110
Feature/speech managed identity#543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
1316950b2307fc080cbcc8e1c441f1f1b15d1b5661994f28eFile filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -4765,6 +4765,24 @@ def _split_audio_file(input_path: str, chunk_seconds: int = 540) -> List[str]: | ||
| print(f"Produced {len(chunks)} WAV chunks: {chunks}") | ||
| return chunks | ||
| # Azure Speech SDK helper to get speech config with fresh token | ||
| def _get_speech_config(settings, endpoint: str, locale: str): | ||
| """Get speech config with fresh token""" | ||
| if settings.get("speech_service_authentication_type") == "managed_identity": | ||
| credential = DefaultAzureCredential() | ||
| token = credential.get_token(cognitive_services_scope) | ||
| speech_config = speechsdk.SpeechConfig(endpoint=endpoint) | ||
| # Set the authorization token AFTER creating the config | ||
| speech_config.authorization_token = token.token | ||
| else: | ||
| key = settings.get("speech_service_key", "") | ||
| speech_config = speechsdk.SpeechConfig(endpoint=endpoint, subscription=key) | ||
| speech_config.speech_recognition_language = locale | ||
| print(f"[Debug] Speech config obtained successfully", flush=True) | ||
| return speech_config | ||
| def process_audio_document( | ||
| document_id: str, | ||
| user_id: str, | ||
| @@ -4804,32 +4822,65 @@ def process_audio_document( | ||
| # 3) transcribe each WAV chunk | ||
| settings = get_settings() | ||
| endpoint = settings.get("speech_service_endpoint", "").rstrip('/') | ||
| key = settings.get("speech_service_key", "") | ||
| locale = settings.get("speech_service_locale", "en-US") | ||
| url = f"{endpoint}/speechtotext/transcriptions:transcribe?api-version=2024-11-15" | ||
| all_phrases: List[str] = [] | ||
| for idx, chunk_path in enumerate(chunk_paths, start=1): | ||
| update_callback(current_file_chunk=idx, status=f"Transcribing chunk {idx}/{len(chunk_paths)}…") | ||
| print(f"Transcribing WAV chunk: {chunk_path}") | ||
| with open(chunk_path, 'rb') as audio_f: | ||
| files = { | ||
| 'audio': (os.path.basename(chunk_path), audio_f, 'audio/wav'), | ||
| 'definition': (None, json.dumps({'locales':[locale]}), 'application/json') | ||
| } | ||
| headers = {'Ocp-Apim-Subscription-Key': key} | ||
| resp = requests.post(url, headers=headers, files=files) | ||
| try: | ||
| resp.raise_for_status() | ||
| except Exception as e: | ||
| print(f"[Error] HTTP error for {chunk_path}: {e}") | ||
| raise | ||
| result = resp.json() | ||
| phrases = result.get('combinedPhrases', []) | ||
| print(f"Received {len(phrases)} phrases") | ||
| all_phrases += [p.get('text','').strip() for p in phrases if p.get('text')] | ||
| # Fast Transcription API not yet available in sovereign clouds, so use SDK | ||
| if AZURE_ENVIRONMENT in ("usgovernment", "custom"): | ||
| for idx, chunk_path in enumerate(chunk_paths, start=1): | ||
| print(f"[Debug] Transcribing chunk {idx}: {chunk_path}") | ||
| # Get fresh config (tokens expire after ~1 hour) | ||
| speech_config = _get_speech_config(settings, endpoint, locale) | ||
| audio_config = speechsdk.AudioConfig(filename=chunk_path) | ||
| speech_recognizer = speechsdk.SpeechRecognizer( | ||
| speech_config=speech_config, | ||
| audio_config=audio_config | ||
| ) | ||
| result = speech_recognizer.recognize_once() | ||
| if result.reason == speechsdk.ResultReason.RecognizedSpeech: | ||
| print(f"[Debug] Recognized: {result.text}") | ||
| all_phrases.append(result.text) | ||
| elif result.reason == speechsdk.ResultReason.NoMatch: | ||
| print(f"[Warning] No speech in {chunk_path}") | ||
| elif result.reason == speechsdk.ResultReason.Canceled: | ||
| print(f"[Error] {result.cancellation_details.reason}: {result.cancellation_details.error_details}") | ||
| raise RuntimeError(f"Transcription canceled for {chunk_path}: {result.cancellation_details.error_details}") | ||
Comment on lines
+4831
to
+4851
CopilotAI | ||
| else: | ||
| # Use the fast-transcription API if not in sovereign or custom cloud | ||
| url = f"{endpoint}/speechtotext/transcriptions:transcribe?api-version=2024-11-15" | ||
| for idx, chunk_path in enumerate(chunk_paths, start=1): | ||
| update_callback(current_file_chunk=idx, status=f"Transcribing chunk {idx}/{len(chunk_paths)}…") | ||
| print(f"[Debug] Transcribing WAV chunk: {chunk_path}") | ||
| with open(chunk_path, 'rb') as audio_f: | ||
| files = { | ||
| 'audio': (os.path.basename(chunk_path), audio_f, 'audio/wav'), | ||
| 'definition': (None, json.dumps({'locales':[locale]}), 'application/json') | ||
| } | ||
| if settings.get("speech_service_authentication_type") == "managed_identity": | ||
| credential = DefaultAzureCredential() | ||
| token = credential.get_token(cognitive_services_scope) | ||
| headers = {'Authorization': f'Bearer {token.token}'} | ||
| else: | ||
| key = settings.get("speech_service_key", "") | ||
| headers = {'Ocp-Apim-Subscription-Key': key} | ||
| resp = requests.post(url, headers=headers, files=files) | ||
| try: | ||
| resp.raise_for_status() | ||
| except Exception as e: | ||
| print(f"[Error] HTTP error for {chunk_path}: {e}") | ||
| raise | ||
| result = resp.json() | ||
| phrases = result.get('combinedPhrases', []) | ||
| print(f"[Debug] Received {len(phrases)} phrases") | ||
| all_phrases += [p.get('text','').strip() for p in phrases if p.get('text')] | ||
| # 4) cleanup WAV chunks | ||
| for p in chunk_paths: | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -369,18 +369,24 @@ <h4>9. Enable Audio File Support</h4> | ||
| <strong>Required:</strong> Audio support configuration is required if workspaces are enabled. | ||
| </div> | ||
| <p class="mb-3">Use the <strong>Audio Support</strong> settings in the Workspaces tab to enable and configure audio file processing.</p> | ||
| <p class="mb-3">Use the <strong>Audio Support</strong> settings on the Search & Extract tab to enable and configure audio file processing.</p> | ||
| <ul class="list-group mb-4"> | ||
| <li class="list-group-item d-flex justify-content-between align-items-center"> | ||
| <span>Speech Service Endpoint</span> | ||
| <span id="audio-endpoint-badge" class="badge bg-danger">Required</span> | ||
| </li> | ||
| <li class="list-group-item d-flex justify-content-between align-items-center"> | ||
| <span>Speech Service Key</span> | ||
| <span id="audio-key-badge" class="badge bg-danger">Required</span> | ||
| <span>Authentication</span> | ||
| <span id="speech-auth-badge" class="badge bg-danger">Required</span> | ||
| </li> | ||
| </ul> | ||
| <div class="alert alert-info"> | ||
| <strong>Note:</strong> If using Managed Identity authentication ensure the Service Principal has been assigned the Cognitive Services Speech Contributor role on the Azure Speech Service and that the Speech endpoint is configured with a custom domain name. | ||
| <i class="bi bi-info-circle ms-2" data-bs-toggle="tooltip" title="When a Cognitive Service has a custom domain name, the endpoint will typically look like https://<resource-name>.cognitiveservices.azure.<com or us> instead of https://<location>.cognitiveservices.azure.<com or us>"></i> | ||
| </div> | ||
| </div> | ||
| <!-- Step 10: Content Safety --> | ||
| @@ -2831,7 +2837,7 @@ <h5>Speech Service Settings</h5> | ||
| <input type="text" class="form-control" | ||
| id="speech_service_endpoint" name="speech_service_endpoint" | ||
| value="{{ settings.speech_service_endpoint or '' }}" | ||
| placeholder="https://<location>.cognitiveservices.azure.<com or us>/"> | ||
| placeholder="https://<location or custom domain>.cognitiveservices.azure.<com or us>/"> | ||
| </div> | ||
| <div class="mb-3"> | ||
| @@ -2849,17 +2855,41 @@ <h5>Speech Service Settings</h5> | ||
| </div> | ||
| <div class="mb-3"> | ||
| <label for="speech_service_key" class="form-label">API Key</label> | ||
| <label for="speech_service_authentication_type" class="form-label"> | ||
| Authentication Type | ||
| </label> | ||
| <select class="form-select" id="speech_service_authentication_type" name="speech_service_authentication_type"> | ||
| <option value="key" {% if settings.speech_service_authentication_type == 'key' or not settings.speech_service_authentication_type %}selected{% endif %}> | ||
| Key | ||
| </option> | ||
| <option value="managed_identity" {% if settings.speech_service_authentication_type == 'managed_identity' %}selected{% endif %}> | ||
| Managed Identity | ||
| </option> | ||
| </select> | ||
| </div> | ||
| <div class="mb-3" id="speech_service_key_container" {% if settings.speech_service_authentication_type == 'managed_identity' %}style="display: none;"{% endif %}> | ||
| <label for="speech_service_key" class="form-label"> | ||
| API Key | ||
| </label> | ||
| <div class="input-group"> | ||
| <input type="password" class="form-control" | ||
| id="speech_service_key" name="speech_service_key" | ||
| value="{{ settings.speech_service_key or '' }}"> | ||
| <button type="button" class="btn btn-outline-secondary" | ||
| id="toggle_speech_service_key">Show</button> | ||
| <input | ||
| type="password" | ||
| class="form-control" | ||
| id="speech_service_key" | ||
| name="speech_service_key" | ||
| value="{{ settings.speech_service_key or '' }}" | ||
| > | ||
| <button | ||
| type="button" | ||
| class="btn btn-outline-secondary" | ||
| id="toggle_speech_service_key" | ||
| > | ||
| Show | ||
| </button> | ||
| </div> | ||
| </div> | ||
| </div> | ||
paullizer marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| </div> | ||
| <p class="mt-2 mb-0"> | ||
| <small class="text-muted"> | ||
| <a href="#citation" onclick="switchTab(event, 'citation-tab')"> | ||
Uh oh!
There was an error while loading. Please reload this page.
CopilotAIDec 19, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Import of 'speechsdk' is not used.