Skip to content

Commit 95f8057

Browse files
authored
GenAI SDK demos (#28)
* Net Standard GenAI demos. * named repo folders correctly * Added net8-windows projects * removed Spread demo an polished Fixed and Flow demos * FIxed namespaces * Removed unused references and files. * Flow Demo: Removed unused references and file.
1 parent b49cd66 commit 95f8057

17 files changed

+423
-165
lines changed

PdfProcessing/AIConnectorDemo/AIConnectorDemo.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
</PropertyGroup>
1414

1515
<ItemGroup>
16-
<Compile Remove="OllamaEmbeddingsStorage.cs" />
16+
<Compile Remove="CustomOpenAIEmbedder.cs" />
1717
<Compile Remove="TextLoader.cs" />
1818
</ItemGroup>
1919

2020
<ItemGroup>
2121
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.2" />
2222
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.1.25161.3" />
23-
<PackageReference Include="Telerik.Windows.Documents.AIConnector" Version="2025.2.520" />
24-
<PackageReference Include="Telerik.Windows.Documents.Fixed" Version="2025.2.520" />
23+
<PackageReference Include="Telerik.Windows.Documents.AIConnector" Version="2025.4.1104" />
24+
<PackageReference Include="Telerik.Windows.Documents.Fixed" Version="2025.4.1104" />
2525
</ItemGroup>
2626

2727
<ItemGroup>

PdfProcessing/AIConnectorDemo/AIConnectorDemo_NetStandard.csproj

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,9 @@
1313

1414
<ItemGroup>
1515
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.2" />
16-
<PackageReference Include="LangChain" Version="0.17.1-dev.12" />
17-
<PackageReference Include="LangChain.Core" Version="0.17.1-dev.12" />
18-
<PackageReference Include="LangChain.Databases.Sqlite" Version="0.17.1-dev.5" />
19-
<PackageReference Include="LangChain.Providers.Ollama" Version="0.17.1-dev.20" />
2016
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.1.25161.3" />
21-
<PackageReference Include="Telerik.Documents.AIConnector" Version="2025.2.520" />
22-
<PackageReference Include="Telerik.Documents.Fixed" Version="2025.2.520" />
17+
<PackageReference Include="Telerik.Documents.AIConnector" Version="2025.4.1104" />
18+
<PackageReference Include="Telerik.Documents.Fixed" Version="2025.4.1104" />
2319
</ItemGroup>
2420

2521
<ItemGroup>
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
using System.Net.Http;
2+
using System.Net.Http.Headers;
3+
using System.Text;
4+
using System.Text.Json;
5+
using Telerik.Documents.AI.Core;
6+
7+
namespace AIConnectorDemo
8+
{
9+
public class CustomOpenAIEmbedder : IEmbedder
10+
{
11+
private readonly HttpClient httpClient;
12+
13+
public CustomOpenAIEmbedder()
14+
{
15+
HttpClient httpClient = new HttpClient();
16+
httpClient.Timeout = TimeSpan.FromMinutes(5);
17+
string endpoint = Environment.GetEnvironmentVariable("AZUREEMBEDDINGOPENAI_ENDPOINT");
18+
string apiKey = Environment.GetEnvironmentVariable("AZUREEMBEDDINGOPENAI_KEY");
19+
20+
httpClient.BaseAddress = new Uri(endpoint);
21+
httpClient.DefaultRequestHeaders.Add("api-key", apiKey);
22+
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
23+
24+
this.httpClient = httpClient;
25+
}
26+
27+
public async Task<IList<Embedding>> EmbedAsync(IList<IFragment> fragments)
28+
{
29+
AzureEmbeddingsRequest requestBody = new AzureEmbeddingsRequest
30+
{
31+
Input = fragments.Select(p => p.ToEmbeddingText()).ToArray(),
32+
Dimensions = 3072
33+
};
34+
35+
string json = JsonSerializer.Serialize(requestBody);
36+
StringContent content = new StringContent(json, Encoding.UTF8, "application/json");
37+
38+
string apiVersion = Environment.GetEnvironmentVariable("AZUREEMBEDDINGOPENAI_APIVERSION");
39+
string deploymentName = Environment.GetEnvironmentVariable("AZUREEMBEDDINGOPENAI_DEPLOYMENT");
40+
string url = $"openai/deployments/{deploymentName}/embeddings?api-version={apiVersion}";
41+
using HttpResponseMessage response = await this.httpClient.PostAsync(url, content, CancellationToken.None);
42+
43+
Embedding[] embeddings = new Embedding[fragments.Count];
44+
45+
string responseJson = await response.Content.ReadAsStringAsync(CancellationToken.None);
46+
AzureEmbeddingsResponse responseObj = JsonSerializer.Deserialize<AzureEmbeddingsResponse>(responseJson);
47+
48+
List<EmbeddingData> sorted = responseObj.Data.OrderBy(d => d.Index).ToList();
49+
List<float[]> result = new List<float[]>(sorted.Count);
50+
51+
for (int i = 0; i < sorted.Count; i++)
52+
{
53+
EmbeddingData item = sorted[i];
54+
embeddings[i] = new Embedding(fragments[i], item.Embedding);
55+
}
56+
57+
return embeddings;
58+
}
59+
60+
private sealed class AzureEmbeddingsRequest
61+
{
62+
[System.Text.Json.Serialization.JsonPropertyName("input")]
63+
public string[] Input { get; set; } = Array.Empty<string>();
64+
65+
[System.Text.Json.Serialization.JsonPropertyName("dimensions")]
66+
public int? Dimensions { get; set; }
67+
}
68+
69+
private sealed class AzureEmbeddingsResponse
70+
{
71+
[System.Text.Json.Serialization.JsonPropertyName("data")]
72+
public EmbeddingData[] Data { get; set; } = Array.Empty<EmbeddingData>();
73+
74+
[System.Text.Json.Serialization.JsonPropertyName("model")]
75+
public string? Model { get; set; }
76+
77+
[System.Text.Json.Serialization.JsonPropertyName("usage")]
78+
public UsageInfo? Usage { get; set; }
79+
}
80+
81+
private sealed class UsageInfo
82+
{
83+
[System.Text.Json.Serialization.JsonPropertyName("prompt_tokens")]
84+
public int PromptTokens { get; set; }
85+
86+
[System.Text.Json.Serialization.JsonPropertyName("total_tokens")]
87+
public int TotalTokens { get; set; }
88+
}
89+
90+
private sealed class EmbeddingData
91+
{
92+
[System.Text.Json.Serialization.JsonPropertyName("embedding")]
93+
public float[] Embedding { get; set; } = Array.Empty<float>();
94+
95+
[System.Text.Json.Serialization.JsonPropertyName("index")]
96+
public int Index { get; set; }
97+
}
98+
}
99+
}

PdfProcessing/AIConnectorDemo/OllamaEmbeddingsStorage.cs

Lines changed: 0 additions & 67 deletions
This file was deleted.

PdfProcessing/AIConnectorDemo/Program.cs

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
using Microsoft.Extensions.AI;
33
using OpenAI.Chat;
44
using System.IO;
5+
using Telerik.Documents.AI.Core;
6+
57
#if NETWINDOWS
68
using Telerik.Windows.Documents.AIConnector;
79
#else
@@ -16,19 +18,22 @@ namespace AIConnectorDemo
1618
internal class Program
1719
{
1820
static int maxTokenCount = 128000;
21+
static int maxNumberOfEmbeddingsSent = 50000;
1922
static IChatClient iChatClient;
23+
static string tokenizationEncoding = "cl100k_base";
24+
static string model = "gpt-4o-mini";
25+
static string key = Environment.GetEnvironmentVariable("AZUREOPENAI_KEY");
26+
static string endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT");
2027

2128
static void Main(string[] args)
2229
{
23-
Console.WriteLine("Hello, World!");
24-
2530
CreateChatClient();
2631

2732
using (Stream input = File.OpenRead("John Grisham.pdf"))
2833
{
2934
PdfFormatProvider pdfFormatProvider = new PdfFormatProvider();
3035
RadFixedDocument inputPdf = pdfFormatProvider.Import(input, null);
31-
ISimpleTextDocument simpleDocument = inputPdf.ToSimpleTextDocument();
36+
SimpleTextDocument simpleDocument = inputPdf.ToSimpleTextDocument(TimeSpan.FromSeconds(10));
3237

3338
Summarize(simpleDocument);
3439

@@ -44,10 +49,6 @@ static void Main(string[] args)
4449

4550
private static void CreateChatClient()
4651
{
47-
string key = Environment.GetEnvironmentVariable("AZUREOPENAI_KEY");
48-
string endpoint = Environment.GetEnvironmentVariable("AZUREOPENAI_ENDPOINT");
49-
string model = "gpt-4o-mini";
50-
5152
AzureOpenAIClient azureClient = new(
5253
new Uri(endpoint),
5354
new Azure.AzureKeyCredential(key),
@@ -57,10 +58,12 @@ private static void CreateChatClient()
5758
iChatClient = new OpenAIChatClient(chatClient);
5859
}
5960

60-
private static void Summarize(ISimpleTextDocument simpleDocument)
61+
private static void Summarize(SimpleTextDocument simpleDocument)
6162
{
62-
SummarizationProcessor summarizationProcessor = new SummarizationProcessor(iChatClient, maxTokenCount);
63-
summarizationProcessor.Settings.PromptAddition = "Summarize the text in a few sentences. Be concise and clear.";
63+
string additionalPrompt = "Summarize the text in a few sentences. Be concise and clear.";
64+
SummarizationProcessorSettings summarizationProcessorSettings = new SummarizationProcessorSettings(maxTokenCount, additionalPrompt);
65+
SummarizationProcessor summarizationProcessor = new SummarizationProcessor(iChatClient, summarizationProcessorSettings);
66+
6467
summarizationProcessor.SummaryResourcesCalculated += SummarizationProcessor_SummaryResourcesCalculated;
6568

6669
string summary = summarizationProcessor.Summarize(simpleDocument).Result;
@@ -73,23 +76,25 @@ private static void SummarizationProcessor_SummaryResourcesCalculated(object? se
7376
e.ShouldContinueExecution = true;
7477
}
7578

76-
private static void AskQuestion(ISimpleTextDocument simpleDocument)
79+
private static void AskQuestion(SimpleTextDocument simpleDocument)
7780
{
78-
CompleteContextQuestionProcessor completeContextQuestionProcessor = new CompleteContextQuestionProcessor(iChatClient, maxTokenCount);
81+
CompleteContextProcessorSettings completeContextProcessorSettings = new CompleteContextProcessorSettings(maxTokenCount, model, tokenizationEncoding, false);
82+
CompleteContextQuestionProcessor completeContextQuestionProcessor = new CompleteContextQuestionProcessor(iChatClient, completeContextProcessorSettings);
7983

8084
string question = "How many pages is the document and what is it about?";
8185
string answer = completeContextQuestionProcessor.AnswerQuestion(simpleDocument, question).Result;
8286
Console.WriteLine(question);
8387
Console.WriteLine(answer);
8488
}
8589

86-
private static void AskPartialContextQuestion(ISimpleTextDocument simpleDocument)
90+
private static void AskPartialContextQuestion(SimpleTextDocument simpleDocument)
8791
{
92+
var settings = EmbeddingSettingsFactory.CreateSettingsForTextDocuments(maxTokenCount, model, tokenizationEncoding, maxNumberOfEmbeddingsSent);
8893
#if NETWINDOWS
89-
PartialContextQuestionProcessor partialContextQuestionProcessor = new PartialContextQuestionProcessor(iChatClient, maxTokenCount, simpleDocument);
94+
PartialContextQuestionProcessor partialContextQuestionProcessor = new PartialContextQuestionProcessor(iChatClient, settings, simpleDocument);
9095
#else
91-
IEmbeddingsStorage embeddingsStorage = new OllamaEmbeddingsStorage();
92-
PartialContextQuestionProcessor partialContextQuestionProcessor = new PartialContextQuestionProcessor(iChatClient, embeddingsStorage, maxTokenCount, simpleDocument);
96+
IEmbedder embedder = new CustomOpenAIEmbedder();
97+
PartialContextQuestionProcessor partialContextQuestionProcessor = new PartialContextQuestionProcessor(iChatClient, embedder, settings, simpleDocument);
9398
#endif
9499
string question = "What is the last book by John Grisham?";
95100
string answer = partialContextQuestionProcessor.AnswerQuestion(question).Result;
Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
In order to run the project, you need to replace the key and endpoint with your Azure Open AI key and endpoint.
22
They are located in the launchSettings.json file in the Properties folder.
33

4-
In NetStandard you need to implement IEmbeddingsStorage if you would like to use the PartialContextQuestionProcessor.
5-
There is a sample implementation called OllamaEmbeddingsStorage in the NetStandard project.
6-
For it to work the Ollama server needs to be running locally. You can follow these steps to run it:
7-
1. Install Ollama: https://ollama.com/
8-
2. Pull the all-minilm model we'll use for embeddings: ollama pull all-minilm
9-
3. Ensure Ollama is running: ollama serve
4+
In NetStandard you need to implement IEmbedder if you would like to use the PartialContextQuestionProcessor.
5+
There is a sample implementation called CustomOpenAIEmbedder in the NetStandard project.

PdfProcessing/AIConnectorDemo/TextLoader.cs

Lines changed: 0 additions & 20 deletions
This file was deleted.

PdfProcessing/PdfProcessing_NetStandard.sln

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
Microsoft Visual Studio Solution File, Format Version 12.00
33
# Visual Studio Version 17
4-
VisualStudioVersion = 17.13.35919.96 d17.13
4+
VisualStudioVersion = 17.13.35919.96
55
MinimumVisualStudioVersion = 10.0.40219.1
66
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CreateDocumentWithImages_NetStandard", "CreateDocumentWithImages\CreateDocumentWithImages_NetStandard.csproj", "{D7CA01E8-E777-4D18-B960-AA0F62040F87}"
77
EndProject
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net8.0-windows</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<UseWPF>true</UseWPF>
9+
</PropertyGroup>
10+
11+
<PropertyGroup>
12+
<DefineConstants>NETWINDOWS;$(DefineConstants)</DefineConstants>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<Compile Remove="CustomOpenAIEmbedder.cs" />
17+
<Compile Remove="TextLoader.cs" />
18+
</ItemGroup>
19+
20+
<ItemGroup>
21+
<PackageReference Include="Azure.AI.OpenAI" Version="2.2.0-beta.2" />
22+
<PackageReference Include="Microsoft.Extensions.AI.OpenAI" Version="9.3.0-preview.1.25161.3" />
23+
<PackageReference Include="Telerik.Windows.Documents.AIConnector" Version="2025.4.1104" />
24+
<PackageReference Include="Telerik.Windows.Documents.Flow" Version="2025.4.1104" />
25+
</ItemGroup>
26+
27+
<ItemGroup>
28+
<None Update="GenAI Document Insights Test Document.docx">
29+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
30+
</None>
31+
</ItemGroup>
32+
33+
</Project>

0 commit comments

Comments
 (0)