memlocal_dart 1.0.0
memlocal_dart: ^1.0.0 copied to clipboard
Local AI memory layer for Flutter. Sensory, short-term, and long-term memory with LLM-driven extraction, vector search, graph relationships, and full-text search. Built on CozoDB.
import 'package:flutter/material.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'models/app_settings.dart';
import 'pages/chat_page.dart';
import 'pages/memory_browser_page.dart';
import 'pages/settings_page.dart';
import 'services/chat_service.dart';
import 'services/memory_service.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await dotenv.load(fileName: '.env');
runApp(const MemlocalExampleApp());
}
class MemlocalExampleApp extends StatelessWidget {
const MemlocalExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'memlocal example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: const Color(0xFF6750A4),
useMaterial3: true,
brightness: Brightness.light,
),
darkTheme: ThemeData(
colorSchemeSeed: const Color(0xFF6750A4),
useMaterial3: true,
brightness: Brightness.dark,
),
themeMode: ThemeMode.system,
home: const HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
int _currentIndex = 0;
final _memoryService = MemoryService();
late final ChatService _chatService;
var _settings = AppSettings();
@override
void initState() {
super.initState();
_chatService = ChatService(memoryService: _memoryService);
_autoInitFromEnv();
}
/// If .env has an API key, auto-initialize on launch.
Future<void> _autoInitFromEnv() async {
if (_settings.isConfigured) {
try {
await _onSettingsSaved(_settings);
} catch (e) {
debugPrint('[memlocal] Auto-init failed: $e');
}
}
}
@override
void dispose() {
_chatService.dispose();
_memoryService.dispose();
super.dispose();
}
Future<void> _onSettingsSaved(AppSettings settings) async {
_settings = settings;
await _memoryService.init(settings);
_chatService.configure(settings);
if (mounted) setState(() {});
}
@override
Widget build(BuildContext context) {
final pages = [
ChatPage(chatService: _chatService),
MemoryBrowserPage(memoryService: _memoryService),
SettingsPage(
settings: _settings,
onSave: _onSettingsSaved,
isInitialized: _memoryService.isInitialized,
memoryCount: _memoryService.getMemoryCount,
),
];
return Scaffold(
appBar: AppBar(
title: const Text('memlocal'),
centerTitle: true,
actions: [
if (_memoryService.isInitialized)
FutureBuilder<int>(
future: _memoryService.getMemoryCount(),
builder: (context, snap) {
final count = snap.data ?? 0;
return Center(
child: Padding(
padding: const EdgeInsets.only(right: 16),
child: Chip(
avatar: const Icon(Icons.memory, size: 16),
label: Text('$count'),
visualDensity: VisualDensity.compact,
),
),
);
},
),
],
),
body: IndexedStack(
index: _currentIndex,
children: pages,
),
bottomNavigationBar: NavigationBar(
selectedIndex: _currentIndex,
onDestinationSelected: (i) => setState(() => _currentIndex = i),
destinations: const [
NavigationDestination(
icon: Icon(Icons.chat_outlined),
selectedIcon: Icon(Icons.chat),
label: 'Chat',
),
NavigationDestination(
icon: Icon(Icons.view_list_outlined),
selectedIcon: Icon(Icons.view_list),
label: 'Memories',
),
NavigationDestination(
icon: Icon(Icons.settings_outlined),
selectedIcon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
}