using ManagerService.Data;
using ManagerService.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace ManagerService.Tests.Infrastructure
{
///
/// Embeddings déterministes, sans appel réseau. Le texte pilote directement la
/// direction du vecteur, ce qui permet d'écrire « ce morceau est proche de cette
/// question » comme un fait vérifiable plutôt que comme une supposition.
///
///
/// Convention : un texte préfixé axis:N produit le vecteur unitaire de l'axe N,
/// éventuellement mêlé d'un peu de bruit stable (axis:N#seed). Deux textes sur
/// des axes différents sont donc quasi orthogonaux — distance cosinus proche de 1.
/// Ce qui suit les chiffres du seed est ignoré : cela permet d'écrire des textes
/// distincts qui partagent un même vecteur, sans quoi la déduplication par texte de
/// SearchAsync écraserait les lignes et fausserait tout comptage de résultats.
///
public class FakeEmbeddingService : IEmbeddingService
{
public int Dimensions => ContentEmbedding.Dimensions;
public Task EmbedAsync(string text, CancellationToken cancellationToken = default) =>
Task.FromResult(Embed(text));
public Task> EmbedBatchAsync(IReadOnlyList texts, CancellationToken cancellationToken = default) =>
Task.FromResult>(texts.Select(Embed).ToList());
public float[] Embed(string text)
{
var vector = new float[Dimensions];
var axis = 0;
var seed = 0;
if (text != null && text.StartsWith("axis:"))
{
var payload = text.Substring("axis:".Length);
var hash = payload.IndexOf('#');
if (hash >= 0)
{
var digits = new string(payload.Substring(hash + 1).TakeWhile(char.IsDigit).ToArray());
int.TryParse(digits, out seed);
payload = payload.Substring(0, hash);
}
int.TryParse(payload, out axis);
}
else
{
axis = Math.Abs((text ?? "").GetHashCode()) % Dimensions;
}
vector[axis % Dimensions] = 1f;
// Bruit stable : deux morceaux du même axe ne sont pas strictement identiques,
// sinon HNSW n'aurait aucun ordre à produire entre eux.
if (seed != 0)
vector[(axis + 1 + (seed % 16)) % Dimensions] = 0.01f * (seed % 10);
return vector;
}
}
}