Skip to content

.Net: Process: Document generation gRPC sample #11206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 31 commits into from
Apr 8, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
06d7086
grpc demo for document generation initial
estenori Mar 25, 2025
b00e34d
updating sample to pass more than a string
estenori Mar 26, 2025
89a35ec
fixing step logic
estenori Mar 26, 2025
243aaa8
Merge branch 'main' into estenori/processes/grpcSample
estenori Mar 26, 2025
ce5f8d7
addressing formatting issues
estenori Mar 26, 2025
796d907
formatting + spelling
estenori Mar 26, 2025
abd2d27
fixing build errors/formatting
estenori Mar 26, 2025
e4dd762
missing class comment + spelling error
estenori Mar 26, 2025
53b6068
missing warnig error
estenori Mar 26, 2025
1319db3
addressing comments
esttenorio Mar 27, 2025
8303c89
readme explaining process
esttenorio Mar 27, 2025
f23a7f1
removing unnecessary package added
esttenorio Mar 27, 2025
9bccfd7
addressing comments
esttenorio Mar 28, 2025
3e1c66f
adding link to additional readme file
esttenorio Mar 28, 2025
05e80b9
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Mar 28, 2025
39da360
updating solutions file
esttenorio Mar 28, 2025
2d2c12a
typo in gitignore
esttenorio Mar 28, 2025
48f2ba2
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Mar 28, 2025
a18f5e6
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Mar 31, 2025
cb9969f
Apply learning website references
esttenorio Mar 31, 2025
bb07422
build errors fix
esttenorio Mar 31, 2025
6096bde
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Mar 31, 2025
dc6d74f
serializing objects internally - dapr working
esttenorio Apr 1, 2025
e9ab500
working with localruntime
esttenorio Apr 2, 2025
43154d7
dapr integration tests working
esttenorio Apr 2, 2025
f072057
Merge pull request #1 from esttenorio/estenori/processes/expSerializa…
esttenorio Apr 2, 2025
60352d3
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Apr 2, 2025
df74ef2
removing unnecesary import
esttenorio Apr 2, 2025
540b5dc
removing commented code
esttenorio Apr 2, 2025
ea36ff1
fixing map step in local and dapr runtime after serialization changes
esttenorio Apr 7, 2025
233408b
Merge branch 'main' into estenori/processes/grpcSample
esttenorio Apr 7, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion dotnet/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
<PackageVersion Include="FastBertTokenizer" Version="1.0.28" />
<PackageVersion Include="Google.Apis.Auth" Version="1.69.0" />
<PackageVersion Include="ModelContextProtocol" Version="0.1.0-preview.1.25171.12" />
<PackageVersion Include="Google.Protobuf" Version="3.27.0" />
<PackageVersion Include="Grpc.AspNetCore" Version="2.70.0" />
<PackageVersion Include="Grpc.AspNetCore.Server" Version="2.70.0" />
<PackageVersion Include="Grpc.AspNetCore.Server.Reflection" Version="2.70.0" />
<PackageVersion Include="Grpc.Tools" Version="2.70.0" />
<PackageVersion Include="mcpdotnet" Version="1.0.1.3" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Testing" Version="8.0.13" />
<PackageVersion Include="Microsoft.AspNetCore.OpenApi" Version="8.0.14" />
<PackageVersion Include="Microsoft.ML.Tokenizers.Data.Cl100kBase" Version="1.0.1" />
Expand Down Expand Up @@ -135,7 +141,7 @@
<PackageVersion Include="Microsoft.OpenApi.ApiManifest" Version="0.5.6-preview" />
<PackageVersion Include="Microsoft.Plugins.Manifest" Version="1.0.0-rc3" />
<PackageVersion Include="Google.Apis.CustomSearchAPI.v1" Version="1.68.0.3520" />
<PackageVersion Include="Grpc.Net.Client" Version="2.66.0" />
<PackageVersion Include="Grpc.Net.Client" Version="2.70.0" />
<PackageVersion Include="protobuf-net" Version="3.2.45" />
<PackageVersion Include="protobuf-net.Reflection" Version="3.2.12" />
<PackageVersion Include="YamlDotNet" Version="15.3.0" />
Expand Down
27 changes: 27 additions & 0 deletions dotnet/SK-dotnet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PineconeIntegrationTests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ModelContextProtocolPlugin", "samples\Demos\ModelContextProtocolPlugin\ModelContextProtocolPlugin.csproj", "{801C9CE4-53AF-D2DB-E0D6-9A6BB47E9654}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ProcessWithCloudEvents", "ProcessWithCloudEvents", "{70E69280-8DD8-463D-A94A-A1C0C4AA3A0B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessWithCloudEvents.Processes", "samples\Demos\ProcessWithCloudEvents\ProcessWithCloudEvents.Processes\ProcessWithCloudEvents.Processes.csproj", "{31F6608A-FD36-F529-A5FC-C954A0B5E29E}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProcessWithCloudEvents.Grpc", "samples\Demos\ProcessWithCloudEvents\ProcessWithCloudEvents.Grpc\ProcessWithCloudEvents.Grpc.csproj", "{08D84994-794A-760F-95FD-4EFA8998A16D}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1403,6 +1409,24 @@ Global
{801C9CE4-53AF-D2DB-E0D6-9A6BB47E9654}.Publish|Any CPU.Build.0 = Release|Any CPU
{801C9CE4-53AF-D2DB-E0D6-9A6BB47E9654}.Release|Any CPU.ActiveCfg = Release|Any CPU
{801C9CE4-53AF-D2DB-E0D6-9A6BB47E9654}.Release|Any CPU.Build.0 = Release|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Publish|Any CPU.ActiveCfg = Release|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Publish|Any CPU.Build.0 = Release|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{31F6608A-FD36-F529-A5FC-C954A0B5E29E}.Release|Any CPU.Build.0 = Release|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Publish|Any CPU.ActiveCfg = Release|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Publish|Any CPU.Build.0 = Release|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{08D84994-794A-760F-95FD-4EFA8998A16D}.Release|Any CPU.Build.0 = Release|Any CPU
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Debug|Any CPU.ActiveCfg = Debug
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Debug|Any CPU.Build.0 = Debug
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Publish|Any CPU.ActiveCfg = Release
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Publish|Any CPU.Build.0 = Release
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Release|Any CPU.ActiveCfg = Release
{D1786E2B-CAA0-4B2D-A974-9845EB9E420F}.Release|Any CPU.Build.0 = Release
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -1594,6 +1618,9 @@ Global
{A5E6193C-8431-4C6E-B674-682CB41EAA0C} = {4F381919-F1BE-47D8-8558-3187ED04A84F}
{E9A74E0C-BC02-4DDD-A487-89847EDF8026} = {4F381919-F1BE-47D8-8558-3187ED04A84F}
{801C9CE4-53AF-D2DB-E0D6-9A6BB47E9654} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
{70E69280-8DD8-463D-A94A-A1C0C4AA3A0B} = {5D4C0700-BBB5-418F-A7B2-F392B9A18263}
{31F6608A-FD36-F529-A5FC-C954A0B5E29E} = {70E69280-8DD8-463D-A94A-A1C0C4AA3A0B}
{08D84994-794A-760F-95FD-4EFA8998A16D} = {70E69280-8DD8-463D-A94A-A1C0C4AA3A0B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FBDC56A3-86AD-4323-AA0F-201E59123B83}
Expand Down
9 changes: 9 additions & 0 deletions dotnet/dapr.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
apps:
- appDirPath: samples\Demos\ProcessWithCloudEvents\ProcessWithCloudEvents.Grpc
appID: processwithcloudevents-grpc
appPort: 58641
command:
- dotnet
- run
appProtocol: h2c
version: 1
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (c) Microsoft. All rights reserved.
using System.Text.Json;
using Grpc.Net.Client;
using Microsoft.SemanticKernel;
using ProcessWithCloudEvents.Grpc.DocumentationGenerator;
using ProcessWithCloudEvents.Processes;
using ProcessWithCloudEvents.Processes.Models;

namespace ProcessWithCloudEvents.Grpc.Clients;

/// <summary>
/// Client that implements the <see cref="IExternalKernelProcessMessageChannel"/> interface used internally by the SK process
/// to emit events to external systems.<br/>
/// This implementation is an example of a gRPC client that emits events to a gRPC server
/// </summary>
public class DocumentGenerationGrpcClient : IExternalKernelProcessMessageChannel
{
private GrpcChannel? _grpcChannel;
private GrpcDocumentationGeneration.GrpcDocumentationGenerationClient? _grpcClient;

/// <inheritdoc/>
public async ValueTask Initialize()
{
this._grpcChannel = GrpcChannel.ForAddress("http://localhost:58641");
this._grpcClient = new GrpcDocumentationGeneration.GrpcDocumentationGenerationClient(this._grpcChannel);
}

/// <inheritdoc/>
public async ValueTask Uninitialize()
{
if (this._grpcChannel != null)
{
await this._grpcChannel.ShutdownAsync();
}
}

/// <inheritdoc/>
public async Task EmitExternalEventAsync(string externalTopicEvent, KernelProcessProxyMessage eventData)
{
if (this._grpcClient != null)
{
switch (externalTopicEvent)
{
case DocumentGenerationProcess.DocGenerationTopics.RequestUserReview:
var requestDocument = JsonSerializer.Deserialize<DocumentInfo>(eventData.EventData!.ToString()!);
if (requestDocument != null)
{
await this._grpcClient.RequestUserReviewDocumentationFromProcessAsync(new()
{
Title = requestDocument.Title,
AssistantMessage = "Document ready for user revision. Approve or reject document",
Content = requestDocument.Content,
ProcessData = new() { ProcessId = eventData.ProcessId }
});
}
return;

case DocumentGenerationProcess.DocGenerationTopics.PublishDocumentation:
var publishedDocument = JsonSerializer.Deserialize<DocumentInfo>(eventData.EventData!.ToString()!);
if (publishedDocument != null)
{
await this._grpcClient.PublishDocumentationAsync(new()
{
Title = publishedDocument.Title,
AssistantMessage = "Published Document Ready",
Content = publishedDocument.Content,
ProcessData = new() { ProcessId = eventData.ProcessId }
});
}
return;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<NoWarn>
$(NoWarn);CA2007,CA1861,VSTHRD111,SKEXP0001,SKEXP0010,SKEXP0020,SKEXP0040,SKEXP0050,SKEXP0060,SKEXP0070,SKEXP0080,SKEXP0110
</NoWarn>
<UserSecretsId>5ee045b0-aea3-4f08-8d31-32d1a6f8fed0</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<Protobuf Include="Protos\documentationGenerator.proto" GrpcServices="Both" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\..\src\Connectors\Connectors.OpenAI\Connectors.OpenAI.csproj" />
<ProjectReference Include="..\..\..\..\src\Experimental\Process.Abstractions\Process.Abstractions.csproj" />
<ProjectReference Include="..\..\..\..\src\Experimental\Process.Core\Process.Core.csproj" />
<ProjectReference Include="..\..\..\..\src\Experimental\Process.Runtime.Dapr\Process.Runtime.Dapr.csproj" />
<ProjectReference Include="..\ProcessWithCloudEvents.Processes\ProcessWithCloudEvents.Processes.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Dapr.Actors" />
<PackageReference Include="Dapr.Actors.AspNetCore" />
<PackageReference Include="Google.Protobuf" />
<PackageReference Include="Grpc.AspNetCore" />
<PackageReference Include="Grpc.AspNetCore.Server.Reflection" />
<PackageReference Include="Grpc.Net.Client" />
<PackageReference Include="Grpc.Tools">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<Folder Include="Media\" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft. All rights reserved.

using Microsoft.SemanticKernel;
using ProcessWithCloudEvents.Grpc.Clients;
using ProcessWithCloudEvents.Grpc.Services;

var builder = WebApplication.CreateBuilder(args);

var config = new ConfigurationBuilder()
.AddUserSecrets<Program>()
.AddEnvironmentVariables()
.Build();

// Configure logging
builder.Services.AddLogging((logging) =>
{
logging.AddConsole();
logging.AddDebug();
});

// Configure the Kernel with DI. This is required for dependency injection to work with processes.
builder.Services.AddKernel();

builder.Services.AddSingleton<DocumentGenerationService>();
// Injecting SK Process custom grpc client IExternalKernelProcessMessageChannel implementation
builder.Services.AddSingleton<IExternalKernelProcessMessageChannel, DocumentGenerationGrpcClient>();

// Configure Dapr
builder.Services.AddActors(static options =>
{
// Register the actors required to run Processes
options.AddProcessActors();
});

// Add grpc related services.
builder.Services.AddGrpc();
builder.Services.AddGrpcReflection();

var app = builder.Build();

// Grpc services mapping
app.MapGrpcReflectionService();
app.MapGrpcService<DocumentGenerationService>();

// Dapr actors related mapping
app.MapActorsHandlers();
app.Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
syntax = "proto3";

option csharp_namespace = "ProcessWithCloudEvents.Grpc.DocumentationGenerator";

service GrpcDocumentationGeneration {
rpc UserRequestFeatureDocumentation (FeatureDocumentationRequest) returns (ProcessData);
rpc RequestUserReviewDocumentationFromProcess (DocumentationContentRequest) returns (Empty);
rpc RequestUserReviewDocumentation (ProcessData) returns (stream DocumentationContentRequest);
rpc UserReviewedDocumentation (DocumentationApprovalRequest) returns (Empty);
rpc PublishDocumentation (DocumentationContentRequest) returns (Empty);
rpc ReceivePublishedDocumentation (ProcessData) returns (stream DocumentationContentRequest);
}

message FeatureDocumentationRequest {
string title = 1;
string userDescription = 2;
string content = 3;
string processId = 10;
}

message DocumentationContentRequest {
string title = 1;
string content = 2;
string assistantMessage = 3;
ProcessData processData = 10;
}

message DocumentationApprovalRequest {
bool documentationApproved = 1;
string reason = 2;
ProcessData processData = 10;
}

message ProcessData {
string processId = 1;
}

message Empty {}
Loading
Loading