Skip to content

Commit 8c244f3

Browse files
committed
generate follow up items in bit Boilerplate AI Chatbot (#11362)
1 parent cab38b1 commit 8c244f3

File tree

6 files changed

+66
-20
lines changed

6 files changed

+66
-20
lines changed

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/AppAiChatPanel.razor

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@
3939
<Body>
4040
<BitStack Class="body">
4141
<BitScrollablePane FullSize
42-
AutoScroll
4342
Class="scr-container"
44-
ScrollbarWidth="BitScrollbarWidth.Thin">
43+
ScrollbarWidth="BitScrollbarWidth.Thin"
44+
AutoScroll="@string.IsNullOrEmpty(userInput)">
4545
<BitStack>
4646
@foreach (var message in chatMessages)
4747
{
@@ -99,6 +99,24 @@
9999
</BitStack>
100100
}
101101

102+
@if (followUpSuggestions.Any())
103+
{
104+
<BitStack Alignment=" BitAlignment.Center" FitHeight FillContent Class="default-prompt-container">
105+
106+
@foreach (var suggestion in followUpSuggestions)
107+
{
108+
<BitButton FixedColor
109+
Variant="BitVariant.Outline"
110+
Class="default-prompt-button"
111+
Color="BitColor.SecondaryBackground"
112+
OnClick="() => SendPromptMessage(suggestion)">
113+
@suggestion
114+
</BitButton>
115+
}
116+
117+
</BitStack>
118+
}
119+
102120
<BitStack FitHeight Style="position:relative">
103121
<BitTextField Rows="1"
104122
Immediate

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Components/Layout/AppAiChatPanel.razor.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public partial class AppAiChatPanel
2424
private Channel<string>? channel;
2525
private AiChatMessage? lastAssistantMessage;
2626
private List<AiChatMessage> chatMessages = []; // TODO: Persist these values in client-side storage to retain them across app restarts.
27+
private List<string> followUpSuggestions = [];
2728
//#if(module == "Sales")
2829
private Action unsubSearchProducts = default!;
2930
//#endif
@@ -92,7 +93,9 @@ private async Task HubConnection_Reconnected(string? _)
9293

9394
private async Task SendPromptMessage(string message)
9495
{
96+
followUpSuggestions = [];
9597
userInput = message;
98+
StateHasChanged();
9699
await SendMessage();
97100
}
98101

@@ -128,6 +131,7 @@ private void SetDefaultValues()
128131
{
129132
isLoading = false;
130133
responseCounter = 0;
134+
followUpSuggestions = [];
131135
lastAssistantMessage = new() { Role = AiChatMessageRole.Assistant };
132136
chatMessages = [
133137
new()
@@ -167,25 +171,32 @@ private async Task StartChannel()
167171
{
168172
int expectedResponsesCount = chatMessages.Count(c => c.Role is AiChatMessageRole.User);
169173

170-
if (response is SharedChatProcessMessages.MESSAGE_RPOCESS_SUCESS)
174+
if (response.Contains(nameof(AiChatFollowUpList.FollowUpSuggestions)))
171175
{
172-
responseCounter++;
173-
isLoading = false;
176+
followUpSuggestions = JsonSerializer.Deserialize<AiChatFollowUpList>(response)?.FollowUpSuggestions ?? [];
174177
}
175-
else if (response is SharedChatProcessMessages.MESSAGE_RPOCESS_ERROR)
178+
else
176179
{
177-
responseCounter++;
178-
if (responseCounter == expectedResponsesCount)
180+
if (response is SharedChatProcessMessages.MESSAGE_RPOCESS_SUCESS)
179181
{
180-
isLoading = false; // Hide loading only if this is an error for the last user's message.
182+
responseCounter++;
183+
isLoading = false;
181184
}
182-
chatMessages[responseCounter * 2].Successful = false;
183-
}
184-
else
185-
{
186-
if ((responseCounter + 1) == expectedResponsesCount)
185+
else if (response is SharedChatProcessMessages.MESSAGE_RPOCESS_ERROR)
186+
{
187+
responseCounter++;
188+
if (responseCounter == expectedResponsesCount)
189+
{
190+
isLoading = false; // Hide loading only if this is an error for the last user's message.
191+
}
192+
chatMessages[responseCounter * 2].Successful = false;
193+
}
194+
else
187195
{
188-
lastAssistantMessage!.Content += response;
196+
if ((responseCounter + 1) == expectedResponsesCount)
197+
{
198+
lastAssistantMessage!.Content += response;
199+
}
189200
}
190201
}
191202

src/Templates/Boilerplate/Bit.Boilerplate/src/Client/Boilerplate.Client.Core/Services/HttpMessageHandlers/ExceptionDelegatingHandler.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
2727
if (response.Headers.TryGetValues("Request-Id", out var requestId))
2828
{
2929
requestIdValue = requestId.First();
30+
logScopeData["RequestId"] = requestIdValue;
3031
}
3132

3233
serverCommunicationSuccess = true;

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/Data/Configurations/Chatbot/SystemPromptConfiguration.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ These are the primary functional areas of the application beyond account managem
134134
* **How to Use:**
135135
- Navigate to the [Upgrade account page](/settings/upgradeaccount).
136136
" +
137-
//#endif
137+
//#endif
138138
@"## 4. Informational Pages
139139
140140
### 4.1. About Page
@@ -197,13 +197,13 @@ These are the primary functional areas of the application beyond account managem
197197
//#endif
198198
//#if (ads == true)
199199
@"### Handling advertisement trouble requests:
200-
**[[[ADS_TROUBLE_RULES_BEGIN]]]**""
200+
**[[[ADS_TROUBLE_RULES_BEGIN]]]""
201201
* **If a user asks about having trouble watching ad (e.g., ""ad not showing"", ""ad is blocked"", ""upgrade is not happening"") :**
202202
1. *Act as a technical support.*
203203
2. **Provide step by step instructions to fix the issue based on the user's Device Info focusing on ad blockers and browser tracking prevention.
204204
**[[[ADS_TROUBLE_RULES_END]]]**
205205
" +
206-
//#endif
206+
//#endif
207207
@"- ### User Feedback and Suggestions:
208208
- If a user provides feedback or suggests a feature, respond: ""Thank you for your feedback! It's valuable to us, and I'll pass it on to the product team."" If the feedback is unclear, ask for clarification: ""Could you please provide more details about your suggestion?""
209209

src/Templates/Boilerplate/Bit.Boilerplate/src/Server/Boilerplate.Server.Api/SignalR/AppHub.Chatbot.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ async Task HandleIncomingMessage(string incomingMessage, CancellationToken messa
8888
ChatOptions chatOptions = new()
8989
{
9090
Tools = [
91-
AIFunctionFactory.Create(async (string emailAddress, string conversationHistory) =>
91+
AIFunctionFactory.Create(async ([Required] string emailAddress, string conversationHistory) =>
9292
{
9393
if (messageSpecificCancellationToken.IsCancellationRequested)
9494
return;
@@ -102,7 +102,7 @@ async Task HandleIncomingMessage(string incomingMessage, CancellationToken messa
102102

103103
}, name: "SaveUserEmailAndConversationHistory", description: "Saves the user's email address and the conversation history for future reference. Use this tool when the user provides their email address during the conversation. Parameters: emailAddress (string), conversationHistory (string)"),
104104
//#if (module == "Sales")
105-
AIFunctionFactory.Create(async ([Description("Concise summary of these user requirements")] string userNeeds,
105+
AIFunctionFactory.Create(async ([Required, Description("Concise summary of these user requirements")] string userNeeds,
106106
[Description("Car manufacturer's name (Optional)")] string? manufacturer,
107107
[Description("Car price below this value (Optional)")] decimal? maxPrice,
108108
[Description("Car price above this value (Optional)")] decimal? minPrice) =>
@@ -154,6 +154,17 @@ async Task HandleIncomingMessage(string incomingMessage, CancellationToken messa
154154
}
155155

156156
await channel.Writer.WriteAsync(SharedChatProcessMessages.MESSAGE_RPOCESS_SUCESS, cancellationToken);
157+
158+
chatOptions.ResponseFormat = ChatResponseFormat.Json;
159+
chatOptions.AdditionalProperties = new() { ["response_format"] = new { type = "json_object" } };
160+
var followUpItems = await chatClient.GetResponseAsync<AiChatFollowUpList>([
161+
new(ChatRole.System, supportSystemPrompt),
162+
new(ChatRole.User, incomingMessage),
163+
new(ChatRole.Assistant, assistantResponse.ToString()),
164+
new(ChatRole.System, @"Return up to 3 relevant follow-up suggestions that help users discover related topics and continue the conversation naturally in JSON object containing string[] named FollowUpSuggestions."),],
165+
chatOptions, cancellationToken: messageSpecificCancellationToken);
166+
167+
await channel.Writer.WriteAsync(JsonSerializer.Serialize(followUpItems.Result), messageSpecificCancellationToken);
157168
}
158169
catch (Exception exp)
159170
{

src/Templates/Boilerplate/Bit.Boilerplate/src/Shared/Dtos/Chatbot/StartChatbotRequest.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,8 @@ public class AiChatMessage
3030
[JsonIgnore]
3131
public bool Successful { get; set; } = true;
3232
}
33+
34+
public class AiChatFollowUpList
35+
{
36+
public List<string> FollowUpSuggestions { get; set; } = [];
37+
}

0 commit comments

Comments
 (0)