import 'package:riverpod_annotation/riverpod_annotation.dart'; import 'package:trainhub_flutter/domain/repositories/note_repository.dart'; import 'package:trainhub_flutter/injection.dart'; import 'package:trainhub_flutter/presentation/settings/knowledge_base_state.dart'; part 'knowledge_base_controller.g.dart'; @riverpod class KnowledgeBaseController extends _$KnowledgeBaseController { late NoteRepository _repo; @override KnowledgeBaseState build() { _repo = getIt(); // Load the current chunk count asynchronously after first build. _loadCount(); return const KnowledgeBaseState(); } // ------------------------------------------------------------------------- // Load chunk count // ------------------------------------------------------------------------- Future _loadCount() async { try { final count = await _repo.getChunkCount(); state = state.copyWith(chunkCount: count); } catch (_) { // Non-fatal — UI stays at 0. } } // ------------------------------------------------------------------------- // Save note // ------------------------------------------------------------------------- /// Chunks [text], generates embeddings via Nomic, and stores the result. Future saveNote(String text) async { if (text.trim().isEmpty) return; state = state.copyWith( isLoading: true, successMessage: null, errorMessage: null, ); try { await _repo.addNote(text.trim()); final count = await _repo.getChunkCount(); state = state.copyWith( isLoading: false, chunkCount: count, successMessage: 'Saved! Knowledge base now has $count chunks.', ); } catch (e) { state = state.copyWith( isLoading: false, errorMessage: _friendlyError(e), ); } } // ------------------------------------------------------------------------- // Clear knowledge base // ------------------------------------------------------------------------- Future clearKnowledgeBase() async { state = state.copyWith( isLoading: true, successMessage: null, errorMessage: null, ); try { await _repo.clearAll(); state = state.copyWith( isLoading: false, chunkCount: 0, successMessage: 'Knowledge base cleared.', ); } catch (e) { state = state.copyWith( isLoading: false, errorMessage: _friendlyError(e), ); } } // ------------------------------------------------------------------------- // Helper // ------------------------------------------------------------------------- String _friendlyError(Object e) { final msg = e.toString(); if (msg.contains('Connection refused') || msg.contains('SocketException')) { return 'Cannot reach the embedding server. ' 'Make sure AI models are downloaded and the app has had time to ' 'start the inference servers.'; } return 'Error: $msg'; } }