-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
.Net Issue Fix - Add FunctionResponse to ChatStreaming interfaces (#3246
) ### Motivation and Context Resolves #3198 Today we can't call functions using streaming, this change allows it to be used. The current approach will require the stream to be buffered while listening to a potential function call. The example shows how that will be achieved. ``` StringBuilder chatContent = new(); // Non function result streaming will happen here. await foreach (var message in chatResult.GetStreamingChatMessageAsync()) { if (message.Content is not null) { Console.Write(message.Content); chatContent.Append(message.Content); } } chatHistory.AddAssistantMessage(chatContent.ToString()); // After all stream was loaded check if a `FunctionResponse` was present. var functionResponse = await chatResult.GetStreamingFunctionResponseAsync(); ``` Remark: Calling `GetStreamingFunctionResponseAsync()` will buffer the stream to capture the full function call definition, use it after all the streaming messages were flushed out. ### Description Allows streaming interfaces to get the function result. This is a simplified approach (Buffer the streaming of a function call request until it's complete). Using the FunctionCall ### Contribution Checklist - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
- Loading branch information
1 parent
f3df736
commit 831ff8e
Showing
7 changed files
with
192 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ChatStreamingModelResult.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using Azure.AI.OpenAI; | ||
|
||
namespace Microsoft.SemanticKernel.Connectors.AI.OpenAI.AzureSdk; | ||
|
||
/// <summary> Represents a singular result of a chat completion.</summary> | ||
public class ChatStreamingModelResult | ||
{ | ||
/// <summary> A unique identifier associated with this chat completion response. </summary> | ||
public string Id { get; } | ||
|
||
/// <summary> | ||
/// The first timestamp associated with generation activity for this completions response, | ||
/// represented as seconds since the beginning of the Unix epoch of 00:00 on 1 Jan 1970. | ||
/// </summary> | ||
public DateTimeOffset Created { get; } | ||
|
||
/// <summary> | ||
/// Content filtering results for zero or more prompts in the request. | ||
/// </summary> | ||
public IReadOnlyList<PromptFilterResult> PromptFilterResults { get; } | ||
|
||
/// <summary> | ||
/// The completion choice associated with this completion result. | ||
/// </summary> | ||
public StreamingChatChoice Choice { get; } | ||
|
||
/// <summary> Initializes a new instance of TextModelResult. </summary> | ||
/// <param name="completionsData"> A completions response object to populate the fields relative the response.</param> | ||
/// <param name="choiceData"> A choice object to populate the fields relative to the resulting choice.</param> | ||
internal ChatStreamingModelResult(StreamingChatCompletions completionsData, StreamingChatChoice choiceData) | ||
{ | ||
this.Id = completionsData.Id; | ||
this.Created = completionsData.Created; | ||
this.PromptFilterResults = completionsData.PromptFilterResults; | ||
this.Choice = choiceData; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
dotnet/src/Connectors/Connectors.AI.OpenAI/AzureSdk/ChatStreamingResultExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
// Copyright (c) Microsoft. All rights reserved. | ||
|
||
using System; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Azure.AI.OpenAI; | ||
using Microsoft.SemanticKernel.AI.ChatCompletion; | ||
|
||
namespace Microsoft.SemanticKernel.Connectors.AI.OpenAI.AzureSdk; | ||
|
||
/// <summary> | ||
/// Provides extension methods for the IChatStreamingResult interface. | ||
/// </summary> | ||
public static class ChatStreamingResultExtensions | ||
{ | ||
/// <summary> | ||
/// Retrieve the resulting function from the chat result. | ||
/// </summary> | ||
/// <param name="chatStreamingResult">Chat streaming result</param> | ||
/// <returns>The <see cref="OpenAIFunctionResponse"/>, or null if no function was returned by the model.</returns> | ||
public static async Task<OpenAIFunctionResponse?> GetOpenAIStreamingFunctionResponseAsync(this IChatStreamingResult chatStreamingResult) | ||
{ | ||
if (chatStreamingResult is not ChatStreamingResult) | ||
{ | ||
throw new NotSupportedException($"Chat streaming result is not OpenAI {nameof(ChatStreamingResult)} supported type"); | ||
} | ||
|
||
StringBuilder arguments = new(); | ||
FunctionCall? functionCall = null; | ||
await foreach (SKChatMessage message in chatStreamingResult.GetStreamingChatMessageAsync()) | ||
{ | ||
functionCall ??= message.FunctionCall; | ||
|
||
arguments.Append(message.FunctionCall.Arguments); | ||
} | ||
|
||
if (functionCall is null) | ||
{ | ||
return null; | ||
} | ||
|
||
functionCall.Arguments = arguments.ToString(); | ||
return OpenAIFunctionResponse.FromFunctionCall(functionCall); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters