外观
JavaScript 示例
以下代码适用于支持原生 fetch 的 Node.js 20 或更高版本。API Key 从 TOPAPIS_API_KEY 读取。
基础请求函数
js
const apiKey = process.env.TOPAPIS_API_KEY
if (!apiKey) {
throw new Error('TOPAPIS_API_KEY is not configured')
}
const baseUrl = 'https://api.topapis.cn/v1'
async function requestJson(path, options = {}) {
const response = await fetch(`${baseUrl}${path}`, {
...options,
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
...options.headers,
},
signal: AbortSignal.timeout(120_000),
})
if (!response.ok) {
const body = await response.text()
throw new Error(`TopAPIs returned HTTP ${response.status}: ${body}`)
}
return response.json()
}错误对象可能包含服务端响应体。写日志前应移除用户内容和其他敏感字段。
查询模型并对话
js
const models = await requestJson('/models')
const model = models.data[0]?.id
if (!model) {
throw new Error('No model is available to this API key')
}
const completion = await requestJson('/chat/completions', {
method: 'POST',
body: JSON.stringify({
model,
messages: [
{ role: 'user', content: '简要说明如何保护 API Key。' },
],
}),
})
console.log(completion.choices[0].message.content)流式对话
SSE 数据可能跨网络分块,不能把每个 Uint8Array 直接当作完整事件。以下示例按空行分隔事件,并保留未完成的尾部数据。
js
const response = await fetch(`${baseUrl}/chat/completions`, {
method: 'POST',
headers: {
Authorization: `Bearer ${apiKey}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model,
messages: [{ role: 'user', content: '流式返回三条安全建议。' }],
stream: true,
}),
signal: AbortSignal.timeout(120_000),
})
if (!response.ok) {
throw new Error(`Streaming request failed with HTTP ${response.status}`)
}
if (!response.body) {
throw new Error('Streaming response has no body')
}
const decoder = new TextDecoder()
let buffer = ''
let streamComplete = false
function writeSseEvent(event) {
const dataLine = event
.split(/\r?\n/)
.find((line) => line.startsWith('data:'))
if (!dataLine) return false
const data = dataLine.slice(5).trim()
if (data === '[DONE]') return true
const payload = JSON.parse(data)
process.stdout.write(payload.choices[0]?.delta?.content ?? '')
return false
}
streamLoop:
for await (const chunk of response.body) {
buffer += decoder.decode(chunk, { stream: true })
const events = buffer.split(/\r?\n\r?\n/)
buffer = events.pop() ?? ''
for (const event of events) {
if (writeSseEvent(event)) {
streamComplete = true
break streamLoop
}
}
}
buffer += decoder.decode()
if (!streamComplete && buffer.trim()) {
writeSseEvent(buffer)
}图片生成
js
const image = await requestJson('/images/generations', {
method: 'POST',
body: JSON.stringify({
model: 'gpt-image-2',
prompt: '清晨的现代城市公园,写实摄影,自然光',
size: '1024x1024',
quality: 'high',
n: 1,
}),
})
const item = image.data[0]
if (item.url) {
console.log('Download temporary URL immediately:', item.url)
} else if (item.b64_json) {
console.log('Received Base64 image data')
} else {
throw new Error('Unexpected image response')
}模型标识必须来自当前 API Key 的 /v1/models 响应。
