chat_pilot_kit_flutter 1.0.0-beta.5
chat_pilot_kit_flutter: ^1.0.0-beta.5 copied to clipboard
Flutter widgets and Riverpod integration for chat_pilot_kit_dart.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:chat_pilot_kit_flutter/chat_pilot_kit_flutter.dart';
import 'app_extensions.dart';
import 'pages/chat_page.dart';
import 'pages/demos_page.dart';
import 'pages/settings_page.dart';
import 'services/mock_agent_service.dart';
void main() {
final controller = createChatPilotKit(
agentService: MockAgentService(),
overrideExtensions: extensions,
);
runApp(
ChatPilotKitScope(
controller: controller,
child: const PlaygroundApp(),
),
);
}
class PlaygroundApp extends StatefulWidget {
const PlaygroundApp({super.key});
@override
State<PlaygroundApp> createState() => _PlaygroundAppState();
}
class _PlaygroundAppState extends State<PlaygroundApp> {
ThemeMode _themeMode = ThemeMode.system;
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Chat Pilot Kit Playground',
themeMode: _themeMode,
theme: ThemeData(
colorSchemeSeed: const Color(0xFF3B82F6),
useMaterial3: true,
brightness: Brightness.light,
),
darkTheme: ThemeData(
colorSchemeSeed: const Color(0xFF3B82F6),
useMaterial3: true,
brightness: Brightness.dark,
),
home: PlaygroundHome(
themeMode: _themeMode,
onThemeModeChanged: (mode) {
setState(() => _themeMode = mode);
},
),
);
}
}
class PlaygroundHome extends ConsumerStatefulWidget {
final ThemeMode themeMode;
final ValueChanged<ThemeMode> onThemeModeChanged;
const PlaygroundHome({
super.key,
required this.themeMode,
required this.onThemeModeChanged,
});
@override
ConsumerState<PlaygroundHome> createState() => _PlaygroundHomeState();
}
class _PlaygroundHomeState extends ConsumerState<PlaygroundHome> {
int _tabIndex = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_titleForTab(_tabIndex)),
centerTitle: false,
),
body: IndexedStack(
index: _tabIndex,
children: [
const ChatPage(),
DemosPage(onDemoTriggered: () => setState(() => _tabIndex = 0)),
SettingsPage(
themeMode: widget.themeMode,
onThemeModeChanged: widget.onThemeModeChanged,
onShowGallery: _showGallery,
),
],
),
bottomNavigationBar: NavigationBar(
selectedIndex: _tabIndex,
onDestinationSelected: (i) => setState(() => _tabIndex = i),
destinations: const [
NavigationDestination(
icon: Icon(Icons.chat_bubble_outline),
selectedIcon: Icon(Icons.chat_bubble),
label: 'Chat',
),
NavigationDestination(
icon: Icon(Icons.science_outlined),
selectedIcon: Icon(Icons.science),
label: 'Demos',
),
NavigationDestination(
icon: Icon(Icons.settings_outlined),
selectedIcon: Icon(Icons.settings),
label: 'Settings',
),
],
),
);
}
String _titleForTab(int index) {
return switch (index) {
0 => 'Chat Pilot Kit',
1 => 'Demos',
2 => 'Settings',
_ => 'Chat Pilot Kit',
};
}
void _showGallery() {
final controller = ref.read(chatPilotKitControllerProvider);
controller.importConversations(
const [
ConversationBeanInput(
role: ConversationRole.client,
nodes: [
ConversationNodeInput(type: 'text', content: 'Show me every NodeView.'),
],
),
ConversationBeanInput(
role: ConversationRole.aiWorker,
nodes: [
ConversationNodeInput(
type: 'markdown',
content:
'# NodeView Gallery\n\nAll built-in node types rendered below.\n\n'
'- **Text**, **Markdown**, **Thinking**, **ToolCall**\n'
'- **Image**, **Audio**, **Video**, **File**\n\n'
'```dart\n'
'final kit = createChatPilotKit(agentService: service);\n'
'```\n',
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'thinking',
content: {
'text': 'This is a collapsed thinking block example.',
'collapsed': false,
},
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'tool_call',
content: {
'name': 'get_weather',
'arguments': '{"city": "Beijing"}',
'status': 'completed',
'result': '{"temperature": "22C"}',
},
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'image',
content: {
'url': 'https://picsum.photos/seed/gallery/480/320',
'alt': 'Random photo',
},
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'audio',
content: {
'url': '#',
'mimeType': 'audio/mpeg',
'duration': 84.0,
},
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'video',
content: {
'url': '#',
'poster': 'https://picsum.photos/seed/gvid/480/270',
'duration': 150.0,
},
),
ConversationNodeInput<Map<String, dynamic>>(
type: 'file',
content: {
'url': '#',
'fileName': 'readme.md',
'fileSize': 1234,
'fileType': 'text/markdown',
},
),
],
),
],
options: const ImportOptions(position: ImportPosition.replace),
);
setState(() => _tabIndex = 0);
}
}