Skip to content

Commit 8e1e776

Browse files
authored
Merge pull request #26 from petermail/bugfix/KX-13474_Kentico_Xperience_OpenAI_Azure
KX-13474 Increased version of OpenAI to 2.0.0 and adjusted rest of th…
2 parents c813c8f + 018acc3 commit 8e1e776

File tree

8 files changed

+96
-73
lines changed

8 files changed

+96
-73
lines changed

src/CMS/CMSApp.csproj

Lines changed: 10 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@
7171
<Reference Include="Azure.AI.TextAnalytics, Version=5.2.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
7272
<HintPath>..\packages\Azure.AI.TextAnalytics.5.2.0\lib\netstandard2.0\Azure.AI.TextAnalytics.dll</HintPath>
7373
</Reference>
74-
<Reference Include="Azure.Core, Version=1.38.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
75-
<HintPath>..\packages\Azure.Core.1.38.0\lib\net472\Azure.Core.dll</HintPath>
74+
<Reference Include="Azure.Core, Version=1.43.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
75+
<HintPath>..\packages\Azure.Core.1.43.0\lib\net472\Azure.Core.dll</HintPath>
7676
</Reference>
7777
<Reference Include="BouncyCastle.Crypto, Version=1.9.0.0, Culture=neutral, PublicKeyToken=0e99375e54769942, processorArchitecture=MSIL">
7878
<HintPath>..\packages\Portable.BouncyCastle.1.9.0\lib\net40\BouncyCastle.Crypto.dll</HintPath>
@@ -125,8 +125,8 @@
125125
<Reference Include="Microsoft.Azure.Storage.Queue, Version=11.2.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
126126
<HintPath>..\packages\Microsoft.Azure.Storage.Queue.11.2.2\lib\net452\Microsoft.Azure.Storage.Queue.dll</HintPath>
127127
</Reference>
128-
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
129-
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.1\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
128+
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
129+
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.6.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
130130
</Reference>
131131
<Reference Include="Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=2.0.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
132132
<HintPath>..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.2.0.1\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll</HintPath>
@@ -328,8 +328,8 @@
328328
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
329329
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
330330
</Reference>
331-
<Reference Include="System.ClientModel, Version=1.0.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
332-
<HintPath>..\packages\System.ClientModel.1.0.0\lib\netstandard2.0\System.ClientModel.dll</HintPath>
331+
<Reference Include="System.ClientModel, Version=1.1.0.0, Culture=neutral, PublicKeyToken=92742159e12e44c8, processorArchitecture=MSIL">
332+
<HintPath>..\packages\System.ClientModel.1.1.0\lib\netstandard2.0\System.ClientModel.dll</HintPath>
333333
</Reference>
334334
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
335335
<HintPath>..\packages\System.ComponentModel.Annotations.4.7.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
@@ -443,11 +443,11 @@
443443
<Reference Include="System.Text.Encoding.CodePages, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
444444
<HintPath>..\packages\System.Text.Encoding.CodePages.6.0.0\lib\net461\System.Text.Encoding.CodePages.dll</HintPath>
445445
</Reference>
446-
<Reference Include="System.Text.Encodings.Web, Version=4.0.5.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
447-
<HintPath>..\packages\System.Text.Encodings.Web.4.7.2\lib\net461\System.Text.Encodings.Web.dll</HintPath>
446+
<Reference Include="System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
447+
<HintPath>..\packages\System.Text.Encodings.Web.6.0.0\lib\net461\System.Text.Encodings.Web.dll</HintPath>
448448
</Reference>
449-
<Reference Include="System.Text.Json, Version=4.0.1.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
450-
<HintPath>..\packages\System.Text.Json.4.7.2\lib\net461\System.Text.Json.dll</HintPath>
449+
<Reference Include="System.Text.Json, Version=6.0.0.9, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
450+
<HintPath>..\packages\System.Text.Json.6.0.9\lib\net461\System.Text.Json.dll</HintPath>
451451
</Reference>
452452
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
453453
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
@@ -14484,24 +14484,14 @@
1448414484
<Compile Include="Old_App_Code\CMS\UpgradeProcedure.cs" />
1448514485
<Compile Include="Properties\AssemblyInfo.cs" />
1448614486
</ItemGroup>
14487-
<ItemGroup>
14488-
</ItemGroup>
1448914487
<ItemGroup>
1449014488
<WebReferences Include="Web References\" />
1449114489
</ItemGroup>
14492-
<ItemGroup>
14493-
</ItemGroup>
14494-
<ItemGroup>
14495-
</ItemGroup>
14496-
<ItemGroup>
14497-
</ItemGroup>
1449814490
<ItemGroup>
1449914491
<Folder Include="CMSModules\EmailEngine\FormControls\" />
1450014492
<Folder Include="CMSScripts\Custom\" />
1450114493
<Folder Include="CMSScripts\WebComponents\" />
1450214494
</ItemGroup>
14503-
<ItemGroup>
14504-
</ItemGroup>
1450514495
<ItemGroup>
1450614496
<ProjectReference Include="..\Kentico.Xperience.OpenAI.Azure\Kentico.Xperience.OpenAI.Azure.csproj">
1450714497
<Project>{5f319bd1-c938-4c04-b4a2-b7d54c667bcb}</Project>

src/CMS/packages.config

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<package id="AWSSDK.Core" version="3.5.1.13" targetFramework="net48" />
77
<package id="AWSSDK.S3" version="3.5.1.4" targetFramework="net48" />
88
<package id="Azure.AI.TextAnalytics" version="5.2.0" targetFramework="net48" />
9-
<package id="Azure.Core" version="1.38.0" targetFramework="net48" />
9+
<package id="Azure.Core" version="1.43.0" targetFramework="net48" />
1010
<package id="DocumentFormat.OpenXml" version="2.19.0" targetFramework="net48" />
1111
<package id="Facebook" version="6.4.2" targetFramework="net48" />
1212
<package id="linqtotwitter" version="4.0.0" targetFramework="net48" />
@@ -26,7 +26,7 @@
2626
<package id="Microsoft.Azure.Storage.Blob" version="11.2.2" targetFramework="net48" />
2727
<package id="Microsoft.Azure.Storage.Common" version="11.2.2" targetFramework="net48" />
2828
<package id="Microsoft.Azure.Storage.Queue" version="11.2.2" targetFramework="net48" />
29-
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.1" targetFramework="net48" />
29+
<package id="Microsoft.Bcl.AsyncInterfaces" version="6.0.0" targetFramework="net48" />
3030
<package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="2.0.1" targetFramework="net48" />
3131
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net48" />
3232
<package id="Microsoft.Data.Edm" version="5.8.4" targetFramework="net48" />
@@ -82,7 +82,7 @@
8282
<package id="SharePointPnP.IdentityModel.Extensions" version="1.2.4" targetFramework="net48" />
8383
<package id="SharePointPnPCoreOnline" version="3.23.2007" targetFramework="net48" />
8484
<package id="System.Buffers" version="4.5.1" targetFramework="net48" />
85-
<package id="System.ClientModel" version="1.0.0" targetFramework="net48" />
85+
<package id="System.ClientModel" version="1.1.0" targetFramework="net48" />
8686
<package id="System.ComponentModel.Annotations" version="4.7.0" targetFramework="net48" />
8787
<package id="System.Data.DataSetExtensions" version="4.5.0" targetFramework="net48" />
8888
<package id="System.Data.HashFunction.Core" version="2.0.0" targetFramework="net48" />
@@ -115,8 +115,8 @@
115115
<package id="System.ServiceModel.Syndication" version="4.5.0" targetFramework="net48" />
116116
<package id="System.Spatial" version="5.8.4" targetFramework="net48" />
117117
<package id="System.Text.Encoding.CodePages" version="6.0.0" targetFramework="net48" />
118-
<package id="System.Text.Encodings.Web" version="4.7.2" targetFramework="net48" />
119-
<package id="System.Text.Json" version="4.7.2" targetFramework="net48" />
118+
<package id="System.Text.Encodings.Web" version="6.0.0" targetFramework="net48" />
119+
<package id="System.Text.Json" version="6.0.9" targetFramework="net48" />
120120
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net48" />
121121
<package id="System.ValueTuple" version="4.5.0" targetFramework="net48" />
122122
<package id="Ude.NetStandard" version="1.2.0" targetFramework="net48" />

src/CMS/web.config

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,15 +222,15 @@
222222
</dependentAssembly>
223223
<dependentAssembly>
224224
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
225-
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
225+
<bindingRedirect oldVersion="0.0.0.0-6.0.0.9" newVersion="6.0.0.9" />
226226
</dependentAssembly>
227227
<dependentAssembly>
228228
<assemblyIdentity name="System.Diagnostics.DiagnosticSource" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
229229
<bindingRedirect oldVersion="0.0.0.0-6.0.0.1" newVersion="6.0.0.1" />
230230
</dependentAssembly>
231231
<dependentAssembly>
232232
<assemblyIdentity name="Azure.Core" publicKeyToken="92742159e12e44c8" culture="neutral" />
233-
<bindingRedirect oldVersion="0.0.0.0-1.38.0.0" newVersion="1.38.0.0" />
233+
<bindingRedirect oldVersion="0.0.0.0-1.43.0.0" newVersion="1.43.0.0" />
234234
</dependentAssembly>
235235
<dependentAssembly>
236236
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
@@ -356,6 +356,14 @@
356356
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
357357
<bindingRedirect oldVersion="0.0.0.0-6.35.0.0" newVersion="6.35.0.0" />
358358
</dependentAssembly>
359+
<dependentAssembly>
360+
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
361+
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
362+
</dependentAssembly>
363+
<dependentAssembly>
364+
<assemblyIdentity name="System.ClientModel" publicKeyToken="92742159e12e44c8" culture="neutral" />
365+
<bindingRedirect oldVersion="0.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
366+
</dependentAssembly>
359367
</assemblyBinding>
360368
</runtime>
361369
<system.codedom>

src/Kentico.Xperience.OpenAI.Azure.Tests/PageCategorizationTests.cs

Lines changed: 42 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
using System;
2+
using System.ClientModel;
3+
using System.ClientModel.Primitives;
24
using System.Collections.Generic;
5+
using System.IO;
36
using System.Linq;
7+
using System.Threading;
8+
using System.Threading.Tasks;
49

510
using CMS.Core;
611
using CMS.DocumentEngine;
712
using CMS.Taxonomy;
813
using CMS.Tests;
914

10-
using Azure;
1115
using Azure.AI.OpenAI;
16+
using OpenAI.Chat;
1217

1318
using NSubstitute;
1419

@@ -19,13 +24,13 @@ namespace Kentico.Xperience.OpenAI.Azure.Tests
1924
[TestFixture]
2025
public class PageCategorizationTests : UnitTests
2126
{
22-
private OpenAIClient client;
27+
private AzureOpenAIClient client;
28+
private ChatClient chatClient;
2329
private IOpenAIClientFactory clientFactory;
2430
private PageCategorizationMock pageCategorizationService;
2531
private ISettingsService settingService;
2632
private ICategoryInfoProvider categoryInfoProvider;
2733
private TreeNode treeNode;
28-
private Response<ChatCompletions> response;
2934

3035
private const string CATEGORY1_NAME = "Category1";
3136
private const string CATEGORY2_NAME = "Category2";
@@ -43,11 +48,14 @@ public void Setup()
4348
FakeCategories();
4449
Fake<TreeNode>();
4550

46-
client = Substitute.For<OpenAIClient>();
51+
client = Substitute.For<AzureOpenAIClient>();
4752

4853
clientFactory = Substitute.For<IOpenAIClientFactory>();
4954
clientFactory.GetOpenAIClient(Arg.Any<string>(), Arg.Any<string>()).Returns(client);
5055

56+
chatClient = Substitute.For<ChatClient>();
57+
client.GetChatClient(DEPLOYMENT_NAME).Returns(chatClient);
58+
5159
settingService = Substitute.For<ISettingsService>();
5260
settingService[PageCategorizationConstants.DEPLOYMENT_NAME_KEY].Returns(DEPLOYMENT_NAME);
5361

@@ -142,13 +150,15 @@ public void CategorizePage_VariousCategories_ReturnsCorrectResponse()
142150

143151
Assert.Multiple(() =>
144152
{
145-
client.Received(1).GetChatCompletions(Arg.Is<ChatCompletionsOptions>(o => o.DeploymentName == DEPLOYMENT_NAME
146-
&& o.MaxTokens == PageCategorizationConstants.MAX_TOKENS
147-
&& o.Temperature == PageCategorizationConstants.DEFAULT_TEMPERATURE
148-
&& o.Messages.Count == 2
149-
&& ((ChatRequestSystemMessage)o.Messages[0]).Content.Equals(PageCategorizationConstants.DEFAULT_SYSTEM_PROMPT + $"Category names: {CATEGORY1_NAME}{DELIMITER}{CATEGORY2_NAME}{DELIMITER}{CATEGORY3_NAME}")
150-
&& ((ChatRequestUserMessage)o.Messages[1]).Content.Equals($"The data will be in the {EXPECTED_LANGUAGE} language. Categorize the following data:\n {EXPECTED_DATA_FORMAT}")
151-
));
153+
_ = client.Received(1);
154+
chatClient.CompleteChat(Arg.Is<ChatMessage[]>(m =>
155+
m.Length == 2
156+
&& m[0].Content.Equals(PageCategorizationConstants.DEFAULT_SYSTEM_PROMPT + $"Category names: {CATEGORY1_NAME}{DELIMITER}{CATEGORY2_NAME}{DELIMITER}{CATEGORY3_NAME}")
157+
&& m[1].Content.Equals($"The data will be in the {EXPECTED_LANGUAGE} language. Categorize the following data:\n {EXPECTED_DATA_FORMAT}")),
158+
Arg.Is<ChatCompletionOptions>(o =>
159+
o.MaxOutputTokenCount == PageCategorizationConstants.MAX_TOKENS
160+
&& o.Temperature == PageCategorizationConstants.DEFAULT_TEMPERATURE
161+
));
152162
_ = settingService.Received(1)[PageCategorizationConstants.API_ENDPOINT_KEY];
153163
_ = settingService.Received(1)[PageCategorizationConstants.API_KEY_KEY];
154164
_ = settingService.Received(1)[PageCategorizationConstants.DEPLOYMENT_NAME_KEY];
@@ -178,15 +188,12 @@ private void FakeCategories() => categoryInfoProvider = (ICategoryInfoProvider)F
178188

179189
private void SetChatCompletionsResponse(string expectedResponse)
180190
{
181-
response = Substitute.For<Response<ChatCompletions>>();
182-
183-
var responseMessage = AzureOpenAIModelFactory.ChatResponseMessage(content: expectedResponse);
184-
var chatChoice = AzureOpenAIModelFactory.ChatChoice(responseMessage);
191+
chatClient = client.GetChatClient(DEPLOYMENT_NAME);
185192

186-
var completion = AzureOpenAIModelFactory.ChatCompletions(choices: new List<ChatChoice>() { chatChoice });
187-
response.Value.Returns(completion);
193+
var completion = OpenAIChatModelFactory.ChatCompletion(content: new ChatMessageContent(expectedResponse));
194+
var result = ClientResult.FromValue(completion, new PipelineResponseMock());
188195

189-
client.GetChatCompletions(Arg.Any<ChatCompletionsOptions>()).Returns(response);
196+
chatClient.CompleteChat(Arg.Any<ChatMessage[]>(), Arg.Any<ChatCompletionOptions>()).Returns(result);
190197
}
191198
}
192199

@@ -213,4 +220,21 @@ internal PageCategorizationMock(
213220

214221
internal override IEnumerable<(string Name, string Value)> GetFields(TreeNode treeNode) => Fields;
215222
}
223+
224+
internal class PipelineResponseMock : PipelineResponse
225+
{
226+
public override int Status => throw new NotImplementedException();
227+
228+
public override string ReasonPhrase => throw new NotImplementedException();
229+
230+
public override Stream ContentStream { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
231+
232+
public override System.BinaryData Content => throw new NotImplementedException();
233+
234+
protected override PipelineResponseHeaders HeadersCore => throw new NotImplementedException();
235+
236+
public override System.BinaryData BufferContent(CancellationToken cancellationToken = default) => throw new NotImplementedException();
237+
public override ValueTask<System.BinaryData> BufferContentAsync(CancellationToken cancellationToken = default) => throw new NotImplementedException();
238+
public override void Dispose() => throw new NotImplementedException();
239+
}
216240
}

src/Kentico.Xperience.OpenAI.Azure/Azure/OpenAIClient/IOpenAIClientFactory.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,6 @@ internal interface IOpenAIClientFactory
1616
/// <param name="apiKey">The subscription key for accessing the Azure OpenAI Content Categorization service.</param>
1717
/// <returns>An instance of the <see cref="OpenAIClient"/> configured with the specified endpoint and key.</returns>
1818
/// <exception cref="InvalidOperationException">Thrown when either <paramref name="apiEndpoint"/> or <paramref name="apiKey"/> is null or empty.</exception>
19-
OpenAIClient GetOpenAIClient(string apiEndpoint, string apiKey);
19+
AzureOpenAIClient GetOpenAIClient(string apiEndpoint, string apiKey);
2020
}
2121
}
Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2+
using System.ClientModel;
23

3-
using Azure;
44
using Azure.AI.OpenAI;
55

66
namespace Kentico.Xperience.OpenAI.Azure
@@ -11,14 +11,14 @@ namespace Kentico.Xperience.OpenAI.Azure
1111
internal class OpenAIClientFactory : IOpenAIClientFactory
1212
{
1313
/// <inheritdoc/>
14-
public OpenAIClient GetOpenAIClient(string apiEndpoint, string apiKey)
14+
public AzureOpenAIClient GetOpenAIClient(string apiEndpoint, string apiKey)
1515
{
1616
if (string.IsNullOrEmpty(apiEndpoint) || string.IsNullOrEmpty(apiKey))
1717
{
1818
throw new InvalidOperationException($"The Azure OpenAI Content Categorization service API endpoint and key are not configured correctly.");
1919
}
2020

21-
return new OpenAIClient(new Uri(apiEndpoint), new AzureKeyCredential(apiKey));
21+
return new AzureOpenAIClient(new Uri(apiEndpoint), new ApiKeyCredential(apiKey));
2222
}
2323
}
2424
}

src/Kentico.Xperience.OpenAI.Azure/Kentico.Xperience.OpenAI.Azure.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<TargetFrameworks>net48</TargetFrameworks>
66
<Authors>Kentico Software</Authors>
77
<Company>Kentico Software</Company>
8-
<Version>1.0.0</Version>
8+
<Version>1.0.1</Version>
99
<IncludeSourceRevisionInInformationalVersion>false</IncludeSourceRevisionInInformationalVersion>
1010
<Copyright>Copyright © 2024</Copyright>
1111
<SignAssembly>true</SignAssembly>
@@ -23,7 +23,7 @@
2323
</Content>
2424
</ItemGroup>
2525
<ItemGroup>
26-
<PackageReference Include="Azure.AI.OpenAI" Version="1.0.0-beta.14" />
26+
<PackageReference Include="Azure.AI.OpenAI" Version="2.0.0" />
2727
</ItemGroup>
2828
<ItemGroup>
2929
<Reference Include="CMS.Base">

0 commit comments

Comments
 (0)