Skip to content

.Net: Add Sessions (Code Interpreter) Core Plugin and Demo Project #6160

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

Merged
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion dotnet/SK-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ContentSafety", "samples\De
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Concepts", "samples\Concepts\Concepts.csproj", "{925B1185-8B58-4E2D-95C9-4CA0BA9364E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FunctionInvocationApproval", "samples\Demos\FunctionInvocationApproval\FunctionInvocationApproval.csproj", "{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FunctionInvocationApproval", "samples\Demos\FunctionInvocationApproval\FunctionInvocationApproval.csproj", "{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodeInterpreterPlugin", "samples\Demos\CodeInterpreterPlugin\CodeInterpreterPlugin.csproj", "{3ED53702-0E53-473A-A0F4-645DB33541C2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -680,6 +682,12 @@ Global
{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2}.Publish|Any CPU.Build.0 = Debug|Any CPU
{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2}.Release|Any CPU.Build.0 = Release|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Publish|Any CPU.ActiveCfg = Debug|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Publish|Any CPU.Build.0 = Debug|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3ED53702-0E53-473A-A0F4-645DB33541C2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -775,6 +783,7 @@ Global
{6EF9663D-976C-4A27-B8D3-8B1E63BA3BF2} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
{925B1185-8B58-4E2D-95C9-4CA0BA9364E5} = {FA3720F1-C99A-49B2-9577-A940257098BF}
{6B56D8EE-9991-43E3-90B2-B8F5C5CE77C2} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
{3ED53702-0E53-473A-A0F4-645DB33541C2} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FBDC56A3-86AD-4323-AA0F-201E59123B83}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>e0f33cbd-1aa5-4117-a097-2810cc363e29</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
<PackageReference Include="Microsoft.Extensions.Configuration.UserSecrets" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" />
<PackageReference Include="Microsoft.Extensions.Http" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\Connectors\Connectors.OpenAI\Connectors.OpenAI.csproj" />
<ProjectReference Include="..\..\..\src\Plugins\Plugins.Core\Plugins.Core.csproj" />
<ProjectReference Include="..\..\..\src\SemanticKernel.Abstractions\SemanticKernel.Abstractions.csproj" />
<ProjectReference Include="..\..\..\src\SemanticKernel.Core\SemanticKernel.Core.csproj" />
</ItemGroup>
</Project>
78 changes: 78 additions & 0 deletions dotnet/samples/Demos/CodeInterpreterPlugin/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) Microsoft. All rights reserved.

using System.Text;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.ChatCompletion;
using Microsoft.SemanticKernel.Connectors.OpenAI;
using Microsoft.SemanticKernel.Plugins.Core.CodeInterpreter;

#pragma warning disable SKEXP0050 // Type is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.

var configuration = new ConfigurationBuilder()
.AddUserSecrets<Program>()
.AddEnvironmentVariables()
.Build();

var apiKey = configuration["OpenAI:ApiKey"];
var token = configuration["AzureContainerApps:BearerKey"];
var endpoint = configuration["AzureContainerApps:Endpoint"];

ArgumentNullException.ThrowIfNull(apiKey);
ArgumentNullException.ThrowIfNull(token);
ArgumentNullException.ThrowIfNull(endpoint);

Task<string> TokenProvider() => Task.FromResult(token);

var settings = new SessionPythonSettings()
{
Endpoint = new Uri(endpoint),
SessionId = Guid.NewGuid().ToString()
};

Console.WriteLine("=== Code Interpreter With Azure Container Apps Plugin Demo ===");

var builder =
Kernel.CreateBuilder()
.AddOpenAIChatCompletion("gpt-3.5-turbo", apiKey);

builder.Services.AddLogging(loggingBuilder => loggingBuilder.AddConsole());
builder.Services.AddHttpClient();
builder.Services.AddSingleton((sp)
=> new SessionsPythonPlugin(
settings,
TokenProvider,
sp.GetRequiredService<IHttpClientFactory>(),
sp.GetRequiredService<ILoggerFactory>()));
var kernel = builder.Build();

kernel.Plugins.AddFromObject(kernel.GetRequiredService<SessionsPythonPlugin>());
var chatCompletion = kernel.GetRequiredService<IChatCompletionService>();

var chatHistory = new ChatHistory();

StringBuilder fullAssistantContent = new();

do
{
Console.Write("\nUser: ");
var input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input)) { break; }

chatHistory.AddUserMessage(input);

Console.WriteLine("Assistant: ");
fullAssistantContent.Clear();
await foreach (var content in chatCompletion.GetStreamingChatMessageContentsAsync(
chatHistory,
new OpenAIPromptExecutionSettings { ToolCallBehavior = ToolCallBehavior.AutoInvokeKernelFunctions },
kernel)
.ConfigureAwait(false))
{
Console.Write(content.Content);
fullAssistantContent.Append(content.Content);
}
chatHistory.AddAssistantMessage(fullAssistantContent.ToString());
} while (true);
33 changes: 33 additions & 0 deletions dotnet/samples/Demos/CodeInterpreterPlugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Semantic Kernel - Code Interpreter Plugin with Azure Container Apps

This example demonstrates how to do AI Code Interpretetion using a Plugin with Azure Container Apps to execute python code in a container.

## Configuring Secrets

The example require credentials to access OpenAI and Azure Container Apps (ACA)

If you have set up those credentials as secrets within Secret Manager or through environment variables for other samples from the solution in which this project is found, they will be re-used.

### To set your secrets with Secret Manager:

```
dotnet user-secrets init

dotnet user-secrets set "OpenAI:ApiKey" "..."

dotnet user-secrets set "AzureContainerApps:BearerKey" " .. current token .. "
dotnet user-secrets set "AzureContainerApps:Endpoint" " .. endpoint .. "
```

### To set your secrets with environment variables

Use these names:

```
# OpenAI
OpenAI__ApiKey

# Azure Container Apps
AzureContainerApps__BearerKey
AzureContainerApps__Endpoint
```
3 changes: 2 additions & 1 deletion dotnet/samples/Demos/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,5 @@ Demonstration applications that leverage the usage of one or many SK features
| Create Chat GPT Plugin | A simple plugin that uses OpenAI GPT-3 to chat |
| Home Automation | This example demonstrates a few dependency injection patterns that can be used with Semantic Kernel. |
| HuggingFace Image to Text | In this demonstration the application uses Semantic Kernel's HuggingFace ImageToText Service to fetch a descriptive analysis of the clicked image. |
| Telemetry With Application Insights | Demo on how an application can be configured to send Semantic Kernel telemetry to Application Insights. |
| Telemetry With Application Insights | Demo on how an application can be configured to send Semantic Kernel telemetry to Application Insights. |
| Code Interpreter Plugin | A plugin that leverages Azure Container Apps service to run python code for AI Agents. |
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.ComponentModel;
using System.Text.Json.Serialization;

namespace Microsoft.SemanticKernel.Plugins.Core.CodeInterpreter;

/// <summary>
/// Settings for a Python session.
/// </summary>
public class SessionPythonSettings
{
/// <summary>
/// Determines if the input should be sanitized.
/// </summary>
[JsonIgnore]
public bool SanitizeInput { get; set; }

/// <summary>
/// The target endpoint.
/// </summary>
[JsonIgnore]
public Uri? Endpoint { get; init; }

/// <summary>
/// The session identifier.
/// </summary>
[JsonPropertyName("identifier")]
public string? SessionId { get; init; }

/// <summary>
/// Code input type.
/// </summary>
[JsonPropertyName("codeInputType")]
public CodeInputTypeSetting CodeInputType { get; set; }

/// <summary>
/// Code execution type.
/// </summary>
[JsonPropertyName("executionType")]
public CodeExecutionTypeSetting CodeExecutionType { get; set; }

/// <summary>
/// Timeout in seconds for the code execution.
/// </summary>
[JsonPropertyName("timeoutInSeconds")]
public int TimeoutInSeconds { get; set; } = 100;

/// <summary>
/// The Python code to execute.
/// </summary>
[JsonPropertyName("pythonCode")]
public string? PythonCode { get; set; }

/// <summary>
/// Code input type.
/// </summary>
[Description("Code input type.")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum CodeInputTypeSetting
{
/// <summary>
/// Code is provided as a inline string.
/// </summary>
[Description("Code is provided as a inline string.")]
[JsonPropertyName("inline")]
Inline
}

/// <summary>
/// Code input type.
/// </summary>
[Description("Code input type.")]
[JsonConverter(typeof(JsonStringEnumConverter))]
public enum CodeExecutionTypeSetting
{
/// <summary>
/// Code is provided as a inline string.
/// </summary>
[Description("Code is provided as a inline string.")]
[JsonPropertyName("synchronous")]
Synchronous
}

internal SessionPythonSettings CloneForRequest(string pythonCode)
{
return new SessionPythonSettings
{
SanitizeInput = this.SanitizeInput,
SessionId = this.SessionId,
CodeInputType = this.CodeInputType,
CodeExecutionType = this.CodeExecutionType,
TimeoutInSeconds = this.TimeoutInSeconds,
PythonCode = pythonCode
};
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.ComponentModel;
using System.Text.Json.Serialization;

namespace Microsoft.SemanticKernel.Plugins.Core.CodeInterpreter;

/// <summary>
/// Metadata for a file in the session.
/// </summary>
public class SessionRemoteFileMetadata
{
/// <summary>
/// Initializes a new instance of the SessionRemoteFileMetadata class.
/// </summary>
[JsonConstructor]
public SessionRemoteFileMetadata(string filename, int size)
{
this.Filename = filename;
this.Size = size;
}

/// <summary>
/// The filename relative to `/mnt/data`.
/// </summary>
[Description("The filename relative to `/mnt/data`.")]
[JsonPropertyName("filename")]
public string Filename { get; set; }

/// <summary>
/// The size of the file in bytes.
/// </summary>
[Description("The size of the file in bytes.")]
[JsonPropertyName("size")]
public int Size { get; set; }

/// <summary>
/// The last modified time.
/// </summary>
[Description("Last modified time.")]
[JsonPropertyName("last_modified_time")]
public DateTime? LastModifiedTime { get; set; }

/// <summary>
/// The full path of the file.
/// </summary>
[Description("The full path of the file.")]
public string FullPath => $"/mnt/data/{this.Filename}";
}
Loading
Loading