chatbotify 0.1.1
chatbotify: ^0.1.1 copied to clipboard
A plug-and-play AI chatbot package for Flutter with support for Gemini and OpenAI, streaming responses, Markdown rendering, theming, and pluggable storage. Minimal setup, production-ready UI.
chatbotify #
A plug-and-play AI chatbot for Flutter. Initialize once, drop in
AiChatScreen(), done. Supports Google Gemini and OpenAI, with
streaming responses, Markdown rendering, theming, and pluggable storage.
Features #
- π Plug-and-play β one
initialize()call, thenAiChatScreen() - π€ Multi-provider β Gemini and OpenAI today, extensible for more
- β‘ Streaming responses β tokens render as they arrive
- π Markdown rendering for assistant replies (code blocks, lists, etc.)
- π¨ Fully themeable β Romind-aligned teal UI, bubbles, fonts, send button
- π Light & dark mode β
ChatbotAppTheme.light/.dark+ in-chat toggle - πΎ Pluggable storage β ships with in-memory, bring your own Hive /
SharedPreferences / Firebase backend via the
ChatStorageinterface - π Retry, clear chat, typing indicator, scroll-to-bottom
- π‘ Empty-state suggestion chips matching the Romind chat layout
- π§― Structured error handling β invalid key, rate limit, no internet, timeout, provider unavailable β each with a reusable error banner
- π§± Built on Riverpod, following SOLID architecture
Installation #
dependencies:
chatbotify: ^0.1.0
flutter_riverpod: ^2.5.1
Then:
flutter pub get
Quick start #
Wrap your app in a ProviderScope, use [ChatbotAppTheme], and initialize
before runApp:
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:chatbotify/chatbotify.dart';
void main() {
AiChatbot.initialize(
provider: AIProvider.gemini,
apiKey: 'YOUR_API_KEY',
systemPrompt: 'You are a helpful assistant.',
);
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({super.key});
@override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
ThemeMode _mode = ThemeMode.dark; // Romind defaults to dark
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ChatbotAppTheme.light,
darkTheme: ChatbotAppTheme.dark,
themeMode: _mode,
home: AiChatScreen(
title: 'Chatbotify',
showThemeToggle: true,
isDarkMode: _mode == ThemeMode.dark,
onToggleTheme: () => setState(() {
_mode = _mode == ThemeMode.dark ? ThemeMode.light : ThemeMode.dark;
}),
),
);
}
}
That's it β chat bubbles, streaming, Markdown, typing indicator, and error handling all work out of the box.
β οΈ Never ship a real API key inside a compiled client app. Use
--dart-define=AI_API_KEY=...for demos, or proxy requests through your own backend for production.
Switching providers #
AiChatbot.initialize(
provider: AIProvider.openai, // was AIProvider.gemini
apiKey: 'YOUR_OPENAI_KEY',
model: 'gpt-4o-mini', // optional, has a sane default per provider
);
Nothing else in your app changes β the UI and controller talk to
AIProviderInterface, not to a specific vendor.
Theming #
Use the bundled Romind-style themes, or override individual chat tokens:
MaterialApp(
theme: ChatbotAppTheme.light,
darkTheme: ChatbotAppTheme.dark,
themeMode: ThemeMode.system,
home: AiChatScreen(
theme: ChatTheme(
// Optional overrides β defaults already match Romind ratios
borderRadius: 18,
bubbleTailRadius: 4,
bubbleMaxWidthFraction: 0.82,
inputBorderRadius: 28,
),
),
);
Any field you omit falls back to a value derived from your app's
ColorScheme and current Brightness, so light and dark both look correct.
Custom storage #
Chat history defaults to in-memory (lost on restart). Implement
ChatStorage to persist it:
class HiveChatStorage implements ChatStorage {
@override
Future<List<ChatMessage>> loadMessages(String sessionId) async { ... }
@override
Future<void> saveMessages(String sessionId, List<ChatMessage> messages) async { ... }
@override
Future<void> clear(String sessionId) async { ... }
}
AiChatbot.initialize(
provider: AIProvider.gemini,
apiKey: 'YOUR_API_KEY',
storage: HiveChatStorage(),
);
Error handling #
All failures surface as ChatbotException with a ChatbotErrorCode
(invalidApiKey, rateLimited, noInternet, timeout,
providerUnavailable, notInitialized, unknown). AiChatScreen renders
these via the built-in ChatErrorWidget; use it standalone if you build a
custom UI on top of ChatController.
Advanced: building your own UI #
Everything above AIProviderInterface is optional. If you want custom UI,
use the same controller the built-in screen uses:
final state = ref.watch(chatControllerProvider);
final controller = ref.read(chatControllerProvider.notifier);
controller.sendMessage('Hello!');
controller.retryLastMessage();
controller.clearChat();
Architecture #
lib/
chatbotify.dart # public barrel export
src/
core/ # enums, exceptions, constants (no Flutter deps)
models/ # ChatMessage, ChatTheme, ChatbotConfig
providers/ # AIProviderInterface + Gemini/OpenAI + factory
services/ # ChatStorage abstraction, HTTP client
controllers/ # ChatController (Riverpod StateNotifier), ChatState
ui/ # AiChatScreen
widgets/ # ChatBubble, TypingIndicator, MessageInput, ...
Each layer depends only on the one below it (Dependency Inversion), and the
provider layer is a Strategy pattern β adding a new AI backend means one
new class implementing AIProviderInterface, registered in
ProviderFactory.
Example app #
See example/ for a runnable app. From the package root:
cd example
flutter run --dart-define=AI_API_KEY=your_key_here
Contributing #
Issues and PRs welcome. Run flutter test before submitting.
License #
MIT β see LICENSE.