icons, styling of AI configs and further simplification
This commit is contained in:
parent
f328ae4bf9
commit
ca4b17bc9b
|
@ -19,7 +19,6 @@ import { DocumentType, SEPARATOR } from "../constants"
|
||||||
import { CacheKey, TTL, withCache } from "../cache"
|
import { CacheKey, TTL, withCache } from "../cache"
|
||||||
import * as context from "../context"
|
import * as context from "../context"
|
||||||
import env from "../environment"
|
import env from "../environment"
|
||||||
import { getConfigParams } from "@budibase/server/src/migrations/functions/backfill/global/configs"
|
|
||||||
|
|
||||||
// UTILS
|
// UTILS
|
||||||
|
|
||||||
|
@ -262,37 +261,37 @@ export async function getSCIMConfig(): Promise<SCIMInnerConfig | undefined> {
|
||||||
// AI
|
// AI
|
||||||
|
|
||||||
// TODO: Can we assume that you are licensed when you hit this endpoint?
|
// TODO: Can we assume that you are licensed when you hit this endpoint?
|
||||||
export async function getAIConfig(): Promise<AIConfig | undefined> {
|
// export async function getAIConfig(): Promise<AIConfig | undefined> {
|
||||||
if (!env.SELF_HOSTED) {
|
// if (!env.SELF_HOSTED) {
|
||||||
// always use the env vars in cloud
|
// // always use the env vars in cloud
|
||||||
// TODO: Licensing stuff - make this right
|
// // TODO: Licensing stuff - make this right
|
||||||
if (env.OPENAI_API_KEY) {
|
// if (env.OPENAI_API_KEY) {
|
||||||
return getDefaultBudibaseAIConfig()
|
// return getDefaultBudibaseAIConfig()
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
// prefer the config in self-host
|
// prefer the config in self-host
|
||||||
let config = await getConfig<AIConfig>(ConfigType.AI)
|
// let config = await getConfig<AIConfig>(ConfigType.AI)
|
||||||
|
|
||||||
// fallback to env vars
|
// fallback to env vars
|
||||||
if (!config || !config.activated) {
|
// if (!config || !config.activated) {
|
||||||
config = getDefaultBudibaseAIConfig()
|
// config = getDefaultBudibaseAIConfig()
|
||||||
}
|
// }
|
||||||
|
|
||||||
return config
|
// return config
|
||||||
}
|
// }
|
||||||
|
|
||||||
export function getDefaultBudibaseAIConfig(): AIInnerConfig | undefined {
|
// export function getDefaultBudibaseAIConfig(): AIInnerConfig | undefined {
|
||||||
if (env.OPENAI_API_KEY) {
|
// if (env.OPENAI_API_KEY) {
|
||||||
return {
|
// return {
|
||||||
provider: "",
|
// provider: "",
|
||||||
isDefault: true,
|
// isDefault: true,
|
||||||
name: "Budibase AI",
|
// name: "Budibase AI",
|
||||||
active: true,
|
// active: true,
|
||||||
baseUrl: "",
|
// baseUrl: "",
|
||||||
apiKey: env.OPENAI_API_KEY,
|
// apiKey: env.OPENAI_API_KEY,
|
||||||
// TODO: should be enum
|
// // TODO: should be enum
|
||||||
defaultModel: ""
|
// defaultModel: ""
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
<script>
|
||||||
|
import {Body, Label, Icon, Tag} from "@budibase/bbui"
|
||||||
|
import OpenAILogo from "./logos/OpenAI.svelte"
|
||||||
|
import AnthropicLogo from "./logos/Anthropic.svelte"
|
||||||
|
import { Providers } from "./constants"
|
||||||
|
|
||||||
|
export let config
|
||||||
|
export let disabled
|
||||||
|
|
||||||
|
export let editHandler
|
||||||
|
export let deleteHandler
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
|
<div on:click class:disabled class="option">
|
||||||
|
<div class="icon">
|
||||||
|
{#if config.provider === Providers.OpenAI.name}
|
||||||
|
<OpenAILogo height="30" width="30"/>
|
||||||
|
{:else if config.provider === Providers.Anthropic.name}
|
||||||
|
<AnthropicLogo height="30" width="30"/>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
<div class="header">
|
||||||
|
<Body>{config.name}</Body>
|
||||||
|
<Label>{config.name}</Label>
|
||||||
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<Icon
|
||||||
|
on:click={editHandler}
|
||||||
|
size="S"
|
||||||
|
hoverable
|
||||||
|
name="Edit"
|
||||||
|
/>
|
||||||
|
<Icon
|
||||||
|
on:click={deleteHandler}
|
||||||
|
size="S"
|
||||||
|
hoverable
|
||||||
|
name="Delete"
|
||||||
|
/>
|
||||||
|
<div>Activated</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.option {
|
||||||
|
background-color: var(--background);
|
||||||
|
border: 1px solid var(--grey-4);
|
||||||
|
padding: 10px 16px 14px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 6% 1fr 20%;
|
||||||
|
grid-gap: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option :global(label) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.option:hover {
|
||||||
|
background-color: var(--background-alt);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
background-color: white;
|
||||||
|
height: 38px;
|
||||||
|
width: 38px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disabled {
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: grid;
|
||||||
|
grid-auto-flow: column;
|
||||||
|
grid-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -8,27 +8,17 @@
|
||||||
Body,
|
Body,
|
||||||
notifications,
|
notifications,
|
||||||
} from "@budibase/bbui"
|
} from "@budibase/bbui"
|
||||||
import { ConfigMap } from "./constants"
|
import { ConfigMap, Providers } from "./constants"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
|
|
||||||
// TODO: Update these
|
export let defaultConfig = {
|
||||||
const providers = [
|
|
||||||
"OpenAI",
|
|
||||||
"Anthropic",
|
|
||||||
"Together AI",
|
|
||||||
"Azure Open AI",
|
|
||||||
"Custom"
|
|
||||||
]
|
|
||||||
|
|
||||||
const models = [
|
|
||||||
"gpt4o-mini",
|
|
||||||
]
|
|
||||||
|
|
||||||
const defaultConfig = {
|
|
||||||
active: false,
|
active: false,
|
||||||
isDefault: false,
|
isDefault: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export let saveHandler
|
||||||
|
export let deleteHandler
|
||||||
|
|
||||||
let aiConfig = defaultConfig
|
let aiConfig = defaultConfig
|
||||||
let validation
|
let validation
|
||||||
|
|
||||||
|
@ -43,48 +33,15 @@
|
||||||
if (ConfigMap[provider]) {
|
if (ConfigMap[provider]) {
|
||||||
aiConfig = {
|
aiConfig = {
|
||||||
...aiConfig,
|
...aiConfig,
|
||||||
...ConfigMap[provider]
|
...ConfigMap[provider],
|
||||||
}
|
|
||||||
} else {
|
|
||||||
aiConfig = {
|
|
||||||
...aiConfig,
|
|
||||||
provider
|
provider
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
}
|
aiConfig.provider = provider
|
||||||
|
// aiConfig = {
|
||||||
async function saveConfig() {
|
// ...aiConfig,
|
||||||
const config = {
|
// provider
|
||||||
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"}`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,8 +50,8 @@
|
||||||
<ModalContent
|
<ModalContent
|
||||||
confirmText={"Save"}
|
confirmText={"Save"}
|
||||||
cancelText={"Delete"}
|
cancelText={"Delete"}
|
||||||
onConfirm={saveConfig}
|
onConfirm={saveHandler}
|
||||||
onCancel={deleteConfig}
|
onCancel={deleteHandler}
|
||||||
disabled={!validation}
|
disabled={!validation}
|
||||||
size="M"
|
size="M"
|
||||||
title="Custom AI Configuration"
|
title="Custom AI Configuration"
|
||||||
|
@ -104,16 +61,16 @@
|
||||||
<Select
|
<Select
|
||||||
placeholder={null}
|
placeholder={null}
|
||||||
bind:value={aiConfig.provider}
|
bind:value={aiConfig.provider}
|
||||||
options={providers}
|
options={Object.keys(Providers)}
|
||||||
on:change={prefillConfig}
|
on:change={prefillConfig}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<Label size="M">Default Model</Label>
|
<Label size="M">Default Model</Label>
|
||||||
<Select
|
<Select
|
||||||
placeholder={null}
|
placeholder={aiConfig.provider ? "Choose an option" : "Select a provider first"}
|
||||||
bind:value={aiConfig.defaultModel}
|
bind:value={aiConfig.defaultModel}
|
||||||
options={models}
|
options={aiConfig.provider ? Providers[aiConfig.provider].models : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
|
@ -126,7 +83,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="form-row">
|
<div class="form-row">
|
||||||
<Label size="M">API Key</Label>
|
<Label size="M">API Key</Label>
|
||||||
<Input bind:value={aiConfig.apiKey}/>
|
<Input type="password" bind:value={aiConfig.apiKey}/>
|
||||||
</div>
|
</div>
|
||||||
<Toggle text="Active" bind:value={aiConfig.active}/>
|
<Toggle text="Active" bind:value={aiConfig.active}/>
|
||||||
<Toggle text="Set as default" bind:value={aiConfig.isDefault}/>
|
<Toggle text="Set as default" bind:value={aiConfig.isDefault}/>
|
||||||
|
|
|
@ -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 = {
|
export const ConfigMap = {
|
||||||
OpenAI: {
|
OpenAI: {
|
||||||
baseUrl: "https://api.openai.com"
|
baseUrl: "https://api.openai.com"
|
||||||
},
|
},
|
||||||
Anthropic: {
|
Anthropic: {
|
||||||
|
baseUrl: ""
|
||||||
|
},
|
||||||
|
TogetherAI: {
|
||||||
baseUrl: "https://api.together.xyz/v1"
|
baseUrl: "https://api.together.xyz/v1"
|
||||||
},
|
},
|
||||||
|
Custom: {
|
||||||
|
baseUrl: ""
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
<script>
|
<script>
|
||||||
|
import { onMount } from "svelte"
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
Layout,
|
Layout,
|
||||||
|
@ -14,8 +15,7 @@
|
||||||
import { admin, licensing } from "stores/portal"
|
import { admin, licensing } from "stores/portal"
|
||||||
import { API } from "api"
|
import { API } from "api"
|
||||||
import AIConfigModal from "./ConfigModal.svelte"
|
import AIConfigModal from "./ConfigModal.svelte"
|
||||||
import { onMount } from "svelte"
|
import AIConfigTile from "./AIConfigTile.svelte"
|
||||||
import { sdk } from "@budibase/shared-core"
|
|
||||||
|
|
||||||
const ConfigTypes = {
|
const ConfigTypes = {
|
||||||
AI: "ai",
|
AI: "ai",
|
||||||
|
@ -23,26 +23,75 @@
|
||||||
|
|
||||||
let modal
|
let modal
|
||||||
let aiConfig
|
let aiConfig
|
||||||
let loading = false
|
let currentlyEditingConfig
|
||||||
|
|
||||||
$: isCloud = $admin.cloud
|
$: isCloud = $admin.cloud
|
||||||
$: budibaseAIEnabled = $licensing.budibaseAIEnabled
|
$: budibaseAIEnabled = $licensing.budibaseAIEnabled
|
||||||
$: customAIConfigsEnabled = $licensing.customAIConfigsEnabled
|
$: customAIConfigsEnabled = $licensing.customAIConfigsEnabled
|
||||||
|
|
||||||
async function fetchAIConfig() {
|
async function fetchAIConfig() {
|
||||||
loading = true
|
|
||||||
try {
|
try {
|
||||||
// Fetch the configs for smtp
|
// Fetch the AI configs
|
||||||
const aiDoc = await API.getConfig(ConfigTypes.AI)
|
const aiDoc = await API.getConfig(ConfigTypes.AI)
|
||||||
if (aiDoc._id) {
|
if (aiDoc._id) {
|
||||||
aiConfig = aiDoc
|
aiConfig = aiDoc
|
||||||
}
|
}
|
||||||
loading = false
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
notifications.error("Error fetching AI config")
|
notifications.error("Error fetching AI config")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function saveConfig() {
|
||||||
|
// Update the config that was changed
|
||||||
|
const updateConfigs = aiConfig.config
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
type: ConfigTypes.AI,
|
||||||
|
config: [
|
||||||
|
// TODO: include the ones that are already there, or just handle this in the backend
|
||||||
|
aiConfig,
|
||||||
|
]
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const isNew = !!aiConfig._rev
|
||||||
|
const savedConfig = await API.saveConfig(config)
|
||||||
|
aiConfig._rev = savedConfig._rev
|
||||||
|
aiConfig._id = savedConfig._id
|
||||||
|
notifications.success(`Successfully saved and activated ${isNew ? "new" : ""} AI Configuration`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error(
|
||||||
|
`Failed to save AI Configuration, reason: ${error?.message || "Unknown"}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function deleteConfig(name) {
|
||||||
|
// Delete a configuration
|
||||||
|
const idx = aiConfig.config.findIndex(config => config.name === currentlyEditingConfig?.name || name)
|
||||||
|
aiConfig.config.splice(idx, 1)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const savedConfig = await API.saveConfig(aiConfig)
|
||||||
|
aiConfig._rev = savedConfig._rev
|
||||||
|
aiConfig._id = savedConfig._id
|
||||||
|
notifications.success(`Deleted config`)
|
||||||
|
} catch (error) {
|
||||||
|
notifications.error(
|
||||||
|
`Failed to delete config, reason: ${error?.message || "Unknown"}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function editConfig(config) {
|
||||||
|
currentlyEditingConfig = config
|
||||||
|
modal.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
function newConfig() {
|
||||||
|
currentlyEditingConfig = undefined
|
||||||
|
modal.show()
|
||||||
|
}
|
||||||
|
|
||||||
onMount(async () => {
|
onMount(async () => {
|
||||||
await fetchAIConfig()
|
await fetchAIConfig()
|
||||||
})
|
})
|
||||||
|
@ -51,7 +100,11 @@
|
||||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||||
<Modal bind:this={modal}>
|
<Modal bind:this={modal}>
|
||||||
<AIConfigModal />
|
<AIConfigModal
|
||||||
|
saveHandler={saveConfig}
|
||||||
|
deleteHandler={deleteConfig}
|
||||||
|
defaultConfig={currentlyEditingConfig}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Layout noPadding>
|
<Layout noPadding>
|
||||||
<Layout gap="XS" noPadding>
|
<Layout gap="XS" noPadding>
|
||||||
|
@ -76,11 +129,20 @@
|
||||||
<Tag icon="LockClosed">Enterprise</Tag>
|
<Tag icon="LockClosed">Enterprise</Tag>
|
||||||
</Tags>
|
</Tags>
|
||||||
{:else}
|
{:else}
|
||||||
<Button size="S" cta on:click={modal.show}>Add configuration</Button>
|
<Button size="S" cta on:click={newConfig}>Add configuration</Button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
<Body size="S">Use the following interface to select your preferred AI configuration.</Body>
|
<Body size="S">Use the following interface to select your preferred AI configuration.</Body>
|
||||||
<Body size="S">Select your AI Model:</Body>
|
<Body size="S">Select your AI Model:</Body>
|
||||||
|
{#if aiConfig}
|
||||||
|
{#each aiConfig.config as config}
|
||||||
|
<AIConfigTile
|
||||||
|
{config}
|
||||||
|
editHandler={() => editConfig(config)}
|
||||||
|
deleteHandler={modal.show}
|
||||||
|
/>
|
||||||
|
{/each}
|
||||||
|
{/if}
|
||||||
</Layout>
|
</Layout>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
<script>
|
||||||
|
export let height
|
||||||
|
export let width
|
||||||
|
</script>
|
||||||
|
<svg id="katman_1" {height} {width} data-name="katman 1" xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.89 595.28">
|
||||||
|
<defs>
|
||||||
|
<style>
|
||||||
|
.cls-1 {
|
||||||
|
fill: #000;
|
||||||
|
stroke-width: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<path class="cls-1" d="M552.13,91.34h-90.99l162.93,412.61h88.87l-160.81-412.61ZM289.76,91.34l-160.81,412.61h90.99l35.97-86.75h169.28l33.86,84.64h90.99L384.97,91.34h-95.22ZM281.29,341.02l55.01-146,57.13,146h-112.14Z"/>
|
||||||
|
</svg>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<script>
|
||||||
|
export let height
|
||||||
|
export let width
|
||||||
|
</script>
|
||||||
|
<svg fill="#000000" {width} {height} viewBox="0 0 24 24" role="img" xmlns="http://www.w3.org/2000/svg"><title>OpenAI icon</title><path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/></svg>
|
|
@ -123,7 +123,7 @@ export interface AIInnerConfig {
|
||||||
defaultModel: string
|
defaultModel: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AIConfig extends Config<AIInnerConfig> {}
|
export interface AIConfig extends Config<AIInnerConfig[]> {}
|
||||||
|
|
||||||
export const isSettingsConfig = (config: Config): config is SettingsConfig =>
|
export const isSettingsConfig = (config: Config): config is SettingsConfig =>
|
||||||
config.type === ConfigType.SETTINGS
|
config.type === ConfigType.SETTINGS
|
||||||
|
|
|
@ -28,7 +28,7 @@ import {
|
||||||
SSOConfig,
|
SSOConfig,
|
||||||
SSOConfigType,
|
SSOConfigType,
|
||||||
UserCtx,
|
UserCtx,
|
||||||
OIDCLogosConfig,
|
OIDCLogosConfig, AIConfig,
|
||||||
} from "@budibase/types"
|
} from "@budibase/types"
|
||||||
import * as pro from "@budibase/pro"
|
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) {
|
export async function find(ctx: UserCtx) {
|
||||||
try {
|
try {
|
||||||
// Find the config with the most granular scope based on context
|
// 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) {
|
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
|
// TODO: do the licensing checks here and return the right things based on the license
|
||||||
|
sanitizeAIConfig(scopedConfig)
|
||||||
}
|
}
|
||||||
ctx.body = scopedConfig
|
ctx.body = scopedConfig
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -73,7 +73,7 @@ function aiValidation() {
|
||||||
isDefault: Joi.boolean().required(),
|
isDefault: Joi.boolean().required(),
|
||||||
name: Joi.string().required(),
|
name: Joi.string().required(),
|
||||||
active: Joi.boolean().required(),
|
active: Joi.boolean().required(),
|
||||||
baseUrl: Joi.string().optional(),
|
baseUrl: Joi.string().optional().allow("", null),
|
||||||
apiKey: Joi.string().required(),
|
apiKey: Joi.string().required(),
|
||||||
// TODO: should be enum
|
// TODO: should be enum
|
||||||
defaultModel: Joi.string().optional(),
|
defaultModel: Joi.string().optional(),
|
||||||
|
|
Loading…
Reference in New Issue