embed method

  1. @override
Future<List<Float32List>> embed(
  1. List<String> texts, {
  2. EmbedPurpose purpose = EmbedPurpose.document,
})
override

Embeds texts, returning one vector per text, in order.

Implementation

@override
Future<List<Float32List>> embed(
  List<String> texts, {
  EmbedPurpose purpose = EmbedPurpose.document,
}) async {
  final out = List<Float32List?>.filled(texts.length, null);
  final missing = <int>[];
  for (var i = 0; i < texts.length; i++) {
    final key = _key(texts[i], purpose);
    final cached = _memory[key] ?? _load(key);
    if (cached != null) {
      hits++;
      _remember(key, cached);
      out[i] = cached;
    } else {
      missing.add(i);
    }
  }
  if (missing.isNotEmpty) {
    misses += missing.length;
    // Embed each distinct missing text once.
    final unique = <String>{for (final i in missing) texts[i]}.toList();
    final vectors = await inner.embed(unique, purpose: purpose);
    if (vectors.length != unique.length) {
      throw LlmException(
        'the embedder returned ${vectors.length} vectors for '
        '${unique.length} texts',
      );
    }
    final byText = {
      for (var j = 0; j < unique.length; j++) unique[j]: vectors[j],
    };
    for (final i in missing) {
      final v = byText[texts[i]];
      if (v == null) {
        throw const LlmException(
          'the embedder returned vectors for different texts than it was '
          'given',
        );
      }
      final key = _key(texts[i], purpose);
      _remember(key, v);
      _store(key, v);
      out[i] = v;
    }
  }
  // Copies, not the cached instances: a caller that normalises a returned
  // vector in place must not corrupt the cache (or another slot that points
  // at the same text).
  return [for (final v in out) Float32List.fromList(v!)];
}