// Copyright (c) Microsoft. All rights reserved. using System.Text.Json; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.HuggingFace; using Microsoft.SemanticKernel.Connectors.InMemory; using Microsoft.SemanticKernel.Embeddings; #pragma warning disable CS8602 // Dereference of a possibly null reference. namespace Memory; /// /// This example shows how to use custom to override Hugging Face HTTP response. /// Generally, an embedding model will return results as a 1 * n matrix for input type [string]. However, the model can have different matrix dimensionality. /// For example, the cointegrated/LaBSE-en-ru model returns results as a 1 * 1 * 4 * 768 matrix, which is different from Hugging Face embedding generation service implementation. /// To address this, a custom can be used to modify the response before sending it back. /// [Obsolete("The IMemoryStore abstraction is being obsoleted")] public class HuggingFace_TextEmbeddingCustomHttpHandler(ITestOutputHelper output) : BaseTest(output) { public async Task RunInferenceApiEmbeddingCustomHttpHandlerAsync() { Console.WriteLine("\n======= Hugging Face Inference API - Embedding Example ========\n"); var hf = new HuggingFaceTextEmbeddingGenerationService( "cointegrated/LaBSE-en-ru", apiKey: TestConfiguration.HuggingFace.ApiKey, httpClient: new HttpClient(new CustomHttpClientHandler() { CheckCertificateRevocationList = true }) ); var inMemoryCollection = new InMemoryCollection( name: "Test", new() { EmbeddingGenerator = hf.AsEmbeddingGenerator() }); await inMemoryCollection.UpsertAsync(new Record { Id = "1", Text = "THIS IS A SAMPLE", Embedding = "An embedding will be generated from this text" }); } public class Record { [VectorStoreKey] public string Id { get; set; } [VectorStoreData] public string Text { get; set; } [VectorStoreVector(Dimensions: 768)] public string Embedding { get; set; } } private sealed class CustomHttpClientHandler : HttpClientHandler { private readonly JsonSerializerOptions _jsonOptions = new(); protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { // Log the request URI //Console.WriteLine($"Request: {request.Method} {request.RequestUri}"); // Send the request and get the response HttpResponseMessage response = await base.SendAsync(request, cancellationToken); // Log the response status code //Console.WriteLine($"Response: {(int)response.StatusCode} {response.ReasonPhrase}"); // You can manipulate the response here // For example, add a custom header // response.Headers.Add("X-Custom-Header", "CustomValue"); // For example, modify the response content Stream originalContent = await response.Content.ReadAsStreamAsync(cancellationToken).ConfigureAwait(false); List>>> modifiedContent = (await JsonSerializer.DeserializeAsync>>>>(originalContent, _jsonOptions, cancellationToken).ConfigureAwait(false))!; Stream modifiedStream = new MemoryStream(); await JsonSerializer.SerializeAsync(modifiedStream, modifiedContent[0][0].ToList(), _jsonOptions, cancellationToken).ConfigureAwait(false); response.Content = new StreamContent(modifiedStream); // Return the modified response return response; } } }