initialize static method
Initialize RagEngine with all dependencies.
This method handles:
- Copying tokenizer asset to documents directory
- Initializing the tokenizer
- Loading the ONNX embedding model
- Initializing the RAG database
config - Configuration containing asset paths and options.
onProgress - Optional callback for initialization status updates.
Example:
final rag = await RagEngine.initialize(
config: RagConfig.fromAssets(
tokenizerAsset: 'assets/tokenizer.json',
modelAsset: 'assets/model.onnx',
),
onProgress: (status) => setState(() => _status = status),
);
Implementation
static Future<RagEngine> initialize({
required RagConfig config,
void Function(String status)? onProgress,
}) async {
// 0. Auto-initialize Rust library (safe to call multiple times)
await _ensureRustInitialized();
// 1. Get app documents directory
final dir = await getApplicationDocumentsDirectory();
final dbPath = "${dir.path}/${config.databaseName ?? 'rag.sqlite'}";
final tokenizerPath = "${dir.path}/tokenizer.json";
final modelPath = "${dir.path}/${config.modelAsset.split('/').last}";
// 2. Copy and initialize tokenizer
onProgress?.call('Initializing tokenizer...');
await _copyAssetToFile(config.tokenizerAsset, tokenizerPath);
await initTokenizer(tokenizerPath: tokenizerPath);
final vocabSize = getVocabSize();
// 3. Prepare ONNX embedding model (Copy logic)
onProgress?.call('Preparing embedding model...');
// Copy model asset to file (optimized for memory)
await _copyAssetToFile(config.modelAsset, modelPath);
// Configure session options if thread limit is requested
OrtSessionOptions? sessionOptions;
// Default to half the cores if not specified to prevent full CPU usage
// Calculate threads based on configuration
int threads;
final totalCores = Platform.numberOfProcessors;
if (config.threadLevel != null) {
// 1. Thread Level (Percentage based)
switch (config.threadLevel!) {
case ThreadUseLevel.low:
threads = (totalCores * 0.2).ceil();
break;
case ThreadUseLevel.medium:
threads = (totalCores * 0.4).ceil();
break;
case ThreadUseLevel.high:
threads = (totalCores * 0.8).ceil();
break;
}
} else if (config.embeddingIntraOpNumThreads != null) {
// 2. Manual Count
threads = config.embeddingIntraOpNumThreads!;
} else {
// 3. Priority: Default (50% safe fallback)
threads = (totalCores > 1 ? (totalCores / 2).ceil() : 1);
}
// Ensure at least 1 thread
if (threads < 1) threads = 1;
// Apply thread configuration
sessionOptions = OrtSessionOptions();
try {
sessionOptions.setIntraOpNumThreads(threads);
debugPrint(
'[RagEngine] Configured ONNX embedding threads: $threads (Total Cores: $totalCores)',
);
} catch (e) {
debugPrint('[RagEngine] Warning: Failed to set intra-op num threads: $e');
}
// Init EmbeddingService with file path
onProgress?.call('Loading embedding model...');
await EmbeddingService.init(modelPath: modelPath, options: sessionOptions);
// 4. Initialize database connection pool
onProgress?.call('Initializing connection pool...');
await initDbPool(dbPath: dbPath, maxSize: 4);
// 5. Initialize RAG service
onProgress?.call('Initializing database...');
final ragService = SourceRagService(
dbPath: dbPath,
modelPath: modelPath,
maxChunkChars: config.maxChunkChars,
overlapChars: config.overlapChars,
);
await ragService.init(deferIndexWarmup: config.deferIndexWarmup);
onProgress?.call('Ready!');
return RagEngine._(
ragService: ragService,
dbPath: dbPath,
vocabSize: vocabSize,
deferIndexWarmup: config.deferIndexWarmup,
);
}