Skip to content

Commit d7520ee

Browse files
authored
Merge pull request #128 from weaviate/feat/generate
2 parents 825a50d + 19331a7 commit d7520ee

35 files changed

+3116
-1069
lines changed

src/Weaviate.Client.Tests/Integration/TestCollectionAggregate.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ await collectionClient.Data.Insert(
195195
);
196196

197197
var result = await collectionClient.Aggregate.OverAll(
198-
filter: filter,
198+
filters: filter,
199199
metrics: new[]
200200
{
201201
Metrics.ForProperty("text").Text(count: true, topOccurrencesValue: true),

src/Weaviate.Client.Tests/Integration/TestCollections.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public async Task Collection_Creates_And_Retrieves_Generative_Config()
127127
// Arrange
128128
var collectionClient = await CollectionFactory(
129129
properties: [Property.Text("Name")],
130-
generativeConfig: new Generative.Custom
130+
generativeConfig: new GenerativeConfig.Custom
131131
{
132132
Type = "generative-dummy",
133133
Config = new { ConfigOption = "ConfigValue" },
@@ -140,7 +140,7 @@ public async Task Collection_Creates_And_Retrieves_Generative_Config()
140140
// Assert
141141
Assert.NotNull(collection);
142142
Assert.NotNull(collection.GenerativeConfig);
143-
Assert.IsType<Generative.Custom>(collection.GenerativeConfig);
143+
Assert.IsType<GenerativeConfig.Custom>(collection.GenerativeConfig);
144144
}
145145

146146
[Fact]
@@ -562,7 +562,7 @@ await collection.Config.AddVector(
562562
public static IEnumerable<object?> GenerativeConfigData()
563563
{
564564
yield return null;
565-
yield return new Generative.AnyscaleConfig();
565+
yield return new GenerativeConfig.Anyscale();
566566
}
567567

568568
public static IEnumerable<object?> VectorizerConfigData()

src/Weaviate.Client.Tests/Integration/TestQueries.cs

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,202 @@ public async Task Test_Sorting(string propertyName)
6161
Assert.Equal(new List<string> { "Charlie", "Bob", "Alice" }, namesDesc);
6262
Assert.Equal(new List<string> { "Alice", "Bob", "Charlie" }, namesAsc);
6363
}
64+
65+
[Fact]
66+
public async Task Test_BM25_Generate_And_GroupBy_With_Everything()
67+
{
68+
// Arrange
69+
var collection = await this.CollectionFactory<object>(
70+
properties: [Property.Text("text"), Property.Text("content")],
71+
vectorConfig: new VectorConfig("default", new Vectorizer.SelfProvided()),
72+
generativeConfig: new GenerativeConfig.Custom
73+
{
74+
Type = "generative-dummy",
75+
Config = new { ConfigOption = "ConfigValue" },
76+
}
77+
);
78+
79+
var testData = new[]
80+
{
81+
new
82+
{
83+
text = "apples are big",
84+
content = "Teddy is the biggest and bigger than everything else",
85+
},
86+
new
87+
{
88+
text = "bananas are small",
89+
content = "cats are the smallest and smaller than everything else",
90+
},
91+
};
92+
93+
await collection.Data.InsertMany(BatchInsertRequest.Create<object>(testData));
94+
95+
// Act
96+
var groupBy = new GroupByRequest
97+
{
98+
PropertyName = "text",
99+
NumberOfGroups = 2,
100+
ObjectsPerGroup = 1,
101+
};
102+
103+
var res = await collection.Generate.BM25(
104+
query: "Teddy",
105+
groupBy: groupBy,
106+
searchFields: new[] { "content" },
107+
prompt: new SinglePrompt
108+
{
109+
Prompt =
110+
"Is there something to eat in {text}? Only answer yes if there is something to eat or no if not without punctuation",
111+
},
112+
groupedPrompt: new GroupedPrompt
113+
{
114+
Task =
115+
"What is the biggest and what is the smallest? Only write the names separated by a space",
116+
}
117+
);
118+
119+
// Assert
120+
Assert.NotNull(res);
121+
Assert.NotNull(res.Generative);
122+
Assert.NotEmpty(res.Generative);
123+
Assert.Contains("prompt: What is the biggest", res.Generative[0]);
124+
Assert.Single(res.Groups);
125+
var groups = res.Groups.Values.ToList();
126+
// Get the first object in the first group and check its generative result
127+
var firstGroupObject = groups[0];
128+
Assert.NotNull(firstGroupObject);
129+
Assert.NotNull(firstGroupObject.Generative);
130+
Assert.Contains(
131+
"Is there something to eat in apples are big",
132+
firstGroupObject.Generative[0]
133+
);
134+
// Get the first object in the result set and check its group
135+
var firstObject = res.Objects[0];
136+
Assert.Equal("apples are big", firstObject.BelongsToGroup);
137+
}
138+
139+
[Fact]
140+
public async Task Test_Collection_Generative_FetchObjects()
141+
{
142+
// Arrange: create collection with no vectorizer
143+
var collection = await CollectionFactory(
144+
properties: [Property.Text("text")],
145+
vectorConfig: Configure.Vectors.SelfProvided(),
146+
generativeConfig: new GenerativeConfig.Custom
147+
{
148+
Type = "generative-dummy",
149+
Config = new { ConfigOption = "ConfigValue" },
150+
}
151+
);
152+
153+
// Insert data
154+
await collection.Data.InsertMany(
155+
BatchInsertRequest.Create<object>(
156+
new[] { new { text = "John Doe" }, new { text = "Jane Doe" } }
157+
)
158+
);
159+
160+
// Act: generative fetch
161+
var res = await collection.Generate.FetchObjects(
162+
prompt: new SinglePrompt { Prompt = "Who is this? {text}" },
163+
groupedPrompt: new GroupedPrompt { Task = "Who are these people?", Properties = "text" }
164+
);
165+
166+
// Assert
167+
Assert.NotNull(res);
168+
Assert.NotNull(res.Generative);
169+
Assert.NotNull(res.Objects);
170+
Assert.Equal(2, res.Objects.Count());
171+
172+
foreach (var obj in res.Objects)
173+
{
174+
Assert.NotNull(obj.Generative);
175+
Assert.Contains(
176+
"I'm sorry, I'm just a dummy and can't generate anything.",
177+
obj.Generative.Values[0].Result
178+
);
179+
180+
// The value of the Result property can be
181+
// accessed by index of Generative,
182+
// or via Generative.Values[] indexer.
183+
// They return the same value.
184+
// The entries in the Values list contain additional properties.
185+
Assert.Same(obj.Generative.Values[0].Result, obj.Generative[0]);
186+
}
187+
}
188+
189+
public static IEnumerable<object?[]> GenerateByIdsTestData()
190+
{
191+
var uuid1 = _reusableUuids[0];
192+
var uuid2 = _reusableUuids[1];
193+
var uuid3 = _reusableUuids[2];
194+
195+
yield return new object?[] { Array.Empty<Guid>(), 0, new HashSet<Guid>() };
196+
yield return new object?[] { new Guid[] { }, 0, new HashSet<Guid>() };
197+
yield return new object?[]
198+
{
199+
new Guid[] { uuid3 },
200+
1,
201+
new HashSet<Guid> { uuid3 },
202+
};
203+
yield return new object?[]
204+
{
205+
new Guid[] { uuid1, uuid2 },
206+
2,
207+
new HashSet<Guid> { uuid1, uuid2 },
208+
};
209+
yield return new object?[]
210+
{
211+
new Guid[] { uuid1, uuid3 },
212+
2,
213+
new HashSet<Guid> { uuid1, uuid3 },
214+
};
215+
yield return new object?[]
216+
{
217+
new Guid[] { uuid1, uuid3, uuid3 },
218+
2,
219+
new HashSet<Guid> { uuid1, uuid3 },
220+
};
221+
}
222+
223+
[Theory]
224+
[MemberData(nameof(GenerateByIdsTestData))]
225+
public async Task Test_Generate_By_Ids(Guid[] ids, int expectedLen, HashSet<Guid> expected)
226+
{
227+
var collection = await CollectionFactory(
228+
vectorConfig: Configure.Vectors.SelfProvided(),
229+
properties: [Property.Text("text")],
230+
generativeConfig: new GenerativeConfig.Custom
231+
{
232+
Type = "generative-dummy",
233+
Config = new { ConfigOption = "ConfigValue" },
234+
}
235+
);
236+
237+
var result = await collection.Data.InsertMany(
238+
(new { text = "John Doe" }, id: _reusableUuids[0]),
239+
(new { text = "Jane Doe" }, id: _reusableUuids[1]),
240+
(new { text = "J. Doe" }, id: _reusableUuids[2])
241+
);
242+
243+
var res = await collection.Generate.FetchObjectsByIDs(
244+
[.. ids],
245+
prompt: new SinglePrompt { Prompt = "Who is this? {text}" },
246+
groupedPrompt: new GroupedPrompt
247+
{
248+
Task = "Who are these people?",
249+
Properties = new List<string> { "text" },
250+
}
251+
);
252+
253+
Assert.NotNull(res);
254+
Assert.NotNull(res.Generative);
255+
Assert.Equal(expectedLen, res.Objects.Count());
256+
Assert.Equal(expected, res.Objects.Select(o => o.ID!.Value).ToHashSet());
257+
foreach (var obj in res.Objects)
258+
{
259+
Assert.NotNull(obj.Generative);
260+
}
261+
}
64262
}

src/Weaviate.Client.Tests/Integration/_Integration.cs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,17 @@ public IntegrationTests()
3939
InnerHandler = new HttpClientHandler(),
4040
};
4141

42-
_weaviate = Connect.Local(httpMessageHandler: _httpMessageHandler);
42+
var builder = WeaviateClientBuilder.Local(httpMessageHandler: _httpMessageHandler);
43+
44+
if (
45+
Environment.GetEnvironmentVariable("WEAVIATE_OPENAI_API_KEY") is { } openaiKey
46+
&& !string.IsNullOrEmpty(openaiKey)
47+
)
48+
{
49+
builder.WithOpenAI(openaiKey);
50+
}
51+
52+
_weaviate = builder.Build();
4353
}
4454

4555
public async ValueTask DisposeAsync()

src/Weaviate.Client.Tests/Unit/TestCollection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ public void Collection_Equals_VectorConfig_Matches_Returns_True()
249249
}
250250

251251
[Fact]
252-
public void Collection_Rerank_Deserializes_Into_IGenerativeConfig()
252+
public void Collection_Generative_Deserializes_Into_IGenerativeConfig()
253253
{
254254
var key = "generative-dummy";
255255
var value = JsonSerializer.Deserialize<object>(
@@ -262,7 +262,7 @@ public void Collection_Rerank_Deserializes_Into_IGenerativeConfig()
262262
Assert.NotNull(config);
263263
Assert.NotNull(config!.Config);
264264
Assert.Equal("ConfigValue", config!.Config.configOption);
265-
Assert.IsType<Generative.Custom>(config);
265+
Assert.IsType<GenerativeConfig.Custom>(config);
266266
Assert.IsAssignableFrom<IGenerativeConfig>(config);
267267
}
268268

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
using System.Text.Json;
2+
using Google.Protobuf;
3+
using Google.Protobuf.WellKnownTypes;
4+
using Weaviate.Client.Models;
5+
6+
namespace Weaviate.Client.Tests.Unit;
7+
8+
public class ResultTests
9+
{
10+
[Fact]
11+
public void SearchReply_Builds_GenerativeGroupByResult_Response()
12+
{
13+
var json =
14+
@"{
15+
""took"": 11.081599,
16+
""generativeGroupedResult"": ""Teddy apples"",
17+
""groupByResults"": [
18+
{
19+
""name"": ""apples are big"",
20+
""numberOfObjects"": ""1"",
21+
""objects"": [
22+
{
23+
""properties"": {
24+
""targetCollection"": ""Test_BM25_Generate_And_GroupBy_With_Everything_a2a43f163495a0d5192c90f24b4ef015eb267eb5e056149c2e60d5c3aab85ae4_Object"",
25+
""nonRefProps"": {
26+
""fields"": {
27+
""text"": { ""textValue"": ""apples are big"" },
28+
""content"": { ""textValue"": ""Teddy is the biggest and bigger than everything else"" }
29+
}
30+
}
31+
},
32+
""metadata"": {
33+
""id"": ""02c8d66d-d314-4b9c-ab2e-4d5daa9e55ae"",
34+
""idAsBytes"": ""AsjWbdMUS5yrLk1dqp5Vrg==""
35+
}
36+
}
37+
],
38+
""generative"": { ""result"": ""yes"" }
39+
}
40+
]
41+
}";
42+
43+
JsonParser jsonParser = new JsonParser(
44+
JsonParser.Settings.Default.WithIgnoreUnknownFields(true)
45+
);
46+
V1.SearchReply reply = jsonParser.Parse<V1.SearchReply>(json);
47+
48+
Assert.NotNull(reply);
49+
50+
GenerativeGroupByResult res = reply;
51+
52+
Assert.Contains("Teddy apples", res.Generative[0]);
53+
Assert.Single(res.Groups);
54+
var groups = res.Groups.Values.ToList();
55+
// Get the first object in the first group and check its generative result
56+
var firstGroupObject = groups[0];
57+
Assert.NotNull(firstGroupObject);
58+
Assert.NotNull(firstGroupObject.Generative);
59+
Assert.Equal("yes", firstGroupObject.Generative[0]);
60+
// Get the first object in the result set and check its group
61+
var firstObject = res.Objects[0];
62+
Assert.Equal("apples are big", firstObject.BelongsToGroup);
63+
}
64+
}

0 commit comments

Comments
 (0)