Cookbook Hızlı Başlangıçları
Cookbook örnekleri examples/llmtr-cookbook/ altında secretsiz ve bağımsız bir
paket olarak tutulur. Örnekler model kimliğini sabitlemek yerine anonim
GET /v1/models yanıtından uygun bir Chat Completions modeli seçer.
Deponun erişim durumundan bağımsız olarak çalıştırılabilir kaynakların tamamı bu sayfada gösterilir. Kodları aşağıdaki dosya adlarıyla yerel klasörünüze kaydedin.
Kurulum
Section titled “Kurulum”mkdir -p llmtr-cookbook/typescript llmtr-cookbook/pythoncd llmtr-cookbooknpm init -ynpm pkg set type=modulenpm install --save-dev tsx typescript @types/nodecp .env.example .env.env içine kendi LLMTR API anahtarınızı yazın. Bu dosyayı Git'e eklemeyin.
TypeScript örneği Node.js'in yerleşik fetch uygulamasını kullanır:
npx tsx typescript/quickstart.tsnpx tsx typescript/streaming.tsPython örneği yalnızca standart kütüphaneyi kullanır:
python python/quickstart.pypython python/streaming.pyLLMTR_API_KEY=
LLMTR_BASE_URL=https://llmtr.com
TypeScript kaynakları
Section titled “TypeScript kaynakları”import { readFileSync } from "node:fs";
import { resolve } from "node:path";
export interface ModelCard {
id: string;
supported_operations?: string[];
supported_endpoints?: string[];
}
interface ModelList {
object: "list";
data: ModelCard[];
}
function loadLocalEnv(): void {
let body: string;
try {
body = readFileSync(resolve(process.cwd(), ".env"), "utf8");
} catch {
return;
}
for (const line of body.split(/\r?\n/)) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) continue;
const separator = trimmed.indexOf("=");
if (separator <= 0) continue;
const key = trimmed.slice(0, separator).trim();
const value = trimmed.slice(separator + 1).trim();
if (key && process.env[key] === undefined) process.env[key] = value;
}
}
loadLocalEnv();
export const baseUrl = (process.env.LLMTR_BASE_URL || "https://llmtr.com").replace(/\/$/, "");
export function requireApiKey(): string {
const apiKey = process.env.LLMTR_API_KEY?.trim();
if (!apiKey) {
throw new Error("LLMTR_API_KEY is missing. Copy .env.example to .env and set it locally.");
}
return apiKey;
}
export async function discoverChatModel(): Promise<ModelCard> {
const response = await fetch(`${baseUrl}/v1/models`, {
headers: { Accept: "application/json" }
});
if (!response.ok) {
throw new Error(`Model discovery failed with HTTP ${response.status}.`);
}
const payload = (await response.json()) as ModelList;
if (payload.object !== "list" || !Array.isArray(payload.data)) {
throw new Error("Model discovery returned an unexpected response shape.");
}
const model = payload.data.find(
(candidate) =>
candidate.supported_operations?.includes("CHAT_COMPLETIONS") &&
candidate.supported_endpoints?.includes("/v1/chat/completions")
);
if (!model) {
throw new Error("No public Chat Completions model is currently discoverable.");
}
return model;
}
export async function readSafeError(response: Response): Promise<string> {
try {
const payload = (await response.json()) as { error?: { message?: unknown; type?: unknown } };
const message = typeof payload.error?.message === "string" ? payload.error.message : "Request failed";
const type = typeof payload.error?.type === "string" ? payload.error.type : "unknown_error";
return `${type}: ${message}`;
} catch {
return "Request failed with a non-JSON response.";
}
}
import { baseUrl, discoverChatModel, readSafeError, requireApiKey } from "./shared.js";
const apiKey = requireApiKey();
const model = await discoverChatModel();
const response = await fetch(`${baseUrl}/v1/chat/completions`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: model.id,
messages: [{ role: "user", content: "Reply with one short sentence." }]
})
});
if (!response.ok) {
throw new Error(`Chat completion failed with HTTP ${response.status}: ${await readSafeError(response)}`);
}
const payload = (await response.json()) as {
choices?: Array<{ message?: { content?: string } }>;
};
const content = payload.choices?.[0]?.message?.content;
if (typeof content !== "string") {
throw new Error("Chat completion returned an unexpected response shape.");
}
console.log(content);
import { baseUrl, discoverChatModel, readSafeError, requireApiKey } from "./shared.js";
const apiKey = requireApiKey();
const model = await discoverChatModel();
const response = await fetch(`${baseUrl}/v1/chat/completions`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
Accept: "text/event-stream",
"Content-Type": "application/json"
},
body: JSON.stringify({
model: model.id,
messages: [{ role: "user", content: "Count from one to three." }],
stream: true,
stream_options: { include_usage: true }
})
});
if (!response.ok) {
throw new Error(`Streaming failed with HTTP ${response.status}: ${await readSafeError(response)}`);
}
if (!response.body) throw new Error("Streaming response has no body.");
const decoder = new TextDecoder();
let buffer = "";
for await (const chunk of response.body) {
buffer += decoder.decode(chunk, { stream: true });
const lines = buffer.split(/\r?\n/);
buffer = lines.pop() ?? "";
for (const line of lines) {
if (!line.startsWith("data:")) continue;
const data = line.slice("data:".length).trim();
if (!data || data === "[DONE]") continue;
const event = JSON.parse(data) as { choices?: Array<{ delta?: { content?: string } }> };
const content = event.choices?.[0]?.delta?.content;
if (content) process.stdout.write(content);
}
}
process.stdout.write("\n");
Python kaynakları
Section titled “Python kaynakları”import json
import os
from pathlib import Path
from typing import Any
from urllib.error import HTTPError
from urllib.request import Request, urlopen
def _load_local_env() -> None:
path = Path.cwd() / ".env"
if not path.is_file():
return
for raw_line in path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, value = line.split("=", 1)
os.environ.setdefault(key.strip(), value.strip())
_load_local_env()
BASE_URL = os.environ.get("LLMTR_BASE_URL", "https://llmtr.com").rstrip("/")
def require_api_key() -> str:
api_key = os.environ.get("LLMTR_API_KEY", "").strip()
if not api_key:
raise RuntimeError("LLMTR_API_KEY is missing. Copy .env.example to .env and set it locally.")
return api_key
def discover_chat_model() -> str:
request = Request(f"{BASE_URL}/v1/models", headers={"Accept": "application/json"})
with urlopen(request, timeout=30) as response:
payload = json.load(response)
if payload.get("object") != "list" or not isinstance(payload.get("data"), list):
raise RuntimeError("Model discovery returned an unexpected response shape.")
for model in payload["data"]:
if (
"CHAT_COMPLETIONS" in model.get("supported_operations", [])
and "/v1/chat/completions" in model.get("supported_endpoints", [])
):
return str(model["id"])
raise RuntimeError("No public Chat Completions model is currently discoverable.")
def safe_http_error(error: HTTPError) -> str:
try:
payload: dict[str, Any] = json.loads(error.read().decode("utf-8"))
details = payload.get("error", {})
return f"{details.get('type', 'unknown_error')}: {details.get('message', 'Request failed')}"
except (UnicodeDecodeError, json.JSONDecodeError):
return "Request failed with a non-JSON response."
import json
from urllib.error import HTTPError
from urllib.request import Request, urlopen
from shared import BASE_URL, discover_chat_model, require_api_key, safe_http_error
api_key = require_api_key()
model = discover_chat_model()
body = json.dumps(
{
"model": model,
"messages": [{"role": "user", "content": "Reply with one short sentence."}],
}
).encode("utf-8")
request = Request(
f"{BASE_URL}/v1/chat/completions",
data=body,
method="POST",
headers={"Authorization": f"Bearer {api_key}", "Content-Type": "application/json"},
)
try:
with urlopen(request, timeout=60) as response:
payload = json.load(response)
except HTTPError as error:
raise RuntimeError(f"Chat completion failed with HTTP {error.code}: {safe_http_error(error)}") from error
try:
print(payload["choices"][0]["message"]["content"])
except (KeyError, IndexError, TypeError) as error:
raise RuntimeError("Chat completion returned an unexpected response shape.") from error
import json
import sys
from urllib.error import HTTPError
from urllib.request import Request, urlopen
from shared import BASE_URL, discover_chat_model, require_api_key, safe_http_error
api_key = require_api_key()
model = discover_chat_model()
body = json.dumps(
{
"model": model,
"messages": [{"role": "user", "content": "Count from one to three."}],
"stream": True,
"stream_options": {"include_usage": True},
}
).encode("utf-8")
request = Request(
f"{BASE_URL}/v1/chat/completions",
data=body,
method="POST",
headers={
"Authorization": f"Bearer {api_key}",
"Accept": "text/event-stream",
"Content-Type": "application/json",
},
)
try:
with urlopen(request, timeout=120) as response:
for raw_line in response:
line = raw_line.decode("utf-8").strip()
if not line.startswith("data:"):
continue
data = line[len("data:") :].strip()
if not data or data == "[DONE]":
continue
event = json.loads(data)
content = event.get("choices", [{}])[0].get("delta", {}).get("content")
if content:
sys.stdout.write(content)
sys.stdout.flush()
except HTTPError as error:
raise RuntimeError(f"Streaming failed with HTTP {error.code}: {safe_http_error(error)}") from error
print()
Örneklerin doğruladığı akış
Section titled “Örneklerin doğruladığı akış”- Anonim model kataloğunu alır.
/v1/chat/completionsdesteği ilan eden bir model seçer.- API anahtarını yalnız
Authorizationheader'ına koyar. - HTTP başarısızsa güvenli hata özetini gösterir.
- Streaming örneğinde SSE
data:satırlarını işler ve[DONE]ile kapanır.
Örnekler prompt veya model yanıtını kalıcı depoya yazmaz. API anahtarını hata mesajına, stdout'a veya history kaydına eklemez.
OpenAI veya OpenRouter'dan geçiş
Section titled “OpenAI veya OpenRouter'dan geçiş”OpenAI SDK kullanıyorsanız base_url / baseURL değerini
https://llmtr.com/v1 olarak ve anahtarı LLMTR anahtarınızla değiştirin. Model
kimliğini model keşfinden alın. Ayrıntılı eşleme için OpenAI/OpenRouter geçiş
rehberini kullanın.
API sözleşmesini istemci üretimi veya doğrulama için kullanmak üzere OpenAPI ve Postman sayfasına bakın.