Skip to content

Commit 1068368

Browse files
authored
.Net: Fix Nullable Bug Gemini Schema Generation (microsoft#11584)
### Motivation and Context - Fix microsoft#10296 This problem arises when `KernelSchema` uses the `AIJsonUtilities.CreateJsonSchema`, where it generates a schema that does not comply with OpenAPI 3.0 for nullables that Google API uses. - dotnet/extensions#6306
1 parent da1e1e5 commit 1068368

File tree

11 files changed

+643
-135
lines changed

11 files changed

+643
-135
lines changed

dotnet/samples/Concepts/ChatCompletion/Google_GeminiChatCompletion.cs

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

3+
using Google.Apis.Auth.OAuth2;
34
using Microsoft.SemanticKernel;
45
using Microsoft.SemanticKernel.ChatCompletion;
56

67
namespace ChatCompletion;
78

9+
/// <summary>
10+
/// These examples demonstrate different ways of using chat completion with Google VertexAI and GoogleAI APIs.
11+
/// </summary>
812
public sealed class Google_GeminiChatCompletion(ITestOutputHelper output) : BaseTest(output)
913
{
1014
[Fact]
11-
public async Task GoogleAIAsync()
15+
public async Task GoogleAIUsingChatCompletion()
1216
{
1317
Console.WriteLine("============= Google AI - Gemini Chat Completion =============");
1418

@@ -27,31 +31,27 @@ public async Task GoogleAIAsync()
2731
apiKey: geminiApiKey)
2832
.Build();
2933

30-
await RunSampleAsync(kernel);
34+
await this.ProcessChatAsync(kernel);
3135
}
3236

3337
[Fact]
34-
public async Task VertexAIAsync()
38+
public async Task VertexAIUsingChatCompletion()
3539
{
3640
Console.WriteLine("============= Vertex AI - Gemini Chat Completion =============");
3741

38-
string geminiBearerKey = TestConfiguration.VertexAI.BearerKey;
39-
string geminiModelId = TestConfiguration.VertexAI.Gemini.ModelId;
40-
string geminiLocation = TestConfiguration.VertexAI.Location;
41-
string geminiProject = TestConfiguration.VertexAI.ProjectId;
42-
43-
if (geminiBearerKey is null || geminiModelId is null || geminiLocation is null || geminiProject is null)
44-
{
45-
Console.WriteLine("Gemini vertex ai credentials not found. Skipping example.");
46-
return;
47-
}
42+
string? bearerToken = null;
43+
Assert.NotNull(TestConfiguration.VertexAI.ClientId);
44+
Assert.NotNull(TestConfiguration.VertexAI.ClientSecret);
45+
Assert.NotNull(TestConfiguration.VertexAI.Location);
46+
Assert.NotNull(TestConfiguration.VertexAI.ProjectId);
47+
Assert.NotNull(TestConfiguration.VertexAI.Gemini.ModelId);
4848

4949
Kernel kernel = Kernel.CreateBuilder()
5050
.AddVertexAIGeminiChatCompletion(
51-
modelId: geminiModelId,
52-
bearerKey: geminiBearerKey,
53-
location: geminiLocation,
54-
projectId: geminiProject)
51+
modelId: TestConfiguration.VertexAI.Gemini.ModelId,
52+
bearerTokenProvider: GetBearerToken,
53+
location: TestConfiguration.VertexAI.Location,
54+
projectId: TestConfiguration.VertexAI.ProjectId)
5555
.Build();
5656

5757
// To generate bearer key, you need installed google sdk or use google web console with command:
@@ -72,23 +72,39 @@ public async Task VertexAIAsync()
7272
// // This is just example, in production we recommend using Google SDK to generate your BearerKey token.
7373
// // This delegate will be called on every request,
7474
// // when providing the token consider using caching strategy and refresh token logic when it is expired or close to expiration.
75-
// return GetBearerKey();
75+
// return GetBearerToken();
7676
// },
7777
// location: TestConfiguration.VertexAI.Location,
7878
// projectId: TestConfiguration.VertexAI.ProjectId);
7979

80-
await RunSampleAsync(kernel);
81-
}
80+
async ValueTask<string> GetBearerToken()
81+
{
82+
if (!string.IsNullOrEmpty(bearerToken))
83+
{
84+
return bearerToken;
85+
}
86+
87+
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
88+
new ClientSecrets
89+
{
90+
ClientId = TestConfiguration.VertexAI.ClientId,
91+
ClientSecret = TestConfiguration.VertexAI.ClientSecret
92+
},
93+
["https://www.googleapis.com/auth/cloud-platform"],
94+
"user",
95+
CancellationToken.None);
96+
97+
var userCredential = await credential.WaitAsync(CancellationToken.None);
98+
bearerToken = userCredential.Token.AccessToken;
99+
100+
return bearerToken;
101+
}
82102

83-
private async Task RunSampleAsync(Kernel kernel)
84-
{
85-
await SimpleChatAsync(kernel);
103+
await this.ProcessChatAsync(kernel);
86104
}
87105

88-
private async Task SimpleChatAsync(Kernel kernel)
106+
private async Task ProcessChatAsync(Kernel kernel)
89107
{
90-
Console.WriteLine("======== Simple Chat ========");
91-
92108
var chatHistory = new ChatHistory("You are an expert in the tool shop.");
93109
var chat = kernel.GetRequiredService<IChatCompletionService>();
94110

dotnet/samples/Concepts/ChatCompletion/Google_GeminiChatCompletionStreaming.cs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
// Copyright (c) Microsoft. All rights reserved.
22

33
using System.Text;
4+
using Google.Apis.Auth.OAuth2;
45
using Microsoft.SemanticKernel;
56
using Microsoft.SemanticKernel.ChatCompletion;
67

78
namespace ChatCompletion;
89

10+
/// <summary>
11+
/// These examples demonstrate different ways of using chat completion with Google VertexAI and GoogleAI APIs.
12+
/// </summary>
913
public sealed class Google_GeminiChatCompletionStreaming(ITestOutputHelper output) : BaseTest(output)
1014
{
1115
[Fact]
12-
public async Task GoogleAIAsync()
16+
public async Task GoogleAIUsingStreamingChatCompletion()
1317
{
1418
Console.WriteLine("============= Google AI - Gemini Chat Completion =============");
1519

@@ -28,31 +32,27 @@ public async Task GoogleAIAsync()
2832
apiKey: geminiApiKey)
2933
.Build();
3034

31-
await RunSampleAsync(kernel);
35+
await this.ProcessStreamingChatAsync(kernel);
3236
}
3337

3438
[Fact]
35-
public async Task VertexAIAsync()
39+
public async Task VertexAIUsingStreamingChatCompletion()
3640
{
3741
Console.WriteLine("============= Vertex AI - Gemini Chat Completion =============");
3842

39-
string geminiBearerKey = TestConfiguration.VertexAI.BearerKey;
40-
string geminiModelId = TestConfiguration.VertexAI.Gemini.ModelId;
41-
string geminiLocation = TestConfiguration.VertexAI.Location;
42-
string geminiProject = TestConfiguration.VertexAI.ProjectId;
43-
44-
if (geminiBearerKey is null || geminiModelId is null || geminiLocation is null || geminiProject is null)
45-
{
46-
Console.WriteLine("Gemini vertex ai credentials not found. Skipping example.");
47-
return;
48-
}
43+
string? bearerToken = null;
44+
Assert.NotNull(TestConfiguration.VertexAI.ClientId);
45+
Assert.NotNull(TestConfiguration.VertexAI.ClientSecret);
46+
Assert.NotNull(TestConfiguration.VertexAI.Location);
47+
Assert.NotNull(TestConfiguration.VertexAI.ProjectId);
48+
Assert.NotNull(TestConfiguration.VertexAI.Gemini.ModelId);
4949

5050
Kernel kernel = Kernel.CreateBuilder()
5151
.AddVertexAIGeminiChatCompletion(
52-
modelId: geminiModelId,
53-
bearerKey: geminiBearerKey,
54-
location: geminiLocation,
55-
projectId: geminiProject)
52+
modelId: TestConfiguration.VertexAI.Gemini.ModelId,
53+
bearerTokenProvider: GetBearerToken,
54+
location: TestConfiguration.VertexAI.Location,
55+
projectId: TestConfiguration.VertexAI.ProjectId)
5656
.Build();
5757

5858
// To generate bearer key, you need installed google sdk or use google web console with command:
@@ -78,18 +78,34 @@ public async Task VertexAIAsync()
7878
// location: TestConfiguration.VertexAI.Location,
7979
// projectId: TestConfiguration.VertexAI.ProjectId);
8080

81-
await RunSampleAsync(kernel);
82-
}
81+
async ValueTask<string> GetBearerToken()
82+
{
83+
if (!string.IsNullOrEmpty(bearerToken))
84+
{
85+
return bearerToken;
86+
}
8387

84-
private async Task RunSampleAsync(Kernel kernel)
85-
{
86-
await StreamingChatAsync(kernel);
88+
var credential = GoogleWebAuthorizationBroker.AuthorizeAsync(
89+
new ClientSecrets
90+
{
91+
ClientId = TestConfiguration.VertexAI.ClientId,
92+
ClientSecret = TestConfiguration.VertexAI.ClientSecret
93+
},
94+
["https://www.googleapis.com/auth/cloud-platform"],
95+
"user",
96+
CancellationToken.None);
97+
98+
var userCredential = await credential.WaitAsync(CancellationToken.None);
99+
bearerToken = userCredential.Token.AccessToken;
100+
101+
return bearerToken;
102+
}
103+
104+
await this.ProcessStreamingChatAsync(kernel);
87105
}
88106

89-
private async Task StreamingChatAsync(Kernel kernel)
107+
private async Task ProcessStreamingChatAsync(Kernel kernel)
90108
{
91-
Console.WriteLine("======== Streaming Chat ========");
92-
93109
var chatHistory = new ChatHistory("You are an expert in the tool shop.");
94110
var chat = kernel.GetRequiredService<IChatCompletionService>();
95111

dotnet/samples/Concepts/ChatCompletion/Google_GeminiGetModelResult.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,15 @@ namespace ChatCompletion;
1111
public sealed class Google_GeminiGetModelResult(ITestOutputHelper output) : BaseTest(output)
1212
{
1313
[Fact]
14-
public async Task GetTokenUsageMetadataAsync()
14+
public async Task GetTokenUsageMetadata()
1515
{
1616
Console.WriteLine("======== Inline Function Definition + Invocation ========");
1717

18+
Assert.NotNull(TestConfiguration.VertexAI.BearerKey);
19+
Assert.NotNull(TestConfiguration.VertexAI.Location);
20+
Assert.NotNull(TestConfiguration.VertexAI.ProjectId);
21+
Assert.NotNull(TestConfiguration.VertexAI.Gemini.ModelId);
22+
1823
// Create kernel
1924
Kernel kernel = Kernel.CreateBuilder()
2025
.AddVertexAIGeminiChatCompletion(

0 commit comments

Comments
 (0)