syncTopic method
- String topicId
Sync a topic's chunks to local storage.
If chunks are already cached locally, this is a no-op. If the local embedding model is ready and chunks lack embeddings, generates embeddings on-device.
Returns the number of chunks synced (0 if already cached).
Implementation
Future<int> syncTopic(String topicId) async {
if (_syncing.contains(topicId)) return 0;
if (!_localStore.isReady) return 0;
// Already cached with embeddings.
if (_localStore.hasTopicEmbeddings(topicId)) {
_synced.add(topicId);
return 0;
}
_syncing.add(topicId);
try {
// Fetch chunks with embeddings from Supabase.
final chunksWithEmbeddings = await _supabase.getChunksWithEmbeddings(
topicId,
);
if (chunksWithEmbeddings.isEmpty) {
_synced.add(topicId);
return 0;
}
final chunks = chunksWithEmbeddings.map((e) => e.$1).toList();
var embeddings = chunksWithEmbeddings.map((e) => e.$2).toList();
// If Supabase doesn't have embeddings but local model is ready,
// generate them on-device.
final hasAnyEmbedding = embeddings.any((e) => e.isNotEmpty);
if (!hasAnyEmbedding && _localEmbedding.isReady) {
dev.log(
'No Supabase embeddings for topic $topicId, generating on-device...',
name: 'ChunkSync',
);
final generated = <List<double>>[];
for (final chunk in chunks) {
final emb = await _localEmbedding.embed(chunk.content);
generated.add(emb);
}
embeddings = generated;
}
_localStore.upsertChunks(chunks, embeddings);
_synced.add(topicId);
dev.log(
'Synced ${chunks.length} chunks for topic $topicId '
'(${embeddings.where((e) => e.isNotEmpty).length} with embeddings)',
name: 'ChunkSync',
);
return chunks.length;
} catch (e) {
dev.log('Sync failed for topic $topicId: $e', name: 'ChunkSync');
return 0;
} finally {
_syncing.remove(topicId);
}
}