Skip to content

Commit 9df00bd

Browse files
committed
Merge branch 'issues/10493-audio-content-openai' of https://github.com/rogerbarreto/semantic-kernel into issues/10493-audio-content-openai
2 parents 80ec5cb + 828ba0d commit 9df00bd

File tree

112 files changed

+2230
-2532
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+2230
-2532
lines changed

.github/workflows/label-needs-port.yml

+26-8
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,39 @@ jobs:
2121
steps:
2222
- name: Create dotnet issue
2323
if: contains(github.event.pull_request.labels.*.name, 'needs_port_to_dotnet') || contains(github.event.issue.labels.*.name, 'needs_port_to_dotnet')
24+
env:
25+
ORIGINAL_URL: ${{ github.event.issue.html_url || github.event.pull_request.html_url }}
26+
ORIGINAL_BODY: ${{ github.event.issue.body || github.event.pull_request.body }}
27+
ORIGINAL_TITLE: ${{ github.event.issue.title || github.event.pull_request.title }}
28+
ORIGINAL_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
2429
run: |
30+
{
31+
echo "# Original issue"
32+
echo "$ORIGINAL_URL"
33+
echo "## Description"
34+
echo "$ORIGINAL_BODY"
35+
echo "\n Relates to #$ORIGINAL_NUMBER"
36+
} > issue_body.md
2537
new_issue_url=$(gh issue create \
2638
--title "Port python feature: ${{ github.event.issue.title || github.event.pull_request.title }}" \
2739
--label ".NET" \
28-
--body "# Original issue
29-
${{ github.event.issue.html_url || github.event.pull_request.html_url }}
30-
## Description
31-
${{ github.event.issue.body || github.event.pull_request.body }}")
40+
--body-file issue_body.md)
3241
- name: Create python issue
3342
if: contains(github.event.pull_request.labels.*.name, 'needs_port_to_python') || contains(github.event.issue.labels.*.name, 'needs_port_to_python')
43+
env:
44+
ORIGINAL_URL: ${{ github.event.issue.html_url || github.event.pull_request.html_url }}
45+
ORIGINAL_BODY: ${{ github.event.issue.body || github.event.pull_request.body }}
46+
ORIGINAL_TITLE: ${{ github.event.issue.title || github.event.pull_request.title }}
47+
ORIGINAL_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
3448
run: |
49+
{
50+
echo "# Original issue"
51+
echo "$ORIGINAL_URL"
52+
echo "## Description"
53+
echo "$ORIGINAL_BODY"
54+
echo "\n Relates to #$ORIGINAL_NUMBER"
55+
} > issue_body.md
3556
new_issue_url=$(gh issue create \
3657
--title "Port dotnet feature: ${{ github.event.issue.title || github.event.pull_request.title }}" \
3758
--label "python" \
38-
--body "# Original issue
39-
${{ github.event.issue.html_url || github.event.pull_request.html_url }}
40-
## Description
41-
${{ github.event.issue.body || github.event.pull_request.body }}")
59+
--body-file issue_body.md)

dotnet/src/SemanticKernel.Abstractions/AI/ChatCompletion/AIFunctionKernelFunction.cs

+24-1
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun
6666
return Array.Empty<KernelParameterMetadata>();
6767
}
6868

69+
HashSet<string>? requiredParameters = GetRequiredParameterNames(aiFunction.JsonSchema);
70+
6971
List<KernelParameterMetadata> kernelParams = [];
7072
var parameterInfos = aiFunction.UnderlyingMethod?.GetParameters().ToDictionary(p => p.Name!, StringComparer.Ordinal);
7173
foreach (var param in properties.EnumerateObject())
@@ -76,7 +78,7 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun
7678
{
7779
Description = param.Value.TryGetProperty("description", out JsonElement description) ? description.GetString() : null,
7880
DefaultValue = param.Value.TryGetProperty("default", out JsonElement defaultValue) ? defaultValue : null,
79-
IsRequired = param.Value.TryGetProperty("required", out JsonElement required) && required.GetBoolean(),
81+
IsRequired = requiredParameters?.Contains(param.Name) ?? false,
8082
ParameterType = paramInfo?.ParameterType,
8183
Schema = param.Value.TryGetProperty("schema", out JsonElement schema)
8284
? new KernelJsonSchema(schema)
@@ -86,4 +88,25 @@ private static IReadOnlyList<KernelParameterMetadata> MapParameterMetadata(AIFun
8688

8789
return kernelParams;
8890
}
91+
92+
/// <summary>
93+
/// Gets the names of the required parameters from the AI function's JSON schema.
94+
/// </summary>
95+
/// <param name="schema">The JSON schema of the AI function.</param>
96+
/// <returns>The names of the required parameters.</returns>
97+
private static HashSet<string>? GetRequiredParameterNames(JsonElement schema)
98+
{
99+
HashSet<string>? requiredParameterNames = null;
100+
101+
if (schema.TryGetProperty("required", out JsonElement requiredElement) && requiredElement.ValueKind == JsonValueKind.Array)
102+
{
103+
foreach (var node in requiredElement.EnumerateArray())
104+
{
105+
requiredParameterNames ??= [];
106+
requiredParameterNames.Add(node.GetString()!);
107+
}
108+
}
109+
110+
return requiredParameterNames;
111+
}
89112
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
3+
using System.Linq;
4+
using Microsoft.Extensions.AI;
5+
using Microsoft.SemanticKernel;
6+
using Microsoft.SemanticKernel.ChatCompletion;
7+
using Xunit;
8+
9+
namespace SemanticKernel.UnitTests.AI.ChatCompletion;
10+
11+
public class AIFunctionKernelFunctionTests
12+
{
13+
[Fact]
14+
public void ShouldAssignIsRequiredParameterMetadataPropertyCorrectly()
15+
{
16+
// Arrange and Act
17+
AIFunction aiFunction = AIFunctionFactory.Create((string p1, int? p2 = null) => p1);
18+
19+
AIFunctionKernelFunction sut = new(aiFunction);
20+
21+
// Assert
22+
KernelParameterMetadata? p1Metadata = sut.Metadata.Parameters.FirstOrDefault(p => p.Name == "p1");
23+
Assert.True(p1Metadata?.IsRequired);
24+
25+
KernelParameterMetadata? p2Metadata = sut.Metadata.Parameters.FirstOrDefault(p => p.Name == "p2");
26+
Assert.False(p2Metadata?.IsRequired);
27+
}
28+
}

dotnet/src/SemanticKernel.UnitTests/SemanticKernel.UnitTests.csproj

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</PackageReference>
2525
<PackageReference Include="Microsoft.ML.Tokenizers" />
2626
<PackageReference Include="Microsoft.Extensions.Logging.Console" />
27-
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
27+
<PackageReference Include="Microsoft.Extensions.AI" />
2828
</ItemGroup>
2929

3030
<ItemGroup>

python/pyproject.toml

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ classifiers = [
2525
dependencies = [
2626
"aiohttp ~= 3.8",
2727
"cloudevents ~=1.0",
28-
"pydantic >=2.0,<2.11,!=2.10.0,!=2.10.1,!=2.10.2,!=2.10.3",
28+
"pydantic >=2.0,!=2.10.0,!=2.10.1,!=2.10.2,!=2.10.3,<2.12",
2929
"pydantic-settings ~= 2.0",
3030
"defusedxml ~= 0.7",
3131
# azure identity
@@ -76,7 +76,7 @@ faiss = [
7676
]
7777
hugging_face = [
7878
"transformers[torch] ~= 4.28",
79-
"sentence-transformers >= 2.2,< 4.0",
79+
"sentence-transformers >= 2.2,< 5.0",
8080
"torch == 2.6.0"
8181
]
8282
mongo = [

python/samples/concepts/agents/chat_completion_agent/chat_completion_agent_function_termination.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ async def main():
9999
print("================================")
100100

101101
# 4. Print out the chat history to view the different types of messages
102-
chat_history = await thread.get_messages()
103-
for message in chat_history.messages:
102+
async for message in thread.get_messages():
104103
_write_content(message)
105104

106105
"""

python/samples/concepts/agents/chat_completion_agent/chat_completion_agent_summary_history_reducer_single_agent.py

+5-11
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,9 @@
33
import asyncio
44
import logging
55

6-
from semantic_kernel.agents import (
7-
ChatCompletionAgent,
8-
ChatHistoryAgentThread,
9-
)
6+
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
107
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
11-
from semantic_kernel.contents import (
12-
ChatHistorySummarizationReducer,
13-
)
8+
from semantic_kernel.contents import ChatHistorySummarizationReducer
149

1510
"""
1611
The following sample demonstrates how to implement a truncation chat
@@ -55,14 +50,13 @@ async def main():
5550
# Attempt reduction
5651
is_reduced = await thread.reduce()
5752
if is_reduced:
58-
print(f"@ History reduced to {len(thread.messages)} messages.")
53+
print(f"@ History reduced to {len(thread)} messages.")
5954

60-
print(f"@ Message Count: {len(thread.messages)}\n")
55+
print(f"@ Message Count: {len(thread)}\n")
6156

6257
# If reduced, print summary if present
6358
if is_reduced:
64-
chat_history = await thread.get_messages()
65-
for msg in chat_history.messages:
59+
async for msg in thread.get_messages():
6660
if msg.metadata and msg.metadata.get("__summary__"):
6761
print(f"\tSummary: {msg.content}")
6862
break

python/samples/concepts/caching/semantic_caching.py

+10-13
Original file line numberDiff line numberDiff line change
@@ -7,25 +7,22 @@
77
from typing import Annotated
88
from uuid import uuid4
99

10+
from semantic_kernel import Kernel
1011
from semantic_kernel.connectors.ai.embedding_generator_base import EmbeddingGeneratorBase
11-
from semantic_kernel.connectors.ai.open_ai.services.open_ai_chat_completion import OpenAIChatCompletion
12-
from semantic_kernel.connectors.ai.open_ai.services.open_ai_text_embedding import OpenAITextEmbedding
12+
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion, OpenAITextEmbedding
1313
from semantic_kernel.connectors.memory.in_memory.in_memory_store import InMemoryVectorStore
14-
from semantic_kernel.data.record_definition import vectorstoremodel
15-
from semantic_kernel.data.record_definition.vector_store_record_fields import (
14+
from semantic_kernel.data import (
15+
VectorizedSearchMixin,
16+
VectorSearchOptions,
17+
VectorStore,
18+
VectorStoreRecordCollection,
1619
VectorStoreRecordDataField,
1720
VectorStoreRecordKeyField,
1821
VectorStoreRecordVectorField,
22+
vectorstoremodel,
1923
)
20-
from semantic_kernel.data.vector_search.vector_search_options import VectorSearchOptions
21-
from semantic_kernel.data.vector_search.vectorized_search import VectorizedSearchMixin
22-
from semantic_kernel.data.vector_storage.vector_store import VectorStore
23-
from semantic_kernel.data.vector_storage.vector_store_record_collection import VectorStoreRecordCollection
24-
from semantic_kernel.filters.filter_types import FilterTypes
25-
from semantic_kernel.filters.functions.function_invocation_context import FunctionInvocationContext
26-
from semantic_kernel.filters.prompts.prompt_render_context import PromptRenderContext
27-
from semantic_kernel.functions.function_result import FunctionResult
28-
from semantic_kernel.kernel import Kernel
24+
from semantic_kernel.filters import FilterTypes, FunctionInvocationContext, PromptRenderContext
25+
from semantic_kernel.functions import FunctionResult
2926

3027
COLLECTION_NAME = "llm_responses"
3128
RECORD_ID_KEY = "cache_record_id"

python/samples/concepts/chat_history/store_chat_history_in_cosmosdb.py

+6-7
Original file line numberDiff line numberDiff line change
@@ -6,19 +6,18 @@
66

77
from samples.concepts.setup.chat_completion_services import Services, get_chat_completion_service_and_request_settings
88
from semantic_kernel import Kernel
9-
from semantic_kernel.connectors.ai.function_choice_behavior import FunctionChoiceBehavior
9+
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
1010
from semantic_kernel.connectors.memory.azure_cosmos_db.azure_cosmos_db_no_sql_store import AzureCosmosDBNoSQLStore
11-
from semantic_kernel.contents import ChatHistory
12-
from semantic_kernel.contents.chat_message_content import ChatMessageContent
11+
from semantic_kernel.contents import ChatHistory, ChatMessageContent
1312
from semantic_kernel.core_plugins.math_plugin import MathPlugin
1413
from semantic_kernel.core_plugins.time_plugin import TimePlugin
15-
from semantic_kernel.data.record_definition.vector_store_model_decorator import vectorstoremodel
16-
from semantic_kernel.data.record_definition.vector_store_record_fields import (
14+
from semantic_kernel.data import (
15+
VectorStore,
16+
VectorStoreRecordCollection,
1717
VectorStoreRecordDataField,
1818
VectorStoreRecordKeyField,
19+
vectorstoremodel,
1920
)
20-
from semantic_kernel.data.vector_storage.vector_store import VectorStore
21-
from semantic_kernel.data.vector_storage.vector_store_record_collection import VectorStoreRecordCollection
2221

2322
"""
2423
This sample demonstrates how to build a conversational chatbot

python/samples/concepts/memory/azure_ai_search_hotel_samples/step_1_interact_with_the_collection.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
import asyncio
44

5+
from step_0_data_model import HotelSampleClass
6+
7+
from semantic_kernel import Kernel
8+
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbedding
9+
from semantic_kernel.connectors.memory.azure_ai_search import AzureAISearchCollection
10+
511
###
612
# The data model used for this sample is based on the hotel data model from the Azure AI Search samples.
713
# When deploying a new index in Azure AI Search using the import wizard you can choose to deploy the 'hotel-samples'
@@ -13,24 +19,19 @@
1319
# This sample assumes the index is deployed, the vector fields can be empty.
1420
# If the vector fields are empty, change the first_run parameter to True to add the vectors.
1521
###
16-
from step_0_data_model import HotelSampleClass
17-
18-
from semantic_kernel import Kernel
19-
from semantic_kernel.connectors.ai.open_ai import OpenAITextEmbedding
20-
from semantic_kernel.connectors.memory.azure_ai_search import AzureAISearchCollection
2122
from semantic_kernel.data import (
2223
VectorSearchOptions,
23-
VectorStoreRecordUtils,
2424
)
25+
from semantic_kernel.data.vector_search import add_vector_to_records
2526

2627
first_run = False
2728

2829
# Note: you may need to update this `collection_name` depending upon how your index is named.
2930
COLLECTION_NAME = "hotels-sample-index"
3031

3132

32-
async def add_vectors(collection: AzureAISearchCollection, vectorizer: VectorStoreRecordUtils):
33-
"""This is a simple function that uses the VectorStoreRecordUtils to add vectors to the records in the collection.
33+
async def add_vectors(collection: AzureAISearchCollection, kernel: Kernel):
34+
"""This is a simple function that uses the add_vector_to_records function to add vectors.
3435
3536
It first uses the search_client within the collection to get a list of ids.
3637
and then uses the upsert to add the vectors to the records.
@@ -42,7 +43,7 @@ async def add_vectors(collection: AzureAISearchCollection, vectorizer: VectorSto
4243
if hotels is not None and isinstance(hotels, list):
4344
for hotel in hotels:
4445
if not hotel.description_vector or not hotel.description_fr_vector:
45-
hotel = await vectorizer.add_vector_to_records(hotel, HotelSampleClass)
46+
hotel = await add_vector_to_records(kernel, hotel, HotelSampleClass)
4647
await collection.upsert(hotel)
4748

4849

@@ -52,10 +53,8 @@ async def main(query: str, first_run: bool = False):
5253
# Add the OpenAI text embedding service
5354
embeddings = OpenAITextEmbedding(service_id="embedding", ai_model_id="text-embedding-3-small")
5455
kernel.add_service(embeddings)
55-
# Create the VectorStoreRecordUtils object
56-
vectorizer = VectorStoreRecordUtils(kernel)
5756
# Create the Azure AI Search collection
58-
collection = AzureAISearchCollection[HotelSampleClass](
57+
collection = AzureAISearchCollection[str, HotelSampleClass](
5958
collection_name=COLLECTION_NAME, data_model_type=HotelSampleClass
6059
)
6160
# Check if the collection exists.
@@ -71,7 +70,7 @@ async def main(query: str, first_run: bool = False):
7170

7271
# If it is the first run and there are no vectors, add them.
7372
if first_run:
74-
await add_vectors(collection, vectorizer)
73+
await add_vectors(collection, kernel)
7574

7675
# Search using just text, by default this will search all the searchable text fields in the index.
7776
results = await collection.text_search(search_text=query)

0 commit comments

Comments
 (0)