createEmbeddingModel method
Future<EmbeddingModel>
createEmbeddingModel({
- String? modelPath,
- String? tokenizerPath,
- 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 = _unifiedManager;
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');
}
// Check if singleton exists and matches the active model
if (_initEmbeddingCompleter != null &&
_initializedEmbeddingModel != null &&
_lastActiveEmbeddingSpec != null) {
final currentSpec = _lastActiveEmbeddingSpec!;
final requestedSpec = activeModel as EmbeddingModelSpec;
if (currentSpec.name != requestedSpec.name) {
// Active model changed - close old model and create new one
debugPrint(
'⚠️ Active embedding model changed: ${currentSpec.name} → ${requestedSpec.name}');
debugPrint('🔄 Closing old embedding model and creating new one...');
await _initializedEmbeddingModel?.close();
// onClose callback will reset _initializedEmbeddingModel and _initEmbeddingCompleter
_lastActiveEmbeddingSpec = null;
} else {
// Same model - return existing singleton
debugPrint('ℹ️ Reusing existing embedding model instance for ${requestedSpec.name}');
return _initEmbeddingCompleter!.future;
}
}
modelPath = activeModelPath;
tokenizerPath = activeTokenizerPath;
debugPrint('Using active embedding model: $modelPath, tokenizer: $tokenizerPath');
} else {
// Legacy API with explicit paths - check if singleton exists
if (_initEmbeddingCompleter case Completer<EmbeddingModel> completer) {
debugPrint('ℹ️ Reusing existing embedding model instance (Legacy API)');
return completer.future;
}
}
final completer = _initEmbeddingCompleter = Completer<EmbeddingModel>();
// Verify the active model is still installed (for Modern API path)
final manager = _unifiedManager;
final activeModel = manager.activeEmbeddingModel;
if (activeModel != null) {
final isModelInstalled = await manager.isModelInstalled(activeModel);
if (!isModelInstalled) {
completer.completeError(
Exception(
'Active embedding model is no longer installed. Use the `modelManager` to load the model first'),
);
return completer.future;
}
}
try {
await _platformService.createEmbeddingModel(
modelPath: modelPath,
tokenizerPath: tokenizerPath,
preferredBackend: preferredBackend,
);
final model = _initializedEmbeddingModel = MobileEmbeddingModel(
onClose: () {
_initializedEmbeddingModel = null;
_initEmbeddingCompleter = null;
_lastActiveEmbeddingSpec = null;
},
);
// Save the spec that was used to create this model (Modern API path only)
if (activeModel != null) {
_lastActiveEmbeddingSpec = activeModel as EmbeddingModelSpec;
}
completer.complete(model);
return model;
} catch (e, st) {
completer.completeError(e, st);
Error.throwWithStackTrace(e, st);
}
}