sarufi 1.0.0
sarufi: ^1.0.0 copied to clipboard
A modern, null-safe Dart & Flutter SDK for the Sarufi Conversational AI platform - build, train and chat with Swahili-first chatbots.
Sarufi - Dart & Flutter SDK #
A modern, null-safe Dart SDK for the Sarufi Conversational AI platform. Build, train and chat with Swahili-first chatbots from any Dart or Flutter app: mobile, desktop, web, server or CLI.
final sarufi = Sarufi('YOUR_API_KEY');
final bot = await sarufi.getBot(42);
final reply = await bot.respond(message: 'Habari');
print(reply.messages); // ['Habari yako? Karibu Weledi']
Why this SDK #
- API-key auth - one line to get started.
- Typed models -
Bot,ChatResponse,ChatState,IntentPrediction; no more digging through raw maps. - Typed errors - a
sealedSarufiExceptionhierarchy you can exhaustivelyswitchon. - Self-documenting -
print(SarufiDocs.chat)prints an endpoint's fields and an example, right in your terminal. - Testable - inject your own
http.Client; unit tests never touch the network. - Pure Dart - no Flutter dependency, so it runs everywhere Dart does.
Contents #
- Install
- Quick start
- Authentication
- Creating bots
- Conversations
- The
Botobject - Self-documenting API
- Error handling
- Logging
- Testing
- API reference
- Examples
- Other Sarufi SDKs
Install #
dart pub add sarufi # or: flutter pub add sarufi
dependencies:
sarufi: ^1.0.0
Then import it:
import 'package:sarufi/sarufi.dart';
Quick start #
import 'package:sarufi/sarufi.dart';
Future<void> main() async {
final sarufi = Sarufi('YOUR_API_KEY');
// Create a bot with intents (example phrases) and a flow (state machine).
final bot = await sarufi.createBot(
name: 'Weledi Bot',
description: 'A friendly Swahili student assistant',
intents: {
'salamu': ['habari', 'mambo', 'hi'],
},
flow: {
'salamu': {
'message': ['Habari! Karibu Weledi'],
'next_state': 'end',
},
},
);
// Chat with it.
final reply = await bot.respond(message: 'Habari');
print(reply.messages); // ['Habari! Karibu Weledi']
print(reply.nextState); // 'end'
sarufi.close(); // release the HTTP client when you're done
}
Authentication #
Grab an API key from the Sarufi dashboard and pass it to the
constructor. Every request is authenticated with a Bearer token automatically.
final sarufi = Sarufi(
'YOUR_API_KEY',
timeout: const Duration(seconds: 30), // optional (default: 120s)
);
Creating bots #
Bots are defined by intents (a map of intent name to example phrases) and a flow (the conversation state machine).
final bot = await sarufi.createBot(
name: 'iBank',
industry: 'banking',
intents: {
'greeting': ['habari', 'mambo', 'hi'],
'balance': ['angalia salio', 'check my balance'],
},
flow: {
'greeting': {
'message': ['Karibu iBank! Naweza kukusaidiaje?'],
'next_state': 'end',
},
},
);
From JSON / YAML files #
Keep your training data in files and load it with the IO helper (uses dart:io,
so it's available everywhere except Flutter web):
import 'package:sarufi/sarufi.dart';
import 'package:sarufi/sarufi_io.dart';
final bot = await sarufi.createFromFile(
intents: 'data/intents.yaml',
flow: 'data/flow.yaml',
metadata: 'data/metadata.json', // name, description, industry, ...
);
// Re-upload after editing the files:
await sarufi.updateFromFile(id: bot.id!, flow: 'data/flow.yaml');
Conversations #
// Reuse a chat id to keep context across turns.
const chatId = 'user-123';
await sarufi.chat(botId: 42, chatId: chatId, message: 'Habari');
await sarufi.chat(botId: 42, chatId: chatId, message: 'Nataka kukopa');
// Where are we in the flow?
final state = await sarufi.chatStatus(botId: 42, chatId: chatId);
print('${state.currentState} -> ${state.nextState}');
// Classify a message without advancing the conversation.
final p = await sarufi.predictIntent(botId: 42, message: 'nataka salio langu');
print('${p.intent} (${p.confidence})');
// Send over WhatsApp instead of the default channel.
await sarufi.chat(botId: 42, message: 'Hi', channel: Channel.whatsapp);
The Bot object #
getBot, bots, createBot and updateBot all return a Bot: a typed
wrapper you can act on directly. Mutating helpers call the API and return a
fresh Bot (no hidden network calls behind a plain setter).
final bot = await sarufi.getBot(42);
bot.name; // 'Weledi Bot'
bot.intents; // Map<String, dynamic>?
bot.flows; // Map<String, dynamic>?
await bot.respond(message: 'Habari'); // ChatResponse
await bot.predictIntent('nataka kozi'); // IntentPrediction
final trained = await bot.addIntent({'bye': ['kwaheri']}); // updated Bot
final renamed = await bot.rename('Weledi v2'); // updated Bot
await bot.delete();
Self-documenting API #
Every operation ships with inline docs, no browser needed. Print one endpoint, or all of them:
print(SarufiDocs.chat);
┌─ chat
│ POST conversation
│ Send a message to a bot and get its reply.
│
│ Set channel to whatsapp to route through the conversation/whatsapp
│ endpoint. Reuse chat_id across turns to keep conversation context.
│
│ Request body:
│ bot_id number required
│ chat_id string optional Conversation session id (auto-generated if omitted).
│ message string required
│ message_type string optional [text, image, audio, video, file]
│
│ Response:
│ message array optional The bot's replies.
│ next_state string optional The state moved to.
│
│ Example:
│ final reply = await sarufi.chat(botId: 42, chatId: 'user-1', message: 'Habari');
│ print(reply.messages);
└─
print(Sarufi.docs); // every operation, in reading order
Error handling #
Every call throws a typed SarufiException on failure. The base type is
sealed, so a switch is exhaustive and the analyzer keeps you honest:
try {
await sarufi.getBot(42);
} on SarufiException catch (e) {
final reason = switch (e) {
SarufiAuthException() => 'Check your API key',
SarufiNotFoundException() => 'That bot does not exist',
SarufiValidationException() => 'Bad request: ${e.message}',
SarufiNetworkException() => 'No connection',
SarufiServerException() => 'Sarufi is having a bad day',
SarufiApiException() => e.message,
};
print(reason);
}
Each exception carries message, statusCode and the decoded body.
Logging #
Nothing is printed by default. Turn on diagnostics during development:
Sarufi.enableConsoleLogging(); // built on the `logging` package
Testing #
Inject a mock http.Client and your integration never hits the network:
import 'package:http/testing.dart';
final sarufi = Sarufi(
'test-key',
httpClient: MockClient((req) async => http.Response('{"id":1}', 200)),
);
API reference #
| Method | HTTP | Returns |
|---|---|---|
createBot(...) |
POST chatbot |
Bot |
updateBot(id, ...) |
PUT chatbot/{id} |
Bot |
getBot(id) |
GET chatbot/{id} |
Bot |
bots() |
GET chatbots |
List<Bot> |
deleteBot(id) |
DELETE chatbot/{id} |
Map |
chat(...) |
POST conversation |
ChatResponse |
chatStatus(...) |
POST conversation/status |
ChatState |
updateConversationState(...) |
POST conversation-state |
Map |
predictIntent(...) |
POST predict/intent |
IntentPrediction |
Base URL: https://developers.sarufi.io/.
Examples #
Runnable examples live in example/:
| Example | What it shows |
|---|---|
example.dart |
End-to-end tour: create, chat, list, train, delete |
weledi/ |
Flagship - a bilingual student bot: browse courses, enroll, pay |
insurance/ |
Build an insurance bot from JSON files |
kubeti/ |
Swahili betting bot, created/updated from JSON |
dart run example/weledi/weledi.dart
Other Sarufi SDKs #
Prefer another language? Sarufi has official and community SDKs:
- Dart & Flutter - this package
- Python - sarufi-python-sdk
Credits #
Built and maintained by Brightius Kalokola at TRIXA. Thanks to the Sarufi and Neurotech Africa team for the platform.
Support #
Please open an issue on GitHub, or contact the maintainer at brightius@trixa.net
Licensed under the MIT License.