Skip to content

Commit 0e9994c

Browse files
github-actions[bot]wadepickettkevinguo-edguardrexIEvangelist
authored
Merge to Live (#35025)
* SignalR with Open AI: Finish as Sample Guide (#34848) * Added article: SignalR with Open AI * Added missing images and fixed formatting issues * Added more details about managing chat history * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Will be pulling all commits into a new PR. Committing suggestions here before that transfer starts. Co-authored-by: Luke Latham <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * SignalR with Open AI: pulling to new PR * Change style to sample guide * Edit pass * Added instruction on code snippet * Update toc.yml: samples repo and AI sample under Samples * Text highlight * Removed code link * Added description for data flow diagram * Small edit on diagram intro * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md committing suggestion by IEvangelist Co-authored-by: David Pine <[email protected]> * Update aspnetcore/tutorials/ai-powered-group-chat/ai-powered-group-chat.md --------- Co-authored-by: Kevin Guo <[email protected]> Co-authored-by: Luke Latham <[email protected]> Co-authored-by: David Pine <[email protected]> * add kubernetes-ingress.md to TOC (#34996) * add kubernetes-ingress.md to TOC * Add YARP Kubernetes Ingress Controller to TOC * Fix link to Kubernetes Ingress sample * Fix invalid XML in an example (#35028) --------- Co-authored-by: Wade Pickett <[email protected]> Co-authored-by: Kevin Guo <[email protected]> Co-authored-by: Luke Latham <[email protected]> Co-authored-by: David Pine <[email protected]> Co-authored-by: Rick Anderson <[email protected]> Co-authored-by: Jan Jones <[email protected]>
1 parent d5dc31f commit 0e9994c

File tree

7 files changed

+172
-18
lines changed

7 files changed

+172
-18
lines changed

aspnetcore/fundamentals/servers/yarp/kubernetes-ingress.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: YARP Kubernetes Ingress Controller
44
description: YARP Kubernetes Ingress Controller
55
author: samsp-msft
66
ms.author: samsp
7-
ms.date: 2/6/2025
7+
ms.date: 3/6/2025
88
ms.topic: article
99
content_well_notification: AI-contribution
1010
ai-usage: ai-assisted
@@ -46,7 +46,7 @@ docker push <REGISTRY_NAME>/yarp-controller:<TAG>
4646

4747
where `REGISTRY_NAME` is the name of your docker registry and `TAG` is a tag for the image (for example 1.0.0).
4848

49-
Then the first step will be to deploy the YARP ingress controller to the Kubernetes cluster. This can be done by navigating to Kubernetes Ingress sample `\samples\KuberenetesIngress.Sample\Ingress`
49+
Then the first step will be to deploy the YARP ingress controller to the Kubernetes cluster. This can be done by navigating to [Kubernetes Ingress sample](https://github.com/dotnet/yarp/tree/release/latest/samples/KubernetesIngress.Sample) `\samples\KuberenetesIngress.Sample\Ingress`
5050
and running (after modifying `ingress-controller.yaml` with the same `REGISTRY_NAME` and `TAG`):
5151

5252
```

aspnetcore/razor-pages/ui-class.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ To include TypeScript files in an RCL:
132132
* Include the TypeScript target as a dependency of the `PrepareForBuildDependsOn` target.
133133
* Remove the output in the `wwwroot folder`.
134134

135-
[!code-xml[](~/razor-pages/ui-class/remove.xml?highlight=6-10,14)]
135+
[!code-xml[](~/razor-pages/ui-class/remove.xml?highlight=5-9,13)]
136136

137137
### Consume content from a referenced RCL
138138

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
<Project Sdk="Microsoft.NET.Sdk.Razor">
2-
<Project Sdk="Microsoft.NET.Sdk.Razor">
32

4-
<PropertyGroup>
5-
// Markup removed for brevity.
6-
<TypescriptOutDir>wwwroot</TypescriptOutDir>
7-
<PrepareForBuildDependsOn>
8-
CompileTypeScriptWithTSConfig;
9-
GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
10-
</PrepareForBuildDependsOn>
11-
</PropertyGroup>
3+
<PropertyGroup>
4+
// Markup removed for brevity.
5+
<TypescriptOutDir>wwwroot</TypescriptOutDir>
6+
<PrepareForBuildDependsOn>
7+
CompileTypeScriptWithTSConfig;
8+
GetTypeScriptOutputForPublishing;$(PrepareForBuildDependsOn)
9+
</PrepareForBuildDependsOn>
10+
</PropertyGroup>
1211

13-
<ItemGroup>
14-
<Content Remove="wwwroot\{path-to-typescript-outputs}" />
15-
</ItemGroup>
12+
<ItemGroup>
13+
<Content Remove="wwwroot\{path-to-typescript-outputs}" />
14+
</ItemGroup>
1615

17-
</Project>
16+
</Project>

aspnetcore/toc.yml

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -903,8 +903,14 @@ items:
903903
- name: SignalR with Blazor
904904
uid: blazor/tutorials/signalr-blazor
905905
- name: Samples
906-
href: https://github.com/aspnet/SignalR-samples
907906
displayName: signalr
907+
items:
908+
- name: AI-powered group chat
909+
uid: tutorials/ai-powered-group-chat
910+
displayName: signalr
911+
- name: SignalR samples repository
912+
href: https://github.com/aspnet/SignalR-samples
913+
displayName: signalr
908914
- name: Server concepts
909915
displayName: signalr
910916
items:
@@ -1297,7 +1303,10 @@ items:
12971303
uid: fundamentals/servers/yarp/httpsys-delegation
12981304
- name: Service Fabric Integration
12991305
displayName: yarp
1300-
uid: fundamentals/servers/yarp/service-fabric-int
1306+
uid: fundamentals/servers/yarp/service-fabric-int
1307+
- name: YARP Kubernetes Ingress Controller
1308+
displayName: yarp
1309+
uid: fundamentals/servers/yarp/kubernetes-ingress
13011310
- name: Troubleshooting
13021311
items:
13031312
- name: Diagnosing proxy issues
46.8 KB
Loading
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
title: Sample AI-Powered Group Chat with SignalR and OpenAI
3+
author: kevinguo-ed
4+
description: A tutorial explaining how SignalR and OpenAI are used together to build an AI-powered group chat
5+
ms.author: wpickett
6+
ms.date: 03/19/2025
7+
uid: tutorials/ai-powered-group-chat
8+
---
9+
10+
# AI-Powered Group Chat sample with SignalR and OpenAI
11+
12+
The AI-Powered Group Chat sample demonstrates how to integrate OpenAI's capabilities into a real-time group chat application using ASP.NET Core SignalR.
13+
14+
* View or download [the complete sample code](https://github.com/microsoft/SignalR-Samples-AI/tree/main/AIStreaming).
15+
16+
## Overview
17+
18+
Integrating AI into applications is becoming essential for developers aiming to enhance user creativity, productivity, and overall experience. AI-powered features, such as intelligent chatbots, personalized recommendations, and contextual responses, add significant value to modern apps. While many AI-powered applications, like those inspired by ChatGPT, focus on interactions between a single user and an AI assistant, there's growing interest in exploring AI's potential within team environments. Developers are now asking, "What value can AI add to a team of collaborators?"
19+
20+
This sample guide highlights the process of building a real-time group chat application. In this chat, a group of human collaborators can interact with an AI assistant that has access to the chat history. Any collaborator can invite the AI to assist by starting their message with `@gpt`. The finished app looks like this:
21+
22+
:::image type="content" source="./ai-powered-group-chat.jpg" alt-text="user interface for the AI-powered group chat":::
23+
24+
This sample uses OpenAI for generating intelligent, context-aware responses and SignalR for delivering the response to users in a group. You can find the complete code [in this repo](https://github.com/microsoft/SignalR-Samples-AI/tree/main/AIStreaming).
25+
26+
## Dependencies
27+
28+
Either Azure OpenAI or OpenAI can be used for this project. Make sure to update the `endpoint` and `key` in `appsettings.json`. `OpenAIExtensions` reads the configuration when the app starts, and the configuration values for `endpoint` and `key` are required to authenticate and use either service.
29+
30+
### [OpenAI](#tab/open-ai)
31+
32+
To build this application, you will need the following:
33+
* ASP.NET Core: To create the web application and host the SignalR hub.
34+
* [SignalR](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client): For real-time communication between clients and the server.
35+
* [OpenAI Client](https://www.nuget.org/packages/OpenAI): To interact with OpenAI's API for generating AI responses.
36+
37+
### [Azure OpenAI](#tab/azure-open-ai)
38+
39+
To build this application, you will need the following:
40+
* ASP.NET Core: To create the web application and host the SignalR hub.
41+
* [SignalR](https://www.nuget.org/packages/Microsoft.AspNetCore.SignalR.Client): For real-time communication between clients and the server.
42+
* [Azure OpenAI](https://www.nuget.org/packages/Azure.AI.OpenAI): `Azure.AI.OpenAI`
43+
44+
---
45+
46+
## Implementation
47+
48+
This section highlights the key parts of the code that integrate SignalR with OpenAI to create an AI-enhanced group chat experience.
49+
50+
### Data flow
51+
52+
The following diagram highlights the step-by-step communication and processing involved in using OpenAI services, employing an iterative approach to responses and data handling:
53+
54+
:::image type="content" source="./sequence-diagram-ai-powered-group-chat.png" alt-text="sequence diagram for the AI-powered group chat":::
55+
56+
In the previous diagram:
57+
58+
* The Client sends instructions to the Server, which then communicates with OpenAI to process these instructions.
59+
* OpenAI responds with partial completion data, which the Server forwards back to the Client. This process repeats multiple times for an iterative exchange of data between these components.
60+
61+
### SignalR Hub integration
62+
63+
The `GroupChatHub` class manages user connections, message broadcasting, and AI interactions.
64+
65+
When a user sends a message starting with `@gpt`:
66+
67+
* The hub forwards it to OpenAI, which generates a response.
68+
* The AI's response is streamed back to the group in real-time.
69+
70+
The following code snippet demonstrates how the `CompleteChatStreamingAsync` method streams responses from OpenAI incrementally:
71+
72+
```csharp
73+
var chatClient = _openAI.GetChatClient(_options.Model);
74+
75+
await foreach (var completion in
76+
chatClient.CompleteChatStreamingAsync(messagesInludeHistory))
77+
{
78+
// ...
79+
// Buffering and sending the AI's response in chunks
80+
await Clients.Group(groupName).SendAsync(
81+
"newMessageWithId",
82+
"ChatGPT",
83+
id,
84+
totalCompletion.ToString());
85+
// ...
86+
}
87+
```
88+
89+
In the previous code:
90+
91+
* `chatClient.CompleteChatStreamingAsync(messagesIncludeHistory)` initiates the streaming of AI responses.
92+
* The `totalCompletion.Append(content)` line accumulates the AI's response.
93+
* If the length of the buffered content exceeds 20 characters, the buffered content is sent to the clients using `Clients.Group(groupName).SendAsync`.
94+
95+
This ensures that the AI's response is delivered to the users in real-time, providing a seamless and interactive chat experience.
96+
97+
### Maintain context with history
98+
99+
Every request to [OpenAI's Chat Completions API](https://platform.openai.com/docs/guides/chat-completions) is stateless. OpenAI doesn't store past interactions. In a chat app, what a user or an assistant has said is important for generating a response that's contextually relevant. To achieve this, include chat history in every request to the Completions API.
100+
101+
The `GroupHistoryStore` class manages chat history for each group. It stores messages posted by both the users and AI assistants, ensuring that the conversation context is preserved across interactions. This context is crucial for generating coherent AI responses.
102+
103+
The following code demonstrates how to store messages generated by the AI assistant in memory. The `UpdateGroupHistoryForAssistant` method is called to add the AI assistant's message to the group history, ensuring that the conversation context is maintained:
104+
105+
```csharp
106+
public void UpdateGroupHistoryForAssistant(string groupName, string message)
107+
{
108+
var chatMessages = _store.GetOrAdd(groupName, _ => InitiateChatMessages());
109+
chatMessages.Add(new AssistantChatMessage(message));
110+
}
111+
```
112+
113+
The `_history.GetOrAddGroupHistory` method is called to add the user's message to the group history, ensuring that the conversation context is maintained:
114+
115+
```csharp
116+
_history.GetOrAddGroupHistory(groupName, userName, message);
117+
```
118+
119+
### Stream AI responses
120+
121+
The `CompleteChatStreamingAsync()` method streams responses from OpenAI incrementally, which allows the app to send partial responses to the client as they're generated.
122+
123+
The code uses a `StringBuilder` to accumulate the AI's response. It checks the length of the buffered content and sends it to the clients when it exceeds a certain threshold, for example, 20 characters. This approach ensures that users see the AI’s response as it forms, mimicking a human-like typing effect.
124+
125+
```csharp
126+
totalCompletion.Append(content);
127+
128+
if (totalCompletion.Length - lastSentTokenLength > 20)
129+
{
130+
await Clients.Group(groupName).SendAsync(
131+
"newMessageWithId",
132+
"ChatGPT",
133+
id,
134+
totalCompletion.ToString());
135+
136+
lastSentTokenLength = totalCompletion.Length;
137+
}
138+
```
139+
140+
## Explore further
141+
142+
This project opens up exciting possibilities for further enhancement:
143+
1. **Advanced AI features**: Leverage other OpenAI capabilities like sentiment analysis, translation, or summarization.
144+
1. **Incorporating multiple AI agents**: You can introduce multiple AI agents with distinct roles or expertise areas within the same chat. For example, one agent might focus on text generation while the other provides image or audio generation. This can create a richer and more dynamic user experience where different AI agents interact seamlessly with users and each other.
145+
1. **Share chat history between server instances**: Implement a database layer to persist chat history across sessions, allowing conversations to resume even after a disconnect. Beyond SQL or NO SQL based solutions, you can also explore using a caching service like Redis. It can significantly improve performance by storing frequently accessed data, such as chat history or AI responses, in memory. This reduces latency and offloads database operations, leading to faster response times, particularly in high-traffic scenarios.
146+
1. **Leveraging Azure SignalR Service**: [Azure SignalR Service](/azure/azure-signalr/signalr-overview) provides scalable and reliable real-time messaging for your application. By offloading the SignalR backplane to Azure, you can scale out the chat application easily to support thousands of concurrent users across multiple servers. Azure SignalR also simplifies management and provides built-in features like automatic reconnections.
42.2 KB
Loading

0 commit comments

Comments
 (0)