aaroh_chat 1.3.0+3
aaroh_chat: ^1.3.0+3 copied to clipboard
Flutter chat SDK by Aaroh for AI-powered conversations, featuring built-in NLP, Claude API integration, and branding options.
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:aaroh_chat/aaroh_chat.dart';
import 'package:http/http.dart' as http;
void main() {
runApp(const ExampleApp());
}
class ExampleApp extends StatelessWidget {
const ExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Aaroh Chat SDK Example',
debugShowCheckedModeBanner: false,
theme: ThemeData(
colorSchemeSeed: Colors.deepPurple,
useMaterial3: true,
),
routes: {
'/pricing': (_) => const _PricingPage(),
},
home: const HomePage(),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// MULTILINGUAL KnowledgeItem HELPER
//
// The SDK's built-in engine and Claude system-prompt both use the `answer`
// field. To make the bot actually reply in the user's chosen language you
// need to supply separate answers for each locale.
//
// Pattern: create a helper that returns the right KnowledgeItem based on
// the current LanguageTone. Pass `language` as an argument so the config
// is rebuilt whenever the user switches languages.
// ─────────────────────────────────────────────────────────────────────────────
/// Returns a bilingual answer for [topic] based on [lang].
String _answer(LanguageTone lang, {required String en, required String hi, required String hinglish}) {
switch (lang) {
case LanguageTone.hindi:
return hi;
case LanguageTone.hinglish:
return hinglish;
case LanguageTone.english:
return en;
}
}
/// Builds a knowledge base that responds in the correct language.
///
/// Call this every time [lang] changes and pass the result into a new
/// [AarohConfig]. The SDK picks up the new answers automatically.
List<Object> buildKnowledgeBase(LanguageTone lang) {
return [
// ── Plain strings: quick facts ──────────────────────────────────────────
_answer(lang,
en: 'ShopMart is an e-commerce platform selling electronics, clothing and home goods.',
hi: 'ShopMart एक ई-कॉमर्स प्लेटफ़ॉर्म है जो इलेक्ट्रॉनिक्स, कपड़े और घर का सामान बेचता है।',
hinglish: 'ShopMart ek e-commerce platform hai jo electronics, kapde aur ghar ka saman bechta hai.',
),
// ── Structured KnowledgeItem entries ────────────────────────────────────
KnowledgeItem(
id: 'return-policy',
question: _answer(lang,
en: 'What is your return policy?',
hi: 'आपकी वापसी नीति क्या है?',
hinglish: 'Aapki return policy kya hai?',
),
answer: _answer(lang,
en: '30-day hassle-free returns, no questions asked.',
hi: '30 दिनों के अंदर बिना किसी सवाल के वापसी करें।',
hinglish: '30 din ke andar bina kisi sawaal ke return kar sakte hain.',
),
category: 'Policies',
keywords: ['refund', 'return', 'exchange', 'send back',
'वापसी', 'रिफंड', 'vapas', 'wapsi'],
),
KnowledgeItem(
id: 'delivery',
question: _answer(lang,
en: 'Is delivery free?',
hi: 'क्या डिलीवरी मुफ्त है?',
hinglish: 'Kya delivery free hai?',
),
answer: _answer(lang,
en: 'Yes — free delivery on all orders above ₹499.',
hi: 'हाँ — ₹499 से अधिक के सभी ऑर्डर पर मुफ्त डिलीवरी।',
hinglish: 'Haan — ₹499 se upar ke sabhi orders par free delivery milti hai.',
),
category: 'Shipping',
keywords: ['shipping', 'delivery', 'courier', 'डिलीवरी', 'शिपिंग'],
),
KnowledgeItem(
id: 'emi',
question: _answer(lang,
en: 'Do you offer EMI?',
hi: 'क्या EMI की सुविधा है?',
hinglish: 'Kya EMI available hai?',
),
answer: _answer(lang,
en: 'Yes — EMI available on orders above ₹2000 via all major banks.',
hi: 'हाँ — ₹2000 से अधिक के ऑर्डर पर सभी प्रमुख बैंकों के माध्यम से EMI उपलब्ध है।',
hinglish: 'Haan — ₹2000 se upar ke orders par sabhi major banks ke through EMI available hai.',
),
category: 'Payments',
keywords: ['emi', 'installment', 'किश्त', 'credit card'],
),
KnowledgeItem(
id: 'working-hours',
question: _answer(lang,
en: 'What are your working hours?',
hi: 'आपके काम के घंटे क्या हैं?',
hinglish: 'Aapke working hours kya hain?',
),
answer: _answer(lang,
en: 'Our support team is available Monday to Saturday, 9 AM – 7 PM IST.',
hi: 'हमारी सपोर्ट टीम सोमवार से शनिवार, सुबह 9 बजे से शाम 7 बजे IST तक उपलब्ध है।',
hinglish: 'Hamari support team Monday se Saturday, 9 AM – 7 PM IST tak available hai.',
),
category: 'Support',
keywords: ['hours', 'timing', 'time', 'समय', 'घंटे', 'support'],
),
];
}
// ─────────────────────────────────────────────────────────────────────────────
// CUSTOM API INTEGRATION
//
// Pass your own backend URL via [AarohConfig.customApiUrl] (or implement the
// [onCustomApiCall] callback pattern shown below). The SDK will POST the user
// message + conversation history to your endpoint and display the reply.
//
// YOUR API CONTRACT (expected request / response shape):
//
// POST https://your-api.com/chat
// Content-Type: application/json
// {
// "message": "User's latest message",
// "language": "english" | "hindi" | "hinglish",
// "history": [ { "role": "user"|"bot", "content": "..." }, ... ]
// }
//
// 200 OK
// { "reply": "Bot's response text" }
//
// Swap the URL and request/response shapes to match your actual backend.
// ─────────────────────────────────────────────────────────────────────────────
/// Calls your own API and returns the bot reply string.
///
/// The SDK's [onCustomApiCall] hook receives the typed user message,
/// the current [LanguageTone], and the chat [history] so your backend
/// can maintain context.
Future<String> callMyApi({
required String userMessage,
required LanguageTone language,
required List<Map<String, String>> history,
}) async {
const url = 'https://your-api.example.com/chat'; // ← replace with your URL
try {
final response = await http.post(
Uri.parse(url),
headers: {'Content-Type': 'application/json'},
body: jsonEncode({
'message': userMessage,
'language': language.name, // 'english' | 'hindi' | 'hinglish'
'history': history,
}),
);
if (response.statusCode == 200) {
final data = jsonDecode(response.body) as Map<String, dynamic>;
return data['reply'] as String? ?? 'Sorry, no reply received.';
} else {
return 'API error ${response.statusCode}: ${response.reasonPhrase}';
}
} catch (e) {
return 'Could not reach the server. Please check your connection.';
}
}
// ─────────────────────────────────────────────────────────────────────────────
// HOME PAGE — language picker + demo buttons
// ─────────────────────────────────────────────────────────────────────────────
class HomePage extends StatefulWidget {
const HomePage({super.key});
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
/// The currently selected language — drives ALL configs below.
LanguageTone _selectedLang = LanguageTone.english;
// ── Greeting per language ───────────────────────────────────────────────────
String get _greeting => switch (_selectedLang) {
LanguageTone.hindi => 'नमस्ते! मैं ShopMart का सहायक हूँ। कैसे मदद करूँ?',
LanguageTone.hinglish => 'Hello! Main ShopMart ka assistant hoon. Kaise help karun?',
_ => 'Hi! I am ShopMart\'s assistant. How can I help?',
};
// ── Config 1: Built-in engine with multilingual knowledge base ──────────────
AarohConfig get _builtInConfig => AarohConfig(
companyName: 'ShopMart',
selectedLanguage: _selectedLang, // ← tells the SDK which tone to use
knowledgeBase: buildKnowledgeBase(_selectedLang), // ← language-matched answers
botGreeting: _greeting,
enableFeedback: true,
enableAnalytics: true,
fallbackReply: _answer(_selectedLang,
en: "I'm not sure about that. Try asking about delivery, EMI or returns.",
hi: 'मुझे यह नहीं पता। डिलीवरी, EMI या वापसी के बारे में पूछें।',
hinglish: 'Mujhe yeh nahi pata. Delivery, EMI ya returns ke baare mein poochhen.',
),
);
// ── Config 2: Claude API + language-aware knowledge base ───────────────────
AarohConfig get _claudeConfig => AarohConfig(
companyName: 'ShopMart',
claudeApiKey: 'sk-ant-YOUR_KEY_HERE', // ← add your key
selectedLanguage: _selectedLang,
knowledgeBase: buildKnowledgeBase(_selectedLang),
botGreeting: _greeting,
// Claude will be instructed to reply in the selected language
// via the system prompt that the SDK builds automatically.
);
// ── Config 3: Your own custom API ──────────────────────────────────────────
AarohConfig get _customApiConfig => AarohConfig(
companyName: 'ShopMart',
selectedLanguage: _selectedLang,
knowledgeBase: buildKnowledgeBase(_selectedLang),
botGreeting: _greeting,
// Your API is wired in via the onCustomApiCall callback on pushAarohChat
// (see the button handler below). The SDK skips its own engines and
// streams your reply directly into the chat bubble.
);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Aaroh Chat SDK Demo'),
centerTitle: true,
),
body: Center(
child: SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 32),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
// ── Language picker ──────────────────────────────────────────
const Text(
'Select Language',
style: TextStyle(fontSize: 13, fontWeight: FontWeight.w500, color: Colors.grey),
),
const SizedBox(height: 8),
SegmentedButton<LanguageTone>(
segments: const [
ButtonSegment(value: LanguageTone.english, label: Text('English')),
ButtonSegment(value: LanguageTone.hindi, label: Text('हिंदी')),
ButtonSegment(value: LanguageTone.hinglish, label: Text('Hinglish')),
],
selected: {_selectedLang},
onSelectionChanged: (sel) => setState(() => _selectedLang = sel.first),
),
const SizedBox(height: 8),
// Tip explaining what the picker does
Text(
'Choosing a language updates the knowledge base answers\n'
'and tells the bot which language to reply in.',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 12, color: Colors.grey.shade600),
),
const Divider(height: 48),
// ── Demo 1: Built-in engine ──────────────────────────────────
_DemoCard(
icon: Icons.chat_bubble_outline,
color: Colors.deepPurple,
title: 'Built-in Engine',
subtitle: 'No API key needed. Answers come from your knowledge base in the chosen language.',
onTap: () => pushAarohChat(
context,
config: _builtInConfig,
onFeedback: (id, feedback, content, source) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text('Feedback: ${feedback.name}'),
));
},
),
),
const SizedBox(height: 16),
// ── Demo 2: Claude API ───────────────────────────────────────
_DemoCard(
icon: Icons.auto_awesome,
color: Colors.indigo,
title: 'Claude API',
subtitle: 'Claude reads your multilingual knowledge base and replies in the chosen language.',
onTap: () => pushAarohChat(
context,
config: _claudeConfig,
),
),
const SizedBox(height: 16),
// ── Demo 3: Custom API ───────────────────────────────────────
_DemoCard(
icon: Icons.cloud_outlined,
color: Colors.teal,
title: 'Custom API',
subtitle: 'Your own backend endpoint handles all responses. Message, language & history are forwarded.',
onTap: () => pushAarohChat(
context,
config: _customApiConfig,
// ← This callback fires for every user message.
// The SDK awaits the returned string and displays it
// as the bot reply. Returning null tells the SDK to
// fall back to its own built-in engine.
onCustomApiCall: (userMessage, language, history) =>
callMyApi(
userMessage: userMessage,
language: language,
history: history,
),
),
),
const Divider(height: 48),
// ── Embedded widget example ──────────────────────────────────
OutlinedButton.icon(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (_) => AarohChatWidget(
config: _builtInConfig,
),
),
),
icon: const Icon(Icons.open_in_new),
label: const Text('Embedded Widget'),
),
],
),
),
),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Small reusable card widget for the demo buttons
// ─────────────────────────────────────────────────────────────────────────────
class _DemoCard extends StatelessWidget {
const _DemoCard({
required this.icon,
required this.color,
required this.title,
required this.subtitle,
required this.onTap,
});
final IconData icon;
final Color color;
final String title;
final String subtitle;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Card(
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: BorderSide(color: color.withOpacity(0.3)),
),
child: InkWell(
borderRadius: BorderRadius.circular(12),
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16),
child: Row(
children: [
CircleAvatar(
backgroundColor: color.withOpacity(0.1),
child: Icon(icon, color: color),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title, style: const TextStyle(fontWeight: FontWeight.w600)),
const SizedBox(height: 4),
Text(subtitle,
style: TextStyle(fontSize: 12, color: Colors.grey.shade600)),
],
),
),
Icon(Icons.chevron_right, color: Colors.grey.shade400),
],
),
),
),
);
}
}
// ─────────────────────────────────────────────────────────────────────────────
// Dummy pricing page (for deep-link demo)
// ─────────────────────────────────────────────────────────────────────────────
class _PricingPage extends StatelessWidget {
const _PricingPage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Pricing')),
body: const Center(child: Text('Pro plan — ₹999/month')),
);
}
}