Skip to content

Commit

Permalink
Merge branch 'main' into users/markwallace/codeql-actions-v3
Browse files Browse the repository at this point in the history
  • Loading branch information
markwallace-microsoft authored Nov 26, 2024
2 parents 0928fe4 + 8c481df commit 7a9e592
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 76 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/python-test-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ jobs:
- name: Setup filename variables
run: echo "FILE_ID=${{ github.event.number }}" >> $GITHUB_ENV
- name: Download coverage
uses: dawidd6/action-download-artifact@v3
uses: dawidd6/action-download-artifact@v6
with:
name: python-coverage-${{ env.FILE_ID }}.txt
github_token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
workflow: python-unit-tests.yml
search_artifacts: true
if_no_artifact_found: warn
- name: Download pytest
uses: dawidd6/action-download-artifact@v3
uses: dawidd6/action-download-artifact@v6
with:
name: pytest-${{ env.FILE_ID }}.xml
github_token: ${{ secrets.GH_ACTIONS_PR_WRITE }}
Expand Down
10 changes: 5 additions & 5 deletions dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@
<PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.Options.DataAnnotations" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.TimeProvider.Testing" Version="8.10.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="[8.0.0, 9.0.0)" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="[8.0.0, 9.0.0)" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Physical" Version="8.0.0" />
<PackageVersion Include="Microsoft.Extensions.FileProviders.Embedded" Version="8.0.0" />
<!-- Test -->
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.11.1" />
<PackageVersion Include="Moq" Version="[4.18.4]" />
Expand All @@ -102,13 +102,13 @@
<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" />
<PackageVersion Include="Microsoft.Graph" Version="[4.51.0, 5)" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="[2.28.0, )" />
<PackageVersion Include="Microsoft.Graph" Version="4.51.0" />
<PackageVersion Include="Microsoft.Identity.Client.Extensions.Msal" Version="2.28.0" />
<PackageVersion Include="Microsoft.OpenApi" Version="1.6.22" />
<PackageVersion Include="Microsoft.OpenApi.Readers" Version="1.6.22" />
<PackageVersion Include="Microsoft.OpenApi.ApiManifest" Version="0.5.6-preview" />
<PackageVersion Include="Microsoft.Plugins.Manifest" Version="1.0.0-rc2" />
<PackageVersion Include="Google.Apis.CustomSearchAPI.v1" Version="[1.60.0.3001, )" />
<PackageVersion Include="Google.Apis.CustomSearchAPI.v1" Version="1.60.0.3001" />
<PackageVersion Include="Grpc.Net.Client" Version="2.66.0" />
<PackageVersion Include="protobuf-net" Version="3.2.45" />
<PackageVersion Include="protobuf-net.Reflection" Version="3.2.12" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1541,6 +1541,10 @@ public async Task GetStreamingChatMessageContentsWithFunctionCallAndEmptyArgumen
{ "V2024_10_01_PREVIEW", "2024-10-01-preview" },
{ "2024_10_01_Preview", "2024-10-01-preview" },
{ "2024-10-01-preview", "2024-10-01-preview" },
{ "V2024_09_01_preview", "2024-09-01-preview" },
{ "V2024_09_01_PREVIEW", "2024-09-01-preview" },
{ "2024_09_01_Preview", "2024-09-01-preview" },
{ "2024-09-01-preview", "2024-09-01-preview" },
{ "V2024_08_01_preview", "2024-08-01-preview" },
{ "V2024_08_01_PREVIEW", "2024-08-01-preview" },
{ "2024_08_01_Preview", "2024-08-01-preview" },
Expand All @@ -1549,6 +1553,7 @@ public async Task GetStreamingChatMessageContentsWithFunctionCallAndEmptyArgumen
{ "2024_06_01", "2024-06-01" },
{ "2024-06-01", "2024-06-01" },
{ AzureOpenAIClientOptions.ServiceVersion.V2024_10_01_Preview.ToString(), null },
{ AzureOpenAIClientOptions.ServiceVersion.V2024_09_01_Preview.ToString(), null },
{ AzureOpenAIClientOptions.ServiceVersion.V2024_08_01_Preview.ToString(), null },
{ AzureOpenAIClientOptions.ServiceVersion.V2024_06_01.ToString(), null }
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,9 @@ internal static AzureOpenAIClientOptions GetAzureOpenAIClientOptions(HttpClient?
{
"2024-06-01" or "V2024_06_01" or "2024_06_01" => AzureOpenAIClientOptions.ServiceVersion.V2024_06_01,
"2024-08-01-PREVIEW" or "V2024_08_01_PREVIEW" or "2024_08_01_PREVIEW" => AzureOpenAIClientOptions.ServiceVersion.V2024_08_01_Preview,
"2024-09-01-PREVIEW" or "V2024_09_01_PREVIEW" or "2024_09_01_PREVIEW" => AzureOpenAIClientOptions.ServiceVersion.V2024_09_01_Preview,
"2024-10-01-PREVIEW" or "V2024_10_01_PREVIEW" or "2024_10_01_PREVIEW" => AzureOpenAIClientOptions.ServiceVersion.V2024_10_01_Preview,

_ => throw new NotSupportedException($"The service version '{serviceVersion}' is not supported.")
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,7 @@ private static string GetCollectionName(string tableName)
/// Returns base Kusto query.
/// </summary>
/// <remarks>
/// Kusto is an append-only store. Although deletions are possible, they are highly discourged,
/// Kusto is an append-only store. Although deletions are possible, they are highly discouraged,
/// and should only be used in rare cases (see: https://learn.microsoft.com/en-us/azure/data-explorer/kusto/concepts/data-soft-delete#use-cases).
/// As such, the recommended approach for dealing with row updates is versioning.
/// An easy way to achieve this is by using the ingestion time of the record (insertion time).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,20 @@ await this.RunOperationAsync(
foreach (var dataProperty in dataProperties)
{
var storageFieldName = this._propertyReader.GetStoragePropertyName(dataProperty.DataModelPropertyName);
var schemaType = QdrantVectorStoreCollectionCreateMapping.s_schemaTypeMap[dataProperty.PropertyType!];

if (QdrantVectorStoreCollectionCreateMapping.s_schemaTypeMap.TryGetValue(dataProperty.PropertyType!, out PayloadSchemaType schemaType))
{
// Do nothing since schemaType is already set.
}
else if (VectorStoreRecordPropertyVerification.IsSupportedEnumerableType(dataProperty.PropertyType) && VectorStoreRecordPropertyVerification.GetCollectionElementType(dataProperty.PropertyType) == typeof(string))
{
// For enumerable of strings, use keyword schema type, since this allows tag filtering.
schemaType = PayloadSchemaType.Keyword;
}
else
{
throw new InvalidOperationException($"Property {nameof(VectorStoreRecordDataProperty.IsFilterable)} on {nameof(VectorStoreRecordDataProperty)} '{dataProperty.DataModelPropertyName}' is set to true, but the property type is not supported for filtering. The Qdrant VectorStore supports filtering on {string.Join(", ", QdrantVectorStoreCollectionCreateMapping.s_schemaTypeMap.Keys.Select(x => x.Name))} properties only.");
}

await this.RunOperationAsync(
"CreatePayloadIndex",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public QdrantVectorStoreFixture()
new VectorStoreRecordDataProperty("HotelCode", typeof(int)) { IsFilterable = true },
new VectorStoreRecordDataProperty("ParkingIncluded", typeof(bool)) { IsFilterable = true, StoragePropertyName = "parking_is_included" },
new VectorStoreRecordDataProperty("HotelRating", typeof(float)) { IsFilterable = true },
new VectorStoreRecordDataProperty("Tags", typeof(List<string>)),
new VectorStoreRecordDataProperty("Tags", typeof(List<string>)) { IsFilterable = true },
new VectorStoreRecordDataProperty("Description", typeof(string)),
new VectorStoreRecordVectorProperty("DescriptionEmbedding", typeof(ReadOnlyMemory<float>?)) { Dimensions = VectorDimensions, DistanceFunction = DistanceFunction.ManhattanDistance }
}
Expand Down Expand Up @@ -146,11 +146,17 @@ await this.QdrantClient.CreateCollectionAsync(

// Create test data common to both named and unnamed vectors.
var tags = new ListValue();
tags.Values.Add("t1");
tags.Values.Add("t2");
tags.Values.Add("t11.1");
tags.Values.Add("t11.2");
var tagsValue = new Value();
tagsValue.ListValue = tags;

var tags2 = new ListValue();
tags2.Values.Add("t13.1");
tags2.Values.Add("t13.2");
var tagsValue2 = new Value();
tagsValue2.ListValue = tags2;

// Create some test data using named vectors.
var embedding = await this.EmbeddingGenerator.GenerateEmbeddingAsync("This is a great hotel.");
var embeddingArray = embedding.ToArray();
Expand Down Expand Up @@ -183,7 +189,7 @@ await this.QdrantClient.CreateCollectionAsync(
{
Id = 13,
Vectors = new Vectors { Vectors_ = namedVectors3 },
Payload = { ["HotelName"] = "My Hotel 13", ["HotelCode"] = 13, ["parking_is_included"] = false, ["Description"] = "This is a great hotel." }
Payload = { ["HotelName"] = "My Hotel 13", ["HotelCode"] = 13, ["parking_is_included"] = false, ["Tags"] = tagsValue2, ["Description"] = "This is a great hotel." }
},
new PointStruct
{
Expand Down Expand Up @@ -214,7 +220,7 @@ await this.QdrantClient.CreateCollectionAsync(
{
Id = 13,
Vectors = embeddingArray,
Payload = { ["HotelName"] = "My Hotel 13", ["HotelCode"] = 13, ["parking_is_included"] = false, ["Description"] = "This is a great hotel." }
Payload = { ["HotelName"] = "My Hotel 13", ["HotelCode"] = 13, ["parking_is_included"] = false, ["Tags"] = tagsValue2, ["Description"] = "This is a great hotel." }
},
];

Expand Down Expand Up @@ -327,7 +333,7 @@ public record HotelInfo()
[VectorStoreRecordData(IsFilterable = true, StoragePropertyName = "parking_is_included")]
public bool ParkingIncluded { get; set; }

[VectorStoreRecordData]
[VectorStoreRecordData(IsFilterable = true)]
public List<string> Tags { get; set; } = new List<string>();

/// <summary>A data field.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task ItCanCreateACollectionUpsertGetAndSearchAsync(bool hasNamedVec
var vector = await fixture.EmbeddingGenerator.GenerateEmbeddingAsync("A great hotel");
var actual = await sut.VectorizedSearchAsync(
vector,
new VectorSearchOptions { Filter = new VectorSearchFilter().EqualTo("HotelCode", 30) });
new VectorSearchOptions { Filter = new VectorSearchFilter().EqualTo("HotelCode", 30).AnyTagEqualTo("Tags", "t2") });

// Assert
var collectionExistResult = await sut.CollectionExistsAsync();
Expand Down Expand Up @@ -221,8 +221,8 @@ public async Task ItCanGetDocumentFromVectorStoreAsync(bool useRecordDefinition,
Assert.True(getResult?.ParkingIncluded);
Assert.Equal(4.5f, getResult?.HotelRating);
Assert.Equal(2, getResult?.Tags.Count);
Assert.Equal("t1", getResult?.Tags[0]);
Assert.Equal("t2", getResult?.Tags[1]);
Assert.Equal("t11.1", getResult?.Tags[0]);
Assert.Equal("t11.2", getResult?.Tags[1]);
Assert.Equal("This is a great hotel.", getResult?.Description);
if (withEmbeddings)
{
Expand Down Expand Up @@ -389,7 +389,7 @@ public async Task ItCanSearchWithFilterAsync(bool useRecordDefinition, string co

// Act.
var vector = await fixture.EmbeddingGenerator.GenerateEmbeddingAsync("A great hotel");
var filter = filterType == "equality" ? new VectorSearchFilter().EqualTo("HotelName", "My Hotel 11") : new VectorSearchFilter().AnyTagEqualTo("Tags", "t1");
var filter = filterType == "equality" ? new VectorSearchFilter().EqualTo("HotelName", "My Hotel 13") : new VectorSearchFilter().AnyTagEqualTo("Tags", "t13.2");
var actual = await sut.VectorizedSearchAsync(
vector,
new()
Expand All @@ -402,12 +402,11 @@ public async Task ItCanSearchWithFilterAsync(bool useRecordDefinition, string co
Assert.Single(searchResults);

var searchResultRecord = searchResults.First().Record;
Assert.Equal(11ul, searchResultRecord?.HotelId);
Assert.Equal("My Hotel 11", searchResultRecord?.HotelName);
Assert.Equal(11, searchResultRecord?.HotelCode);
Assert.Equal(4.5f, searchResultRecord?.HotelRating);
Assert.Equal(true, searchResultRecord?.ParkingIncluded);
Assert.Equal(new string[] { "t1", "t2" }, searchResultRecord?.Tags.ToArray());
Assert.Equal(13ul, searchResultRecord?.HotelId);
Assert.Equal("My Hotel 13", searchResultRecord?.HotelName);
Assert.Equal(13, searchResultRecord?.HotelCode);
Assert.Equal(false, searchResultRecord?.ParkingIncluded);
Assert.Equal(new string[] { "t13.1", "t13.2" }, searchResultRecord?.Tags.ToArray());
Assert.Equal("This is a great hotel.", searchResultRecord?.Description);
}

Expand Down Expand Up @@ -448,7 +447,7 @@ public async Task ItCanUpsertAndRetrieveUsingTheGenericMapperAsync()
Assert.Equal(11, baseSetGetResult.Data["HotelCode"]);
Assert.True((bool)baseSetGetResult.Data["ParkingIncluded"]!);
Assert.Equal(4.5f, baseSetGetResult.Data["HotelRating"]);
Assert.Equal(new[] { "t1", "t2" }, ((List<string>)baseSetGetResult.Data["Tags"]!).ToArray());
Assert.Equal(new[] { "t11.1", "t11.2" }, ((List<string>)baseSetGetResult.Data["Tags"]!).ToArray());
Assert.Equal("This is a great hotel.", baseSetGetResult.Data["Description"]);
Assert.NotNull(baseSetGetResult.Vectors["DescriptionEmbedding"]);
Assert.IsType<ReadOnlyMemory<float>>(baseSetGetResult.Vectors["DescriptionEmbedding"]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,12 @@

import json
import logging
import sys
from collections.abc import AsyncGenerator, Mapping
from collections.abc import Mapping
from copy import deepcopy
from typing import Any, TypeVar
from uuid import uuid4

if sys.version_info >= (3, 12):
from typing import override # pragma: no cover
else:
from typing_extensions import override # pragma: no cover

from openai import AsyncAzureOpenAI, AsyncStream
from openai import AsyncAzureOpenAI
from openai.lib.azure import AsyncAzureADTokenProvider
from openai.types.chat.chat_completion import ChatCompletion, Choice
from openai.types.chat.chat_completion_chunk import ChatCompletionChunk
Expand All @@ -23,24 +17,19 @@
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.azure_chat_prompt_execution_settings import (
AzureChatPromptExecutionSettings,
)
from semantic_kernel.connectors.ai.open_ai.prompt_execution_settings.open_ai_prompt_execution_settings import (
OpenAIChatPromptExecutionSettings,
)
from semantic_kernel.connectors.ai.open_ai.services.azure_config_base import AzureOpenAIConfigBase
from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion_base import OpenAIChatCompletionBase
from semantic_kernel.connectors.ai.open_ai.services.open_ai_handler import OpenAIModelTypes
from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_completion_base import OpenAITextCompletionBase
from semantic_kernel.connectors.ai.open_ai.settings.azure_open_ai_settings import AzureOpenAISettings
from semantic_kernel.connectors.ai.prompt_execution_settings import PromptExecutionSettings
from semantic_kernel.contents.chat_history import ChatHistory
from semantic_kernel.contents.chat_message_content import ChatMessageContent
from semantic_kernel.contents.function_call_content import FunctionCallContent
from semantic_kernel.contents.function_result_content import FunctionResultContent
from semantic_kernel.contents.streaming_chat_message_content import StreamingChatMessageContent
from semantic_kernel.contents.text_content import TextContent
from semantic_kernel.contents.utils.finish_reason import FinishReason
from semantic_kernel.exceptions.service_exceptions import ServiceInitializationError, ServiceInvalidResponseError
from semantic_kernel.utils.telemetry.model_diagnostics.decorators import trace_streaming_chat_completion
from semantic_kernel.exceptions.service_exceptions import ServiceInitializationError

logger: logging.Logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -121,42 +110,6 @@ def __init__(
client=async_client,
)

@override
@trace_streaming_chat_completion(OpenAIChatCompletionBase.MODEL_PROVIDER_NAME)
async def _inner_get_streaming_chat_message_contents(
self,
chat_history: "ChatHistory",
settings: "PromptExecutionSettings",
) -> AsyncGenerator[list["StreamingChatMessageContent"], Any]:
"""Override the base method.
This is because the latest Azure OpenAI API GA version doesn't support `stream_option`
yet and it will potentially result in errors if the option is included.
This method will be called instead of the base method.
TODO: Remove this method when the `stream_option` is supported by the Azure OpenAI API.
GitHub Issue: https://github.com/microsoft/semantic-kernel/issues/8996
"""
if not isinstance(settings, OpenAIChatPromptExecutionSettings):
settings = self.get_prompt_execution_settings_from_settings(settings)
assert isinstance(settings, OpenAIChatPromptExecutionSettings) # nosec

settings.stream = True
settings.messages = self._prepare_chat_history_for_request(chat_history)
settings.ai_model_id = settings.ai_model_id or self.ai_model_id

response = await self._send_request(settings)
if not isinstance(response, AsyncStream):
raise ServiceInvalidResponseError("Expected an AsyncStream[ChatCompletionChunk] response.")
async for chunk in response:
if len(chunk.choices) == 0:
continue

assert isinstance(chunk, ChatCompletionChunk) # nosec
chunk_metadata = self._get_metadata_from_streaming_chat_response(chunk)
yield [
self._create_streaming_chat_message_content(chunk, choice, chunk_metadata) for choice in chunk.choices
]

@classmethod
def from_dict(cls, settings: dict[str, Any]) -> "AzureChatCompletion":
"""Initialize an Azure OpenAI service from a dictionary of settings.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -948,4 +948,8 @@ async def test_cmc_streaming(
model=azure_openai_unit_test_env["AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"],
stream=True,
messages=azure_chat_completion._prepare_chat_history_for_request(chat_history),
# NOTE: The `stream_options={"include_usage": True}` is explicitly enforced in
# `OpenAIChatCompletionBase._inner_get_streaming_chat_message_contents`.
# To ensure consistency, we align the arguments here accordingly.
stream_options={"include_usage": True},
)

0 comments on commit 7a9e592

Please sign in to comment.