KKiosapi.id

← Dokumentasi

Panduan Java

Kiosapi kompatibel OpenAI lewat REST biasa. Contoh di bawah pakai java.net.http.HttpClient bawaan JDK 11+ (tanpa dependensi eksternal) — gampang diadaptasi ke Jackson/Gson kalau proyek Anda sudah memakainya.

Daftar isi

1. Persiapan

Masuk ke dashboard → Kunci API, beri nama, klik Buat key, salin kios_live_… (ditampilkan sekali). Butuh JDK 11+ untuk java.net.http.

Keamanan: panggil API dari server, bukan dari kode client-side. Simpan key sebagai environment variable, jangan hardcode.
export KIOSAPI_API_KEY="kios_live_xxxxxxxxxxxx"

2. Fungsi helper request

Contoh JSON manual pakai string builder sederhana — di proyek nyata, pakai Jackson (ObjectMapper) atau Gson untuk serialisasi yang lebih rapi.

import java.net.URI;
import java.net.http.*;
import java.net.http.HttpResponse.BodyHandlers;

public class Kiosapi {
    static final String BASE = "https://api.kiosapi.id/v1";
    static final String API_KEY = System.getenv("KIOSAPI_API_KEY");
    static final HttpClient client = HttpClient.newHttpClient();

    static String post(String path, String jsonBody) throws Exception {
        var req = HttpRequest.newBuilder(URI.create(BASE + path))
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(jsonBody))
            .build();
        var res = client.send(req, BodyHandlers.ofString());
        if (res.statusCode() >= 400) throw new RuntimeException("Kiosapi error " + res.statusCode() + ": " + res.body());
        return res.body();
    }

    static String get(String path) throws Exception {
        var req = HttpRequest.newBuilder(URI.create(BASE + path))
            .header("Authorization", "Bearer " + API_KEY)
            .GET().build();
        return client.send(req, BodyHandlers.ofString()).body();
    }
}

Model ID berformat provider/nama-model — lihat daftar lengkap via GET /v1/models atau /pricing.

3. Chat completion dasar

var body = """
  {"model":"anthropic/claude-sonnet-4-6",
   "messages":[
     {"role":"system","content":"Kamu asisten yang ringkas dan ramah."},
     {"role":"user","content":"Jelaskan apa itu RAG dalam 2 kalimat."}
   ]}
  """;
String json = Kiosapi.post("/chat/completions", body);
System.out.println(json); // parse dengan Jackson/Gson untuk ambil choices[0].message.content

4. Streaming

Tambahkan "stream": true dan konsumsi respons per-baris (SSE) lewat BodyHandlers.ofLines().

var body = """
  {"model":"deepseek/deepseek-v4-flash",
   "messages":[{"role":"user","content":"Tulis puisi pendek tentang hujan di Jakarta."}],
   "stream":true}
  """;
var req = HttpRequest.newBuilder(URI.create(Kiosapi.BASE + "/chat/completions"))
    .header("Authorization", "Bearer " + Kiosapi.API_KEY)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();

Kiosapi.client.send(req, HttpResponse.BodyHandlers.ofLines()).body()
    .filter(line -> line.startsWith("data: ") && !line.equals("data: [DONE]"))
    .map(line -> line.substring(6))
    .forEach(chunkJson -> {
        // parse chunkJson dengan Jackson/Gson, ambil choices[0].delta.content
        System.out.print(extractDeltaContent(chunkJson));
    });

Model reasoning (🧠) bisa mengirim delta reasoning_content terpisah dari content — cek field itu di JSON delta untuk status "sedang berpikir".

5. Tool calling / function calling

Format sama persis OpenAI — didukung untuk model bertanda 🔧 di katalog, termasuk Claude & Gemini (diterjemahkan otomatis oleh gateway). Body JSON di bawah disederhanakan — pakai Jackson untuk membangun/membaca struktur ini di proyek nyata.

var body = """
  {"model":"openai/gpt-4o",
   "messages":[{"role":"user","content":"Cuaca di Bandung sekarang gimana?"}],
   "tools":[{
     "type":"function",
     "function":{
       "name":"get_weather",
       "description":"Ambil cuaca terkini untuk sebuah kota",
       "parameters":{"type":"object",
         "properties":{"city":{"type":"string","description":"Nama kota"}},
         "required":["city"]}
     }
   }]}
  """;
String json = Kiosapi.post("/chat/completions", body);
// Jika respons mengandung tool_calls: kirim balik pesan assistant + { "role":"tool",
// "tool_call_id": ..., "content": "{\"suhu_celsius\":27,\"kondisi\":\"berawan\"}" }
// sebagai entri messages tambahan, lalu panggil ulang /chat/completions.

6. Vision (kirim gambar ke model)

Kirim gambar lewat content berbentuk array (image_url + text) — format persis yang dipakai perintah lihat di Kiosapi CLI.

import java.util.Base64;
import java.nio.file.Files;
import java.nio.file.Path;

String b64 = Base64.getEncoder().encodeToString(Files.readAllBytes(Path.of("foto.jpg")));

var body = """
  {"model":"google/gemini-2.5-flash",
   "messages":[{"role":"user","content":[
     {"type":"text","text":"Ada apa saja di foto ini?"},
     {"type":"image_url","image_url":{"url":"data:image/jpeg;base64,%s"}}
   ]}]}
  """.formatted(b64);
String json = Kiosapi.post("/chat/completions", body);
System.out.println(json);

Catatan: fitur ini sudah jalan di level API/CLI. Tombol upload gambar langsung di dashboard web belum tersedia.

7. Structured output / JSON mode

response_format diteruskan langsung ke provider upstream — jalan penuh untuk model yang mendukungnya secara native. Belum ada lapisan pemaksaan JSON yang seragam untuk semua model di katalog.

var body = """
  {"model":"openai/gpt-4o",
   "messages":[{"role":"user","content":"Beri saya data profil singkat dalam JSON: nama, umur."}],
   "response_format":{"type":"json_object"}}
  """;
String json = Kiosapi.post("/chat/completions", body);
// parse choices[0].message.content sebagai JSON dengan Jackson/Gson

8. Embeddings

var body = """
  {"model":"openai/text-embedding-3-small","input":"Selamat datang di Kiosapi!"}
  """;
String json = Kiosapi.post("/embeddings", body);
// parse data[0].embedding sebagai array double

9. Daftar model & cek saldo

String models = Kiosapi.get("/models");

// Saldo & kuota gratis harian (endpoint khusus Kiosapi)
String saldo = Kiosapi.get("/saldo");
System.out.println(saldo);

10. Endpoint khusus Kiosapi

Bentuknya beda dari chat completions standar, tapi tetap lewat helper Kiosapi.post/Kiosapi.get yang sama.

Gambar — POST /v1/images/generations (sinkron)

var body = """
  {"model":"google/imagen-3","prompt":"kucing oranye memakai topi koki, fotorealistik",
   "option":"standard","n":1}
  """;
String json = Kiosapi.post("/images/generations", body);
// parse data[0].b64_json, lalu:
// Files.write(Path.of("hasil.png"), Base64.getDecoder().decode(b64Json));

Video — POST /v1/videos/generations (asinkron, perlu polling)

var submitBody = """
  {"model":"alibaba/wan2.7-t2v","prompt":"ombak pantai saat matahari terbenam, sinematik",
   "option":"standard","duration_seconds":5}
  """;
String submitJson = Kiosapi.post("/videos/generations", submitBody);
String jobId = extractJobId(submitJson); // parse "job_id" dengan Jackson/Gson

String status;
String jobJson;
do {
    Thread.sleep(5000);
    jobJson = Kiosapi.get("/jobs/" + jobId);
    status = extractStatus(jobJson);
} while ("running".equals(status));

if ("succeeded".equals(status)) System.out.println("Video siap: " + extractVideoUrl(jobJson));
else System.out.println("Gagal: " + extractError(jobJson));

Image-to-video: sertakan image (base64) + image_mime di body request.

Musik — POST /v1/music/generations

var body = """
  {"model":"minimax/music-2.6","prompt":"pop akustik Indonesia yang hangat, vokal wanita",
   "lyrics":"[Verse]\nPagi cerah di kota\n[Chorus]\nBersama kita bisa"}
  """;
String submitJson = Kiosapi.post("/music/generations", body);
// poll GET /jobs/{job_id} sampai status "succeeded" → field "audio_url"

Text-to-speech — POST /v1/audio/speech

Respons berupa bytes audio mentah, jadi dipanggil pakai BodyHandlers.ofByteArray() alih-alih helper post() di atas.

var body = """
  {"model":"minimax/speech-2.8-turbo","input":"Selamat datang di Kiosapi!",
   "voice":"Indonesian_CalmWoman"}
  """;
var req = HttpRequest.newBuilder(URI.create(Kiosapi.BASE + "/audio/speech"))
    .header("Authorization", "Bearer " + Kiosapi.API_KEY)
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();
var res = Kiosapi.client.send(req, HttpResponse.BodyHandlers.ofByteArray());
Files.write(Path.of("suara.mp3"), res.body());

Reranking — POST /v1/rerank (bentuk Cohere, self-hosted)

var body = """
  {"model":"baai/bge-reranker-base","query":"apa itu kucing?",
   "documents":["Kucing adalah hewan mamalia berkaki empat.","Mobil listrik semakin populer di Indonesia."],
   "return_documents":true}
  """;
String json = Kiosapi.post("/rerank", body);
// parse results[] → { index, relevance_score }

Vector DB — POST /v1/vector-indexes/... (bentuk Pinecone, self-hosted)

// 1) Bikin index (gratis)
Kiosapi.post("/vector-indexes", "{\"name\":\"artikel-saya\"}");

// 2) Buat embedding lalu upsert (values wajib 1536 angka, cocok text-embedding-3-small)
String emb = Kiosapi.post("/embeddings", "{\"model\":\"openai/text-embedding-3-small\",\"input\":\"Isi artikel di sini\"}");
// ambil vector dari emb → data[0].embedding, lalu:
Kiosapi.post("/vector-indexes/artikel-saya/vectors/upsert",
    "{\"vectors\":[{\"id\":\"artikel-1\",\"values\":" + vectorJson + ",\"metadata\":{\"kategori\":\"berita\"}}]}");

// 3) Cari yang paling relevan
String hasil = Kiosapi.post("/vector-indexes/artikel-saya/query",
    "{\"vector\":" + vectorJson + ",\"top_k\":5,\"include_metadata\":true}");
System.out.println(hasil); // parse matches[]

11. Penanganan error

try {
    String json = Kiosapi.post("/chat/completions",
        "{\"model\":\"openai/gpt-4o\",\"messages\":[{\"role\":\"user\",\"content\":\"Halo!\"}]}");
} catch (RuntimeException e) {
    // Kiosapi.post sudah membungkus status HTTP >= 400 ke pesan exception
    System.err.println(e.getMessage());
}

Kode HTTP umum: 401 API key salah, 400 model tak dikenal/parameter salah, 402 saldo kurang atau batas pengeluaran bulanan tercapai, 422 ditolak moderasi, 429 rate limit, 502/504 provider upstream bermasalah/timeout. Kode error media lengkap ada di /docs.

12. Rate limit & kuota

FreeBerbayar
Rate limit5 req/menit60 req/menit
Kuota harian50 request/hari (reset 07:00 WIB), email terverifikasitanpa batas harian
Output maks~2048 tokensesuai maxOutput model
Input maks~24k karaktersesuai kapasitas model

13. Contoh lengkap — mini pipeline RAG

Menggabungkan embeddings + vector DB + chat dalam satu alur (pemetaan JSON disederhanakan — pakai Jackson ObjectMapper di proyek nyata untuk serialisasi/deserialisasi yang aman-tipe).

// 1) Index dokumen (sekali saja)
Kiosapi.post("/vector-indexes", "{\"name\":\"basis-pengetahuan\"}");

String[] dokumen = {
    "Kiosapi adalah AI API gateway Indonesia.",
    "Kiosapi mendukung 100+ model AI.",
};
for (int i = 0; i < dokumen.length; i++) {
    String emb = Kiosapi.post("/embeddings",
        "{\"model\":\"openai/text-embedding-3-small\",\"input\":\"" + dokumen[i] + "\"}");
    String vectorJson = extractEmbedding(emb); // parse data[0].embedding
    Kiosapi.post("/vector-indexes/basis-pengetahuan/vectors/upsert",
        "{\"vectors\":[{\"id\":\"doc-" + i + "\",\"values\":" + vectorJson +
        ",\"metadata\":{\"text\":\"" + dokumen[i] + "\"}}]}");
}

// 2) Query + jawab pakai konteks yang relevan
String pertanyaan = "Apa itu Kiosapi?";
String embQ = Kiosapi.post("/embeddings",
    "{\"model\":\"openai/text-embedding-3-small\",\"input\":\"" + pertanyaan + "\"}");
String vectorQJson = extractEmbedding(embQ);
String hasil = Kiosapi.post("/vector-indexes/basis-pengetahuan/query",
    "{\"vector\":" + vectorQJson + ",\"top_k\":2,\"include_metadata\":true}");
String konteks = extractContextFromMatches(hasil); // gabungkan metadata.text tiap match

String jawaban = Kiosapi.post("/chat/completions", """
  {"model":"anthropic/claude-sonnet-4-6",
   "messages":[
     {"role":"system","content":"Jawab berdasar konteks ini:\n%s"},
     {"role":"user","content":"%s"}
   ]}
  """.formatted(konteks, pertanyaan));
System.out.println(jawaban);

Referensi lain: spesifikasi OpenAPI 3.1 lengkap, harga & daftar model di /pricing, dan dokumentasi utama di /docs.