Toàn bộ API trong một lệnh curl
Hãy quên SDK đi một lúc. Mọi ví dụ dưới đây đều gửi cùng một thứ: một body JSON đến POST /v1/chat/completions với bearer token. Nếu bạn có thể gửi điều đó, bạn đã xong. Lấy một khóa từ trang đăng ký (tín dụng dùng thử không cần thông tin thanh toán), xuất nó dưới dạng API_KEY và chạy cái đầu tiên này.
curl https://api.unrestrictedaiapi.com/v1/chat/completions \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "uncensored",
"messages": [{"role": "user", "content": "Write a two-line noir opening set in a laundromat."}],
"max_tokens": 120
}'Phản hồi là một đối tượng kiểu OpenAI. Văn bản nằm ở choices[0].message.content, và một khối usage cho bạn biết cuộc gọi đã tốn bao nhiêu token. Chỉ có một mô hình, uncensored, nên trường model không bao giờ thay đổi. Bạn có thể xác nhận điều này với GET /v1/models.
curl https://api.unrestrictedaiapi.com/v1/models -H "Authorization: Bearer $API_KEY"Hai giới hạn đáng để ghi nhớ trước khi viết bất kỳ mã nào: cửa sổ ngữ cảnh là 100.000 token dùng chung cho prompt và completion, và max_tokens mặc định là 2048 trừ khi bạn tăng nó (lên đến 32.000). Nếu đầu ra của bạn liên tục bị ngắt giữa chừng, thì mặc định đó là nguyên nhân thường gặp.
Python với httpx
httpx cung cấp cho bạn một client đồng bộ với các thời gian chờ hợp lý và một bản song song bất đồng bộ khi bạn cần. Đặt thời gian chờ một cách rõ ràng. Các quá trình tạo dài có thể mất nhiều thời gian và thời gian chờ mặc định năm giây sẽ ngắt chúng.
import os
import httpx
resp = httpx.post(
"https://api.unrestrictedaiapi.com/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={
"model": "uncensored",
"messages": [
{"role": "system", "content": "You are a blunt, vivid fiction writer."},
{"role": "user", "content": "Pitch a heist where the vault is a night market."},
],
"temperature": 0.9,
"max_tokens": 300,
},
timeout=60.0,
)
resp.raise_for_status()
print(resp.json()["choices"][0]["message"]["content"])raise_for_status() chuyển đổi bất kỳ 4xx hoặc 5xx nào thành ngoại lệ, điều này ổn cho một script. Đối với bất cứ thứ gì chạy dài, hãy bao bọc cuộc gọi để hai trạng thái có cơ hội khác: 429 (bạn đã đạt giới hạn 300 yêu cầu mỗi phút cho mỗi khóa) và 503 (upstream_busy, sẽ hết sau vài giây). Mọi thứ khác, bao gồm 401, 402 và 403, sẽ không tự sửa được khi thử lại.
import os
import time
import httpx
def chat(messages, retries=3):
for attempt in range(retries + 1):
r = httpx.post(
"https://api.unrestrictedaiapi.com/v1/chat/completions",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
json={"model": "uncensored", "messages": messages, "max_tokens": 400},
timeout=60.0,
)
if r.status_code in (429, 503) and attempt < retries:
time.sleep(2 ** attempt)
continue
r.raise_for_status()
return r.json()["choices"][0]["message"]["content"]
print(chat([{"role": "user", "content": "Name five cursed objects found in a thrift store."}]))Thay thế httpx.post bằng httpx.AsyncClient().post bên trong một async def và bạn có phiên bản không đồng bộ với cùng payload.
JavaScript với fetch
Node 18 trở lên có sẵn fetch, nên không cần cài đặt gì thêm. Lưu tệp dưới dạng .mjs (hoặc đặt "type": "module") để await ở cấp cao nhất hoạt động. Trình duyệt có cùng API, nhưng đừng đặt khóa trong mã front-end. Proxy cuộc gọi qua backend của riêng bạn.
const res = await fetch("https://api.unrestrictedaiapi.com/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: "uncensored",
messages: [{ role: "user", content: "Describe a villain's morning routine in four bullets." }],
max_tokens: 250,
}),
});
if (!res.ok) {
const err = await res.json().catch(() => ({}));
throw new Error(`HTTP ${res.status}: ${err?.error?.message ?? "unknown error"}`);
}
const data = await res.json();
console.log(data.choices[0].message.content);Lưu ý thứ tự kiểm tra. fetch chỉ từ chối khi lỗi mạng, nên 402 hoặc 403 xuất hiện dưới dạng phản hồi bình thường. Tự kiểm tra res.ok và đọc JSON lỗi, luôn có định dạng {"error":{"code":...,"message":...}}.
Go với net/http
Go cần thêm một vài dòng nhưng không cần thư viện bên ngoài. Chỉ định các trường struct bạn đọc; encoding/json sẽ bỏ qua phần còn lại. Đọc body thành byte trước khi kiểm tra trạng thái cho phép bạn in thông báo lỗi của máy chủ khi có sự cố.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
)
type reply struct {
Choices []struct {
Message struct {
Content string `json:"content"`
} `json:"message"`
} `json:"choices"`
}
func main() {
payload, _ := json.Marshal(map[string]any{
"model": "uncensored",
"messages": []map[string]string{
{"role": "user", "content": "Give me a ghost story in exactly three sentences."},
},
"max_tokens": 200,
})
req, _ := http.NewRequest("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions", bytes.NewReader(payload))
req.Header.Set("Authorization", "Bearer "+os.Getenv("API_KEY"))
req.Header.Set("Content-Type", "application/json")
resp, err := http.DefaultClient.Do(req)
if err != nil {
panic(err)
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode != http.StatusOK {
panic(fmt.Sprintf("HTTP %d: %s", resp.StatusCode, body))
}
var out reply
if err := json.Unmarshal(body, &out); err != nil {
panic(err)
}
fmt.Println(out.Choices[0].Message.Content)
}Đối với sản xuất, hãy tạo một http.Client{Timeout: 60 * time.Second} và tái sử dụng nó. Client mặc định không có thời gian chờ, đây là cách một yêu cầu bị treo trở thành một goroutine bị treo.
PHP với cURL và Ruby với Net::HTTP
Phần mở rộng cURL của PHP đã có trên hầu hết các máy chủ. Xây dựng body với json_encode, trả về kết quả chuyển đổi dưới dạng chuỗi, sau đó đọc trạng thái bằng curl_getinfo. Bỏ qua kiểm tra trạng thái là lỗi kinh điển: body 402 giải mã thành JSON một cách bình thường và mã của bạn sau đó sẽ thất bại do thiếu khóa choices.
<?php
$payload = json_encode([
"model" => "uncensored",
"messages" => [
["role" => "user", "content" => "Write a villanelle opening about a broken vending machine."],
],
"max_tokens" => 200,
]);
$ch = curl_init("https://api.unrestrictedaiapi.com/v1/chat/completions");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => $payload,
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($body === false || $status !== 200) {
fwrite(STDERR, "HTTP $status: $body\n");
exit(1);
}
$data = json_decode($body, true);
echo $data["choices"][0]["message"]["content"], "\n";Trên máy chủ chia sẻ với max_execution_time thấp, hãy giữ max_tokens ở mức vừa phải hoặc chuyển cuộc gọi vào worker hàng đợi.
Thư viện chuẩn cũng đủ ở đây. ENV.fetch sẽ ném lỗi ngay lập tức nếu biến bị thiếu, điều này tốt hơn là gửi một bearer token trống và gỡ lỗi 401 trong mười phút.
require "net/http"
require "json"
require "uri"
uri = URI("https://api.unrestrictedaiapi.com/v1/chat/completions")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer #{ENV.fetch('API_KEY')}"
req["Content-Type"] = "application/json"
req.body = JSON.generate(
model: "uncensored",
messages: [{ role: "user", content: "Invent a tavern rumor that sounds too specific to be fake." }],
max_tokens: 200
)
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true, read_timeout: 60) { |http| http.request(req) }
abort("HTTP #{res.code}: #{res.body}") unless res.is_a?(Net::HTTPSuccess)
puts JSON.parse(res.body).dig("choices", 0, "message", "content")Nếu sau này bạn chuyển sang Rails, cùng body đó hoạt động từ một job nền. Giữ cuộc gọi ra khỏi vòng lặp yêu cầu; quá trình sinh chậm hơn một truy vấn cơ sở dữ liệu.
Cả hai đoạn mã đều gửi chính xác body mà đoạn Python gửi, đó là điểm mấu chốt: nếu một ngôn ngữ hoạt động và ngôn ngữ khác không, hãy so sánh JSON, không phải client. In body yêu cầu thô một lần và so sánh byte cho byte. Chín lần trong mười trường hợp, nguyên nhân là thiếu tiêu đề Content-Type hoặc tên model được gõ bằng chữ hoa.
Streaming không dùng thư viện
Streaming là nơi mà HTTP thuần yêu cầu bạn nhiều hơn một chút. Với stream: true, máy chủ trả về các sự kiện do máy chủ gửi: mỗi dòng bắt đầu bằng data: , chứa một chunk JSON và luồng kết thúc bằng data: [DONE]. Một chunk usage cuối cùng được thêm tự động, vì vậy bạn nhận được số token ngay cả khi streaming. Chunk đó không có mục choices, đó là lý do tại sao vòng lặp bên dưới kiểm tra trước khi truy xuất chỉ mục.
import json
import os
import httpx
body = {
"model": "uncensored",
"messages": [{"role": "user", "content": "Tell a campfire story about a lighthouse keeper."}],
"stream": True,
"max_tokens": 400,
}
headers = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
with httpx.stream("POST", "https://api.unrestrictedaiapi.com/v1/chat/completions",
headers=headers, json=body, timeout=60.0) as r:
r.raise_for_status()
for line in r.iter_lines():
if not line.startswith("data: "):
continue
data = line[6:]
if data == "[DONE]":
break
chunk = json.loads(data)
if chunk.get("choices"):
print(chunk["choices"][0]["delta"].get("content") or "", end="", flush=True)
print()Mẫu tương tự được chuyển trực tiếp. Trong JavaScript, đọc res.body bằng trình đọc và chia theo dòng mới. Trong Go, bao bọc resp.Body trong một bufio.Scanner. Trong Ruby, truyền một khối vào http.request và sử dụng read_body. Trong PHP, đặt callback CURLOPT_WRITEFUNCTION. Logic không bao giờ thay đổi: loại bỏ tiền tố, dừng tại sentinel, phân tích cú pháp JSON, in delta.
Bài kiểm tra nhanh 5 phút và kiểm tra ngân sách
Trước khi xây dựng dựa trên bất kỳ đoạn mã nào trong số này, hãy chạy một lần kiểm tra nhanh. Đầu tiên, gọi /v1/models với khóa của bạn; 200 chứng minh khóa và đường dẫn mạng. Thứ hai, gửi yêu cầu chat nhỏ nhất có thể với max_tokens được đặt là 20. Thứ ba, cố tình làm hỏng thứ gì đó, chẳng hạn như bearer token trống, và xác nhận mã của bạn hiển thị rõ ràng 401 thay vì bị lỗi do thiếu trường.
Sau đó, hãy thực hiện phép tính số học một lần để không có gì bất ngờ. Giá là $0.25 cho mỗi triệu token đầu vào và $1.00 cho mỗi triệu token đầu ra. Với giả định minh họa, hãy nói một yêu cầu gửi 600 token prompt và nhận lại 400 token. Đó là 600 x $0.25 / 1,000,000 = $0.00015 đầu vào, cộng với 400 x $1.00 / 1,000,000 = $0.0004 đầu ra, khoảng $0.00055 cho mỗi lệnh gọi. Tín dụng dùng thử $0.50 sẽ bao gồm khoảng 900 lệnh gọi có kích thước đó. Các prompt thực tế của bạn sẽ khác, vì vậy hãy đọc khối usage trên một vài phản hồi và nhân từ đó.
Tín dụng dùng thử có hiệu lực trong bảy ngày và không cần thông tin thanh toán, điều này đủ cho việc kiểm tra tất cả năm ngôn ngữ. Nếu bạn muốn một trường hợp sử dụng để hướng tới, hướng dẫn nội dung NSFW hiển thị một ví dụ hoàn chỉnh. Hãy nhớ rằng một khóa thuộc về một tài khoản; nếu bạn tạo lại nó, hãy cập nhật mọi script cùng một lúc, vì khóa cũ sẽ ngừng hoạt động ngay lập tức.
Lỗi giống nhau ở mọi ngôn ngữ
Vì API là HTTP thuần túy, việc xử lý lỗi giống hệt nhau bất kể ngôn ngữ bạn chọn. Ghi nhớ bảng này và bạn có thể chuyển đổi bất kỳ đoạn mã nào ở trên.
| Trạng thái | Ý nghĩa | Hành động |
|---|---|---|
| 400 | Yêu cầu không hợp lệ, chẳng hạn như prompt cộng với max_tokens vượt quá 100k | Giảm prompt hoặc giảm max_tokens |
| 401 | Thiếu hoặc khóa không hợp lệ | Kiểm tra API_KEY; một khóa được tạo lại sẽ vô hiệu hóa khóa cũ ngay lập tức |
| 402 | no_credit: số dư đã hết hoặc tín dụng dùng thử đã hết hạn | Nạp tiền vào số dư trả trước |
| 403 | content_blocked | Không thử lại; nội dung tình dục liên quan đến người vị thành niên luôn bị chặn |
| 429 | Hơn 300 yêu cầu mỗi phút | Giảm tần suất và thử lại |
| 503 | upstream_busy | Thử lại sau vài giây |
Khi các bước cơ bản đã hoạt động, hãy đặt stream: true để nhận đầu ra từng token và đọc các dòng sự kiện do máy chủ gửi theo từng dòng. Tạo prompt tốt hơn với hướng dẫn về prompt, hoặc tích hợp cùng một lệnh gọi vào nền tảng bot bằng hướng dẫn bot. Mức giá có trên trang giá cả.