dartantic_firebase_ai 0.1.0 copy "dartantic_firebase_ai: ^0.1.0" to clipboard
dartantic_firebase_ai: ^0.1.0 copied to clipboard

Firebase AI provider for dartantic_ai. Provides access to Google's Gemini models through Firebase with App Check security and Firebase Auth integration.

example/lib/main.dart

import 'dart:typed_data';

import 'package:dartantic_firebase_ai/dartantic_firebase_ai.dart';
import 'package:dartantic_interface/dartantic_interface.dart';
import 'package:firebase_ai_example/firebase_options.dart';
import 'package:firebase_core/firebase_core.dart';
import 'package:flutter/material.dart';

/// Simple chat example using the Firebase AI ChatModel directly.
///
/// Demonstrates low-level streaming without the Agent orchestration layer.
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await Firebase.initializeApp(options: DefaultFirebaseOptions.currentPlatform);
  runApp(const SimpleChatApp());
}

/// Root widget for the simple chat example.
class SimpleChatApp extends StatelessWidget {
  /// Creates the simple chat app.
  const SimpleChatApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Firebase AI Simple Chat',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.orange),
        useMaterial3: true,
      ),
      home: const SimpleChatScreen(),
    );
  }
}

/// A minimal chat screen that streams responses from the ChatModel.
class SimpleChatScreen extends StatefulWidget {
  /// Creates the simple chat screen.
  const SimpleChatScreen({super.key});

  @override
  State<SimpleChatScreen> createState() => _SimpleChatScreenState();
}

class _SimpleChatScreenState extends State<SimpleChatScreen> {
  final _controller = TextEditingController();
  final _scrollController = ScrollController();
  final _messages = <ChatMessage>[];
  final _provider = FirebaseAIProvider(backend: FirebaseAIBackend.googleAI);
  late final FirebaseAIChatModel _chatModel;
  late final FirebaseAIMediaGenerationModel _imagenModel;
  late final FirebaseAIMediaGenerationModel _geminiImageModel;

  String _streamingText = '';
  bool _isStreaming = false;
  Uint8List? _generatedImage;
  String? _imageCaption;

  @override
  void initState() {
    super.initState();
    _chatModel =
        _provider.createChatModel(name: 'gemini-2.5-flash')
            as FirebaseAIChatModel;
    _imagenModel =
        _provider.createMediaModel(name: 'imagen-4.0-generate-001')
            as FirebaseAIMediaGenerationModel;
    _geminiImageModel =
        _provider.createMediaModel(
              name: 'gemini-2.5-flash-image',
              options: const FirebaseAIGeminiMediaGenerationModelOptions(),
            )
            as FirebaseAIMediaGenerationModel;
  }

  @override
  void dispose() {
    _controller.dispose();
    _scrollController.dispose();
    _chatModel.dispose();
    _imagenModel.dispose();
    _geminiImageModel.dispose();
    super.dispose();
  }

  Future<void> _generateViaImagen() async {
    if (_isStreaming) return;

    setState(() {
      _isStreaming = true;
      _generatedImage = null;
      _imageCaption = null;
    });

    try {
      await for (final result in _imagenModel.generateMediaStream(
        'A friendly robot mascot waving hello, pixel art style',
        mimeTypes: ['image/png'],
      )) {
        if (!mounted) return;
        for (final asset in result.assets) {
          if (asset is DataPart) {
            setState(() => _generatedImage = asset.bytes);
          }
        }
      }

      if (!mounted) return;
      setState(() => _isStreaming = false);
    } finally {
      if (mounted && _isStreaming) {
        setState(() => _isStreaming = false);
      }
    }
  }

  Future<void> _generateViaGemini() async {
    if (_isStreaming) return;

    setState(() {
      _isStreaming = true;
      _generatedImage = null;
      _imageCaption = null;
    });

    try {
      await for (final result in _geminiImageModel.generateMediaStream(
        'Generate an image of a friendly robot mascot waving hello, '
        'pixel art style',
        mimeTypes: ['image/png'],
      )) {
        if (!mounted) return;
        for (final asset in result.assets) {
          if (asset is DataPart) {
            setState(() => _generatedImage = asset.bytes);
          }
        }
        for (final message in result.messages) {
          final text = message.parts.text;
          if (text.isNotEmpty) {
            setState(() => _imageCaption = text);
          }
        }
      }

      if (!mounted) return;
      setState(() => _isStreaming = false);
    } finally {
      if (mounted && _isStreaming) {
        setState(() => _isStreaming = false);
      }
    }
  }

  Future<void> _sendMessage() async {
    final text = _controller.text.trim();
    if (text.isEmpty || _isStreaming) return;

    _controller.clear();
    setState(() {
      _messages.add(ChatMessage.user(text));
      _streamingText = '';
      _isStreaming = true;
    });
    _scrollToBottom();

    try {
      final buffer = StringBuffer();
      await for (final chunk in _chatModel.sendStream(_messages)) {
        final delta = chunk.output.text;
        buffer.write(delta);
        if (!mounted) return;
        setState(() => _streamingText = buffer.toString());
        _scrollToBottom();
      }

      if (!mounted) return;
      setState(() {
        _messages.add(ChatMessage.model(buffer.toString()));
        _streamingText = '';
        _isStreaming = false;
      });
    } finally {
      if (mounted && _isStreaming) {
        setState(() => _isStreaming = false);
      }
    }
  }

  void _scrollToBottom() {
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (_scrollController.hasClients) {
        _scrollController.animateTo(
          _scrollController.position.maxScrollExtent,
          duration: const Duration(milliseconds: 200),
          curve: Curves.easeOut,
        );
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Firebase AI Simple Chat'),
        actions: [
          IconButton(
            onPressed: _isStreaming ? null : _generateViaImagen,
            icon: const Icon(Icons.image),
            tooltip: 'Generate Image (Imagen)',
          ),
          IconButton(
            onPressed: _isStreaming ? null : _generateViaGemini,
            icon: const Icon(Icons.auto_awesome),
            tooltip: 'Generate Image (Gemini)',
          ),
        ],
      ),
      body: Column(
        children: [
          if (_generatedImage != null || _imageCaption != null)
            Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                children: [
                  if (_generatedImage != null)
                    Image.memory(
                      _generatedImage!,
                      height: 200,
                      fit: BoxFit.contain,
                    ),
                  if (_imageCaption != null)
                    Padding(
                      padding: const EdgeInsets.only(top: 8),
                      child: Text(
                        _imageCaption!,
                        style: Theme.of(context).textTheme.bodySmall,
                      ),
                    ),
                ],
              ),
            ),
          Expanded(
            child: ListView.builder(
              controller: _scrollController,
              padding: const EdgeInsets.all(16),
              itemCount: _messages.length + (_streamingText.isNotEmpty ? 1 : 0),
              itemBuilder: (context, index) {
                if (index < _messages.length) {
                  return _MessageBubble(message: _messages[index]);
                }
                return _MessageBubble(
                  message: ChatMessage.model(_streamingText),
                  isStreaming: true,
                );
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(8),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: _controller,
                    decoration: const InputDecoration(
                      hintText: 'Type a message...',
                      border: OutlineInputBorder(),
                    ),
                    onSubmitted: (_) => _sendMessage(),
                    enabled: !_isStreaming,
                  ),
                ),
                const SizedBox(width: 8),
                IconButton(
                  onPressed: _isStreaming ? null : _sendMessage,
                  icon: const Icon(Icons.send),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}

class _MessageBubble extends StatelessWidget {
  const _MessageBubble({required this.message, this.isStreaming = false});

  final ChatMessage message;
  final bool isStreaming;

  @override
  Widget build(BuildContext context) {
    final isUser = message.role == ChatMessageRole.user;
    return Align(
      alignment: isUser ? Alignment.centerRight : Alignment.centerLeft,
      child: Container(
        margin: const EdgeInsets.symmetric(vertical: 4),
        padding: const EdgeInsets.all(12),
        constraints: BoxConstraints(
          maxWidth: MediaQuery.of(context).size.width * 0.75,
        ),
        decoration: BoxDecoration(
          color: isUser
              ? Theme.of(context).colorScheme.primaryContainer
              : Theme.of(context).colorScheme.surfaceContainerHighest,
          borderRadius: BorderRadius.circular(12),
        ),
        child: Text(message.parts.text),
      ),
    );
  }
}
0
likes
150
points
0
downloads

Documentation

API reference

Publisher

verified publishersellsbrothers.com

Weekly Downloads

Firebase AI provider for dartantic_ai. Provides access to Google's Gemini models through Firebase with App Check security and Firebase Auth integration.

Homepage
Repository (GitHub)
View/report issues

License

BSD-3-Clause (license)

Dependencies

dartantic_interface, firebase_ai, firebase_app_check, firebase_auth, firebase_core, flutter, logging, meta, uuid

More

Packages that depend on dartantic_firebase_ai