diff --git a/packages/backend-core/src/configs/configs.ts b/packages/backend-core/src/configs/configs.ts index 1771716f57..17f4abfe24 100644 --- a/packages/backend-core/src/configs/configs.ts +++ b/packages/backend-core/src/configs/configs.ts @@ -19,7 +19,6 @@ import { DocumentType, SEPARATOR } from "../constants" import { CacheKey, TTL, withCache } from "../cache" import * as context from "../context" import env from "../environment" -import { getConfigParams } from "@budibase/server/src/migrations/functions/backfill/global/configs" // UTILS @@ -262,37 +261,37 @@ export async function getSCIMConfig(): Promise { // AI // TODO: Can we assume that you are licensed when you hit this endpoint? -export async function getAIConfig(): Promise { - if (!env.SELF_HOSTED) { - // always use the env vars in cloud - // TODO: Licensing stuff - make this right - if (env.OPENAI_API_KEY) { - return getDefaultBudibaseAIConfig() - } - } +// export async function getAIConfig(): Promise { + // if (!env.SELF_HOSTED) { + // // always use the env vars in cloud + // // TODO: Licensing stuff - make this right + // if (env.OPENAI_API_KEY) { + // return getDefaultBudibaseAIConfig() + // } + // } // prefer the config in self-host - let config = await getConfig(ConfigType.AI) + // let config = await getConfig(ConfigType.AI) // fallback to env vars - if (!config || !config.activated) { - config = getDefaultBudibaseAIConfig() - } + // if (!config || !config.activated) { + // config = getDefaultBudibaseAIConfig() + // } - return config -} + // return config +// } -export function getDefaultBudibaseAIConfig(): AIInnerConfig | undefined { - if (env.OPENAI_API_KEY) { - return { - provider: "", - isDefault: true, - name: "Budibase AI", - active: true, - baseUrl: "", - apiKey: env.OPENAI_API_KEY, - // TODO: should be enum - defaultModel: "" - } - } -} +// export function getDefaultBudibaseAIConfig(): AIInnerConfig | undefined { +// if (env.OPENAI_API_KEY) { +// return { +// provider: "", +// isDefault: true, +// name: "Budibase AI", +// active: true, +// baseUrl: "", +// apiKey: env.OPENAI_API_KEY, +// // TODO: should be enum +// defaultModel: "" +// } +// } +// } diff --git a/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte b/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte new file mode 100644 index 0000000000..12cfa1d174 --- /dev/null +++ b/packages/builder/src/pages/builder/portal/settings/ai/AIConfigTile.svelte @@ -0,0 +1,90 @@ + + + + +
+
+ {#if config.provider === Providers.OpenAI.name} + + {:else if config.provider === Providers.Anthropic.name} + + {/if} +
+
+ {config.name} + +
+
+ + +
Activated
+
+
+ + diff --git a/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte b/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte index 749cebeb2c..70ddba5407 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte +++ b/packages/builder/src/pages/builder/portal/settings/ai/ConfigModal.svelte @@ -8,27 +8,17 @@ Body, notifications, } from "@budibase/bbui" - import { ConfigMap } from "./constants" + import { ConfigMap, Providers } from "./constants" import { API } from "api" - // TODO: Update these - const providers = [ - "OpenAI", - "Anthropic", - "Together AI", - "Azure Open AI", - "Custom" - ] - - const models = [ - "gpt4o-mini", - ] - - const defaultConfig = { + export let defaultConfig = { active: false, isDefault: false, } + export let saveHandler + export let deleteHandler + let aiConfig = defaultConfig let validation @@ -43,48 +33,15 @@ if (ConfigMap[provider]) { aiConfig = { ...aiConfig, - ...ConfigMap[provider] - } - } else { - aiConfig = { - ...aiConfig, + ...ConfigMap[provider], provider } - } - } - - async function saveConfig() { - const config = { - type: "ai", - config: [ - // TODO: include the ones that are already there, or just handle this in the backend - aiConfig, - ] - } - try { - const savedConfig = await API.saveConfig(config) - aiConfig._rev = savedConfig._rev - aiConfig._id = savedConfig._id - notifications.success(`Configuration saved`) - } catch (error) { - notifications.error( - `Failed to save AI Configuration, reason: ${error?.message || "Unknown"}` - ) - } - } - - async function deleteConfig() { - // Delete a configuration - try { - // await API.deleteConfig({ - // id: smtpConfig._id, - // rev: smtpConfig._rev, - // }) - notifications.success(`Deleted config`) - } catch (error) { - notifications.error( - `Failed to clear email settings, reason: ${error?.message || "Unknown"}` - ) + } else { + aiConfig.provider = provider + // aiConfig = { + // ...aiConfig, + // provider + // } } } @@ -93,8 +50,8 @@
+
diff --git a/packages/builder/src/pages/builder/portal/settings/ai/constants.ts b/packages/builder/src/pages/builder/portal/settings/ai/constants.ts index df5508109d..07e0ea1cb7 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/constants.ts +++ b/packages/builder/src/pages/builder/portal/settings/ai/constants.ts @@ -1,8 +1,47 @@ +export const Providers = { + OpenAI: { + name: "OpenAI", + models: [ + "gpt-4o-mini", + "gpt-4o", + "gpt-3.5-turbo", + "chatgpt-4o-latest", + "gpt-4-turbo", + "gpt-4", + ] + }, + Anthropic: { + name: "Anthropic", + models: [ + "claude-3-5-sonnet-20240620", + "claude-3-sonnet-20240229", + "claude-3-opus-20240229", + "claude-3-haiku-20240307" + ] + }, + TogetherAI: { + name: "Together AI", + // TODO: too many - probably need to use an autocomplete for this + models: [""] + }, + Custom: { + name: "Custom", + // TODO: too many - probably need to use an autocomplete for this + models: [""] + }, +} + export const ConfigMap = { OpenAI: { baseUrl: "https://api.openai.com" }, Anthropic: { + baseUrl: "" + }, + TogetherAI: { baseUrl: "https://api.together.xyz/v1" }, + Custom: { + baseUrl: "" + } } \ No newline at end of file diff --git a/packages/builder/src/pages/builder/portal/settings/ai/index.svelte b/packages/builder/src/pages/builder/portal/settings/ai/index.svelte index 427b09a7f2..65cd137833 100644 --- a/packages/builder/src/pages/builder/portal/settings/ai/index.svelte +++ b/packages/builder/src/pages/builder/portal/settings/ai/index.svelte @@ -1,4 +1,5 @@ + + + + + + \ No newline at end of file diff --git a/packages/builder/src/pages/builder/portal/settings/ai/logos/OpenAI.svelte b/packages/builder/src/pages/builder/portal/settings/ai/logos/OpenAI.svelte new file mode 100644 index 0000000000..a7a2927dbc --- /dev/null +++ b/packages/builder/src/pages/builder/portal/settings/ai/logos/OpenAI.svelte @@ -0,0 +1,5 @@ + +OpenAI icon \ No newline at end of file diff --git a/packages/types/src/documents/global/config.ts b/packages/types/src/documents/global/config.ts index 246874d0f1..249893520c 100644 --- a/packages/types/src/documents/global/config.ts +++ b/packages/types/src/documents/global/config.ts @@ -123,7 +123,7 @@ export interface AIInnerConfig { defaultModel: string } -export interface AIConfig extends Config {} +export interface AIConfig extends Config {} export const isSettingsConfig = (config: Config): config is SettingsConfig => config.type === ConfigType.SETTINGS diff --git a/packages/worker/src/api/controllers/global/configs.ts b/packages/worker/src/api/controllers/global/configs.ts index 43aac19b18..e5c142f562 100644 --- a/packages/worker/src/api/controllers/global/configs.ts +++ b/packages/worker/src/api/controllers/global/configs.ts @@ -28,7 +28,7 @@ import { SSOConfig, SSOConfigType, UserCtx, - OIDCLogosConfig, + OIDCLogosConfig, AIConfig, } from "@budibase/types" import * as pro from "@budibase/pro" @@ -313,6 +313,13 @@ function enrichOIDCLogos(oidcLogos: OIDCLogosConfig) { ) } +function sanitizeAIConfig(aiConfig: AIConfig) { + for (let providerConfig of aiConfig.config) { + delete providerConfig.apiKey + } + return aiConfig +} + export async function find(ctx: UserCtx) { try { // Find the config with the most granular scope based on context @@ -325,8 +332,8 @@ export async function find(ctx: UserCtx) { } if (type === ConfigType.AI) { - // TODO: strip the keys from the configs here // TODO: do the licensing checks here and return the right things based on the license + sanitizeAIConfig(scopedConfig) } ctx.body = scopedConfig } else { diff --git a/packages/worker/src/api/routes/global/configs.ts b/packages/worker/src/api/routes/global/configs.ts index b857647652..417498d829 100644 --- a/packages/worker/src/api/routes/global/configs.ts +++ b/packages/worker/src/api/routes/global/configs.ts @@ -73,7 +73,7 @@ function aiValidation() { isDefault: Joi.boolean().required(), name: Joi.string().required(), active: Joi.boolean().required(), - baseUrl: Joi.string().optional(), + baseUrl: Joi.string().optional().allow("", null), apiKey: Joi.string().required(), // TODO: should be enum defaultModel: Joi.string().optional(),