/** * Millisa AI Client for Android (Kotlin) * ───────────────────────────────────────────────────────────────────────────── * Dependency: com.squareup.okhttp3:okhttp:4.12.0 * org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0 * com.google.code.gson:gson:2.10.1 */ package com.example.millisa import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import okhttp3.MediaType.Companion.toMediaType import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.RequestBody.Companion.toRequestBody import org.json.JSONArray import org.json.JSONObject import java.io.IOException import java.util.concurrent.TimeUnit class MillisaClient( private val apiKey: String, private val baseUrl: String = "https://millisa.codly.in/api/v1" ) { private val client = OkHttpClient.Builder() .connectTimeout(30, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .build() private val jsonMediaType = "application/json; charset=utf-8".toMediaType() /** * Send a query to Millisa AI Agent * * @param prompt The message or question for Millisa * @param model Model to use (e.g., "millisa-auto", "millisa-gemini-flash", "millisa-gpt-4o-mini") * @return The text response from Millisa */ suspend fun queryAgent(prompt: String, model: String = "millisa-auto"): Result { return withContext(Dispatchers.IO) { try { val payload = JSONObject().apply { put("prompt", prompt) put("model", model) } val request = Request.Builder() .url("$baseUrl/agent/query") .addHeader("Authorization", "Bearer $apiKey") .addHeader("Content-Type", "application/json") .post(payload.toString().toRequestBody(jsonMediaType)) .build() val response = client.newCall(request).execute() val responseBody = response.body?.string() ?: "" if (!response.isSuccessful) { val errorMsg = try { JSONObject(responseBody).getJSONObject("error").getString("message") } catch (e: Exception) { "HTTP ${response.code}: $responseBody" } return@withContext Result.failure(IOException(errorMsg)) } val json = JSONObject(responseBody) val reply = json.optString("response", "No response received.") Result.success(reply) } catch (e: Exception) { Result.failure(e) } } } /** * Send OpenAI-compatible multi-turn Chat Completion */ suspend fun chatCompletion( messages: List>, // role to content model: String = "millisa-auto" ): Result { return withContext(Dispatchers.IO) { try { val jsonMessages = JSONArray() for ((role, content) in messages) { jsonMessages.put(JSONObject().apply { put("role", role) put("content", content) }) } val payload = JSONObject().apply { put("model", model) put("messages", jsonMessages) } val request = Request.Builder() .url("$baseUrl/chat/completions") .addHeader("Authorization", "Bearer $apiKey") .addHeader("Content-Type", "application/json") .post(payload.toString().toRequestBody(jsonMediaType)) .build() val response = client.newCall(request).execute() val body = response.body?.string() ?: "" if (!response.isSuccessful) { return@withContext Result.failure(IOException("Error ${response.code}: $body")) } val reply = JSONObject(body) .getJSONArray("choices") .getJSONObject(0) .getJSONObject("message") .getString("content") Result.success(reply) } catch (e: Exception) { Result.failure(e) } } } } // ───────────────────────────────────────────────────────────────────────────── // Usage Example in Android ViewModel / Activity / Jetpack Compose: // ───────────────────────────────────────────────────────────────────────────── /* val millisa = MillisaClient(apiKey = "mls_live_YOUR_MILLISA_API_KEY") lifecycleScope.launch { val result = millisa.queryAgent("Hello Millisa, how do I build a modern Android UI?") result.onSuccess { reply -> println("Millisa replied: $reply") }.onFailure { error -> println("Error connecting to Millisa: ${error.message}") } } */