- 
                Notifications
    You must be signed in to change notification settings 
- Fork 70
Implement embedders, vector search and similar documents #638
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 4 commits
68ba575
              4f8d55b
              bac47c4
              fc8e4c7
              0247ac1
              e1ba052
              3e97224
              256de5f
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| MEILISEARCH_VERSION=v1.9.0 | ||
| MEILISEARCH_VERSION=v1.13 | ||
| PROXIED_MEILISEARCH=http://nginx/api/ | ||
| MEILISEARCH_URL=http://meilisearch:7700 | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| using System; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Serialization; | ||
|  | ||
| namespace Meilisearch.Converters | ||
| { | ||
| internal class EmbedderSourceConverter : JsonConverter<EmbedderSource> | ||
| { | ||
| public override EmbedderSource Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) | ||
| { | ||
| if (reader.TokenType == JsonTokenType.String) | ||
| { | ||
| var enumValue = reader.GetString(); | ||
| if (Enum.TryParse<EmbedderSource>(enumValue, true, out var embedderSource)) | ||
| { | ||
| return embedderSource; | ||
| } | ||
| } | ||
|  | ||
| return EmbedderSource.Unknown; | ||
| } | ||
|  | ||
| public override void Write(Utf8JsonWriter writer, EmbedderSource value, JsonSerializerOptions options) | ||
| { | ||
| string source; | ||
| switch (value) | ||
| { | ||
| case EmbedderSource.OpenAi: | ||
| source = "openAi"; | ||
| break; | ||
| case EmbedderSource.HuggingFace: | ||
| source = "huggingFace"; | ||
| break; | ||
| case EmbedderSource.Ollama: | ||
| source = "ollama"; | ||
| break; | ||
| case EmbedderSource.Rest: | ||
| source = "rest"; | ||
| break; | ||
| case EmbedderSource.UserProvided: | ||
| source = "userProvided"; | ||
| break; | ||
| case EmbedderSource.Unknown: | ||
| default: | ||
| throw new ArgumentOutOfRangeException(nameof(value), value, null); | ||
| } | ||
|         
                  coderabbitai[bot] marked this conversation as resolved.
              Outdated
          
            Show resolved
            Hide resolved | ||
|  | ||
| writer.WriteStringValue(source); | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,84 @@ | ||||||||||||||||
| using System; | ||||||||||||||||
| using System.Collections.Generic; | ||||||||||||||||
| using System.Text.Json.Serialization; | ||||||||||||||||
|  | ||||||||||||||||
| namespace Meilisearch | ||||||||||||||||
| { | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Embedder configuration. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| public class Embedder | ||||||||||||||||
| { | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the source. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("source")] | ||||||||||||||||
| public EmbedderSource Source { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the URL. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("url")] | ||||||||||||||||
| public string Url { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the API key. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("apiKey")] | ||||||||||||||||
| public string ApiKey { get; set; } | ||||||||||||||||
| 
      Comment on lines
    
      +26
     to 
      +27
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainConsider security implications for ApiKey property The ApiKey property likely contains sensitive information. Consider: 
 Also, consider adding documentation to warn users about the sensitivity of this property. 🏁 Script executed: #!/bin/bash
# Check for any existing security measures for API keys in the codebase
grep -r --include="*.cs" "ApiKey" --include="*.cs" "api key" src/Length of output: 1890 Secure handling of Embedder.ApiKey Ensure the  
 Example diff: --- a/src/Meilisearch/Embedder.cs
+++ b/src/Meilisearch/Embedder.cs
@@ -25,8 +25,11 @@ namespace Meilisearch
-        [JsonPropertyName("apiKey")]
-        public string ApiKey { get; set; }
+        /// <summary>
+        /// API key for authentication (Sensitive: excluded from JSON; only sent via HTTP header).
+        /// </summary>
+        [JsonIgnore]
+        public string ApiKey { get; internal set; }📝 Committable suggestion
 
        Suggested change
       
 | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the model. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("model")] | ||||||||||||||||
| public string Model { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the document template. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("documentTemplate")] | ||||||||||||||||
| public string DocumentTemplate { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the document template max bytes. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("documentTemplateMaxBytes")] | ||||||||||||||||
| public int? DocumentTemplateMaxBytes { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the dimensions. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("dimensions")] | ||||||||||||||||
| public int? Dimensions { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the revision. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("revision")] | ||||||||||||||||
| public string Revision { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the distribution. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("distribution")] | ||||||||||||||||
| public EmbedderDistribution Distribution { get; set; } | ||||||||||||||||
|         
                  philipproplesch marked this conversation as resolved.
              Show resolved
            Hide resolved | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the request. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("request")] | ||||||||||||||||
| public Dictionary<string, object> Request { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets the response. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("response")] | ||||||||||||||||
| public Dictionary<string, object> Response { get; set; } | ||||||||||||||||
|  | ||||||||||||||||
| /// <summary> | ||||||||||||||||
| /// Gets or sets whether the vectors should be compressed. | ||||||||||||||||
| /// </summary> | ||||||||||||||||
| [JsonPropertyName("binaryQuantized")] | ||||||||||||||||
| public bool? BinaryQuantized { get; set; } | ||||||||||||||||
| } | ||||||||||||||||
| } | ||||||||||||||||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| using System; | ||
| using System.Text.Json.Serialization; | ||
|  | ||
| namespace Meilisearch | ||
| { | ||
| /// <summary> | ||
| /// Embedder distribution. | ||
| /// </summary> | ||
| public class EmbedderDistribution | ||
| { | ||
| /// <summary> | ||
| /// Creates a new instance of <see cref="EmbedderDistribution"/>. | ||
| /// </summary> | ||
| /// <param name="mean">Mean value between 0 and 1.</param> | ||
| /// <param name="sigma">Sigma value between 0 and 1.</param> | ||
| /// <exception cref="ArgumentOutOfRangeException"></exception> | ||
| public EmbedderDistribution(double mean, double sigma) | ||
| { | ||
| if (mean < 0 || mean > 1) | ||
| { | ||
| throw new ArgumentOutOfRangeException(nameof(mean), "Mean must be between 0 and 1."); | ||
| } | ||
|  | ||
| if (sigma < 0 || sigma > 1) | ||
| { | ||
| throw new ArgumentOutOfRangeException(nameof(sigma), "Sigma must be between 0 and 1."); | ||
| } | ||
| } | ||
|         
                  coderabbitai[bot] marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
|  | ||
| /// <summary> | ||
| /// Gets or sets the mean. | ||
| /// </summary> | ||
| [JsonPropertyName("mean")] | ||
| public double Mean { get; set; } | ||
|  | ||
| /// <summary> | ||
| /// Gets or sets the sigma. | ||
| /// </summary> | ||
| [JsonPropertyName("sigma")] | ||
| public double Sigma { get; set; } | ||
|  | ||
| /// <summary> | ||
| /// Creates a new instance of <see cref="EmbedderDistribution"/> with a uniform distribution. | ||
| /// </summary> | ||
| /// <returns></returns> | ||
| public static EmbedderDistribution Uniform() => new EmbedderDistribution(0.5, 0.5); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| using System.Text.Json.Serialization; | ||
|  | ||
| using Meilisearch.Converters; | ||
|  | ||
| namespace Meilisearch | ||
| { | ||
| /// <summary> | ||
| /// Embedder source. | ||
| /// </summary> | ||
| [JsonConverter(typeof(EmbedderSourceConverter))] | ||
| public enum EmbedderSource | ||
| { | ||
| /// <summary> | ||
| /// OpenAI | ||
| /// </summary> | ||
| OpenAi, | ||
|  | ||
| /// <summary> | ||
| /// Hugging Face | ||
| /// </summary> | ||
| HuggingFace, | ||
|  | ||
| /// <summary> | ||
| /// Ollama | ||
| /// </summary> | ||
| Ollama, | ||
|  | ||
| /// <summary> | ||
| /// REST | ||
| /// </summary> | ||
| Rest, | ||
|  | ||
| /// <summary> | ||
| /// User-provided | ||
| /// </summary> | ||
| UserProvided, | ||
|  | ||
| /// <summary> | ||
| /// Unknown | ||
| /// </summary> | ||
| Unknown | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| using System.Text.Json.Serialization; | ||
|  | ||
| namespace Meilisearch | ||
| { | ||
| public class HybridSearch | ||
| { | ||
| /// <summary> | ||
| /// Gets or sets the embedder. | ||
| /// </summary> | ||
| [JsonPropertyName("embedder")] | ||
| public string Embedder { get; set; } | ||
|  | ||
| /// <summary> | ||
| /// Gets or sets the semantic ratio. | ||
| /// </summary> | ||
| [JsonPropertyName("semanticRatio")] | ||
| public double SemanticRatio { get; set; } | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,63 @@ | ||
| using System.Collections.Generic; | ||
| using System.Net.Http.Json; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|  | ||
| using Meilisearch.Extensions; | ||
|  | ||
| namespace Meilisearch | ||
| { | ||
| public partial class Index | ||
| { | ||
| /// <summary> | ||
| /// Gets the embedders setting. | ||
| /// </summary> | ||
| /// <param name="cancellationToken">The cancellation token for this call.</param> | ||
| /// <returns>Returns the embedders setting.</returns> | ||
| public async Task<Dictionary<string, Embedder>> GetEmbeddersAsync(CancellationToken cancellationToken = default) | ||
| { | ||
| return await _http | ||
| .GetFromJsonAsync<Dictionary<string, Embedder>>( | ||
| $"indexes/{Uid}/settings/embedders", | ||
| cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
| } | ||
|  | ||
| /// <summary> | ||
| /// Updates the embedders setting. | ||
| /// </summary> | ||
| /// <param name="embedders">Collection of embedders.</param> | ||
| /// <param name="cancellationToken">The cancellation token for this call.</param> | ||
| /// <returns>Returns the task info of the asynchronous task.</returns> | ||
| public async Task<TaskInfo> UpdateEmbeddersAsync(Dictionary<string, Embedder> embedders, CancellationToken cancellationToken = default) | ||
| { | ||
| var responseMessage = | ||
| await _http.PatchAsJsonAsync( | ||
| $"indexes/{Uid}/settings/embedders", | ||
| embedders, | ||
| Constants.JsonSerializerOptionsRemoveNulls, | ||
| cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
|  | ||
| return await responseMessage.Content | ||
| .ReadFromJsonAsync<TaskInfo>(cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
| } | ||
|  | ||
| /// <summary> | ||
| /// Resets the embedders setting. | ||
| /// </summary> | ||
| /// <param name="cancellationToken">The cancellation token for this call.</param> | ||
| /// <returns>Returns the task info of the asynchronous task.</returns> | ||
| public async Task<TaskInfo> ResetEmbeddersAsync(CancellationToken cancellationToken = default) | ||
| { | ||
| var response = await _http | ||
| .DeleteAsync($"indexes/{Uid}/settings/embedders", cancellationToken) | ||
| .ConfigureAwait(false); | ||
|  | ||
| return await response.Content | ||
| .ReadFromJsonAsync<TaskInfo>(cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
| } | ||
| } | ||
| } | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| using System.Net.Http.Json; | ||
| using System.Threading; | ||
| using System.Threading.Tasks; | ||
|  | ||
| namespace Meilisearch | ||
| { | ||
| public partial class Index | ||
| { | ||
| /// <summary> | ||
| /// Search for similar documents. | ||
| /// </summary> | ||
| /// <param name="query">The query to search for similar documents.</param> | ||
| /// <param name="cancellationToken">The cancellation token for this call.</param> | ||
| /// <typeparam name="T">The type of the documents to return.</typeparam> | ||
| /// <returns>Returns the similar documents.</returns> | ||
| public async Task<SimilarDocumentsResult<T>> SearchSimilarDocumentsAsync<T>( | ||
| SimilarDocumentsQuery query, | ||
| CancellationToken cancellationToken = default) | ||
| { | ||
| var responseMessage = await _http | ||
| .PostAsJsonAsync( | ||
| $"indexes/{Uid}/similar", | ||
| query, | ||
| Constants.JsonSerializerOptionsRemoveNulls, | ||
| cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
|  | ||
| return await responseMessage.Content | ||
| .ReadFromJsonAsync<SimilarDocumentsResult<T>>(cancellationToken: cancellationToken) | ||
| .ConfigureAwait(false); | ||
| } | ||
| } | ||
| } | 
Uh oh!
There was an error while loading. Please reload this page.