Why Use a Unified Gateway
Last month I took over a small intelligent customer service project, and the product manager's exact words were: "Let's connect one model first to test the waters; we might switch later, or bring in a few more providers for comparison."
With the traditional approach, I'd need to read documentation, register accounts, and adapt to each provider's request format separately. The last time I did this, just digesting three different SDKs and their error code systems took me two full days—not to mention the ongoing cost of maintaining multiple sets of authentication logic.
This time I took a different approach: connect directly to the unified gateway ThisToken.AI. It consolidates multiple models behind a single OpenAI-compatible interface, so my frontend components only need to be written once, and switching models is just changing one string parameter. Actual timing results:
- Old way (per-provider adaptation): registration + reading docs + writing the adaptation layer, about 12–14 hours
- This time (unified gateway): registration + getting the Key + getting the components working, under 2 hours
With the dozen-plus hours saved, I polished the typewriter effect for streaming output and error retry—things users can actually perceive. For indie developers, time is the most expensive resource; compressing the grunt work of the integration layer leaves you room to focus on the product itself.
Step 1: Register and Get an API Key
Open ThisToken.AI's registration page, verify your email, and enter the console. On the "API Keys" page, click Create, then copy and safely store the generated Key—it's shown only once; if you lose it, you'll have to recreate it.
As for pricing, I won't quote specific numbers—refer to the official pricing page. One hidden benefit of a unified gateway: consumption across multiple models is consolidated into a single bill, so at month-end reconciliation you don't have to jump between five or six dashboards. My own monthly bill-checking time dropped from about 40 minutes to 5 minutes.
Step 2: Vue3 Chat Component Encapsulation
Core idea: encapsulate a useChat composable + a display component, configure the gateway address via environment variables, and from then on switching models only requires changing the single VITE_MODEL value.
Project structure:
src/
├── composables/useChat.js
├── components/AiChat.vue
└── .env.local.env.local:
VITE_API_BASE=https://api.thistoken.ai/v1
VITE_API_KEY=你的Key
VITE_MODEL=gpt-4o-miniuseChat.js (complete, ready to copy):
import { ref } from 'vue'
export function useChat() {
const messages = ref([
{ role: 'system', content: '你是一个乐于助人的中文助手。' }
])
const input = ref('')
const loading = ref(false)
const error = ref(null)
async function send() {
const text = input.value.trim()
if (!text || loading.value) return
input.value = ''
messages.value.push({ role: 'user', content: text })
loading.value = true
error.value = null
// 占位一条 assistant 消息,流式填充
messages.value.push({ role: 'assistant', content: '' })
const replyIndex = messages.value.length - 1
try {
const res = await fetch(
`${import.meta.env.VITE_API_BASE}/chat/completions`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${import.meta.env.VITE_API_KEY}`
},
body: JSON.stringify({
model: import.meta.env.VITE_MODEL,
messages: messages.value.slice(0, -1), // 不带空的占位消息
stream: true
})
}
)
if (!res.ok) throw new Error(`网关返回 ${res.status}`)
const reader = res.body.getReader()
const decoder = new TextDecoder()
let buffer = ''
while (true) {
const { done, value } = await reader.read()
if (done) break
buffer += decoder.decode(value, { stream: true })
const lines = buffer.split('\n')
buffer = lines.pop() // 保留不完整的行
for (const line of lines) {
const trimmed = line.trim()
if (!trimmed.startsWith('data:')) continue
const data = trimmed.slice(5).trim()
if (data === '[DONE]') continue
try {
const json = JSON.parse(data)
const delta = json.choices?.[0]?.delta?.content
if (delta) messages.value[replyIndex].content += delta
} catch { /* 忽略无法解析的片段 */ }
}
}
} catch (e) {
error.value = `请求失败:${e.message},请稍后重试`
if (!messages.value[replyIndex].content) {
messages.value.splice(replyIndex, 1)
}
} finally {
loading.value = false
}
}
return { messages, input, loading, error, send }
}AiChat.vue:
<script setup>
import { useChat } from '../composables/useChat'
const { messages, input, loading, error, send } = useChat()
</script>
<template>
<div class="chat">
<div class="msgs">
<div v-for="(m, i) in messages.slice(1)" :key="i" :class="m.role">
{{ m.content }}<span v-if="loading && i === messages.length - 2" class="cursor">▍</span>
</div>
<p v-if="error" class="err">{{ error }}</p>
</div>
<div class="bar">
<input v-model="input" @keyup.enter="send" placeholder="输入消息,回车发送" :disabled="loading" />
<button @click="send" :disabled="loading">{{ loading ? '生成中' : '发送' }}</button>
</div>
</div>
</template>A few points worth noting when encapsulating:
- Don't commit your Key to the repository. Add
.env.localto.gitignore; for production deployment, a safer approach is putting request forwarding in a lightweight backend layer (or a Serverless function), with the frontend only talking to your own forwarding layer. - Streaming parsing must handle partial chunks. The
bufferretention logic in the code above is there to handle chunks being cut off mid-line. - Switching models means changing one environment variable. This is the core benefit of a unified gateway: when the product required switching to a different model, I changed one line of config and restarted the dev server—90 seconds total. In the past, this would have meant re-registering an account, re-reading a new set of docs, and modifying authentication code—at least half a day.
The Time Ledger
Total cost of this integration round:
| Item | Time |
|---|---|
| Registration + getting API Key | 10 minutes |
| Component encapsulation + streaming working | ~70 minutes |
| Error handling and retry polish | ~30 minutes |
And what's even more valuable for indie developers is the long-term maintenance cost: one interface format, one bill, one authentication logic. Whatever changes on the provider side, my frontend code doesn't need a single change.
Get the first piece of code running first, then talk architecture. If you haven't registered yet, you can start right here: https://api.thistoken.ai/register —once you've registered and gotten your Key, drop the three files above into any Vue3 project, run npm run dev, and by this afternoon you'll see your own AI chat box come alive.
---
Ready to try it yourself? Sign up at https://api.thistoken.ai/register to get your API key and start building.
Хотите попробовать Token.AI?
Создайте API Key уровня проекта, включите каналы в консоли и настройте маршрутизацию, бюджеты и журналы аудита.
注册 ThisToken.AI 并获取 API Key