Skip to content

Commit

Permalink
Merge branch 'main' into taochen/python-remove-retry-mechanism
Browse files Browse the repository at this point in the history
  • Loading branch information
TaoChenOSU authored Dec 13, 2024
2 parents 0d06bb6 + fbbd444 commit acc30dc
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 7 deletions.
9 changes: 9 additions & 0 deletions .github/workflows/python-test-coverage-report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,19 @@ jobs:
merge-multiple: true
- name: Display structure of downloaded files
run: ls
- name: Read and set PR number
# Need to read the PR number from the file saved in the previous workflow
# because the workflow_run event does not have access to the PR number
# The PR number is needed to post the comment on the PR
run: |
PR_NUMBER=$(cat pr_number)
echo "PR number: $PR_NUMBER"
echo "::set-env name=PR_NUMBER::$PR_NUMBER"
- name: Pytest coverage comment
id: coverageComment
uses: MishaKav/pytest-coverage-comment@main
with:
issue-number: ${{ env.PR_NUMBER }}
pytest-coverage-path: python/python-coverage.txt
title: "Python Test Coverage Report"
badge-title: "Python Test Coverage"
Expand Down
6 changes: 6 additions & 0 deletions .github/workflows/python-test-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ jobs:
UV_PYTHON: "3.10"
steps:
- uses: actions/checkout@v4
# Save the PR number to a file since the workflow_run event
# in the coverage report workflow does not have access to it
- name: Save PR number
run: |
echo ${{ github.event.number }} > ./pr_number
- name: Set up uv
uses: astral-sh/setup-uv@v4
with:
Expand All @@ -37,6 +42,7 @@ jobs:
path: |
python/python-coverage.txt
python/pytest.xml
python/pr_number
overwrite: true
retention-days: 1
if-no-files-found: error
2 changes: 1 addition & 1 deletion dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
<PackageVersion Include="Docker.DotNet" Version="3.125.15" />
<!-- Plugins -->
<PackageVersion Include="DocumentFormat.OpenXml" Version="3.1.0" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="8.0.10" />
<PackageVersion Include="Microsoft.Data.Sqlite" Version="9.0.0" />
<PackageVersion Include="DuckDB.NET.Data.Full" Version="1.1.2.1" />
<PackageVersion Include="DuckDB.NET.Data" Version="1.1.2.1" />
<PackageVersion Include="MongoDB.Driver" Version="2.30.0" />
Expand Down
34 changes: 34 additions & 0 deletions dotnet/samples/Concepts/Memory/OpenAI_EmbeddingGeneration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Embeddings;
using xRetry;

#pragma warning disable format // Format item can be simplified
#pragma warning disable CA1861 // Avoid constant arrays as arguments

namespace Memory;

// The following example shows how to use Semantic Kernel with OpenAI.
public class OpenAI_EmbeddingGeneration(ITestOutputHelper output) : BaseTest(output)
{
[RetryFact(typeof(HttpOperationException))]
public async Task RunEmbeddingAsync()
{
Assert.NotNull(TestConfiguration.OpenAI.EmbeddingModelId);
Assert.NotNull(TestConfiguration.OpenAI.ApiKey);

IKernelBuilder kernelBuilder = Kernel.CreateBuilder();
kernelBuilder.AddOpenAITextEmbeddingGeneration(
modelId: TestConfiguration.OpenAI.EmbeddingModelId!,
apiKey: TestConfiguration.OpenAI.ApiKey!);
Kernel kernel = kernelBuilder.Build();

var embeddingGenerator = kernel.GetRequiredService<ITextEmbeddingGenerationService>();

// Generate embeddings for the specified text.
var embeddings = await embeddingGenerator.GenerateEmbeddingsAsync(["Semantic Kernel is a lightweight, open-source development kit that lets you easily build AI agents and integrate the latest AI models into your C#, Python, or Java codebase."]);

Console.WriteLine($"Generated {embeddings.Count} embeddings for the provided text");
}
}
1 change: 1 addition & 0 deletions dotnet/samples/Concepts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ dotnet test -l "console;verbosity=detailed" --filter "FullyQualifiedName=ChatCom

### Memory - Using AI [`Memory`](https://github.com/microsoft/semantic-kernel/tree/main/dotnet/src/SemanticKernel.Abstractions/Memory) concepts

- [OpenAI_EmbeddingGeneration](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Memory/OpenAI_EmbeddingGeneration.cs)
- [Ollama_EmbeddingGeneration](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Memory/Ollama_EmbeddingGeneration.cs)
- [Onnx_EmbeddingGeneration](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Memory/Onnx_EmbeddingGeneration.cs)
- [HuggingFace_EmbeddingGeneration](https://github.com/microsoft/semantic-kernel/blob/main/dotnet/samples/Concepts/Memory/HuggingFace_EmbeddingGeneration.cs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -430,19 +430,48 @@ private static List<RestApiParameter> CreateRestApiOperationParameters(string op
return null;
}

var mediaType = s_supportedMediaTypes.FirstOrDefault(requestBody.Content.ContainsKey) ?? throw new KernelException($"Neither of the media types of {operationId} is supported.");
var mediaType = GetMediaType(requestBody.Content) ?? throw new KernelException($"Neither of the media types of {operationId} is supported.");
var mediaTypeMetadata = requestBody.Content[mediaType];

var payloadProperties = GetPayloadProperties(operationId, mediaTypeMetadata.Schema);

return new RestApiPayload(mediaType, payloadProperties, requestBody.Description, mediaTypeMetadata?.Schema?.ToJsonSchema());
}

/// <summary>
/// Returns the first supported media type. If none of the media types are supported, an exception is thrown.
/// </summary>
/// <remarks>
/// Handles the case when the media type contains additional parameters e.g. application/json; x-api-version=2.0.
/// </remarks>
/// <param name="content">The OpenAPI request body content.</param>
/// <returns>The first support ed media type.</returns>
/// <exception cref="KernelException"></exception>
private static string? GetMediaType(IDictionary<string, OpenApiMediaType> content)
{
foreach (var mediaType in s_supportedMediaTypes)
{
foreach (var key in content.Keys)
{
var keyParts = key.Split(';');
if (keyParts[0].Equals(mediaType, StringComparison.OrdinalIgnoreCase))
{
return key;
}
}
}
return null;
}

/// <summary>
/// Create collection of expected responses for the REST API operation for the supported media types.
/// </summary>
/// <param name="responses">Responses from the OpenAPI endpoint.</param>
private static IEnumerable<(string, RestApiExpectedResponse)> CreateRestApiOperationExpectedResponses(OpenApiResponses responses)
{
foreach (var response in responses)
{
var mediaType = s_supportedMediaTypes.FirstOrDefault(response.Value.Content.ContainsKey);
var mediaType = GetMediaType(response.Value.Content);
if (mediaType is not null)
{
var matchingSchema = response.Value.Content[mediaType].Schema;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,23 @@ public async Task ItCanExtractExtensionsOfAllTypesAsync(string documentName)
Assert.True(operation.Extensions.TryGetValue("x-object-extension", out var objectValue));
Assert.Equal("{\"key1\":\"value1\",\"key2\":\"value2\"}", objectValue);
}

[Theory]
[InlineData("documentV3_0.json")]
[InlineData("documentV3_1.yaml")]
public async Task ItCanParseMediaTypeAsync(string documentName)
{
// Arrange.
using var openApiDocument = ResourcePluginsProvider.LoadFromResource(documentName);

// Act.
var restApi = await this._sut.ParseAsync(openApiDocument);

// Assert.
Assert.NotNull(restApi.Operations);
Assert.Equal(7, restApi.Operations.Count);
var operation = restApi.Operations.Single(o => o.Id == "Joke");
Assert.NotNull(operation);
Assert.Equal("application/json; x-api-version=2.0", operation.Payload?.MediaType);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public async Task ItCanExtractAllPathsAsOperationsAsync()
var restApi = await this._sut.ParseAsync(this._openApiDocument);

// Assert
Assert.Equal(6, restApi.Operations.Count);
Assert.Equal(7, restApi.Operations.Count);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ public async Task ItCanExtractAllPathsAsOperationsAsync()
var restApi = await this._sut.ParseAsync(this._openApiDocument);

// Assert
Assert.Equal(6, restApi.Operations.Count);
Assert.Equal(7, restApi.Operations.Count);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ public async Task ItShouldHandleEmptyOperationNameAsync()
var plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync("fakePlugin", content, this._executionParameters);

// Assert
Assert.Equal(6, plugin.Count());
Assert.Equal(7, plugin.Count());
Assert.True(plugin.TryGetFunction("GetSecretsSecretname", out var _));
}

Expand All @@ -372,7 +372,7 @@ public async Task ItShouldHandleNullOperationNameAsync()
var plugin = await OpenApiKernelPluginFactory.CreateFromOpenApiAsync("fakePlugin", content, this._executionParameters);

// Assert
Assert.Equal(6, plugin.Count());
Assert.Equal(7, plugin.Count());
Assert.True(plugin.TryGetFunction("GetSecretsSecretname", out var _));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,63 @@
}
}
},
"/FunPlugin/Joke": {
"post": {
"summary": "Generate a funny joke",
"operationId": "Joke",
"requestBody": {
"description": "Joke subject",
"content": {
"text/plain; x-api-version=2.0": {
"schema": {
"type": "string"
}
},
"application/json; x-api-version=2.0": {
"schema": {
"required": [
"scenario"
],
"type": "object",
"properties": {
"scenario": {
"type": "string",
"description": "Joke subject"
}
}
}
}
},
"x-bodyName": "body"
},
"responses": {
"200": {
"description": "The OK response",
"content": {
"text/plain; x-api-version=2.0": {
"schema": {
"type": "string"
}
},
"application/json; x-api-version=2.0": {
"schema": {
"required": [
"scenario"
],
"type": "object",
"properties": {
"scenario": {
"type": "string",
"description": "Joke subject"
}
}
}
}
}
}
}
}
},
"/test-default-values/{string-parameter}": {
"put": {
"summary": "Operation to test default parameter values.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,38 @@ paths:
text/plain:
schema:
type: string
/FunPlugin/Joke:
post:
summary: Gneerate a funny joke
operationId: Joke
requestBody:
description: Joke subject
content:
application/json; x-api-version=2.0:
schema:
type: object
properties:
scenario:
type: string
description: Joke subject
text/plain; x-api-version=2.0:
schema:
type: string
x-bodyName: body
responses:
'200':
description: The OK response
content:
text/plain; x-api-version=2.0:
schema:
type: string
application/json; x-api-version=2.0:
schema:
type: object
properties:
scenario:
type: string
description: Joke subject
'/test-default-values/{string-parameter}':
put:
summary: Operation to test default parameter values.
Expand Down

0 comments on commit acc30dc

Please sign in to comment.