uncloseai.

Kotlin Examples - Free LLM & TTS AI Service

Kotlin Examples

This page demonstrates how to use the uncloseai. API endpoints with Kotlin using the openai-kotlin community library. All examples use the same OpenAI-compatible API interface, making it easy to switch between different models and endpoints.

Available Endpoints:

Both chat hostnames currently serve the same model, turboderp/Qwen3.8-27B-exl3 (read live from /v1/models). Hostnames are routing labels, not model names: every example below asks the endpoint which model it serves instead of hard-coding an id, so a model swap on the cards never breaks your code. The served model reasons before it answers (the reasoning arrives in a separate reasoning field), so give it room: the samples ask for 600 tokens because at 150 the budget ran out before the answer began.

Many endpoints from environment variables

Our clients (uncloseai-cli, uncloseai.js, opencompletion and the downloadable implementation for every language on this site) share one convention, so an endpoint is configuration, never code:

VariableMeaning
MODEL_ENDPOINT_NBase URL of the N-th OpenAI-compatible endpoint, ending in /v1. The only required variable. Scan N from 0 upward and skip gaps: uncloseai-cli counts from 0, the per-language implementations from 1.
MODEL_API_KEY_NBearer key for endpoint N. Unset means no key, which is all our free relay needs; a cloud endpoint sets one.
MODEL_ID_NModel id to send. Unset means ask /v1/models and take the first id, the rule used by every sample on this page.
MODEL_LABEL_NA display name for endpoint N; defaults to its hostname.
TTS_ENDPOINT_NThe same shape for text-to-speech endpoints.
export MODEL_ENDPOINT_0="https://hermes.ai.unturf.com/v1"
export MODEL_ENDPOINT_1="https://qwen.ai.unturf.com/v1"
# export MODEL_API_KEY_1="sk-..."      # only for an endpoint that needs one
export TTS_ENDPOINT_0="https://speech.ai.unturf.com/v1"

The first endpoint is the default; the rest fail over, in order. The Kotlin implementation under /languages/ reads these variables and discovers each endpoint's models at startup.

Kotlin Client Installation

Add openai-kotlin to your build.gradle.kts:

dependencies {
    implementation("com.aallam.openai:openai-client:3.8.2")
    implementation("io.ktor:ktor-client-okhttp:2.3.12")
}

Non-Streaming Examples

Non-streaming mode waits for the complete response before returning. This is simpler to use but provides no intermediate feedback during generation.

Using hermes.ai.unturf.com (RTX 4090)

import com.aallam.openai.api.chat.*
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.aallam.openai.client.OpenAIHost

suspend fun main() {
    val openAI = OpenAI(
        OpenAIConfig(
            token = "choose-any-value",
            host = OpenAIHost("https://hermes.ai.unturf.com/v1")
        )
    )

    // Ask the endpoint which model it serves; never hard-code an id.
    val model = openAI.models().first().id

    val chatCompletionRequest = ChatCompletionRequest(
        model = model,
        messages = listOf(
            ChatMessage(
                role = ChatRole.User,
                content = "Give a Python Fizzbuzz solution in one line of code?"
            )
        ),
        temperature = 0.5,
        maxTokens = 600
    )

    val completion = openAI.chatCompletion(chatCompletionRequest)
    println(completion.choices[0].message.content)
}

Using qwen.ai.unturf.com (RTX 3090)

import com.aallam.openai.api.chat.*
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.aallam.openai.client.OpenAIHost

suspend fun main() {
    val openAI = OpenAI(
        OpenAIConfig(
            token = "choose-any-value",
            host = OpenAIHost("https://qwen.ai.unturf.com/v1")
        )
    )

    // Ask the endpoint which model it serves; never hard-code an id.
    val model = openAI.models().first().id

    val chatCompletionRequest = ChatCompletionRequest(
        model = model,
        messages = listOf(
            ChatMessage(
                role = ChatRole.User,
                content = "Give a Python Fizzbuzz solution in one line of code?"
            )
        ),
        temperature = 0.5,
        maxTokens = 600
    )

    val completion = openAI.chatCompletion(chatCompletionRequest)
    println(completion.choices[0].message.content)
}

Streaming Examples

Streaming mode returns chunks of the response as they are generated, providing real-time feedback. This is ideal for interactive applications and long responses.

Using hermes.ai.unturf.com (RTX 4090)

import com.aallam.openai.api.chat.*
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.aallam.openai.client.OpenAIHost
import kotlinx.coroutines.flow.collect

suspend fun main() {
    val openAI = OpenAI(
        OpenAIConfig(
            token = "choose-any-value",
            host = OpenAIHost("https://hermes.ai.unturf.com/v1")
        )
    )

    // Ask the endpoint which model it serves; never hard-code an id.
    val model = openAI.models().first().id

    val chatCompletionRequest = ChatCompletionRequest(
        model = model,
        messages = listOf(
            ChatMessage(
                role = ChatRole.User,
                content = "Give a Python Fizzbuzz solution in one line of code?"
            )
        ),
        temperature = 0.5,
        maxTokens = 600
    )

    openAI.chatCompletions(chatCompletionRequest).collect { chunk ->
        chunk.choices.forEach { choice ->
            choice.delta.content?.let { print(it) }
        }
    }
}

Using qwen.ai.unturf.com (RTX 3090)

import com.aallam.openai.api.chat.*
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.aallam.openai.client.OpenAIHost
import kotlinx.coroutines.flow.collect

suspend fun main() {
    val openAI = OpenAI(
        OpenAIConfig(
            token = "choose-any-value",
            host = OpenAIHost("https://qwen.ai.unturf.com/v1")
        )
    )

    // Ask the endpoint which model it serves; never hard-code an id.
    val model = openAI.models().first().id

    val chatCompletionRequest = ChatCompletionRequest(
        model = model,
        messages = listOf(
            ChatMessage(
                role = ChatRole.User,
                content = "Give a Python Fizzbuzz solution in one line of code?"
            )
        ),
        temperature = 0.5,
        maxTokens = 600
    )

    openAI.chatCompletions(chatCompletionRequest).collect { chunk ->
        chunk.choices.forEach { choice ->
            choice.delta.content?.let { print(it) }
        }
    }
}

Text-to-Speech Example

Generate audio speech from text using the TTS endpoint. The audio is saved as an MP3 file.

import com.aallam.openai.api.audio.SpeechRequest
import com.aallam.openai.api.audio.Voice
import com.aallam.openai.api.model.ModelId
import com.aallam.openai.client.OpenAI
import com.aallam.openai.client.OpenAIConfig
import com.aallam.openai.client.OpenAIHost
import java.io.File

suspend fun main() {
    val openAI = OpenAI(
        OpenAIConfig(
            token = "YOLO",
            host = OpenAIHost("https://speech.ai.unturf.com/v1")
        )
    )

    val speechRequest = SpeechRequest(
        model = ModelId("tts-1-f5"),
        input = "I think so therefore, Today is a wonderful day to grow something people love!",
        voice = Voice("foxhop"),
        speed = 0.9
    )

    val speech = openAI.speech(speechRequest)
    File("speech.mp3").writeBytes(speech)
}