File: SpeechToText\SpeechToTextResponseUpdateExtensions.cs
Web Access
Project: src\src\Libraries\Microsoft.Extensions.AI.Abstractions\Microsoft.Extensions.AI.Abstractions.csproj (Microsoft.Extensions.AI.Abstractions)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Shared.Diagnostics;
 
namespace Microsoft.Extensions.AI;
 
/// <summary>
/// Provides extension methods for working with <see cref="SpeechToTextResponseUpdate"/> instances.
/// </summary>
[Experimental("MEAI001")]
public static class SpeechToTextResponseUpdateExtensions
{
    /// <summary>Combines <see cref="SpeechToTextResponseUpdate"/> instances into a single <see cref="SpeechToTextResponse"/>.</summary>
    /// <param name="updates">The updates to be combined.</param>
    /// <returns>The combined <see cref="SpeechToTextResponse"/>.</returns>
    public static SpeechToTextResponse ToSpeechToTextResponse(
        this IEnumerable<SpeechToTextResponseUpdate> updates)
    {
        _ = Throw.IfNull(updates);
 
        SpeechToTextResponse response = new();
        List<AIContent> contents = [];
        string? responseId = null;
        string? modelId = null;
        AdditionalPropertiesDictionary? additionalProperties = null;
 
        TimeSpan? endTime = null;
        foreach (var update in updates)
        {
            // Track the first start time provided by the updates
            response.StartTime ??= update.StartTime;
 
            // Track the last end time provided by the updates
            if (update.EndTime is not null)
            {
                endTime = update.EndTime;
            }
 
            ProcessUpdate(update, contents, ref responseId, ref modelId, ref additionalProperties);
        }
 
        ChatResponseExtensions.CoalesceTextContent(contents);
        response.EndTime = endTime;
        response.Contents = contents;
        response.ResponseId = responseId;
        response.ModelId = modelId;
        response.AdditionalProperties = additionalProperties;
 
        return response;
    }
 
    /// <summary>Combines <see cref="SpeechToTextResponseUpdate"/> instances into a single <see cref="SpeechToTextResponse"/>.</summary>
    /// <param name="updates">The updates to be combined.</param>
    /// <param name="cancellationToken">The <see cref="CancellationToken"/> to monitor for cancellation requests. The default is <see cref="CancellationToken.None"/>.</param>
    /// <returns>The combined <see cref="SpeechToTextResponse"/>.</returns>
    public static Task<SpeechToTextResponse> ToSpeechToTextResponseAsync(
        this IAsyncEnumerable<SpeechToTextResponseUpdate> updates, CancellationToken cancellationToken = default)
    {
        _ = Throw.IfNull(updates);
 
        return ToResponseAsync(updates, cancellationToken);
 
        static async Task<SpeechToTextResponse> ToResponseAsync(
            IAsyncEnumerable<SpeechToTextResponseUpdate> updates, CancellationToken cancellationToken)
        {
            SpeechToTextResponse response = new();
            List<AIContent> contents = [];
            string? responseId = null;
            string? modelId = null;
            AdditionalPropertiesDictionary? additionalProperties = null;
 
            TimeSpan? endTime = null;
            await foreach (var update in updates.WithCancellation(cancellationToken).ConfigureAwait(false))
            {
                // Track the first start time provided by the updates
                response.StartTime ??= update.StartTime;
 
                // Track the last end time provided by the updates
                if (update.EndTime is not null)
                {
                    endTime = update.EndTime;
                }
 
                ProcessUpdate(update, contents, ref responseId, ref modelId, ref additionalProperties);
            }
 
            ChatResponseExtensions.CoalesceTextContent(contents);
 
            response.EndTime = endTime;
            response.Contents = contents;
            response.ResponseId = responseId;
            response.ModelId = modelId;
            response.AdditionalProperties = additionalProperties;
 
            return response;
        }
    }
 
    /// <summary>Processes the <see cref="SpeechToTextResponseUpdate"/>, incorporating its contents and properties.</summary>
    /// <param name="update">The update to process.</param>
    /// <param name="contents">The list of content items being accumulated.</param>
    /// <param name="responseId">The response ID to update if the update has one.</param>
    /// <param name="modelId">The model ID to update if the update has one.</param>
    /// <param name="additionalProperties">The additional properties to update if the update has any.</param>
    private static void ProcessUpdate(
        SpeechToTextResponseUpdate update,
        List<AIContent> contents,
        ref string? responseId,
        ref string? modelId,
        ref AdditionalPropertiesDictionary? additionalProperties)
    {
        if (update.ResponseId is not null)
        {
            responseId = update.ResponseId;
        }
 
        if (update.ModelId is not null)
        {
            modelId = update.ModelId;
        }
 
        contents.AddRange(update.Contents);
 
        if (update.AdditionalProperties is not null)
        {
            if (additionalProperties is null)
            {
                additionalProperties = new(update.AdditionalProperties);
            }
            else
            {
                foreach (var entry in update.AdditionalProperties)
                {
                    additionalProperties[entry.Key] = entry.Value;
                }
            }
        }
    }
}