Addis AI

Mobile Applications

Build voice-first mobile apps with Flutter, React Native, and Kotlin.

Mobile apps are the primary way users interact with technology in Africa. Addis AI provides the low-latency infrastructure needed to build responsive Chat and Voice applications on mobile networks.

Use the backend SDKs

Addis AI provides official Node.js and Python SDKs for your backend. Mobile applications should use standard clients (http for Dart, fetch for React Native, or OkHttp for Kotlin) to call that backend proxy.

Security: APKs are Public

Do not embed keys in your App

Mobile applications (APKs/IPAs) can be decompiled. If you hardcode your sk_ key in your Flutter or Android code, it will be stolen.

Pattern: Mobile App ➝ Your Backend (Secure) ➝ Addis AI API.


Integration Patterns

These examples call a developer-owned backend. That backend uses the official Node.js or Python SDK and keeps the Addis AI key private.

Flutter (Dart)

Flutter is the dominant framework in our ecosystem. Use the http package.

import 'dart:convert';
import 'package:http/http.dart' as http;

Future<String> generateText(String prompt) async {
  // Call your authenticated backend.
  final url = Uri.parse('https://your-backend.com/api/chat');
  
  // 2. Prepare payload
  final body = jsonEncode({
    "message": prompt
  });

  // 3. Send Request
  try {
    final response = await http.post(
      url,
      headers: {"Content-Type": "application/json"},
      body: body,
    );

    if (response.statusCode == 200) {
      final data = jsonDecode(response.body);
      return data['response_text'];
    } else {
      throw Exception('Failed to load: ${response.statusCode}');
    }
  } catch (e) {
    return "Error: $e";
  }
}

Addis Voices 2 returns a signed clip URL through your backend. Dependency: audioplayers

import 'package:audioplayers/audioplayers.dart';

Future<void> playVoice2Clip(String audioUrl) async {
  final player = AudioPlayer();
  await player.play(UrlSource(audioUrl));
}

Playing Base64 audio in Flutter requires decoding to bytes. Dependencies: audioplayers, path_provider

import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:path_provider/path_provider.dart';
import 'package:audioplayers/audioplayers.dart';

Future<void> playBase64Audio(String base64String) async {
  // 1. Decode Base64
  Uint8List bytes = base64Decode(base64String);

  // 2. Save to temporary file
  final dir = await getTemporaryDirectory();
  final file = File('${dir.path}/speech.wav');
  await file.writeAsBytes(bytes);

  // 3. Play
  final player = AudioPlayer();
  await player.play(DeviceFileSource(file.path));
}

React Native

Similar to the web, but ensure you handle network permissions on Android.

const chatWithAddis = async (userMessage) => {
  try {
    const response = await fetch('https://your-backend.com/api/chat', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        message: userMessage
      }),
    });

    const json = await response.json();
    console.log(json.response_text);
    return json.response_text;
    
  } catch (error) {
    console.error(error);
  }
};

Android (Kotlin)

Using OkHttp for networking.

val client = OkHttpClient()
val JSON = "application/json; charset=utf-8".toMediaType()

fun chat(prompt: String) {
    val jsonBody = """
        {
            "message": "$prompt"
        }
    """.trimIndent()

    val body = RequestBody.create(JSON, jsonBody)
    val request = Request.Builder()
        .url("https://your-backend.com/api/chat")
        .post(body)
        .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            e.printStackTrace()
        }

        override fun onResponse(call: Call, response: Response) {
            response.use {
                if (!response.isSuccessful) throw IOException("Unexpected code $response")
                println(response.body!!.string())
            }
        }
    })
}

Handling Audio (TTS)

Addis Voices 2 returns a completed clip with a signed audio URL. Your backend should return that URL—or proxy the clip after authorizing the user—and the mobile app can pass it to its native player.

final player = AudioPlayer();
await player.play(UrlSource(response.audioUrl));

Legacy Voice 1

The Base64 workflow below is preserved for existing Voice 1 applications. New applications should use Text-to-Speech; see the Legacy Text-to-Speech guide only when maintaining the retired response format.

Legacy Voice 1 returns a Base64 string, not a URL.

Strategy

Since you cannot stream Base64 directly into most native media players easily:

  1. Decode the Base64 string to a Byte Array.
  2. Write the bytes to a temporary file (cache directory).
  3. Play the file using the device's native player.

Caching

Mobile data in Africa can be expensive. Always cache the audio file locally. Hash the input text to create a filename key. If the user requests the same text again, play the local file instead of calling the API.

Best Practices

  • Permissions: If using Speech-to-Text, remember to request Microphone Permission (android.permission.RECORD_AUDIO / NSMicrophoneUsageDescription) in your manifest/plist.
  • Timeouts: Mobile networks fluctuate. Set your connection timeouts to at least 30 seconds to avoid SocketTimeoutExceptions during long generations.
  • Background Threading: Network requests (especially file uploads) should never run on the UI thread. Use Isolates in Flutter or Coroutines in Kotlin to keep your UI responsive.

On this page