> ## Documentation Index
> Fetch the complete documentation index at: https://liquidai-alay2shah-sync-notebook-snippets.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Cloud AI Comparison

> Compare LEAP Android SDK with cloud-based AI APIs like OpenAI

If you are familiar with cloud-based AI APIs (e.g. [OpenAI API](https://openai.com/api/)), this document
shows the similarity and differences between these clould APIs and Leap.

We will inspect this piece of Python-based OpenAI API chat completion request to figure out how to migrate it to LeapSDK.
This example code is modified from [OpenAI API documentation](https://platform.openai.com/docs/guides/streaming-responses?api-mode=chat).

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
from openai import OpenAI
client = OpenAI()

stream = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {
            "role": "user",
            "content": "Say 'double bubble bath' ten times fast.",
        },
    ],
    stream=True,
)

for chunk in stream:
    if chunk.choices:
        delta_content = chunk.choices[0].delta.get("content")
        if delta_content:
            print(delta_content, end="", flush=True)

print("")
print("Generation done!")
```

## Loading the model

While models can be directly used on the cloud-based APIs once the API client is created,
LeapSDK requires the developers to explicitly load the model before requesting the generation,
since the model will run locally. This step generally takes a few seconds
depending on the model size and the device performance.

On cloud API, you need to create a API client:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
client = OpenAI()
```

In LeapSDK, you need to download and load the model to create a model runner.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Using LeapModelDownloader (Android - recommended)
val downloader = LeapModelDownloader(context)
val modelRunner = downloader.loadModel(
    modelSlug = "LFM2.5-1.2B-Instruct",
    quantizationSlug = "Q4_K_M"
)

// OR using LeapDownloader (cross-platform)
val downloader = LeapDownloader()
val modelRunner = downloader.loadModel(
    modelSlug = "LFM2.5-1.2B-Instruct",
    quantizationSlug = "Q4_K_M"
)
```

The return value is a "model runner" which plays a similar role to the client object in the cloud API –
except that it carries the model weights. If the model runner is released, the app has to
reload the model before requesting new generations.

## Request for generation

In the cloud API calls, `client.chat.completions.create` will return a stream object for the
caller to fetch the generated contents.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
stream = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {
            "role": "user",
            "content": "Say 'double bubble bath' ten times fast.",
        },
    ],
    stream=True,
)
```

In LeapSDK for Android, we use `generateResponse` on
the conversation object to obtain a Kotlin flow (equivalent to a Python stream) for generation. Since
the model runner object contains all information about the model, we don't need to indicate the model name
in the call again.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
val conversation = modelRunner.createConversation()
val stream = conversation.generateResponse(
    ChatMessage(
        ChatMessage.Role.USER,
        listOf(ChatMessageContent.Text("Say 'double bubble bath' ten times fast."))
    )
)

// This simplified call has the exactly same effect of the above call
val stream = conversation.generateResponse("Say 'double bubble bath' ten times fast.")
```

## Process generated contents

In cloud API Python code, a for-loop on the stream object retrieves the contents.

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
for chunk in stream:
    if chunk.choices:
        delta_content = chunk.choices[0].delta.get("content")
        if delta_content:
            print(delta_content, end="", flush=True)

print("")
print("Generation done!")
```

In LeapSDK, we call `onEach` function on the Kotlin flow to process the content. When the completion is done, the
callback in `onCompletion` will be invoked. In the end, a call to `collect()` is necessary to start the generation.

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
stream.onEach { chunk ->
    when (chunk) {
        is MessageResponse.Chunk -> {
            print(chunk.text)
        }
        else -> {}
    }
}.onCompletion {
    print("")
    print("Generation done!")
}.collect()
```

## Coroutine scope

Hopefully by now it is clear how similar LeapSDK API is to cloud-based APIs. It is worth noting that most LeapSDK
Android APIs are based on [Kotlin coroutine](https://kotlinlang.org/docs/coroutines-basics.html). You will need to use
a coroutine scope to execute these functions. In Android, we recommend using `viewModelScope` in a ViewModel:

```kotlin theme={"theme":{"light":"github-light","dark":"github-dark"}}
class ChatViewModel(application: Application) : AndroidViewModel(application) {
    private val downloader = LeapModelDownloader(application)
    private var modelRunner: ModelRunner? = null
    private var conversation: Conversation? = null

    fun loadModelAndGenerate() {
        viewModelScope.launch {
            // Load model
            modelRunner = downloader.loadModel(
                modelSlug = "LFM2.5-1.2B-Instruct",
                quantizationSlug = "Q4_K_M"
            )

            // Create conversation
            conversation = modelRunner?.createConversation()

            // Generate response
            conversation?.generateResponse(
                ChatMessage(
                    ChatMessage.Role.USER,
                    listOf(ChatMessageContent.Text("Say 'double bubble bath' ten times fast."))
                )
            )?.onEach { chunk ->
                when (chunk) {
                    is MessageResponse.Chunk -> {
                        print(chunk.text)
                    }
                    else -> {}
                }
            }?.onCompletion {
                print("")
                print("Generation done!")
            }?.collect()
        }
    }

    override fun onCleared() {
        super.onCleared()
        runBlocking(Dispatchers.IO) {
            modelRunner?.unload()
        }
    }
}
```

## Next steps

For more information, please refer to the [quick start guide](./android-quick-start-guide).
