A comprehensive Dart/Flutter client for OpenAI's powerful AI models
Quick Start • Documentation • Examples • API Coverage • Contributing
Dart OpenAI is an unofficial but comprehensive client package that allows developers to easily integrate OpenAI's state-of-the-art AI models into their Dart/Flutter applications. The package provides simple, intuitive methods for making requests to OpenAI's various APIs, including GPT models, DALL-E image generation, Whisper audio processing, and more.
⚠️ Note: This is an unofficial package. OpenAI does not have an official Dart library.
- 🚀 Easy Integration - Simple, intuitive API that mirrors OpenAI's documentation
- 🔐 Secure Authentication - One-time setup, use anywhere in your application
- 📡 Streaming Support - Real-time streaming for completions, chat, and fine-tune events
- 🛠️ Developer Friendly - Comprehensive error handling and logging
- 📚 Rich Examples - Ready-to-use examples for every implemented feature
- 🎨 Modern UI Support - Optimized for Flutter applications
- 🔄 Custom APIs - Additional custom endpoints for enhanced functionality
Add the package to your pubspec.yaml:
dependencies:
dart_openai: import'package:dart_openai/dart_openai.dart';
voidmain() {
// Set your API keyOpenAI.apiKey ="your-api-key-here";
// Optional: Set organization IDOpenAI.organization ="your-org-id";
// Optional: Configure timeoutOpenAI.requestsTimeOut =Duration(seconds:60);
// Optional: Enable loggingOpenAI.showLogs =true;
runApp(MyApp());
}// Simple chat completionfinal chatCompletion =awaitOpenAI.instance.chat.create(
model:"gpt-3.5-turbo",
messages: [
OpenAIChatCompletionChoiceMessageModel(
role:OpenAIChatMessageRole.user,
content:"Hello, how are you?",
),
],
);
print(chatCompletion.choices.first.message.content);| API feature | Status | Details | Last Updated |
|---|---|---|---|
| 📋 Responses | ✅ Complete | All | 11-08-2025 17:33:39 |
| 💭 Conversations | ✅ Complete | All | 11-08-2025 17:38:56 |
| 🎵 Audio | ✅ Complete | All | 11-08-2025 17:42:54 |
| 🎬 Videos | 🗓️ planned | - | |
| 🎨 Images | ✅ Complete | All | 11-08-2025 17:53:45 |
| 🎨 Images Streaaming | 🗓️ planned | - | |
| 📊 Embeddings | ✅ Complete | All | 11-08-2025 17:56:30 |
| ⚖️ Evals | ✅ Complete | All | 11-08-2025 21:04:36 |
| 🔧 Fine-tuning | 🧩 70% Complete | missing newer endpoints | |
| 📊 Graders | ✅ Complete | All | 11-08-2025 21:46:48 |
| 📦 Batch | 🗓️ planned | - | |
| 📁 Files | ✅ Complete | All | 11-08-2025 21:51:34 |
| 📤 Uploads | 🗓️ planned | - | |
| 🤖 Models | ✅ Complete | All | 11-08-2025 21:53:13 |
| 🛡️ Moderation | ✅ Complete | All | 11-08-2025 21:54:01 |
| 🗃️ Vector Stores | ✅ Complete | All | 11-19-2025 12:24:15 |
| 💬 ChatKit | ❌ Not planned | Beta feature | |
| 📦 Containers | ✅ Complete | All | 11-19-2025 12:24:15 |
| 🕛 Real-time | 🗓️ planned | - | |
| 💬 Chat Completions | ✅ Complete | excluding stream functionality | |
| 🤖 Assistants | ❌ Not planned | beta feature | |
| 🤖 Administration | 🗓️ planned | - | |
| 📝 Completions (Legacy) | ✅ Complete | All | |
| ✏️ Edits (Legacy) | ✅ Complete | All |
// Create responseOpenAiResponse response =awaitOpenAI.instance.responses.create(
input:"Your input text here", model:"gpt-4",
);
// Get responseOpenAiResponse response =awaitOpenAI.instance.responses.get(
responseId:"response-id-here",
startingAfter:0, );
// Delete responseawaitOpenAI.instance.responses.delete(
responseId:"response-id-here",
);
// Cancel responseOpenAiResponse response =awaitOpenAI.instance.responses.cancel(
responseId:"response-id-here",
);
// list input itemsOpenAiResponseInputItemsList response =awaitOpenAI.instance.responses.listInputItems(
responseId:"response-id-here",
limit:10, );
// Get input token countsint inputTokens =awaitOpenAI.instance.responses.getInputTokenCounts(
model:"gpt-5",
input:"Your input text here",
);// Create conversationOpenAIConversation conversation =awaitOpenAI.instance.conversations.create(
items: [{
"type":"message",
"role":"user",
"content":"Hello!",
}],
metadata: {
"key":"value",
"another_key":"another_value",
},
);
// Get conversationOpenAIConversation conversation =awaitOpenAI.instance.conversations.get(
conversationId:"conversation-id-here",
);
// Update conversationOpenAIConversation updatedConversation =awaitOpenAI.instance.conversations.update(
conversationId:"conversation-id",
metadata: {
"key":"new_value",
},
);
// Delete conversationawaitOpenAI.instance.conversations.delete(
conversationId:"conversation-id-here",
);
// list itemsOpenAIConversationItemsResponse itemsList =awaitOpenAI.instance.conversations.listItems(
conversationId:"conversation-id-here",
limit:10, );
// Create itemOpenAIConversationItem item =awaitOpenAI.instance.conversations.createItems(
conversationId:"conversation-id-here",
items: [
// ...
],
);
// get itemOpenAIConversationItem item =awaitOpenAI.instance.conversations.getItem(
conversationId:"conversation-id-here",
itemId:"item-id-here",
);
// delete itemawaitOpenAI.instance.conversations.deleteItem(
conversationId:"conversation-id-here",
itemId:"item-id-here",
);// Create speechFile speechFile =awaitOpenAI.instance.audio.createSpeech(
model:"tts-1",
input:"Text to convert to speech",
voice:OpenAIAudioVoice.fable,
responseFormat:OpenAIAudioSpeechResponseFormat.mp3,
outputDirectory:"/path/to/output/directory",
outputFileName:"output_speech.mp3",
);
// Create speech as bytes (useful on web or when you do not want a temp file)Uint8List speechBytes =awaitOpenAI.instance.audio.createSpeechBytes(
model:"tts-1",
input:"Text to convert to speech",
voice:OpenAIAudioVoice.fable,
responseFormat:OpenAIAudioSpeechResponseFormat.mp3,
);
// Note: tts-1 and tts-1-hd only support alloy, ash, coral, echo, fable,// nova, onyx, sage, and shimmer. Use gpt-4o-mini-tts for newer voices// such as ballad, verse, marin, and cedar.// Transcribe audioOpenAITranscriptionGeneralModel transcription =awaitOpenAI.instance.audio.createTranscription(
model:"whisper-1",
file:File("path/to/audio.mp3"),
include: ["logprobs"],
responseFormat:OpenAIAudioResponseFormat.verbose_json,
language:"en",
prompt:"This is a sample prompt to guide transcription",
);
// Handling different transcription response formatsif (transcription isOpenAITranscriptionModel) {
print(transcription.logprobs);
print(transcription.text);
print(transcription.usage);
} elseif (transcription isOpenAITranscriptionVerboseModel) {
// print the transcription.print(transcription.text);
print(transcription.segments?.map((e) => e.end));
}
// Create Translationfinal translationText =awaitOpenAI.instance.audio.createTranslation(
file:File("path/to/audio.mp3"),
model:"whisper-1",
prompt:"use unusual english words",
responseFormat:OpenAIAudioResponseFormat.json,
);
// (To be implemented)
// Generate imageOpenAIImageModel image =awaitOpenAI.instance.image.create(
model:"dall-e-3",
prompt:"image of a cat in a spaceship",
responseFormat:OpenAIImageResponseFormat.url,
size:OpenAIImageSize.size1024,
quality:OpenAIImageQuality.standard,
style:OpenAIImageStyle.vivid,
);
// Edit imageOpenAIImageModel imageEdit =awaitOpenAI.instance.image.edit(
prompt:'A fantasy landscape with mountains and a river',
image:File("path/to/image.png"),
size:OpenAIImageSize.size1024,
responseFormat:OpenAIImageResponseFormat.b64Json,
);
// Create variationList<OpenAIImageModel> imageVariation =awaitOpenAI.instance.image.variation(
model:"dall-e-2",
image:File("path/to/image.png"),
size:OpenAIImageSize.size512,
responseFormat:OpenAIImageResponseFormat.url,
);// (To be implemented)
OpenAIEmbeddingsModel embedding =awaitOpenAI.instance.embedding.create(
model:"text-embedding-ada-002",
input:"This is a sample text",
);// Create evalOpenAIEval eval =awaitOpenAI.instance.evals.create(
dataSourceConfig:RequestDatatSourceConfig.logs(),
);
// Get evalOpenAIEval eval =awaitOpenAI.instance.evals.get(
evalId:"eval-id-here",
);
// Update evalOpenAIEval updatedEval =awaitOpenAI.instance.evals.update(
evalId:"eval-id-here",
metadata: {
"key":"new_value",
},
);
// Delete evalawaitOpenAI.instance.evals.delete(
evalId:"eval-id-here",
);
// List evalsOpenAIEvalsList evalsList =awaitOpenAI.instance.evals.list(
limit:10, );
// Get eval runs.OpenAIEvalRunsList evalRuns =awaitOpenAI.instance.evals.getRuns(
evalId:"eval-id-here",
limit:3, );
// Get Eval runOpenAIEvalRun evalRun =awaitOpenAI.instance.evals.getRun(
evalId:"eval-id-here",
runId:"run-id-here",
);
// Create runOpenAIEvalRun createdRun =awaitOpenAI.instance.evals.createRun(
evalId:"eval-id-here",
dataSource:EvalRunDataSource.jsonl(),
);
// Cancel runOpenAIEvalRun canceledRun =awaitOpenAI.instance.evals.cancel(
evalId:"eval-id-here",
runId:"run-id-here",
);
// Delete runawaitOpenAI.instance.evals.deleteRun(
evalId:"eval-id-here",
runId:"run-id-here",
);
// Get output item of eval run.OpenAIEvalRunOutputItem outputItem =awaitOpenAI.instance.evals.getEvalRunOutputItem(
evalId:"eval-id-here",
runId:"run-id-here",
outputItemIdn:"item-id-here",
);
// Get eval run output items.OpenAIEvalRunOutputItemsList outputItems =awaitOpenAI.instance.evals.getEvalRunOutputItems(
evalId:"eval-id-here",
runId:"run-id-here",
limit:10,
);// (To be implemented)
// gradersfinal grader =OpenAIGraders.stringCheckGrader(...);
final grader2 =OpenAIGraders.textSimilarityGrader(...);
final grader3 =OpenAIGraders.scoreModelGrader(...);
final grader4 =OpenAIGraders.labelModelGrader(...);
final grader5 =OpenAIGraders.pythonGrader(...);
final grader6 =OpenAIGraders.multiGrader(...);
// Run graderfinal grader =awaitOpenAI.instance.graders.runGrader(
grader: grader,
modelSample:"The model output to be graded", );
// Validate Graderfinal isValid =OpenAI.instance.graders.validateGrader(
grader: grader
);// (To be implemented)
// Upload fileOpenAIFileModel file =awaitOpenAI.instance.files.upload(
file:File("path/to/file.jsonl"),
purpose:"assistants",
);
// List filesList<OpenAIFileModel> files =awaitOpenAI.instance.files.list(
limit:10,
);
// Retrieve fileOpenAIFileModel file =awaitOpenAI.instance.files.retrieve(
"file_id" );
// Delete fileawaitOpenAI.instance.files.delete("file-id-here");
// Retrieve file contentfinal content =awaitOpenAI.instance.files.retrieveContent(
"file_id"
);// (To be implemented)
// List all available modelsList<OpenAIModelModel> models =awaitOpenAI.instance.model.list();
// Retrieve specific modelOpenAIModelModel model =awaitOpenAI.instance.model.retrieve("gpt-3.5-turbo");
// Delete fine-tuned modelbool deleted =awaitOpenAI.instance.model.delete("fine-tuned-model-id");OpenAIModerationModel moderation =awaitOpenAI.instance.moderation.create(
input: ["Text to classify for moderation"],
model:"omni-moderation-latest",
);// Create vector storeOpenAIVectorStoreModel vectorStore =awaitOpenAI.instance.vectorStores.vectorStores.create(
name:"example_vector_store",
chunkingStrategy:OpenAIVectorStoreChunkingStrategy.static(
chunkOverlapTokens:300,
maxChunkSizeTokens:750,
),
expiresAfter:OpenAIVectorStoreExpiresAfter(
anchor:"last_active_at",
days:1,
),
); // List vector storesOpenAIVectorStoreListModel allVEctorStores =awaitOpenAI.instance.vectorStores.vectorStores.list(limit:30);
// Get vector storefinal firstVectorStoreAsync =awaitOpenAI.instance.vectorStores.vectorStores.get(
vectorStoreId:"vector_store_id",
);
// Modify vector storefinal updatedVectorStore =awaitOpenAI.instance.vectorStores.vectorStores.modify(
vectorStoreId:"vector_store_id",
name:"updated_vector_store_name",
);
// Delete vector storeawaitOpenAI.instance.vectorStores.vectorStores.delete(
vectorStoreId:"vector_store_id",
);
// search in vector storefinal searchVEctorStoreResult =awaitOpenAI.instance.vectorStores.vectorStores.search(
vectorStoreId: updatedVectorStore.id,
query:"example",
maxNumResults:10,
filters:OpenAIVectorStoresSearchFilter.comparison(
type:"eq",
key:"metadata.example_key",
value:"example_value",
),
rankingOptions:OpenAIVectorStoresRankingOptions(
ranker:"none",
scoreThreshold:0,
),
);
// Create vector store filefinal createdVectorStoreFile =awaitOpenAI.instance.vectorStores.vectorStoresFiles.create(
vectorStoreId:"vector_store_id",
fileId:"file_id",
attributes: {
"chapter":"Chapter 1",
},
chunckingStrategy:OpenAIVectorStoreChunkingStrategy.static(
chunkOverlapTokens:300,
maxChunkSizeTokens:750,
),
);
// List vector store filesfinal vectorStoreFiles =awaitOpenAI.instance.vectorStores.vectorStoresFiles.list(
vectoreStoreId:"vector_store_id",
limit:60,
);
// Get vector store filefinal vectorStoreFile =awaitOpenAI.instance.vectorStores.vectorStoresFiles.get(
fileId:"file_id",
vectorStoreId:"vector_store_id",
);
// Get vector store file contentfinal vectorStoreFileContent =awaitOpenAI.instance.vectorStores.vectorStoresFiles.getContent(
fileId:"file_id",
vectorStoreId:"vector_store_id",
);
// Update vector store filefinal updatedVectorStoreFile =awaitOpenAI.instance.vectorStores.vectorStoresFiles.update(
fileId:"file_id",
vectorStoreId:"vector_store_id",
attributes: {
"chapter":"Updated Chapter 1",
},
);
// Delete vector store fileawaitOpenAI.instance.vectorStores.vectorStoresFiles.delete(
fileId:"file_id",
vectorStoreId:"vector_store_id",
);
// Create vector store file batchfinal vectoreStoreFileBatch =awaitOpenAI.instance.vectorStores.vectorStoreFileBatch.create(
vectorStoreId:"vector_store_id",
chunkingStrategy:OpenAIVectorStoreChunkingStrategy.static(
chunkOverlapTokens:200,
maxChunkSizeTokens:550,
),
attributes: {
"batch_name":"My First Batch",
},
fileIds: ["file-abc123", "file-def456"],
);
// Get vector store file batchfinal batch =awaitOpenAI.instance.vectorStores.vectorStoreFileBatch.get(
batchId:"batch_id",
vectorStoreId:"vector_store_id",
);
// Cancel vector store file batchfinal cancelledBatch =awaitOpenAI.instance.vectorStores.vectorStoreFileBatch.cancel(
batchId:"batch_id",
vectorStoreId:"vector_store_id",
);
// List vector store files in a batchfinal vectorStoreBatchFiles =awaitOpenAI.instance.vectorStores.vectorStoreFileBatch.list(
vectorStoreId:"vector_store_id",
batchId:'batch_id',
);
// Create containerfinal container =awaitOpenAI.instance.container.containers.create(
name:"my special container",
);
// List containersfinal containers =awaitOpenAI.instance.container.containers.list(
limit:20,
);
// Get containerfinal firstContainer =awaitOpenAI.instance.container.containers.get(
containerId:"container_id",
);
// Delete containerawaitOpenAI.instance.container.containers.delete(
containerId:"container_id",
);
// Create container filefinal containerFile =awaitOpenAI.instance.container.containerFiles.create(
file:File("path/to/file"),
containerId:"container_id",
);
// Get container filefinal gotContainerFile =awaitOpenAI.instance.container.containerFiles.get(
containerId:"container_id",
fileId:"file_id",
);
// Get container file contentfinal gotContainerFileContent =awaitOpenAI.instance.container.containerFiles.getContent(
containerId:"container_id",
fileId:"file_id",
);
// List container filesfinal allContainerFiles =awaitOpenAI.instance.container.containerFiles.list(
containerId:"container_id",
limit:20,
);
// Delete container fileawaitOpenAI.instance.container.containerFiles.delete(
fileId:"file_id",
containerId:"container_id",
);
// (To be implemented)
// Basic chat completionOpenAIChatCompletionModel chat =awaitOpenAI.instance.chat.create(
model:"gpt-3.5-turbo",
messages: [
OpenAIChatCompletionChoiceMessageModel(
role:OpenAIChatMessageRole.user,
content:"Hello, how can you help me?",
),
],
temperature:0.7,
maxTokens:150,
);
// Streaming chat completionStream<OpenAIStreamChatCompletionModel> chatStream =OpenAI.instance.chat.createStream(
model:"gpt-3.5-turbo",
messages: [
OpenAIChatCompletionChoiceMessageModel(
role:OpenAIChatMessageRole.user,
content:"Tell me a story",
),
],
);
chatStream.listen((event) {
print(event.choices.first.delta.content);
});// (To be implemented)
// Using envied package@Envied(path:".env")
abstractclassEnv {
@EnviedField(varName:'OPEN_AI_API_KEY')
staticconst apiKey =_Env.apiKey;
}
voidmain() {
OpenAI.apiKey =Env.apiKey;
runApp(MyApp());
}voidmain() {
// Set API keyOpenAI.apiKey ="your-api-key";
// Set organization (optional)OpenAI.organization ="your-org-id";
// Set custom base URL (optional)OpenAI.baseUrl ="https://api.openai.com/v1";
// Set request timeout (optional)OpenAI.requestsTimeOut =Duration(seconds:60);
// Enable logging (optional)OpenAI.showLogs =true;
OpenAI.showResponsesLogs =true;
runApp(MyApp());
}try {
final chat =awaitOpenAI.instance.chat.create(
model:"gpt-3.5-turbo",
messages: [
OpenAIChatCompletionChoiceMessageModel(
role:OpenAIChatMessageRole.user,
content:"Hello",
),
],
);
} onRequestFailedExceptioncatch (e) {
print("Request failed: ${e.message}");
print("Status code: ${e.statusCode}");
} onMissingApiKeyExceptioncatch (e) {
print("API key not set: ${e.message}");
} onUnexpectedExceptioncatch (e) {
print("Unexpected error: ${e.message}");
}We welcome contributions! Here's how you can help:
- Use GitHub Issues to report bugs
- Include reproduction steps and environment details
- Suggest new features via GitHub Issues
- Check existing issues before creating new ones
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
- Help improve documentation
- Add examples for missing features
- Fix typos and improve clarity
- Sponsor the project
- Help maintain and improve the package
This project is licensed under the MIT License - see the LICENSE file for details.
- OpenAI for providing the amazing AI models and APIs
- Contributors who help maintain and improve this package
- Sponsors who support the project financially
- Community for feedback and suggestions
Made with ❤️ by the Dart OpenAI community
⭐ Star this repo • 🐛 Report Bug • 💡 Request Feature • 📖 Documentation