ai_abstracted
One set of contracts for generative AI, across many providers and every medium.
You pick a capability (text, image, video, speech, sound effect, or music), hand a typed request plus credentials to a provider client, and get back bytes with normalized metadata. The same shape works whether the bytes came from Gemini, Claude, OpenAI, Flux, Veo, ElevenLabs, or Suno. Switching providers is a constructor swap, not a rewrite.
It is pure Dart with no Flutter and no dart:io in the library, so it runs on
servers, the Dart VM, CLIs, and inside Flutter apps. It never writes files: you
decide how to store or cache what comes back.
Install
dart pub add ai_abstracted
import 'package:ai_abstracted/ai_abstracted.dart';
A first look
Every capability has an in-memory fake, so you can see the shape without a key or a network:
import 'package:ai_abstracted/ai_abstracted.dart';
Future<void> main() async {
final TextGenerator generator = FakeTextGenerator(text: 'Hello there.');
final result = await generator.generateText(
const TextRequest(prompt: 'Say hello.'),
);
print(result.text); // Hello there.
}
Moving to a real provider is the same call with a real client:
import 'dart:io';
import 'package:ai_abstracted/ai_abstracted.dart';
Future<void> main() async {
final credentials = credentialsFromEnv(ProviderId.claude, Platform.environment);
if (credentials == null) {
stderr.writeln('Set ANTHROPIC_API_KEY first.');
return;
}
final generator = ClaudeTextClient(credentials: credentials);
final result = await generator.generateText(
const TextRequest(
prompt: 'Write a one-line haiku about Dart.',
system: 'You reply with a single line.',
),
);
print(result.text);
}
Media comes back as bytes. You write them where you want:
import 'dart:io';
import 'package:ai_abstracted/ai_abstracted.dart';
Future<void> main() async {
final images = OpenAiImageClient(
credentials: const ProviderCredentials(apiKey: 'sk-...'),
);
final result = await images.generateImage(
const ImageRequest(prompt: 'a red bicycle on a white wall', width: 1024, height: 1024),
);
await File('bicycle.png').writeAsBytes(result.bytes);
}
Capabilities and providers
| Medium | Providers |
|---|---|
| Text | Gemini, Claude, Mistral, Ollama |
| Image | Gemini, OpenAI, Flux |
| Video | Veo (Veo 3 includes audio) |
| Speech | ElevenLabs |
| Sound effect | ElevenLabs |
| Music | Suno (via sunoapi.org) |
Each provider has its own page with setup, examples, and tips. See the provider directory.
What you get
- Typed requests and one
GenerationResult(bytes, MIME type, kind, metadata) for every medium. - A typed error hierarchy that maps HTTP failures to
AiAuthException,AiRateLimitException,AiInvalidRequestException, and friends. - Built-in retries with backoff, and polling for the providers that run long jobs (Veo, Flux, Suno).
- An in-memory fake per capability, so your code stays testable without a network or keys.
- A provider registry for choosing a provider at runtime, and an environment credential loader.
Documentation
The full documentation lives in doc/ and is published at
simonerich.github.io/dart_ai_abstracted/.
Good places to start:
- Installation
- Your first request
- Core concepts
- Provider directory
- Testing with fakes
- Writing your own provider
Example
A runnable example lives in example/main.dart. It uses a
fake, so it runs offline:
dart run example/main.dart
Contributing
Contributions are welcome, especially new providers. See CONTRIBUTING.md for the setup, the quality checks, and how the commit messages are formatted. If you add a provider for your own project, a pull request means everyone else can use it too.
License
MIT. See LICENSE.
Libraries
- ai_abstracted
- Provider-agnostic generative AI: one set of contracts for text, image, video, speech, sound-effect, and music generation across many providers.