Why use the mistralai_dart Flutter package?

The mistralai_dart Flutter package is a lightweight, typed client for Mistral AI’s REST API. It lets you call chat completions, generate embeddings, manage fine‑tuned models, and orchestrate multi‑step agents directly from Flutter or pure Dart code without writing low‑level HTTP boilerplate.

  • Typed request and response models for compile‑time safety.
  • Built‑in async/await support and optional streaming for chat.
  • Cross‑platform – works on Android, iOS, web, and desktop.
  • Retry logic helps smooth over transient network errors.
Tip: Keep your API key out of source control. Use Flutter’s --dart-define flag or a secure secret manager.

When to choose mistralai_dart

Use this package when you need any of the following in a Flutter project:

  • Real‑time conversational assistants (chatbot UI).
  • Semantic search or recommendation engines powered by embeddings.
  • Automated content generation (articles, code snippets, etc.).
  • Fine‑tuning workflows that require programmatic model management.

Installation

Add the dependency with the Flutter CLI:

Code
flutter pub add mistralai_dart

Then run flutter pub get to fetch the package.

Basic Chat Example

The following minimal app demonstrates a single‑turn chat using MistralClient. Replace YOUR_API_KEY with a valid Mistral API key.

Dart / Flutter
import 'package:flutter/material.dart';
import 'package:mistralai_dart/mistralai_dart.dart';

void main() => runApp(const MyApp());

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: ChatScreen(),
    );
  }
}

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

  @override
  State createState() => _ChatScreenState();
}

class _ChatScreenState extends State {
  final TextEditingController _controller = TextEditingController();
  final MistralClient _client = MistralClient(apiKey: 'YOUR_API_KEY');
  String _response = '';
  bool _isLoading = false;

  Future _send() async {
    final userMessage = _controller.text.trim();
    if (userMessage.isEmpty) return;

    setState(() => _isLoading = true);
    try {
      final result = await _client.chat(messages: [
        ChatMessage(role: Role.user, content: userMessage),
      ]);
      setState(() => _response = result.choices.first.message.content);
    } on MistralException catch (e) {
      setState(() => _response = 'Error: ${e.message}');
    } finally {
      setState(() => _isLoading = false);
      _controller.clear();
    }
  }

  @override
  Widget build(BuildContext context) => Scaffold(
        appBar: AppBar(title: const Text('Mistral Chat')),
        body: Padding(
          padding: const EdgeInsets.all(16),
          child: Column(
            children: [
              Expanded(
                child: SingleChildScrollView(
                  child: Text(_response, style: const TextStyle(fontSize: 16)),
                ),
              ),
              const SizedBox(height: 12),
              Row(
                children: [
                  Expanded(
                    child: TextField(
                      controller: _controller,
                      decoration: const InputDecoration(
                        hintText: 'Ask something...',
                        border: OutlineInputBorder(),
                      ),
                      onSubmitted: (_) => _send(),
                    ),
                  ),
                  const SizedBox(width: 8),
                  _isLoading
                      ? const CircularProgressIndicator()
                      : IconButton(
                          icon: const Icon(Icons.send),
                          onPressed: _send,
                        ),
                ],
              ),
            ],
          ),
        ),
      );
}

This example shows the typical data flow:

  • Collect user input.
  • Call client.chat with a list of ChatMessage objects.
  • Update UI with the assistant’s response.

Streaming responses (optional)

If you need token‑by‑token updates, the package offers a chatStream method. Below is a concise illustration:

Code
Future _sendStreaming() async {
  final userMessage = _controller.text.trim();
  if (userMessage.isEmpty) return;

  setState(() => _response = '');
  final stream = _client.chatStream(messages: [
    ChatMessage(role: Role.user, content: userMessage),
  ]);

  await for (final chunk in stream) {
    setState(() => _response += chunk.choices.first.delta?.content ?? '');
  }
}

Remember to handle cancellation and errors when using streams in production.

Embedding Use‑case

Generating vector embeddings is straightforward. The following snippet creates an embedding for a short paragraph and prints the first five dimensions.

Code
Future generateEmbedding() async {
  final result = await _client.embeddings(input: 'Flutter makes beautiful UIs easy.');
  final vector = result.data.first.embedding;
  print('First 5 dimensions: ${vector.take(5).toList()}');
}

Common Mistakes & How to Avoid Them

  • Hard‑coding the API key. This exposes credentials in version control. Use environment variables or --dart-define instead.
  • Ignoring rate limits. Mistral enforces per‑minute limits. Implement exponential back‑off or respect the Retry-After header.
  • Assuming the response is always non‑null. Network failures or malformed requests throw MistralException. Always wrap calls in try/catch.
  • Using the same MistralClient instance across isolates without synchronization. The client holds an internal http.Client; create separate instances per isolate or share a thread‑safe wrapper.
Tip: The package includes built‑in retry logic, but you may still want to add your own exponential back‑off for critical flows.

Setup Checklist

  • Obtain a Mistral API key from the Mistral console.
  • Add mistralai_dart to pubspec.yaml via flutter pub add.
  • Store the API key securely (e.g., --dart-define=MISTRAL_API_KEY=…).
  • Test a simple chat request before building complex UI.
  • Monitor usage in the Mistral dashboard to avoid unexpected billing.

Further Reading

For detailed type definitions, streaming options, and fine‑tuning endpoints, refer to the official package documentation on Pub.dev:

FAQ

  • Q: Does the package support web? A: Yes. The client uses http which works on Flutter web, mobile, and desktop.
  • Q: How do I handle streaming chat on a background isolate? A: Create a separate MistralClient inside the isolate and forward streamed chunks via SendPort. The package itself does not manage isolates.
  • Q: Can I use the same client for embeddings and chat? A: Absolutely. The client exposes methods for all supported endpoints.
  • Q: What happens if I exceed the rate limit? A: The API returns a 429 response. The client throws a MistralException containing the status code; you should catch it and optionally respect the Retry-After header.
  • Q: Is there a way to cancel an ongoing request? A: Pass a CancelToken (if using the underlying dio client) or close the stream returned by chatStream. The package does not expose a direct cancel method.

Frequently Asked Questions

Does the mistralai_dart package work on Flutter web?

Yes. The client uses the standard http package, which is compatible with Flutter web, mobile, and desktop platforms.

How can I keep my Mistral API key secure in a Flutter project?

Avoid hard‑coding the key. Use Flutter's --dart-define flag, a .env file with flutter_dotenv, or a secure secret manager. Never commit the key to version control.

What should I do if I receive a 429 Too Many Requests error?

The client throws a MistralException containing the status code. Inspect the response's Retry-After header and implement exponential back‑off before retrying.

Can I stream chat responses token by token?

Yes. Use the client.chatStream method, which returns a Stream of partial responses. Remember to handle cancellation and errors when consuming the stream.

Is there built‑in support for fine‑tuning models?

The package includes endpoints for managing fine‑tuned models. Refer to the official documentation on pub.dev for request/response models and usage examples.