flutter_chat_kit_ui 0.1.1 copy "flutter_chat_kit_ui: ^0.1.1" to clipboard
flutter_chat_kit_ui: ^0.1.1 copied to clipboard

Unofficial Flutter port of the OpenAI ChatKit UI. A drop-in chat widget compatible with OpenAI ChatKit backends.

flutter_chat_kit_ui #

An unofficial Flutter port of the OpenAI ChatKit UI. A drop-in chat widget that communicates with OpenAI ChatKit backends or any self-hosted server implementing the same HTTP/SSE protocol.

Note: This package is not affiliated with or endorsed by OpenAI.

Features #

  • Full chat interface out of the box -- message list, composer, history panel, start screen
  • Real-time streaming via Server-Sent Events with hand-rolled parser
  • Markdown rendering for assistant messages with annotation/citation support
  • Thread management with cursor-based pagination
  • File and image attachments with upload progress tracking
  • Interactive widget system (cards, forms, tables, buttons, etc.)
  • Workflow visualization (reasoning chains, search tasks, file tasks)
  • Tool call display with status indicators
  • Feedback, copy, and retry actions on messages
  • Comprehensive theming (colors, typography, radius, density) with light/dark modes
  • Localization support with English defaults
  • Zero external state management dependencies -- built on ChangeNotifier + InheritedWidget

Requirements #

  • Dart SDK >=3.5.0
  • Flutter >=3.22.0

Installation #

Add to your pubspec.yaml:

dependencies:
  flutter_chat_kit_ui:
    path: ../flutter_chat_kit_ui  # local path

Or from a git repository:

dependencies:
  flutter_chat_kit_ui:
    git:
      url: https://github.com/your-org/flutter_chat_kit_ui.git
      ref: main

Quick start #

Self-hosted backend #

import 'package:flutter/material.dart';
import 'package:flutter_chat_kit_ui/flutter_chat_kit_ui.dart';

class MyChatScreen extends StatefulWidget {
  const MyChatScreen({super.key});

  @override
  State<MyChatScreen> createState() => _MyChatScreenState();
}

class _MyChatScreenState extends State<MyChatScreen> {
  late final ChatKitController _controller;

  @override
  void initState() {
    super.initState();
    _controller = ChatKitController(
      options: ChatKitOptions(
        api: CustomApiConfig(url: 'http://localhost:8000/chatkit'),
      ),
    );
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: ChatKit(controller: _controller),
    );
  }
}

OpenAI-hosted backend #

_controller = ChatKitController(
  options: ChatKitOptions(
    api: HostedApiConfig(
      getClientSecret: (existing) async {
        // Call your backend to get a client secret token
        final response = await http.get(Uri.parse('/api/chatkit/token'));
        return jsonDecode(response.body)['client_secret'];
      },
    ),
  ),
);

Configuration #

ChatKitOptions controls every aspect of the UI. All sub-options have sensible defaults.

ChatKitOptions(
  api: CustomApiConfig(
    url: 'http://localhost:8000/chatkit',
    headers: {'X-Api-Key': 'your-key'},
  ),

  // Start screen with greeting and suggested prompts
  startScreen: StartScreenOption(
    greeting: 'How can I help you?',
    suggestedPrompts: [
      SuggestedPrompt(label: 'Tell me a joke', prompt: 'Tell me a funny joke'),
      SuggestedPrompt(label: 'Write a poem', prompt: 'Write a short poem'),
    ],
  ),

  // Header bar (set show: false to hide entirely)
  header: HeaderOption(
    show: true,
    title: 'My Assistant',
    showTitle: true,
    showHistoryButton: true,
    showModelPicker: false,
  ),

  // Thread history panel
  history: HistoryOption(enabled: true, pageSize: 20),

  // Composer
  composer: ComposerOption(
    placeholder: 'Ask me anything...',
    sendIcon: Icons.send,       // custom send button icon
    cancelIcon: Icons.close,    // custom cancel button icon
    fileUpload: FileUploadOption(
      enabled: true,
      maxFileSize: 10 * 1024 * 1024,
      allowedMimeTypes: ['image/png', 'image/jpeg', 'application/pdf'],
    ),
    showToolPicker: false,
    showModelPicker: false,
  ),

  // Message actions
  threadItemActions: ThreadItemActionsOption(
    showFeedback: true,
    showCopy: true,
    showRetry: true,
  ),

  // Disclaimer below composer
  disclaimer: DisclaimerOption(
    enabled: true,
    text: 'AI can make mistakes. Check important info.',
  ),

  // Event callbacks
  events: ChatKitEventCallbacks(
    onThreadCreated: (thread) => print('New thread: ${thread.id}'),
    onError: (code, message, allowRetry) => print('Error: $message'),
  ),
)

Theming #

flutter_chat_kit_ui has its own theme system that works alongside Flutter's ThemeData. If no ChatKitTheme is provided, it derives sensible defaults from the current Flutter theme.

// Use built-in light/dark themes
ChatKit(
  controller: _controller,
  theme: ChatKitThemeData.dark(),
)

// Customize specific aspects
ChatKit(
  controller: _controller,
  theme: ChatKitThemeData.light().copyWith(
    colorScheme: ChatKitColorScheme.light.copyWith(
      primary: Colors.indigo,
    ),
    typography: const ChatKitTypography(fontFamily: 'Inter'),
    radius: const ChatKitRadius(
      messageBubble: Radius.circular(20),
    ),
    density: const ChatKitDensity(
      messageSpacing: 12,
    ),
  ),
)

// Or wrap a subtree with ChatKitTheme directly
ChatKitTheme(
  data: ChatKitThemeData.dark(),
  child: ChatKit(controller: _controller),
)

Controller API #

ChatKitController is the primary programmatic interface. It composes several sub-controllers:

final controller = ChatKitController(options: options);

// Thread operations
await controller.selectThread('thread_123');
controller.startNewThread();
await controller.loadMoreThreads();

// Sending messages
controller.setComposerText('Hello!');
await controller.send();                     // creates thread or adds to active
controller.cancelStream();                   // cancel streaming response

// Retry and feedback
await controller.retryFromItem('item_456');
await controller.submitFeedback(['item_456'], 'thumbs_up');

// State accessors
controller.threads;          // List<ThreadMetadata>
controller.activeThread;     // Thread?
controller.items;            // List<ThreadItem> (current messages)
controller.isStreamActive;   // bool
controller.composerText;     // String
controller.canSend;          // bool

// Cleanup
controller.dispose();

Architecture #

flutter_chat_kit_ui/
  lib/src/
    models/          Data models (Thread, ThreadItem, Attachment, Annotation, ...)
    events/          SSE event types (ThreadStreamEvent, ThreadItemUpdate)
    client/          HTTP client, SSE parser, token manager
    config/          Configuration options
    state/           ChangeNotifier controllers
    theme/           Theming system (colors, typography, radius, density)
    widgets/         Flutter UI widgets
    widget_system/   Interactive widget renderer (cards, forms, tables)
    l10n/            Localization

Key design decisions:

  • Dart 3 sealed classes for type-safe discriminated unions with exhaustive pattern matching
  • ChangeNotifier + InheritedWidget for state management with zero external dependencies
  • Hand-rolled SSE parser -- simple data: line protocol doesn't warrant a dependency
  • Composition over inheritance -- small, focused, independently testable widgets

Running tests #

flutter test

209 tests covering model serialization, SSE parsing, configuration, token management, and theme behavior.

License #

See LICENSE for details.

1
likes
160
points
169
downloads

Publisher

verified publishermeadworks.io

Weekly Downloads

Unofficial Flutter port of the OpenAI ChatKit UI. A drop-in chat widget compatible with OpenAI ChatKit backends.

Repository (GitHub)
View/report issues

Documentation

API reference

License

MIT (license)

Dependencies

collection, flutter, flutter_markdown_plus, http, intl, mime

More

Packages that depend on flutter_chat_kit_ui