UNPKG

@nuxthub/core

Version:

Build full-stack Nuxt applications on Cloudflare, with zero configuration.

103 lines (102 loc) 3.5 kB
import { ofetch } from "ofetch"; import { joinURL } from "ufo"; import { createError } from "h3"; import { requireNuxtHubFeature } from "../../../utils/features.js"; import { getCloudflareAccessHeaders } from "../../../utils/cloudflareAccess.js"; import { requireNuxtHubLinkedProject } from "../../../utils/auth.js"; import { useRuntimeConfig } from "#imports"; let _ai; export function hubAI() { requireNuxtHubFeature("ai"); if (_ai) { return _ai; } const hub = useRuntimeConfig().hub; const binding = process.env.AI || globalThis.__env__?.AI || globalThis.AI; if (hub.remote && hub.projectUrl && !binding) { const cfAccessHeaders = getCloudflareAccessHeaders(hub.cloudflareAccess); _ai = proxyHubAI(hub.projectUrl, hub.projectSecretKey || hub.userToken, cfAccessHeaders); } else if (import.meta.dev) { _ai = { async run(model, params, options) { requireNuxtHubLinkedProject(hub, "hubAI"); return $fetch(`/api/projects/${hub.projectKey}/ai/run`, { baseURL: hub.url, method: "POST", headers: { authorization: `Bearer ${hub.userToken}` }, body: { model, params, options }, responseType: params?.stream ? "stream" : void 0 }).catch(handleProxyError); }, async models(params) { requireNuxtHubLinkedProject(hub, "hubAI"); return $fetch(`/api/projects/${hub.projectKey}/ai/models`, { baseURL: hub.url, method: "POST", headers: { authorization: `Bearer ${hub.userToken}` }, body: { params } }).catch(handleProxyError); }, async toMarkdown(_files, _options) { throw createError({ statusCode: 501, message: "hubAI().toMarkdown() is only supported with remote storage in development mode." }); } }; } else if (binding) { _ai = binding; } if (!_ai) { throw createError("Missing Cloudflare AI binding (AI)"); } return _ai; } export function proxyHubAI(projectUrl, secretKey, headers) { requireNuxtHubFeature("ai"); const aiAPI = ofetch.create({ baseURL: joinURL(projectUrl, "/api/_hub/ai"), method: "POST", headers: { Authorization: `Bearer ${secretKey}`, ...headers } }); return { async run(model, params, options) { return aiAPI("/run", { body: { model, params, options }, responseType: params?.stream ? "stream" : void 0 }).catch(handleProxyError); }, async models(params) { return aiAPI("/models", { body: { params } }).catch(handleProxyError); }, async toMarkdown(files, options) { return aiAPI("/to-markdown", { body: { files, options } }).catch(handleProxyError); } }; } async function handleProxyError(err) { if (import.meta.dev && err.statusCode === 403) { console.warn("It seems that your Cloudflare API token does not have the `Worker AI` permission.\nOpen `https://dash.cloudflare.com/profile/api-tokens` and edit your NuxtHub token.\nAdd the `Account > Worker AI > Read` permission to your token and save it."); } let data = err.data; if (!err.data && typeof err.response?.json === "function") { data = (await err.response.json())?.data || {}; } throw createError({ statusCode: data?.statusCode || err.statusCode, statusMessage: data?.statusMessage || err.statusMessage, message: data?.message || err.message, data }); }