Sarvam Conversational AI SDK for Flutter

A Flutter SDK for building real-time voice-to-voice and text-based conversational AI applications with Sarvam AI agents.

Features

  • 🎤 Real-time voice conversations with automatic audio handling
  • 💬 Text-based chat interactions
  • 🌐 Support for 11 Indian languages
  • 🔒 Proxy server support for secure API key management
  • 📱 iOS and Android support

Installation

Add to your pubspec.yaml:

dependencies:
  sarvamconv_ai_sdk: ^1.0.0

Platform Setup

iOS - Add to ios/Runner/Info.plist:

<key>NSMicrophoneUsageDescription</key>
<string>This app needs microphone access for voice conversations</string>

Android - Add to android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />

Quick Start

Voice Conversation

import 'package:sarvamconv_ai_sdk/sarvamconv_ai_sdk.dart';

// 1. Create audio interface
final audioInterface = DefaultAudioInterface(inputSampleRate: 16000);

// 2. Create configuration
final config = InteractionConfig(
  orgId: 'your_org_id',
  workspaceId: 'your_workspace_id',
  appId: 'your_app_id',
  userIdentifier: 'user123',
  userIdentifierType: UserIdentifierType.custom,
  interactionType: InteractionType.call,
  sampleRate: 16000,
);

// 3. Create and start agent
final agent = SamvaadAgent(
  apiKey: 'your_api_key',
  config: config,
  audioInterface: audioInterface,
  textCallback: (msg) async {
    if (msg is ServerTextChunkMsg) {
      print('Agent: ${msg.text}');
    }
  },
  eventCallback: (event) async {
    if (event is ServerInteractionConnectedEvent) {
      print('Connected!');
    }
  },
);

await agent.start();
await agent.waitForConnect(timeout: Duration(seconds: 10));

// 4. Stop when done
await agent.stop();

Text Conversation

final config = InteractionConfig(
  orgId: 'your_org_id',
  workspaceId: 'your_workspace_id',
  appId: 'your_app_id',
  userIdentifier: 'user@example.com',
  userIdentifierType: UserIdentifierType.email,
  interactionType: InteractionType.chat, // Use chat for text
  sampleRate: 16000,
);

final agent = SamvaadAgent(
  apiKey: 'your_api_key',
  config: config,
  textCallback: (msg) async {
    if (msg is ServerTextMsg) {
      print('Agent: ${msg.text}');
    }
  },
);

await agent.start();
await agent.waitForConnect(timeout: Duration(seconds: 10));

// Send text messages
await agent.sendText('Hello, how can you help me?');

// Stop when done
await agent.stop();

Configuration Options

Field Type Required Description
orgId String Yes Your organization ID
workspaceId String Yes Your workspace ID
appId String Yes Your application ID
userIdentifier String Yes User identifier (email, phone, or custom)
userIdentifierType UserIdentifierType Yes .email, .phoneNumber, .custom, .unknown
interactionType InteractionType Yes .call (voice) or .chat (text)
sampleRate int Yes Audio sample rate: 8000, 16000, or 48000
version int? No App version (uses latest if not specified)
initialLanguageName SarvamToolLanguageName? No Starting language
agentVariables Map? No Custom variables for the agent

Supported Languages

SarvamToolLanguageName.english   // English
SarvamToolLanguageName.hindi     // Hindi
SarvamToolLanguageName.bengali   // Bengali
SarvamToolLanguageName.tamil     // Tamil
SarvamToolLanguageName.telugu    // Telugu
SarvamToolLanguageName.marathi   // Marathi
SarvamToolLanguageName.gujarati  // Gujarati
SarvamToolLanguageName.kannada   // Kannada
SarvamToolLanguageName.malayalam // Malayalam
SarvamToolLanguageName.punjabi   // Punjabi
SarvamToolLanguageName.odia      // Odia

Proxy Server Setup (Production)

For production apps, hide your API key using a proxy server:

┌─────────────────┐         ┌─────────────────┐         ┌─────────────────┐
│   Flutter App   │ ──────▶ │  Proxy Server   │ ──────▶ │   Sarvam API    │
│  (No API Key)   │         │ (Adds API Key)  │         │                 │
└─────────────────┘         └─────────────────┘         └─────────────────┘

Flutter Client (with Proxy)

final agent = SamvaadAgent(
  config: config,
  // No API key - proxy adds it
  baseUrl: 'https://your-proxy-server.com/sarvam-proxy/',
  headers: {
    'Authorization': 'Bearer user_session_token',
  },
  audioInterface: DefaultAudioInterface(),
);

Node.js Proxy Server

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();
const SARVAM_API_KEY = process.env.SARVAM_API_KEY;

app.use('/sarvam-proxy', createProxyMiddleware({
  target: 'https://apps.sarvam.ai/api/app-runtime',
  changeOrigin: true,
  pathRewrite: { '^/sarvam-proxy': '' },
  onProxyReq: (proxyReq, req, res) => {
    // Add API key
    proxyReq.setHeader('X-API-Key', SARVAM_API_KEY);
    
    // Verify user auth
    if (!req.headers['authorization']) {
      res.status(401).json({ error: 'Unauthorized' });
      return;
    }
  },
}));

app.listen(3000);

Python Proxy Server (FastAPI)

from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import StreamingResponse
import httpx
import os

app = FastAPI()
SARVAM_API_KEY = os.environ.get("SARVAM_API_KEY")

@app.api_route("/sarvam-proxy/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(request: Request, path: str):
    if not request.headers.get("Authorization"):
        raise HTTPException(status_code=401, detail="Unauthorized")
    
    target_url = f"https://apps.sarvam.ai/api/app-runtime/{path}"
    if request.query_params:
        target_url += f"?{request.query_params}"
    
    async with httpx.AsyncClient() as client:
        headers = dict(request.headers)
        headers["X-API-Key"] = SARVAM_API_KEY
        headers.pop("host", None)
        
        response = await client.request(
            method=request.method,
            url=target_url,
            headers=headers,
            content=await request.body(),
        )
        
        return StreamingResponse(
            content=response.iter_bytes(),
            status_code=response.status_code,
        )

Security Best Practices

  1. Always authenticate users before proxying requests
  2. Rate limit to prevent abuse
  3. Never commit .env files with API keys
  4. Validate request paths to only allow expected endpoints
# .env (never commit!)
SARVAM_API_KEY=sk_samvaad_your_api_key

Event Handling

eventCallback: (event) async {
  if (event is ServerInteractionConnectedEvent) {
    print('Connected: ${event.interactionId}');
  } else if (event is ServerInteractionEndEvent) {
    print('Call ended');
  } else if (event is ServerUserInterruptEvent) {
    print('User interrupted');
  } else if (event is ServerUserSpeechStartEvent) {
    print('User speaking...');
  } else if (event is ServerUserSpeechEndEvent) {
    print('User stopped speaking');
  }
}

Error Handling

try {
  await agent.start();
  
  final connected = await agent.waitForConnect(
    timeout: Duration(seconds: 10),
  );
  
  if (!connected) {
    throw Exception('Connection timeout');
  }
} catch (e) {
  print('Error: $e');
} finally {
  await agent.stop();
}

Cleanup

Always stop the agent when done:

@override
void dispose() {
  agent?.stop();
  super.dispose();
}

Example App

See the example app for a complete implementation with:

  • Voice call screen with real-time transcription
  • Settings management
  • Audio visualization

License

MIT License - see LICENSE for details.

Libraries

sarvamconv_ai_sdk