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,
}) async {
  // Modern API: Use active embedding model if paths not provided
  if (modelPath == null || tokenizerPath == null) {
    final manager = modelManager as WebModelManager;
    final activeModel = manager.activeEmbeddingModel;

    // No active embedding model - user must set one first
    if (activeModel == null) {
      throw StateError(
          'No active embedding model set. Use `FlutterGemma.installEmbedder()` or `modelManager.setActiveModel()` to set a model first');
    }

    // Get the actual model file paths through unified system
    final modelFilePaths = await manager.getModelFilePaths(activeModel);
    if (modelFilePaths == null || modelFilePaths.isEmpty) {
      throw StateError(
          'Embedding model file paths not found. Use the `modelManager` to load the model first');
    }

    // Extract model and tokenizer paths from spec
    final activeModelPath = modelFilePaths[PreferencesKeys.embeddingModelFile];
    final activeTokenizerPath = modelFilePaths[PreferencesKeys.embeddingTokenizerFile];

    if (activeModelPath == null || activeTokenizerPath == null) {
      throw StateError('Could not find model or tokenizer path in active embedding model');
    }

    modelPath = activeModelPath;
    tokenizerPath = activeTokenizerPath;

    if (kDebugMode) {
      debugPrint('Using active embedding model: $modelPath, tokenizer: $tokenizerPath');
    }
  }

  // Check if model already exists with different parameters
  if (_initializedEmbeddingModel != null) {
    final existing = _initializedEmbeddingModel! as WebEmbeddingModel;

    // Check if paths changed (indicates different model)
    final bool modelChanged =
      existing.modelPath != modelPath ||
      existing.tokenizerPath != tokenizerPath;

    if (modelChanged) {
      if (kDebugMode) {
        debugPrint('[FlutterGemmaWeb] Embedding model paths changed, closing existing model');
      }
      await existing.close();
      _initializedEmbeddingModel = null;
    }
  }

  // Create or return existing model instance
  // Note: preferredBackend is ignored on web (LiteRT.js uses WebGPU when available)
  final model = _initializedEmbeddingModel ??= WebEmbeddingModel(
    modelPath: modelPath,
    tokenizerPath: tokenizerPath,
    onClose: () {
      _initializedEmbeddingModel = null;
    },
  );
  return model;
}