KKiosapi.id

← Dokumentasi

Panduan Python — SDK OpenAI

Kiosapi 100% kompatibel dengan SDK resmi openai Python untuk chat, streaming, tool-calling, vision, dan embeddings — cukup ganti base_url & api_key. Endpoint khusus Kiosapi (gambar, video, musik, TTS, reranking, vector DB) punya bentuk sendiri, dipanggil lewat requests biasa — contoh lengkap di bagian 10.

Daftar isi

1. Persiapan

Dapatkan API key

Masuk ke dashboard → Kunci API, beri nama (mis. "python-app"), klik Buat key, salin kios_live_… (ditampilkan sekali).

Install SDK

pip install openai
Keamanan: panggil API dari server/backend, bukan dari kode frontend/browser. Simpan key sebagai environment variable, jangan hardcode.
export KIOSAPI_API_KEY="kios_live_xxxxxxxxxxxx"

2. Inisialisasi client

import os
from openai import OpenAI

client = OpenAI(
    base_url="https://api.kiosapi.id/v1",
    api_key=os.environ["KIOSAPI_API_KEY"],
)

Model ID berformat provider/nama-model — lihat daftar lengkap via GET /v1/models atau /pricing. Contoh: openai/gpt-4o, anthropic/claude-sonnet-4-6, deepseek/deepseek-v4-flash.

3. Chat completion dasar

resp = client.chat.completions.create(
    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."},
    ],
)
print(resp.choices[0].message.content)
print("Token dipakai:", resp.usage.total_tokens)

4. Streaming

Tambahkan stream=True — respons muncul token demi token (SSE).

stream = client.chat.completions.create(
    model="deepseek/deepseek-v4-flash",
    messages=[{"role": "user", "content": "Tulis puisi pendek tentang hujan di Jakarta."}],
    stream=True,
)
for chunk in stream:
    delta = chunk.choices[0].delta.content
    if delta:
        print(delta, end="", flush=True)

Model reasoning (🧠) bisa mengirim delta reasoning_content terpisah dari content — cek atribut itu untuk menampilkan status "sedang berpikir" alih-alih menganggapnya bagian jawaban akhir.

5. Tool calling / function calling

Format sama persis dengan OpenAI — didukung untuk model bertanda 🔧 di katalog, termasuk Claude & Gemini (diterjemahkan otomatis oleh gateway ke format native masing-masing).

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"],
            },
        },
    }
]

messages = [{"role": "user", "content": "Cuaca di Bandung sekarang gimana?"}]
resp = client.chat.completions.create(model="openai/gpt-4o", messages=messages, tools=tools)

msg = resp.choices[0].message
if msg.tool_calls:
    for call in msg.tool_calls:
        print("Model minta panggil:", call.function.name, call.function.arguments)
        messages.append(msg)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "content": '{"suhu_celsius": 27, "kondisi": "berawan"}',
        })
    followup = client.chat.completions.create(model="openai/gpt-4o", messages=messages)
    print(followup.choices[0].message.content)

6. Vision (kirim gambar ke model)

Kirim gambar lewat content berbentuk array (image_url + text) — format persis yang dipakai perintah lihat di Kiosapi CLI. Gambar bisa berupa URL publik atau data URL base64.

import base64

with open("foto.jpg", "rb") as f:
    b64 = base64.b64encode(f.read()).decode()

resp = client.chat.completions.create(
    model="google/gemini-2.5-flash",  # pilih model yang mendukung vision
    messages=[
        {
            "role": "user",
            "content": [
                {"type": "text", "text": "Ada apa saja di foto ini?"},
                {"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{b64}"}},
            ],
        }
    ],
)
print(resp.choices[0].message.content)

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

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 — untuk model yang tidak mendukung native, parameter ini bisa diabaikan diam-diam, jadi tetap validasi hasilnya sendiri.

resp = client.chat.completions.create(
    model="openai/gpt-4o",
    messages=[{"role": "user", "content": "Beri saya data profil singkat dalam JSON: nama, umur."}],
    response_format={"type": "json_object"},
)
import json
data = json.loads(resp.choices[0].message.content)
print(data)

8. Embeddings

resp = client.embeddings.create(
    model="openai/text-embedding-3-small",
    input="Selamat datang di Kiosapi!",
)
vector = resp.data[0].embedding
print(len(vector), "dimensi")

9. Daftar model & cek saldo

import requests

headers = {"Authorization": f"Bearer {os.environ['KIOSAPI_API_KEY']}"}

models = requests.get("https://api.kiosapi.id/v1/models", headers=headers).json()

# Saldo & kuota gratis harian (endpoint khusus Kiosapi)
saldo = requests.get("https://api.kiosapi.id/v1/saldo", headers=headers).json()
print(saldo)

10. Endpoint khusus Kiosapi (via requests)

Bentuknya beda dari method SDK OpenAI standar (mis. images.generate), jadi dipanggil langsung lewat HTTP.

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

import base64, requests

res = requests.post(
    "https://api.kiosapi.id/v1/images/generations",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "model": "google/imagen-3",
        "prompt": "kucing oranye memakai topi koki, fotorealistik",
        "option": "standard",
        "n": 1,
    },
)
data = res.json()
img_b64 = data["data"][0]["b64_json"]
with open("hasil.png", "wb") as f:
    f.write(base64.b64decode(img_b64))
print("Biaya:", data["kiosapi"]["cost_rupiah"], "rupiah")

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

import time, requests

submit = requests.post(
    "https://api.kiosapi.id/v1/videos/generations",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "model": "alibaba/wan2.7-t2v",
        "prompt": "ombak pantai saat matahari terbenam, sinematik",
        "option": "standard",
        "duration_seconds": 5,
    },
).json()
job_id = submit["job_id"]

while True:
    job = requests.get(f"https://api.kiosapi.id/v1/jobs/{job_id}", headers=headers).json()
    if job["status"] == "succeeded":
        print("Video siap:", job["video_url"])
        break
    if job["status"] == "failed":
        print("Gagal:", job["error"])
        break
    time.sleep(5)

Image-to-video: sertakan "image": "<base64>" + "image_mime": "image/png" di body request.

Musik — POST /v1/music/generations

google/lyria-2 = klip instrumental 30 detik, sinkron. minimax/music-2.6 = lagu bervokal penuh hingga ±5 menit, asinkron (pola polling sama seperti video, hasil di audio_url).

resp = requests.post(
    "https://api.kiosapi.id/v1/music/generations",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "model": "minimax/music-2.6",
        "prompt": "pop akustik Indonesia yang hangat, vokal wanita",
        "lyrics": "[Verse]\nPagi cerah di kota\n[Chorus]\nBersama kita bisa",
    },
).json()
job_id = resp["job_id"]  # poll GET /v1/jobs/{job_id} sampai status "succeeded" → "audio_url"

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

Kompatibel OpenAI (input + voice), respons berupa bytes audio mentah.

res = requests.post(
    "https://api.kiosapi.id/v1/audio/speech",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "model": "minimax/speech-2.8-turbo",
        "input": "Selamat datang di Kiosapi!",
        "voice": "Indonesian_CalmWoman",  # 9 suara asli Indonesia (model MiniMax)
    },
)
with open("suara.mp3", "wb") as f:
    f.write(res.content)

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

res = requests.post(
    "https://api.kiosapi.id/v1/rerank",
    headers={**headers, "Content-Type": "application/json"},
    json={
        "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,
    },
).json()
for r in res["results"]:
    print(r["index"], r["relevance_score"])

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

# 1) Bikin index (gratis)
requests.post(
    "https://api.kiosapi.id/v1/vector-indexes",
    headers={**headers, "Content-Type": "application/json"},
    json={"name": "artikel-saya"},
)

# 2) Buat embedding lalu upsert (values wajib 1536 angka, cocok text-embedding-3-small)
emb = client.embeddings.create(model="openai/text-embedding-3-small", input="Isi artikel di sini")
vector = emb.data[0].embedding

requests.post(
    "https://api.kiosapi.id/v1/vector-indexes/artikel-saya/vectors/upsert",
    headers={**headers, "Content-Type": "application/json"},
    json={"vectors": [{"id": "artikel-1", "values": vector, "metadata": {"kategori": "berita"}}]},
)

# 3) Cari yang paling relevan
hasil = requests.post(
    "https://api.kiosapi.id/v1/vector-indexes/artikel-saya/query",
    headers={**headers, "Content-Type": "application/json"},
    json={"vector": vector, "top_k": 5, "include_metadata": True},
).json()
print(hasil["matches"])

11. Penanganan error

from openai import APIError, APIStatusError

try:
    resp = client.chat.completions.create(
        model="openai/gpt-4o",
        messages=[{"role": "user", "content": "Halo!"}],
    )
except APIStatusError as e:
    print("HTTP status:", e.status_code)
    print("Detail:", e.response.text)
except APIError as e:
    print("Error API:", e)

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.

import os, requests
from openai import OpenAI

client = OpenAI(base_url="https://api.kiosapi.id/v1", api_key=os.environ["KIOSAPI_API_KEY"])
headers = {"Authorization": f"Bearer {os.environ['KIOSAPI_API_KEY']}", "Content-Type": "application/json"}
BASE = "https://api.kiosapi.id/v1"

def embed(text: str) -> list[float]:
    return client.embeddings.create(model="openai/text-embedding-3-small", input=text).data[0].embedding

# Index dokumen (sekali saja)
requests.post(f"{BASE}/vector-indexes", headers=headers, json={"name": "basis-pengetahuan"})
dokumen = ["Kiosapi adalah AI API gateway Indonesia.", "Kiosapi mendukung 100+ model AI."]
vectors = [{"id": f"doc-{i}", "values": embed(d), "metadata": {"text": d}} for i, d in enumerate(dokumen)]
requests.post(f"{BASE}/vector-indexes/basis-pengetahuan/vectors/upsert", headers=headers, json={"vectors": vectors})

# Query + jawab pakai konteks yang relevan
pertanyaan = "Apa itu Kiosapi?"
hasil = requests.post(
    f"{BASE}/vector-indexes/basis-pengetahuan/query",
    headers=headers,
    json={"vector": embed(pertanyaan), "top_k": 2, "include_metadata": True},
).json()
konteks = "\n".join(m["metadata"]["text"] for m in hasil["matches"])

jawaban = client.chat.completions.create(
    model="anthropic/claude-sonnet-4-6",
    messages=[
        {"role": "system", "content": f"Jawab berdasar konteks ini:\n{konteks}"},
        {"role": "user", "content": pertanyaan},
    ],
)
print(jawaban.choices[0].message.content)

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