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 β bubble colors, fonts, border radius, send button
- π Light & dark mode aware by default
- πΎ Pluggable storage β ships with in-memory, bring your own Hive /
SharedPreferences / Firebase backend via the
ChatStorageinterface - π Retry, clear chat, typing indicator, scroll-to-bottom
- π§― Structured error handling β invalid key, rate limit, no internet, timeout, provider unavailable β each with a reusable error widget
- π§± 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 and initialize the package 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()));
}
Then drop the ready-made screen in anywhere:
Navigator.push(
context,
MaterialPageRoute(builder: (_) => const AiChatScreen()),
);
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
AiChatScreen(
theme: ChatTheme(
userBubbleColor: Colors.deepPurple,
assistantBubbleColor: Colors.grey.shade200,
borderRadius: 24,
sendButtonColor: Colors.deepPurple,
),
)
Any field you omit falls back to a value derived from your app's
ThemeData and current Brightness, so ChatTheme() alone already looks
good in both light and dark mode.
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.
Libraries
- chatbotify
- Plug-and-play AI chatbot UI + logic for Flutter apps.