Если приложение построено на Supabase, свой сервер для LLM не нужен: Edge Function на Deno становится серверной частью. Клиент вызывает функцию, функция обращается к Heli API, а ключ sk-heli- хранится в Supabase Secrets и не попадает в браузер или мобильное приложение.
Функция
// supabase/functions/heli-chat/index.ts
import OpenAI from "npm:openai";
const heli = new OpenAI({
apiKey: Deno.env.get("HELI_API_KEY"),
baseURL: "https://getheli.ru/v1",
});
const cors = {
"Access-Control-Allow-Origin": "https://ваш-домен.ru",
"Access-Control-Allow-Headers": "authorization, x-client-info, apikey, content-type",
};
Deno.serve(async (req) => {
if (req.method === "OPTIONS") return new Response("ok", { headers: cors });
const { message } = await req.json();
const res = await heli.chat.completions.create({
model: "openai/gpt-5.4-mini",
messages: [{ role: "user", content: String(message).slice(0, 4000) }],
max_tokens: 800,
});
return new Response(JSON.stringify({ reply: res.choices[0].message.content }), {
headers: { ...cors, "Content-Type": "application/json" },
});
});Секрет, деплой и вызов
- Локально функцию запускают командой supabase functions serve, а ключ берут из файла env, который не попадает в git.
- По умолчанию Edge Function проверяет JWT из заголовка Authorization. supabase-js передаёт его сам, поэтому функцию могут вызвать только пользователи вашего проекта.
- Не отключайте проверку JWT для функции с LLM: открытый эндпоинт быстро израсходует баланс.
supabase functions new heli-chat
supabase secrets set HELI_API_KEY=sk-heli-…
supabase functions deploy heli-chat
// клиент (supabase-js)
const { data, error } = await supabase.functions.invoke("heli-chat", {
body: { message: "Привет!" },
});Ограничения и практика
- У Edge Functions есть лимит времени выполнения, который зависит от тарифа. Для длинных ответов задавайте max_tokens или отдавайте ответ стримом: поток из SDK превращается в ReadableStream методом toReadableStream().
- Ограничьте длину входного текста и частоту вызовов на пользователя — например, через таблицу счётчиков в Postgres.
- Модель и системный промпт задавайте в функции, а не принимайте от клиента.
- Отдельный ключ для Supabase и бюджет на него во вкладке «Лимиты» отделят расход этого приложения от остальных.
Модели
Для чата в приложении обычно хватает быстрой модели. Для обработки документов и сложных ответов подключите сильную модель отдельной функцией.
Почему не звать Heli прямо из клиента
Ключ, встроенный в веб- или мобильное приложение, можно извлечь из сборки, и тогда кто угодно будет тратить ваш баланс. Edge Function решает это: ключ остаётся в секретах проекта, а функция знает, какой пользователь её вызвал, и может ограничить его запросы.
Секреты Supabase общие для всех функций проекта. Для тестового и боевого окружения используйте разные проекты и разные ключи Heli. В функции также доступны стандартные переменные SUPABASE_URL и SUPABASE_SERVICE_ROLE_KEY — через них удобно записывать в базу счётчики запросов по пользователям. В логи функции не пишите полные промпты с персональными данными.
Попробуйте Heli
Ключ sk-heli- появляется после подтверждения почты. Через Google и Яндекс — сразу в кабинете.