Skip to content

Commit 0c2e1c9

Browse files
authored
KnowPro.NET updates (#1761)
* Entity merging * For distinct operator etc. * For answer generation * Updated test app
1 parent 53f27c6 commit 0c2e1c9

File tree

12 files changed

+485
-74
lines changed

12 files changed

+485
-74
lines changed

dotnet/typeagent/examples/examplesLib/KnowProWriter.cs

Lines changed: 144 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Microsoft Corporation.
22
// Licensed under the MIT License.
33

4+
using System.Threading.Tasks;
45
using TypeAgent.ExamplesLib.CommandLine;
56

67
namespace TypeAgent.ExamplesLib;
@@ -35,16 +36,16 @@ public static async Task WriteSemanticRefsAsync(IConversation conversation)
3536
}
3637
}
3738

38-
public static async Task WriteMessagesAsync(IConversation conversation)
39-
{
40-
await foreach (var message in conversation.Messages)
39+
public static async Task WriteMessagesAsync(IConversation conversation)
4140
{
42-
WriteMessage(message);
43-
WriteLine();
41+
await foreach (var message in conversation.Messages)
42+
{
43+
WriteMessage(message);
44+
WriteLine();
45+
}
4446
}
45-
}
4647

47-
public static void WriteMessage(IMessage message)
48+
public static void WriteMessage(IMessage message)
4849
{
4950
PushColor(ConsoleColor.Cyan);
5051
WriteNameValue("Timestamp", message.Timestamp);
@@ -71,7 +72,7 @@ public static void WriteMetadata(IMessage message)
7172
}
7273
}
7374

74-
public static void WriteEntity(ConcreteEntity? entity)
75+
public static void WriteEntity(ConcreteEntity? entity)
7576
{
7677
if (entity is not null)
7778
{
@@ -85,10 +86,36 @@ public static void WriteEntity(ConcreteEntity? entity)
8586
}
8687
}
8788

89+
public static void WriteAction(TypeAgent.KnowPro.Action? action)
90+
{
91+
if (action is not null)
92+
{
93+
WriteLine(action.ToString());
94+
}
95+
}
96+
97+
public static void WriteTopic(Topic? topic)
98+
{
99+
if (topic is not null)
100+
{
101+
WriteLine(topic.Text);
102+
}
103+
}
104+
105+
public static void WriteTag(Tag tag)
106+
{
107+
if (tag is not null)
108+
{
109+
WriteLine(tag.Text);
110+
}
111+
}
112+
88113
public static async Task WriteConversationSearchResultsAsync(
89-
IConversation conversation,
90-
ConversationSearchResult? searchResult,
91-
bool verbose = false
114+
IConversation conversation,
115+
ConversationSearchResult? searchResult,
116+
bool showKnowledge,
117+
bool showMessages,
118+
bool verbose = false
92119
)
93120
{
94121
if (searchResult is null)
@@ -118,7 +145,7 @@ public static async Task WriteConversationSearchResultsAsync(
118145
if (!searchResult.KnowledgeMatches.IsNullOrEmpty())
119146
{
120147
WriteLineHeading("Knowledge");
121-
WriteKnowledgeSearchResults(conversation, searchResult.KnowledgeMatches);
148+
await WriteKnowledgeSearchResultsAsync(conversation, searchResult.KnowledgeMatches);
122149
}
123150
}
124151

@@ -131,9 +158,11 @@ IList<ScoredMessageOrdinal> messageOrdinals
131158
WriteJson(messageOrdinals);
132159
}
133160

134-
public static void WriteKnowledgeSearchResults(
161+
public static async Task WriteKnowledgeSearchResultsAsync(
135162
IConversation conversation,
136-
IDictionary<KnowledgeType, SemanticRefSearchResult>? results
163+
IDictionary<KnowledgeType, SemanticRefSearchResult>? results,
164+
int? maxToDisplay = null,
165+
bool isAsc = false
137166
)
138167
{
139168
if (results.IsNullOrEmpty())
@@ -144,15 +173,17 @@ public static void WriteKnowledgeSearchResults(
144173

145174
foreach (var kv in results!)
146175
{
147-
WriteKnowledgeSearchResult(conversation, kv.Key, kv.Value);
176+
await WriteKnowledgeSearchResultAsync(conversation, kv.Key, kv.Value, maxToDisplay, isAsc);
148177
WriteLine();
149178
}
150179
}
151180

152-
public static void WriteKnowledgeSearchResult(
181+
public static async Task WriteKnowledgeSearchResultAsync(
153182
IConversation conversation,
154183
KnowledgeType kType,
155-
SemanticRefSearchResult result
184+
SemanticRefSearchResult result,
185+
int? maxToDisplay = null,
186+
bool isAsc = true
156187
)
157188
{
158189
WriteLineUnderline(kType.ToString().ToUpper());
@@ -162,7 +193,102 @@ SemanticRefSearchResult result
162193
ListType.Ol)
163194
);
164195
WriteLine($"{result.SemanticRefMatches.Count} matches");
165-
WriteJson(result.SemanticRefMatches);
196+
197+
await WriteScoredSemanticRefsAsync(
198+
result.SemanticRefMatches,
199+
conversation.SemanticRefs,
200+
kType,
201+
maxToDisplay is not null ? maxToDisplay.Value : result.SemanticRefMatches.Count,
202+
isAsc
203+
);
204+
}
205+
206+
public static void WriteSemanticRef(SemanticRef sr)
207+
{
208+
switch (sr.KnowledgeType)
209+
{
210+
default:
211+
break;
212+
213+
case KnowledgeType.EntityTypeName:
214+
case KnowledgeType.STagTypeName:
215+
WriteEntity(sr.AsEntity());
216+
break;
217+
218+
case KnowledgeType.ActionTypeName:
219+
WriteAction(sr.AsAction());
220+
break;
221+
222+
case KnowledgeType.TopicTypeName:
223+
WriteTopic(sr.AsTopic());
224+
break;
225+
226+
case KnowledgeType.TagTypeName:
227+
WriteTag(sr.AsTag());
228+
break;
229+
}
230+
}
231+
232+
public static async Task WriteScoredSemanticRefsAsync(
233+
IList<ScoredSemanticRefOrdinal> semanticRefMatches,
234+
ISemanticRefCollection semanticRefCollection,
235+
KnowledgeType kType,
236+
int maxToDisplay,
237+
bool isAsc = true
238+
)
239+
{
240+
if (isAsc)
241+
{
242+
WriteLine("Sorted in ascending order(lowest first)");
243+
}
244+
245+
var matchesToDisplay = semanticRefMatches.Slice(0, maxToDisplay);
246+
WriteLine($"Displaying {matchesToDisplay.Count} matches of total {semanticRefMatches.Count}");
247+
248+
if (kType == KnowledgeType.Entity)
249+
{
250+
IList<Scored<ConcreteEntity>> entities = await semanticRefCollection.GetDistinctEntitiesAsync(matchesToDisplay);
251+
for (int i = 0; i < entities.Count; ++i)
252+
{
253+
var pos = isAsc ? matchesToDisplay.Count - (i + 1) : i;
254+
WriteLine(
255+
ConsoleColor.Green,
256+
$"{pos + 1} / {matchesToDisplay.Count}: [{entities[i].Score}]"
257+
);
258+
WriteEntity(entities[i]);
259+
WriteLine();
260+
}
261+
}
262+
else
263+
{
264+
IList<SemanticRef> semanticRefs = await semanticRefCollection.GetAsync(matchesToDisplay);
265+
for (int i = 0; i < matchesToDisplay.Count; ++i)
266+
{
267+
var pos = isAsc ? matchesToDisplay.Count - (i + 1) : i;
268+
WriteScoredRef(
269+
pos,
270+
matchesToDisplay.Count,
271+
matchesToDisplay[pos],
272+
semanticRefs[pos]
273+
);
274+
}
275+
}
276+
277+
}
278+
279+
public static void WriteScoredRef(
280+
int matchNumber,
281+
int totalMatches,
282+
ScoredSemanticRefOrdinal scoredRef,
283+
SemanticRef semanticRef
284+
)
285+
{
286+
WriteLine(
287+
ConsoleColor.Green,
288+
$"#{matchNumber + 1} / {totalMatches}: <{scoredRef.SemanticRefOrdinal}::{semanticRef.Range.Start.MessageOrdinal}> {semanticRef.KnowledgeType} [{scoredRef.Score}]"
289+
);
290+
WriteSemanticRef(semanticRef);
291+
WriteLine();
166292
}
167293

168294
public static void WriteDataFileStats<TMessage>(ConversationData<TMessage> data)

dotnet/typeagent/examples/knowProConsole/MemoryCommands.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,12 @@ private async Task SearchRagAsync(ParseResult args, CancellationToken cancellati
154154
namedArgs.Get<int>("budget"),
155155
cancellationToken
156156
);
157-
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, matches, true);
157+
await KnowProWriter.WriteConversationSearchResultsAsync(
158+
conversation,
159+
matches,
160+
true,
161+
true
162+
);
158163
}
159164

160165
private IConversation EnsureConversation()

dotnet/typeagent/examples/knowProConsole/TestCommands.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,12 @@ private async Task SearchMessagesAsync(ParseResult result, CancellationToken can
124124
null,
125125
cancellationToken
126126
);
127-
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, searchResults);
127+
await KnowProWriter.WriteConversationSearchResultsAsync(
128+
conversation,
129+
searchResults,
130+
true,
131+
true
132+
);
128133

129134
DateRange? conversationDateRange = await conversation.GetDateRangeAsync();
130135
if (conversationDateRange is not null)
@@ -148,7 +153,7 @@ private async Task SearchMessagesAsync(ParseResult result, CancellationToken can
148153
},
149154
cancellationToken
150155
);
151-
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, searchResults, true);
156+
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, searchResults, true, true);
152157
}
153158

154159
private Command TestEmbeddingsDef()
@@ -280,7 +285,7 @@ async Task TestSearchKnowledgeAsync(IConversation conversation, SearchTermGroup
280285
cancellationToken
281286
).ConfigureAwait(false);
282287

283-
KnowProWriter.WriteKnowledgeSearchResults(_kpContext.Conversation!, results);
288+
await KnowProWriter.WriteKnowledgeSearchResultsAsync(_kpContext.Conversation!, results);
284289
}
285290

286291
private Command SearchQueryTermsDef()
@@ -334,9 +339,14 @@ private async Task SearchLangAsync(ParseResult args, CancellationToken cancellat
334339
if (conversation is IMemory memory)
335340
{
336341
IList<ConversationSearchResult> results = await memory.SearchAsync(query, null, null, null, cancellationToken);
337-
foreach(var result in results)
342+
foreach (var result in results)
338343
{
339-
await KnowProWriter.WriteConversationSearchResultsAsync(conversation, result);
344+
await KnowProWriter.WriteConversationSearchResultsAsync(
345+
conversation,
346+
result,
347+
true,
348+
false
349+
);
340350
}
341351
}
342352
}

dotnet/typeagent/src/common/EnumerationExtensions.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,4 +78,13 @@ public static IEnumerable<List<T>> Batch<T>(this IEnumerable<T> items, int batch
7878
yield return batch;
7979
}
8080
}
81+
82+
public static List<Scored<T>> GetTopK<T>(this IEnumerable<Scored<T>> items, int topk)
83+
{
84+
ArgumentVerify.ThrowIfNull(items, nameof(items));
85+
86+
var topNList = new TopNCollection<T>(topk);
87+
topNList.Add(items);
88+
return topNList.ByRankAndClear();
89+
}
8190
}

dotnet/typeagent/src/common/ListExtensions.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -140,13 +140,6 @@ public static int BinarySearchFirst<T, TSearchValue>(
140140
return lo;
141141
}
142142

143-
public static List<Scored<T>> GetTopK<T>(this IEnumerable<Scored<T>> list, int topK)
144-
{
145-
var topNList = new TopNCollection<T>(topK);
146-
topNList.Add(list);
147-
return topNList.ByRankAndClear();
148-
}
149-
150143
public static void Fill<T>(this IList<T> list, T value, int count)
151144
{
152145
for (int i = 0; i < count; ++i)

dotnet/typeagent/src/common/Multiset.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,23 @@ public void Add(IEnumerable<KeyValuePair<TKey, TValue>> keyValues)
7373
}
7474
}
7575

76+
public void AddUnique(TKey key, TValue value)
77+
{
78+
List<TValue>? values = Get(key);
79+
if (values is null)
80+
{
81+
Add(key, value);
82+
}
83+
else
84+
{
85+
int pos = values.IndexOf(value);
86+
if (pos < 0)
87+
{
88+
Add(key, value);
89+
}
90+
}
91+
}
92+
7693
public void Remove(TKey key, TValue value)
7794
{
7895
if (TryGetValue(key, out var valueList))

dotnet/typeagent/src/common/StringExtensions.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,16 @@ int maxCharsPerChunk
4747
yield return chunk;
4848
}
4949
}
50+
51+
public static List<string> LowerAndSort(this List<string> list)
52+
{
53+
int count = list.Count;
54+
for (int i = 0; i < count; ++i)
55+
{
56+
list[i] = list[i].ToLower();
57+
}
58+
list.Sort();
59+
return list;
60+
}
61+
5062
}

0 commit comments

Comments
 (0)