createEmbeddingModel method

  1. @override
Future<EmbeddingModel> createEmbeddingModel({
  1. String? modelPath,
  2. String? tokenizerPath,
  3. PreferredBackend? preferredBackend,
})
override

Creates and returns a new EmbeddingModel instance.

Modern API: If paths are not provided, uses the active embedding model set via FlutterGemma.installEmbedder() or modelManager.setActiveModel().

Legacy API: Provide explicit paths for backward compatibility.

modelPath — path to the embedding model file (optional if active model set). tokenizerPath — path to the tokenizer file (optional if active model set). preferredBackend — backend preference (e.g., CPU, GPU).

Implementation

@override
Future<EmbeddingModel> createEmbeddingModel({
  String? modelPath,
  String? tokenizerPath,
  PreferredBackend? preferredBackend,
}) {
  // FIRST statement, before every guard. It is idempotent and one-shot, so
  // it needs neither resolved paths nor cache state — and putting it in a
  // branch is what made it unreachable twice: once behind the singleton
  // cache, once behind "only on reuse". The ordinary shape is a single call
  // held for the app's lifetime; if it does not speak here it never speaks.
  noticeWebEmbedderBackendIgnored(preferredBackend);

  // Serialised, so that resolving paths, comparing them and constructing the
  // model are one step — which is what stops two concurrent first callers from
  // each building one, the defect this shell actually had.
  //
  // Note what this does NOT cover on either web arm: the model constructors
  // are trivial and the WASM/WebGPU compile happens lazily on the first
  // `generateEmbedding`, outside this lane. Concurrent first embeddings are
  // deduped by each model's own single in-flight init future — this lane only
  // guarantees one MODEL, not one compile.
  return _embedderCache.serialize(
    () => _reuseOrBuildEmbedder(
      modelPath: modelPath,
      tokenizerPath: tokenizerPath,
      preferredBackend: preferredBackend,
    ),
  );
}