Skip to content

Commit ba78ef5

Browse files
committed
feat: add ChatHistory
1 parent 7e6e25a commit ba78ef5

File tree

2 files changed

+104
-41
lines changed

2 files changed

+104
-41
lines changed

src/Web/Components/Pages/Chat.razor

+6
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,12 @@
7676
OnClick="@(() => SubmitMessageAsync("What project is used the most by other projects?"))">What
7777
project is used the most by other projects?</MudLink>
7878
</div>
79+
<div class="ma-1">
80+
<MudLink Typo="Typo.body2"
81+
OnClick="@(() => SubmitMessageAsync("What is the longest dependencies chain of .csproj? Only .csproj are included"))">
82+
What is the longest dependencies chain of .csproj? Only .csproj are included
83+
</MudLink>
84+
</div>
7985
<div class="ma-1">
8086
<MudLink Typo="Typo.body2"
8187
OnClick="@(() => SubmitMessageAsync("Analyze the complexity of the solution. Suggest improvements if needed."))">

src/Web/Components/Pages/Chat.razor.cs

+98-41
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ namespace Web.Components.Pages;
66
using Microsoft.AspNetCore.Components;
77
using Microsoft.JSInterop;
88
using Microsoft.SemanticKernel;
9+
using Microsoft.SemanticKernel.ChatCompletion;
10+
using Microsoft.SemanticKernel.Connectors.OpenAI;
911
using MudBlazor;
1012

1113
public partial class Chat
@@ -21,33 +23,103 @@ public partial class Chat
2123

2224
private string? selectedSolution;
2325

26+
private Kernel? Kernel { get; set; }
27+
28+
private IChatCompletionService? chatCompletionService;
29+
2430
private MarkdownPipeline pipeline = new MarkdownPipelineBuilder().UseDiagrams().Build();
2531

32+
private static readonly OpenAIPromptExecutionSettings ExecutionSettings =
33+
new()
34+
{
35+
FrequencyPenalty = 0,
36+
PresencePenalty = 0,
37+
Temperature = 1.0,
38+
TopP = 0.8,
39+
};
40+
2641
protected override Task OnInitializedAsync()
2742
{
2843
this.LoadSolutions();
2944

3045
this.selectedSolution = this.SolutionRegistry.Solutions.FirstOrDefault()?.Id;
3146

47+
this.InitAssistant();
48+
3249
return Task.CompletedTask;
3350
}
3451

52+
private void InitAssistant()
53+
{
54+
if (!this.OpenAIOptions.Value.IsEnabled)
55+
{
56+
return;
57+
}
58+
this.Kernel = this.ServiceProvider.GetRequiredService<Kernel>();
59+
this.chatCompletionService = this.Kernel.Services.GetRequiredService<IChatCompletionService>();
60+
}
61+
62+
private ChatHistory CalculateChatHistory(string diagramContent)
63+
{
64+
var persona = $"""
65+
You are .NET expert (aka Dependify expert) that answers user's questions regarding project and it's dependencies.
66+
67+
Constraints:
68+
- You can only use the information from the diagram.
69+
- Instead of mentioning the diagram in your answer, use the "source"
70+
- Use the diagram as source of knowledge.
71+
- When user asks for a project or a package, find the best match use it even if it is misspelled or abbreviated. If you don't find a match, ask the user to provide more information.
72+
- When referring to a project or package, use full name of the project as it is in the diagram
73+
- Short answers are preferred
74+
- Generate answer in Markdown format
75+
- Always provide a short version mermaidjs diagram to prove your answer. The mermaid diagram is enclosed in ```mermaid ``` markdown code block.
76+
- Be concise and focus on the question.
77+
78+
- Dependencies are unidirectional, when calculating the dependency only use direct dependencies:
79+
For example:
80+
A.csproj --> B.csproj
81+
Means that:
82+
- A.csproj "uses" or "depends on" or "has a dependency on" B.csproj
83+
84+
For example:
85+
A.csproj --> PackageB
86+
Means that:
87+
- A.csproj "uses" or "depends on" or "has a dependency on" PackageB
88+
89+
---
90+
Diagram: {diagramContent}
91+
---
92+
Task: Give an answer to the user question
93+
""";
94+
var chatHistory = new ChatHistory(persona);
95+
96+
foreach (var message in this.messages)
97+
{
98+
if (message is null || string.IsNullOrWhiteSpace(message.Message))
99+
{
100+
continue;
101+
}
102+
103+
if (message.Role == ChatRole.User)
104+
{
105+
chatHistory.AddUserMessage(message.Message);
106+
}
107+
else if (message.Role == ChatRole.Assistant)
108+
{
109+
chatHistory.AddAssistantMessage(message.Message);
110+
}
111+
}
112+
113+
return chatHistory;
114+
}
115+
35116
[JSInvokable]
36117
public async Task SubmitMessageAsync(string? input)
37118
{
38119
if (!string.IsNullOrWhiteSpace(this.CurrentMessage) || !string.IsNullOrWhiteSpace(input))
39120
{
40121
var message = string.IsNullOrWhiteSpace(input) ? this.CurrentMessage : input;
41122

42-
this.messages.Add(
43-
new ChatMessage
44-
{
45-
Message = message,
46-
CreatedDate = DateTime.Now,
47-
Role = ChatRole.User
48-
}
49-
);
50-
51123
if (!this.OpenAIOptions.Value.IsEnabled)
52124
{
53125
this.PromptUserToRestartWithAISettings();
@@ -61,40 +133,24 @@ public async Task SubmitMessageAsync(string? input)
61133
return;
62134
}
63135

64-
var diagramContent = this.CalculateCurrentContext();
65-
var prompt = $"""
66-
You are .NET expert (aka Dependify expert) that will assist a user to answer his question regarding project and it's dependencies.
67-
68-
For example:
69-
A.csproj --> B.csproj
70-
71-
Means that: A.csproj "uses" or "depends on" B.csproj
136+
this.messages.Add(
137+
new ChatMessage
138+
{
139+
Message = message,
140+
CreatedDate = DateTime.Now,
141+
Role = ChatRole.User
142+
}
143+
);
72144

73-
For example:
74-
A.csproj --> PackageB
75-
76-
Means that: A.csproj "uses" or "depends on" PackageB
77-
78-
Constraints:
79-
- You can only use the information from the diagram.
80-
- Instead of mentioning the diagram in your answer, use the "source"
81-
- Use the diagram as source of knowledge.
82-
- When user asks for a project or a package, find the best match use it even if it is misspelled or abbreviated. If you don't find a match, ask the user to provide more information.
83-
- When referring to a project or package, use full name of the project as it is in the diagram
84-
- Short answers are preferred
85-
- Generate answer in Markdown format
86-
- If the question is about dependencies, provide a short version mermaidjs diagram to prove your answer. The mermaid diagram is enclosed in ```mermaid ``` markdown code block.
87-
- Be concise and focus on the question.
88-
- If you found something that could be improved - suggest it. Add "💡Tip:" followed by the suggestion.
89-
- Don't ask for more information, just answer the question.
145+
var diagramContent = this.CalculateCurrentContext();
90146

91-
Task:
92-
Give a answer to the question: "{message}"
93-
---
94-
Diagram: {diagramContent}
95-
""";
147+
var chatHistory = this.CalculateChatHistory(diagramContent);
96148

97-
var resultTask = this.ServiceProvider.GetRequiredService<Kernel>().InvokePromptAsync(prompt);
149+
var resultTask = this.chatCompletionService!.GetChatMessageContentAsync(
150+
chatHistory,
151+
ExecutionSettings,
152+
this.Kernel
153+
);
98154

99155
var delayTask = Task.Delay(TimeSpan.FromSeconds(3));
100156

@@ -117,6 +173,7 @@ You are .NET expert (aka Dependify expert) that will assist a user to answer his
117173

118174
await this.InvokeAsync(this.StateHasChanged);
119175
}
176+
120177
try
121178
{
122179
await resultTask;
@@ -173,7 +230,7 @@ private void PromptUserToRestartWithAISettings()
173230
this.messages.Add(
174231
new ChatMessage
175232
{
176-
Message = "export DEPENDIFY__AI__ENDPOINT=\"https:/<endpoint>.openai.azure.com\"",
233+
Message = "export DEPENDIFY__AI__ENDPOINT=\"https://api.openai.azure.com\"",
177234
CreatedDate = DateTime.Now,
178235
Role = ChatRole.DisplayOnly
179236
}

0 commit comments

Comments
 (0)