mirror of
https://github.com/StanGirard/quivr.git
synced 2024-12-25 04:12:44 +03:00
feat: add api brain creation frontend (#1631)
Issue: https://github.com/StanGirard/quivr/issues/1607 Demo: https://github.com/StanGirard/quivr/assets/63923024/a087d856-e201-4b88-80b3-b001d7bb6b16
This commit is contained in:
parent
e71e79cf3e
commit
223af1d3f6
@ -23,7 +23,7 @@ class ApiBrainDefinitionSchema(BaseModel, extra=Extra.forbid):
|
|||||||
required: list[str] = []
|
required: list[str] = []
|
||||||
|
|
||||||
|
|
||||||
class ApiBrainDefinitionSecret(BaseModel):
|
class ApiBrainDefinitionSecret(BaseModel, extra=Extra.forbid):
|
||||||
name: str
|
name: str
|
||||||
type: str
|
type: str
|
||||||
|
|
||||||
|
@ -1,20 +1,51 @@
|
|||||||
import { BrainRoleType } from "@/lib/components/BrainUsers/types";
|
import { BrainRoleType } from "@/lib/components/BrainUsers/types";
|
||||||
import { BrainStatus, BrainType } from "@/lib/types/brainConfig";
|
import { BrainStatus, BrainType, Model } from "@/lib/types/brainConfig";
|
||||||
|
|
||||||
|
export type ApiBrainDefinitionSchemaPropertyType = "string" | "number";
|
||||||
|
|
||||||
|
export type ApiBrainDefinitionSchemaProperty = {
|
||||||
|
type: ApiBrainDefinitionSchemaPropertyType;
|
||||||
|
description: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
export const allowedRequestMethods = ["GET", "POST", "PUT", "DELETE"];
|
||||||
|
|
||||||
|
export type AllowedRequestMethod = (typeof allowedRequestMethods)[number];
|
||||||
|
|
||||||
|
export type ApiBrainDefinitionSchema = {
|
||||||
|
properties: ApiBrainDefinitionSchemaProperty[];
|
||||||
|
required: string[];
|
||||||
|
};
|
||||||
|
|
||||||
export type SubscriptionUpdatableProperties = {
|
export type SubscriptionUpdatableProperties = {
|
||||||
role: BrainRoleType | null;
|
role: BrainRoleType | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type ApiBrainDefinitionSecret = {
|
||||||
|
name: string;
|
||||||
|
type: ApiBrainDefinitionSchemaPropertyType;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type ApiBrainDefinition = {
|
||||||
|
method: AllowedRequestMethod;
|
||||||
|
url: string;
|
||||||
|
search_params: ApiBrainDefinitionSchema;
|
||||||
|
params: ApiBrainDefinitionSchema;
|
||||||
|
secrets?: ApiBrainDefinitionSecret[];
|
||||||
|
};
|
||||||
|
|
||||||
export type CreateBrainInput = {
|
export type CreateBrainInput = {
|
||||||
name: string;
|
name: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
status?: BrainStatus;
|
status?: BrainStatus;
|
||||||
model?: string;
|
model?: Model;
|
||||||
temperature?: number;
|
temperature?: number;
|
||||||
max_tokens?: number;
|
max_tokens?: number;
|
||||||
openai_api_key?: string;
|
openai_api_key?: string;
|
||||||
prompt_id?: string | null;
|
prompt_id?: string | null;
|
||||||
brain_type?: BrainType;
|
brain_type?: BrainType;
|
||||||
|
brain_definition?: ApiBrainDefinition;
|
||||||
|
brain_secrets_values?: Record<string, string>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type UpdateBrainInput = Partial<CreateBrainInput>;
|
export type UpdateBrainInput = Partial<CreateBrainInput>;
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { FormProvider, useForm } from "react-hook-form";
|
import { FormProvider, useForm } from "react-hook-form";
|
||||||
|
|
||||||
import { defaultBrainConfig } from "@/lib/config/defaultBrainConfig";
|
import { addBrainDefaultValues } from "@/lib/config/defaultBrainConfig";
|
||||||
import { BrainConfig } from "@/lib/types/brainConfig";
|
|
||||||
|
|
||||||
import { AddBrainConfig } from "./components/AddBrainConfig/AddBrainConfig";
|
import { AddBrainConfig } from "./components/AddBrainConfig/AddBrainConfig";
|
||||||
|
import { CreateBrainProps } from "./components/AddBrainConfig/types";
|
||||||
|
|
||||||
type AddBrainModalProps = {
|
type AddBrainModalProps = {
|
||||||
triggerClassName?: string;
|
triggerClassName?: string;
|
||||||
@ -12,8 +12,17 @@ type AddBrainModalProps = {
|
|||||||
export const AddBrainModal = ({
|
export const AddBrainModal = ({
|
||||||
triggerClassName,
|
triggerClassName,
|
||||||
}: AddBrainModalProps): JSX.Element => {
|
}: AddBrainModalProps): JSX.Element => {
|
||||||
const methods = useForm<BrainConfig>({
|
const defaultValues: CreateBrainProps = {
|
||||||
defaultValues: defaultBrainConfig,
|
...addBrainDefaultValues,
|
||||||
|
prompt: {
|
||||||
|
title: "",
|
||||||
|
content: "",
|
||||||
|
},
|
||||||
|
setDefault: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const methods = useForm<CreateBrainProps>({
|
||||||
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -11,6 +11,7 @@ import { Modal } from "@/lib/components/ui/Modal";
|
|||||||
import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
|
import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
|
import { ApiRequestDefinition } from "./components/ApiRequestDefinition";
|
||||||
import { PublicAccessConfirmationModal } from "./components/PublicAccessConfirmationModal";
|
import { PublicAccessConfirmationModal } from "./components/PublicAccessConfirmationModal";
|
||||||
import { useAddBrainConfig } from "./hooks/useAddBrainConfig";
|
import { useAddBrainConfig } from "./hooks/useAddBrainConfig";
|
||||||
import { useAddBrainConfigLabels } from "./hooks/useAddBrainConfigLabels";
|
import { useAddBrainConfigLabels } from "./hooks/useAddBrainConfigLabels";
|
||||||
@ -105,22 +106,25 @@ export const AddBrainConfig = ({
|
|||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
{brainApiIsOn && (
|
{brainApiIsOn && (
|
||||||
|
<>
|
||||||
<fieldset className="w-full flex flex-col">
|
<fieldset className="w-full flex flex-col">
|
||||||
<Radio
|
<Radio
|
||||||
items={knowledgeSourceOptions}
|
items={knowledgeSourceOptions}
|
||||||
label={t("knowledge_source_label", { ns: "brain" })}
|
label={t("knowledge_source_label", { ns: "brain" })}
|
||||||
value={brainType}
|
value={brainType}
|
||||||
className="flex-1 justify-between w-[50%]"
|
className="flex-1 justify-between w-[50%]"
|
||||||
{...register("brainType")}
|
{...register("brain_type")}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
<ApiRequestDefinition />
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
<Field
|
<Field
|
||||||
label={t("openAiKeyLabel", { ns: "config" })}
|
label={t("openAiKeyLabel", { ns: "config" })}
|
||||||
placeholder={t("openAiKeyPlaceholder", { ns: "config" })}
|
placeholder={t("openAiKeyPlaceholder", { ns: "config" })}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
{...register("openAiKey")}
|
{...register("openai_api_key")}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<fieldset className="w-full flex flex-col">
|
<fieldset className="w-full flex flex-col">
|
||||||
@ -163,7 +167,7 @@ export const AddBrainConfig = ({
|
|||||||
min="10"
|
min="10"
|
||||||
max={defineMaxTokens(model)}
|
max={defineMaxTokens(model)}
|
||||||
value={maxTokens}
|
value={maxTokens}
|
||||||
{...register("maxTokens")}
|
{...register("max_tokens")}
|
||||||
/>
|
/>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<Divider text={t("customPromptSection", { ns: "config" })} />
|
<Divider text={t("customPromptSection", { ns: "config" })} />
|
||||||
|
@ -1,53 +1,95 @@
|
|||||||
import { Content, Root } from "@radix-ui/react-tabs";
|
import { Content, List, Root } from "@radix-ui/react-tabs";
|
||||||
|
import { Fragment } from "react";
|
||||||
|
import { useFormContext } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
|
||||||
import { BrainType } from "@/lib/types/brainConfig";
|
import { allowedRequestMethods, CreateBrainInput } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
import { useApiDefinitionTabs } from "./hooks/useApiDefinitionTabs";
|
import { BrainDefinitionTabTrigger } from "./components/BrainDefinitionTabTrigger";
|
||||||
import { HeadersDefinition } from "./tabs/HeadersDefinition";
|
import { ParamsDefinition } from "./components/ParamsDefinition/ParamsDefinition";
|
||||||
import { ParamsDefinition } from "./tabs/ParamsDefinition";
|
import { SecretsDefinition } from "./components/SecretsDefinition/SecretsDefinition";
|
||||||
import { SearchParamsDefinition } from "./tabs/SearchParamsDefinition";
|
import { useApiRequestDefinition } from "./hooks/useApiRequestDefinition";
|
||||||
export const ApiRequestDefinition = (brainType: {
|
|
||||||
brainType: BrainType;
|
|
||||||
}): JSX.Element => {
|
|
||||||
const { selectedTab, setSelectedTab } = useApiDefinitionTabs();
|
|
||||||
console.log(brainType);
|
|
||||||
|
|
||||||
setSelectedTab("searchParams");
|
export const ApiRequestDefinition = (): JSX.Element => {
|
||||||
|
const { selectedTab, setSelectedTab } = useApiRequestDefinition();
|
||||||
|
const { t } = useTranslation(["external_api_definition"]);
|
||||||
|
|
||||||
|
const { watch, register } = useFormContext<CreateBrainInput>();
|
||||||
|
|
||||||
|
const brainType = watch("brain_type");
|
||||||
|
|
||||||
|
if (brainType !== "api") {
|
||||||
|
return <Fragment />;
|
||||||
|
}
|
||||||
|
|
||||||
|
const allowedMethodsOptions = allowedRequestMethods.map((method) => ({
|
||||||
|
label: method,
|
||||||
|
value: method,
|
||||||
|
}));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Root
|
<>
|
||||||
className="flex flex-col w-full h-full overflow-scroll bg-white dark:bg-black p-4 md:p-10 max-w-5xl"
|
<div className="flex gap-2 w-full">
|
||||||
value={selectedTab}
|
|
||||||
>
|
|
||||||
<div className="flex gap-2 p-4">
|
|
||||||
<select
|
<select
|
||||||
className="block w-32 px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
className="block w-32 px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
defaultValue="GET"
|
defaultValue="GET"
|
||||||
// {...register("api.method")}
|
{...register("brain_definition.method")}
|
||||||
>
|
>
|
||||||
<option value="GET">GET</option>
|
{allowedMethodsOptions.map(({ label, value }) => (
|
||||||
<option value="POST">POST</option>
|
<option key={value} value={value}>
|
||||||
<option value="PUT">PUT</option>
|
{label}
|
||||||
<option value="DELETE">DELETE</option>
|
</option>
|
||||||
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
className="flex-1 px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:outline-none focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50"
|
||||||
placeholder="https://api.example.com/resource"
|
placeholder="https://api.example.com/resource"
|
||||||
// {...register("api.url", { required: true })}
|
{...register("brain_definition.url", { required: true })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<Root
|
||||||
|
className="flex flex-col w-full h-full overflow-scroll bg-white dark:bg-black py-4 md:py-10 max-w-5xl"
|
||||||
|
value={selectedTab}
|
||||||
|
>
|
||||||
|
<List className="flex flex-col md:flex-row justify-between space-y-2 md:space-y-0">
|
||||||
|
<BrainDefinitionTabTrigger
|
||||||
|
value="params"
|
||||||
|
label={t("params")}
|
||||||
|
selected={selectedTab === "params"}
|
||||||
|
onChange={setSelectedTab}
|
||||||
|
/>
|
||||||
|
<BrainDefinitionTabTrigger
|
||||||
|
value="searchParams"
|
||||||
|
label={t("searchParams")}
|
||||||
|
selected={selectedTab === "searchParams"}
|
||||||
|
onChange={setSelectedTab}
|
||||||
|
/>
|
||||||
|
<BrainDefinitionTabTrigger
|
||||||
|
value="secrets"
|
||||||
|
label={t("secrets")}
|
||||||
|
selected={selectedTab === "secrets"}
|
||||||
|
onChange={setSelectedTab}
|
||||||
|
/>
|
||||||
|
</List>
|
||||||
<div className="flex-1 md:pt-0 pb-0">
|
<div className="flex-1 md:pt-0 pb-0">
|
||||||
<Content value="people">
|
<Content value="params">
|
||||||
<SearchParamsDefinition />
|
<ParamsDefinition
|
||||||
|
description={t("paramsTabDescription")}
|
||||||
|
name="brain_definition.params"
|
||||||
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
<Content value="settings">
|
<Content value="searchParams">
|
||||||
<HeadersDefinition />
|
<ParamsDefinition
|
||||||
|
description={t("searchParamsTabDescription")}
|
||||||
|
name="brain_definition.search_params"
|
||||||
|
/>
|
||||||
</Content>
|
</Content>
|
||||||
<Content value="knowledge">
|
<Content value="secrets">
|
||||||
<ParamsDefinition />
|
<SecretsDefinition />
|
||||||
</Content>
|
</Content>
|
||||||
</div>
|
</div>
|
||||||
</Root>
|
</Root>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,29 @@
|
|||||||
|
import { Trigger } from "@radix-ui/react-tabs";
|
||||||
|
|
||||||
|
import { ApiTab } from "../types";
|
||||||
|
|
||||||
|
type BrainDefinitionTabTriggerProps = {
|
||||||
|
label: string;
|
||||||
|
value: ApiTab;
|
||||||
|
selected: boolean;
|
||||||
|
onChange: (value: ApiTab) => unknown;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const BrainDefinitionTabTrigger = ({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
selected,
|
||||||
|
onChange,
|
||||||
|
}: BrainDefinitionTabTriggerProps): JSX.Element => {
|
||||||
|
return (
|
||||||
|
<Trigger
|
||||||
|
className={`flex-1 pb-2 border-gray-500 text-md align-center mb-0 ${
|
||||||
|
selected ? "font-medium border-b-2" : ""
|
||||||
|
}`}
|
||||||
|
value={value}
|
||||||
|
onClick={() => onChange(value)}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Trigger>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,72 @@
|
|||||||
|
import { useFieldArray } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { MdAdd } from "react-icons/md";
|
||||||
|
import { TiInfoOutline } from "react-icons/ti";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
|
||||||
|
import { ParamDefinitionRow } from "./components/ParamDefinitionRow";
|
||||||
|
import { defaultParamDefinitionRow } from "./config";
|
||||||
|
import { useParamsDefinition } from "./hooks/useParamsDefinition";
|
||||||
|
import { tabDescriptionStyle } from "../../styles";
|
||||||
|
|
||||||
|
type ParamsDefinitionProps = {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const paramsNameStyle = "flex flex-1 justify-center";
|
||||||
|
|
||||||
|
export const ParamsDefinition = ({
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
}: ParamsDefinitionProps): JSX.Element => {
|
||||||
|
const { t } = useTranslation(["brain"]);
|
||||||
|
const { control, register } = useParamsDefinition({
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={tabDescriptionStyle}>
|
||||||
|
<TiInfoOutline size={30} />
|
||||||
|
<p className="ml-5">{description}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="flex flex-1 font-medium">
|
||||||
|
<div className="flex flex-1">
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.name")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.description")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.type")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.required")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<ParamDefinitionRow
|
||||||
|
name={name}
|
||||||
|
key={field.id}
|
||||||
|
index={index}
|
||||||
|
remove={remove}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<div className="flex justify-end mt-3">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
append(defaultParamDefinitionRow);
|
||||||
|
}}
|
||||||
|
className="p-2"
|
||||||
|
variant={"secondary"}
|
||||||
|
>
|
||||||
|
<MdAdd size={20} /> {t("api_brain.addRow")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,79 @@
|
|||||||
|
import { UseFormRegister } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { MdCancel } from "react-icons/md";
|
||||||
|
|
||||||
|
import { paramsNameStyle } from "../../styles";
|
||||||
|
import { ParameterDefinition } from "../types";
|
||||||
|
|
||||||
|
type ParamControl = {
|
||||||
|
[name: string]: ParameterDefinition[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type ParamDefinitionRowProps = {
|
||||||
|
register: UseFormRegister<ParamControl>;
|
||||||
|
index: number;
|
||||||
|
remove: (index: number) => void;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ParamDefinitionRow = ({
|
||||||
|
index,
|
||||||
|
remove,
|
||||||
|
register,
|
||||||
|
name,
|
||||||
|
}: ParamDefinitionRowProps): JSX.Element => {
|
||||||
|
const { t } = useTranslation(["brain"]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2">
|
||||||
|
<div className={paramsNameStyle}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block shadow-sm sm:text-sm border-gray-300 dark:bg-gray-800 dark:text-gray-100 rounded-md w-full outline-none"
|
||||||
|
placeholder={t("api_brain.name")}
|
||||||
|
{...register(
|
||||||
|
`${name}.properties[${index}].name` as `${typeof name}.${number}.name`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id={`description-${index}`}
|
||||||
|
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 dark:bg-gray-800 dark:text-gray-100 rounded-md outline-none"
|
||||||
|
placeholder={t("api_brain.description")}
|
||||||
|
{...register(
|
||||||
|
`${name}.properties[${index}].description` as `${typeof name}.${number}.description`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<select
|
||||||
|
id={`type-${index}`}
|
||||||
|
className="mt-1 block w-full py-2 px-3 border border-gray-300 dark:bg-gray-800 dark:text-gray-100 bg-white dark:border-gray-800 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
|
{...register(
|
||||||
|
`${name}.properties[${index}].type` as `${typeof name}.${number}.type`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<option value="string">string</option>
|
||||||
|
<option value="number">number</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 justify-center flex">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
className="form-checkbox h-5 w-5 text-indigo-600 rounded focus:ring-2 focus:ring-indigo-400 outline-none"
|
||||||
|
{...register(`${name}.required[${index}]`)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer"
|
||||||
|
>
|
||||||
|
<MdCancel />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
import { ParameterDefinition } from "./types";
|
||||||
|
|
||||||
|
export const defaultParamDefinitionRow: ParameterDefinition = {
|
||||||
|
name: "",
|
||||||
|
type: "string",
|
||||||
|
required: false,
|
||||||
|
description: "",
|
||||||
|
};
|
@ -0,0 +1,55 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm, useFormContext, useWatch } from "react-hook-form";
|
||||||
|
|
||||||
|
import { ApiBrainDefinitionSchema } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
import { defaultParamDefinitionRow } from "../config";
|
||||||
|
import { ParameterDefinition } from "../types";
|
||||||
|
import { mapApiBrainDefinitionSchemaToParameterDefinition } from "../utils/mapApiBrainDefinitionSchemaToParameterDefinition";
|
||||||
|
import { mapParameterDefinitionToApiBrainDefinitionSchema } from "../utils/mapParameterDefinitionToApiBrainDefinitionSchema";
|
||||||
|
|
||||||
|
type UseParamsDefinitionProps = {
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const useParamsDefinition = ({ name }: UseParamsDefinitionProps) => {
|
||||||
|
const { watch, register } = useFormContext();
|
||||||
|
const existingParams = watch(name) as ApiBrainDefinitionSchema;
|
||||||
|
const existingProperties =
|
||||||
|
mapApiBrainDefinitionSchemaToParameterDefinition(existingParams);
|
||||||
|
|
||||||
|
const { control } = useForm<{
|
||||||
|
[name: string]: ParameterDefinition[];
|
||||||
|
}>({
|
||||||
|
defaultValues: {
|
||||||
|
[name]:
|
||||||
|
existingProperties.length > 0
|
||||||
|
? existingProperties
|
||||||
|
: [defaultParamDefinitionRow],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const params = useWatch({
|
||||||
|
control,
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { setValue } = useFormContext();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const paramsWithValues = params.filter(
|
||||||
|
(param) => param.name !== "" && param.description !== ""
|
||||||
|
);
|
||||||
|
|
||||||
|
setValue(
|
||||||
|
name,
|
||||||
|
mapParameterDefinitionToApiBrainDefinitionSchema(paramsWithValues)
|
||||||
|
);
|
||||||
|
}, [params, name, setValue]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
control,
|
||||||
|
register,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,8 @@
|
|||||||
|
import { ApiBrainDefinitionSchemaPropertyType } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
export type ParameterDefinition = {
|
||||||
|
name: string;
|
||||||
|
type: ApiBrainDefinitionSchemaPropertyType;
|
||||||
|
required: boolean;
|
||||||
|
description: string;
|
||||||
|
};
|
@ -0,0 +1,23 @@
|
|||||||
|
import { ApiBrainDefinitionSchema } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
import { ParameterDefinition } from "../types";
|
||||||
|
|
||||||
|
export const mapApiBrainDefinitionSchemaToParameterDefinition = (
|
||||||
|
schema?: ApiBrainDefinitionSchema
|
||||||
|
): ParameterDefinition[] => {
|
||||||
|
if (schema === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const { properties, required } = schema;
|
||||||
|
|
||||||
|
return properties.map((property) => {
|
||||||
|
const { name, type, description } = property;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
type: type === "string" ? "string" : "number",
|
||||||
|
required: required.includes(name),
|
||||||
|
description,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
};
|
@ -0,0 +1,34 @@
|
|||||||
|
import {
|
||||||
|
ApiBrainDefinitionSchema,
|
||||||
|
ApiBrainDefinitionSchemaProperty,
|
||||||
|
} from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
import { ParameterDefinition } from "../types";
|
||||||
|
|
||||||
|
export const mapParameterDefinitionToApiBrainDefinitionSchema = (
|
||||||
|
params: ParameterDefinition[]
|
||||||
|
): ApiBrainDefinitionSchema => {
|
||||||
|
const properties: ApiBrainDefinitionSchemaProperty[] = [];
|
||||||
|
const required: string[] = [];
|
||||||
|
|
||||||
|
params.forEach((param) => {
|
||||||
|
const { name, type, required: isRequired, description } = param;
|
||||||
|
|
||||||
|
const property: ApiBrainDefinitionSchemaProperty = {
|
||||||
|
name,
|
||||||
|
type: type === "string" ? "string" : "number",
|
||||||
|
description,
|
||||||
|
};
|
||||||
|
|
||||||
|
properties.push(property);
|
||||||
|
|
||||||
|
if (isRequired) {
|
||||||
|
required.push(name);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
properties,
|
||||||
|
required,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,66 @@
|
|||||||
|
import { useFieldArray } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { MdAdd } from "react-icons/md";
|
||||||
|
import { TiInfoOutline } from "react-icons/ti";
|
||||||
|
|
||||||
|
import Button from "@/lib/components/ui/Button";
|
||||||
|
|
||||||
|
import { SecretDefinitionRow } from "./components/SecretDefinitionRow";
|
||||||
|
import {
|
||||||
|
brainSecretsSchemaDefinitionKeyInForm,
|
||||||
|
defaultSecretDefinitionRow,
|
||||||
|
} from "./config";
|
||||||
|
import { useSecretsDefinition } from "./hooks/useSecretsDefinition";
|
||||||
|
import { tabDescriptionStyle } from "../../styles";
|
||||||
|
|
||||||
|
const paramsNameStyle = "flex flex-1 justify-center";
|
||||||
|
|
||||||
|
export const SecretsDefinition = (): JSX.Element => {
|
||||||
|
const { t } = useTranslation(["brain", "external_api_definition"]);
|
||||||
|
|
||||||
|
const { control, register } = useSecretsDefinition();
|
||||||
|
|
||||||
|
const { fields, append, remove } = useFieldArray({
|
||||||
|
control,
|
||||||
|
name: brainSecretsSchemaDefinitionKeyInForm,
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className={tabDescriptionStyle}>
|
||||||
|
<TiInfoOutline size={30} />
|
||||||
|
<p className="ml-5">
|
||||||
|
{t("secretsTabDescription", { ns: "external_api_definition" })}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-1 font-medium">
|
||||||
|
<div className="flex flex-1">
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.name")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.description")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.type")}</div>
|
||||||
|
<div className={paramsNameStyle}>{t("api_brain.value")}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{fields.map((field, index) => (
|
||||||
|
<SecretDefinitionRow
|
||||||
|
key={field.id}
|
||||||
|
index={index}
|
||||||
|
remove={remove}
|
||||||
|
register={register}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
|
<div className="flex justify-end mt-3">
|
||||||
|
<Button
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
append(defaultSecretDefinitionRow);
|
||||||
|
}}
|
||||||
|
className="p-2"
|
||||||
|
variant={"secondary"}
|
||||||
|
>
|
||||||
|
<MdAdd size={20} /> {t("api_brain.addRow")}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,81 @@
|
|||||||
|
import { UseFormRegister } from "react-hook-form";
|
||||||
|
import { useTranslation } from "react-i18next";
|
||||||
|
import { MdCancel } from "react-icons/md";
|
||||||
|
|
||||||
|
import { paramsNameStyle } from "../../styles";
|
||||||
|
import { brainSecretsSchemaDefinitionKeyInForm } from "../config";
|
||||||
|
import { SecretDefinition } from "../types";
|
||||||
|
|
||||||
|
type SecretControl = {
|
||||||
|
[name: string]: SecretDefinition[];
|
||||||
|
};
|
||||||
|
|
||||||
|
type SecretDefinitionRowProps = {
|
||||||
|
register: UseFormRegister<SecretControl>;
|
||||||
|
index: number;
|
||||||
|
remove: (index: number) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SecretDefinitionRow = ({
|
||||||
|
index,
|
||||||
|
remove,
|
||||||
|
register,
|
||||||
|
}: SecretDefinitionRowProps): JSX.Element => {
|
||||||
|
const { t } = useTranslation(["brain"]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2">
|
||||||
|
<div className={paramsNameStyle}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block shadow-sm sm:text-sm border-gray-300 dark:bg-gray-800 dark:text-gray-100 rounded-md w-full outline-none"
|
||||||
|
placeholder={t("api_brain.name")}
|
||||||
|
{...register(
|
||||||
|
`${brainSecretsSchemaDefinitionKeyInForm}[${index}].name`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
id={`description-${index}`}
|
||||||
|
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 dark:bg-gray-800 dark:text-gray-100 rounded-md outline-none"
|
||||||
|
placeholder={t("api_brain.description")}
|
||||||
|
{...register(
|
||||||
|
`${brainSecretsSchemaDefinitionKeyInForm}[${index}].description`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<select
|
||||||
|
id={`type-${index}`}
|
||||||
|
className="mt-1 block w-full py-2 px-3 border border-gray-300 dark:bg-gray-800 dark:text-gray-100 bg-white dark:border-gray-800 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm"
|
||||||
|
{...register(
|
||||||
|
`${brainSecretsSchemaDefinitionKeyInForm}[${index}].type`
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
<option value="string">string</option>
|
||||||
|
<option value="number">number</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className={paramsNameStyle}>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 dark:bg-gray-800 dark:text-gray-100 rounded-md outline-none"
|
||||||
|
placeholder={t("api_brain.value")}
|
||||||
|
{...register(
|
||||||
|
`${brainSecretsSchemaDefinitionKeyInForm}[${index}].value`
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => remove(index)}
|
||||||
|
className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer"
|
||||||
|
>
|
||||||
|
<MdCancel />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,11 @@
|
|||||||
|
import { SecretDefinition } from "./types";
|
||||||
|
|
||||||
|
export const defaultSecretDefinitionRow: SecretDefinition = {
|
||||||
|
name: "",
|
||||||
|
type: "string",
|
||||||
|
value: "",
|
||||||
|
description: "",
|
||||||
|
};
|
||||||
|
|
||||||
|
export const brainSecretsSchemaDefinitionKeyInForm = "brain_definition.secrets";
|
||||||
|
export const brainSecretsValueKeyInForm = "brain_secrets_values";
|
@ -0,0 +1,67 @@
|
|||||||
|
import { useEffect } from "react";
|
||||||
|
import { useForm, useFormContext, useWatch } from "react-hook-form";
|
||||||
|
|
||||||
|
import {
|
||||||
|
brainSecretsSchemaDefinitionKeyInForm,
|
||||||
|
brainSecretsValueKeyInForm,
|
||||||
|
defaultSecretDefinitionRow,
|
||||||
|
} from "../config";
|
||||||
|
import { SecretDefinition, SecretRelatedFields } from "../types";
|
||||||
|
import { mapSecretDefinitionToApiBrainSecretsDefinitionsAndValue } from "../utils/mapSecretDefinitionToApiBrainSecretDefinition";
|
||||||
|
import { mapSecretsDefinitionsAndValuesToSecretDefinition } from "../utils/mapSecretsDefinitionsAndValuesToSecretDefinition";
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
|
export const useSecretsDefinition = () => {
|
||||||
|
const { getValues: getContextValues } = useFormContext<{
|
||||||
|
[brainSecretsSchemaDefinitionKeyInForm]: SecretDefinition[];
|
||||||
|
[brainSecretsValueKeyInForm]: Record<string, string>;
|
||||||
|
}>();
|
||||||
|
const { setValue } = useFormContext();
|
||||||
|
|
||||||
|
const { register, control } = useForm<SecretRelatedFields>({
|
||||||
|
defaultValues: {
|
||||||
|
[brainSecretsSchemaDefinitionKeyInForm]: [defaultSecretDefinitionRow],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const existingSecretsDefinitionsSchemas = getContextValues(
|
||||||
|
brainSecretsSchemaDefinitionKeyInForm
|
||||||
|
);
|
||||||
|
const existingSecretsValues = getContextValues(brainSecretsValueKeyInForm);
|
||||||
|
|
||||||
|
const secretDefinition = mapSecretsDefinitionsAndValuesToSecretDefinition(
|
||||||
|
existingSecretsDefinitionsSchemas,
|
||||||
|
existingSecretsValues
|
||||||
|
);
|
||||||
|
if (secretDefinition.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValue(brainSecretsSchemaDefinitionKeyInForm, secretDefinition);
|
||||||
|
}, [getContextValues, setValue]);
|
||||||
|
|
||||||
|
const secretsDefinitionSchemas = useWatch({
|
||||||
|
control,
|
||||||
|
name: brainSecretsSchemaDefinitionKeyInForm,
|
||||||
|
}) as SecretDefinition[] | undefined;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (secretsDefinitionSchemas === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const paramsWithValues = secretsDefinitionSchemas.filter(
|
||||||
|
(param) => param.name !== "" && param.description !== ""
|
||||||
|
);
|
||||||
|
|
||||||
|
const { secrets, brain_secrets_values } =
|
||||||
|
mapSecretDefinitionToApiBrainSecretsDefinitionsAndValue(paramsWithValues);
|
||||||
|
|
||||||
|
setValue(brainSecretsSchemaDefinitionKeyInForm, secrets);
|
||||||
|
setValue(brainSecretsValueKeyInForm, brain_secrets_values);
|
||||||
|
}, [secretsDefinitionSchemas, setValue]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
control,
|
||||||
|
register,
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,12 @@
|
|||||||
|
import { ApiBrainDefinitionSchemaPropertyType } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
export type SecretDefinition = {
|
||||||
|
name: string;
|
||||||
|
type: ApiBrainDefinitionSchemaPropertyType;
|
||||||
|
description: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type SecretRelatedFields = {
|
||||||
|
[name: string]: SecretDefinition[];
|
||||||
|
};
|
@ -0,0 +1,31 @@
|
|||||||
|
import { ApiBrainDefinitionSecret } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
import { SecretDefinition } from "../types";
|
||||||
|
|
||||||
|
export type ApiBrainSecretsDefinitionsAndValues = {
|
||||||
|
secrets: ApiBrainDefinitionSecret[];
|
||||||
|
brain_secrets_values: Record<string, string>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mapSecretDefinitionToApiBrainSecretsDefinitionsAndValue = (
|
||||||
|
secretDefinitions: SecretDefinition[]
|
||||||
|
): ApiBrainSecretsDefinitionsAndValues => {
|
||||||
|
const secrets: ApiBrainDefinitionSecret[] = secretDefinitions.map(
|
||||||
|
(secretDefinition) => {
|
||||||
|
const { name, type } = secretDefinition;
|
||||||
|
|
||||||
|
return { name, type };
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const brain_secrets_values: Record<string, string> = secretDefinitions.reduce(
|
||||||
|
(acc, secretDefinition) => {
|
||||||
|
const { name, value } = secretDefinition;
|
||||||
|
|
||||||
|
return { ...acc, [name]: value };
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
);
|
||||||
|
|
||||||
|
return { secrets, brain_secrets_values };
|
||||||
|
};
|
@ -0,0 +1,29 @@
|
|||||||
|
import { ApiBrainDefinition } from "@/lib/api/brain/types";
|
||||||
|
|
||||||
|
import { defaultSecretDefinitionRow } from "../config";
|
||||||
|
import { SecretDefinition } from "../types";
|
||||||
|
|
||||||
|
export const mapSecretsDefinitionsAndValuesToSecretDefinition = (
|
||||||
|
apiBrainDefinition?: ApiBrainDefinition,
|
||||||
|
brainSecretsValue?: Record<string, string>
|
||||||
|
): SecretDefinition[] => {
|
||||||
|
if (
|
||||||
|
apiBrainDefinition === undefined ||
|
||||||
|
brainSecretsValue === undefined ||
|
||||||
|
apiBrainDefinition.secrets === undefined ||
|
||||||
|
apiBrainDefinition.secrets.length === 0
|
||||||
|
) {
|
||||||
|
return [defaultSecretDefinitionRow];
|
||||||
|
}
|
||||||
|
|
||||||
|
const secrets = apiBrainDefinition.secrets;
|
||||||
|
|
||||||
|
const secretDefinition: SecretDefinition[] = secrets.map((secret) => {
|
||||||
|
const { name, type } = secret;
|
||||||
|
const value = brainSecretsValue[name] ?? "";
|
||||||
|
|
||||||
|
return { name, type, description: "", value };
|
||||||
|
});
|
||||||
|
|
||||||
|
return secretDefinition;
|
||||||
|
};
|
@ -0,0 +1 @@
|
|||||||
|
export const paramsNameStyle = "flex flex-1 justify-center";
|
@ -3,8 +3,8 @@ import { useState } from "react";
|
|||||||
import { ApiTab } from "../types";
|
import { ApiTab } from "../types";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useApiDefinitionTabs = () => {
|
export const useApiRequestDefinition = () => {
|
||||||
const [selectedTab, setSelectedTab] = useState<ApiTab>("searchParams");
|
const [selectedTab, setSelectedTab] = useState<ApiTab>("params");
|
||||||
|
|
||||||
return {
|
return {
|
||||||
selectedTab,
|
selectedTab,
|
@ -0,0 +1 @@
|
|||||||
|
export const tabDescriptionStyle = "flex items-center text-gray-500 my-3";
|
@ -1,3 +0,0 @@
|
|||||||
export const HeadersDefinition = (): JSX.Element => {
|
|
||||||
return <></>;
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export const ParamsDefinition = (): JSX.Element => {
|
|
||||||
return <></>;
|
|
||||||
};
|
|
@ -1,3 +0,0 @@
|
|||||||
export const SearchParamsDefinition = (): JSX.Element => {
|
|
||||||
return <></>;
|
|
||||||
};
|
|
@ -1,3 +1,3 @@
|
|||||||
export const apiTabs = ["searchParams", "headers", "params"] as const;
|
export const apiTabs = ["params", "searchParams", "secrets"] as const;
|
||||||
|
|
||||||
export type ApiTab = (typeof apiTabs)[number];
|
export type ApiTab = (typeof apiTabs)[number];
|
||||||
|
@ -10,12 +10,12 @@ import { useBrainApi } from "@/lib/api/brain/useBrainApi";
|
|||||||
import { usePromptApi } from "@/lib/api/prompt/usePromptApi";
|
import { usePromptApi } from "@/lib/api/prompt/usePromptApi";
|
||||||
import { USER_DATA_KEY } from "@/lib/api/user/config";
|
import { USER_DATA_KEY } from "@/lib/api/user/config";
|
||||||
import { useUserApi } from "@/lib/api/user/useUserApi";
|
import { useUserApi } from "@/lib/api/user/useUserApi";
|
||||||
import { defaultBrainConfig } from "@/lib/config/defaultBrainConfig";
|
|
||||||
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
|
||||||
import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
|
import { defineMaxTokens } from "@/lib/helpers/defineMaxTokens";
|
||||||
import { getAccessibleModels } from "@/lib/helpers/getAccessibleModels";
|
import { getAccessibleModels } from "@/lib/helpers/getAccessibleModels";
|
||||||
import { useToast } from "@/lib/hooks";
|
import { useToast } from "@/lib/hooks";
|
||||||
import { BrainConfig } from "@/lib/types/brainConfig";
|
|
||||||
|
import { CreateBrainProps } from "../types";
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||||
export const useAddBrainConfig = () => {
|
export const useAddBrainConfig = () => {
|
||||||
@ -38,17 +38,6 @@ export const useAddBrainConfig = () => {
|
|||||||
queryFn: getUser,
|
queryFn: getUser,
|
||||||
});
|
});
|
||||||
|
|
||||||
const defaultValues = {
|
|
||||||
...defaultBrainConfig,
|
|
||||||
name: "",
|
|
||||||
description: "",
|
|
||||||
setDefault: false,
|
|
||||||
prompt: {
|
|
||||||
title: "",
|
|
||||||
content: "",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
getValues,
|
getValues,
|
||||||
@ -56,14 +45,14 @@ export const useAddBrainConfig = () => {
|
|||||||
watch,
|
watch,
|
||||||
setValue,
|
setValue,
|
||||||
formState: { dirtyFields },
|
formState: { dirtyFields },
|
||||||
} = useFormContext<BrainConfig>();
|
} = useFormContext<CreateBrainProps>();
|
||||||
|
|
||||||
const openAiKey = watch("openAiKey");
|
const openAiKey = watch("openai_api_key");
|
||||||
const model = watch("model");
|
const model = watch("model");
|
||||||
const temperature = watch("temperature");
|
const temperature = watch("temperature");
|
||||||
const maxTokens = watch("maxTokens");
|
const maxTokens = watch("max_tokens");
|
||||||
const status = watch("status");
|
const status = watch("status");
|
||||||
const brainType = watch("brainType");
|
const brainType = watch("brain_type");
|
||||||
|
|
||||||
const accessibleModels = getAccessibleModels({
|
const accessibleModels = getAccessibleModels({
|
||||||
openAiKey,
|
openAiKey,
|
||||||
@ -77,7 +66,9 @@ export const useAddBrainConfig = () => {
|
|||||||
}, [dirtyFields.status, status]);
|
}, [dirtyFields.status, status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setValue("maxTokens", Math.min(maxTokens, defineMaxTokens(model)));
|
if (maxTokens !== undefined && model !== undefined) {
|
||||||
|
setValue("max_tokens", Math.min(maxTokens, defineMaxTokens(model)));
|
||||||
|
}
|
||||||
}, [maxTokens, model, setValue]);
|
}, [maxTokens, model, setValue]);
|
||||||
|
|
||||||
const getCreatingBrainPromptId = async (): Promise<string | undefined> => {
|
const getCreatingBrainPromptId = async (): Promise<string | undefined> => {
|
||||||
@ -91,7 +82,13 @@ export const useAddBrainConfig = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
const { name, description, setDefault } = getValues();
|
const {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
setDefault,
|
||||||
|
brain_definition,
|
||||||
|
brain_secrets_values,
|
||||||
|
} = getValues();
|
||||||
|
|
||||||
if (name.trim() === "" || isPending) {
|
if (name.trim() === "" || isPending) {
|
||||||
publish({
|
publish({
|
||||||
@ -117,6 +114,8 @@ export const useAddBrainConfig = () => {
|
|||||||
prompt_id,
|
prompt_id,
|
||||||
status,
|
status,
|
||||||
brain_type: brainType,
|
brain_type: brainType,
|
||||||
|
brain_definition,
|
||||||
|
brain_secrets_values,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (createdBrainId === undefined) {
|
if (createdBrainId === undefined) {
|
||||||
@ -135,7 +134,7 @@ export const useAddBrainConfig = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsShareModalOpen(false);
|
setIsShareModalOpen(false);
|
||||||
reset(defaultValues);
|
reset();
|
||||||
publish({
|
publish({
|
||||||
variant: "success",
|
variant: "success",
|
||||||
text: t("brainCreated", { ns: "brain" }),
|
text: t("brainCreated", { ns: "brain" }),
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
import { CreateBrainInput } from "@/lib/api/brain/types";
|
||||||
|
import { CreatePromptProps } from "@/lib/api/prompt/prompt";
|
||||||
|
|
||||||
|
export type CreateBrainProps = CreateBrainInput & {
|
||||||
|
prompt: CreatePromptProps;
|
||||||
|
setDefault: boolean;
|
||||||
|
};
|
@ -1,5 +1,18 @@
|
|||||||
|
import { CreateBrainInput } from "../api/brain/types";
|
||||||
import { BrainConfig } from "../types/brainConfig";
|
import { BrainConfig } from "../types/brainConfig";
|
||||||
|
|
||||||
|
export const addBrainDefaultValues: CreateBrainInput = {
|
||||||
|
model: "gpt-3.5-turbo",
|
||||||
|
temperature: 0,
|
||||||
|
max_tokens: 500,
|
||||||
|
openai_api_key: undefined,
|
||||||
|
prompt_id: undefined,
|
||||||
|
status: "private",
|
||||||
|
name: "",
|
||||||
|
description: "",
|
||||||
|
brain_type: "doc",
|
||||||
|
};
|
||||||
|
|
||||||
export const defaultBrainConfig: BrainConfig = {
|
export const defaultBrainConfig: BrainConfig = {
|
||||||
model: "gpt-3.5-turbo",
|
model: "gpt-3.5-turbo",
|
||||||
temperature: 0,
|
temperature: 0,
|
||||||
|
@ -51,7 +51,10 @@ export const useBrainProvider = () => {
|
|||||||
try {
|
try {
|
||||||
setCurrentBrainId(createdBrain.id);
|
setCurrentBrainId(createdBrain.id);
|
||||||
|
|
||||||
void track("BRAIN_CREATED");
|
void track("BRAIN_CREATED", {
|
||||||
|
brainType: brain.brain_type,
|
||||||
|
});
|
||||||
|
|
||||||
void fetchAllBrains();
|
void fetchAllBrains();
|
||||||
|
|
||||||
return createdBrain.id;
|
return createdBrain.id;
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import { Model, PaidModels } from "../types/brainConfig";
|
import { Model, PaidModels } from "../types/brainConfig";
|
||||||
|
|
||||||
export const defineMaxTokens = (model: Model | PaidModels): number => {
|
export const defineMaxTokens = (
|
||||||
|
model: Model | PaidModels | undefined
|
||||||
|
): number => {
|
||||||
//At the moment is evaluating only models from OpenAI
|
//At the moment is evaluating only models from OpenAI
|
||||||
switch (model) {
|
switch (model) {
|
||||||
case "gpt-3.5-turbo":
|
case "gpt-3.5-turbo":
|
||||||
|
@ -6,6 +6,8 @@ export const brainTypes = ["doc", "api"] as const;
|
|||||||
|
|
||||||
export type BrainType = (typeof brainTypes)[number];
|
export type BrainType = (typeof brainTypes)[number];
|
||||||
|
|
||||||
|
export type Model = (typeof freeModels)[number];
|
||||||
|
|
||||||
export type BrainConfig = {
|
export type BrainConfig = {
|
||||||
model: Model;
|
model: Model;
|
||||||
temperature: number;
|
temperature: number;
|
||||||
@ -57,5 +59,3 @@ export const freeModels = [
|
|||||||
export const paidModels = [...openAiPaidModels] as const;
|
export const paidModels = [...openAiPaidModels] as const;
|
||||||
|
|
||||||
export type PaidModels = (typeof paidModels)[number];
|
export type PaidModels = (typeof paidModels)[number];
|
||||||
|
|
||||||
export type Model = (typeof freeModels)[number];
|
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "My Brains",
|
"myBrains": "My Brains",
|
||||||
"knowledge_source_doc": "Documents",
|
"knowledge_source_doc": "Documents",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "Knowledge source"
|
"knowledge_source_label": "Knowledge source",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "Name",
|
||||||
|
"description": "Description",
|
||||||
|
"type": "Type",
|
||||||
|
"required": "Required",
|
||||||
|
"addRow": "Add row",
|
||||||
|
"value": "Value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"paramsTabDescription": "These values are sent as the request body.",
|
||||||
|
"searchParamsTabDescription": "These values are sent as the query string.",
|
||||||
|
"secretsTabDescription": "These values are sent as header keys"
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "Mis cerebros",
|
"myBrains": "Mis cerebros",
|
||||||
"knowledge_source_doc": "Documentos",
|
"knowledge_source_doc": "Documentos",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "Fuente de conocimiento"
|
"knowledge_source_label": "Fuente de conocimiento",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "Nombre",
|
||||||
|
"description": "Descripción",
|
||||||
|
"type": "Tipo",
|
||||||
|
"required": "Requerido",
|
||||||
|
"addRow": "Agregar fila",
|
||||||
|
"value": "Valor"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "Secretos",
|
||||||
|
"paramsTabDescription": "Estos valores se envían como cuerpo de la solicitud.",
|
||||||
|
"searchParamsTabDescription": "Estos valores se envían como cadena de consulta.",
|
||||||
|
"secretsTabDescription": "Estos valores se envían como claves de encabezado."
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "Mes cerveaux",
|
"myBrains": "Mes cerveaux",
|
||||||
"knowledge_source_doc": "Documents",
|
"knowledge_source_doc": "Documents",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "Source de connaissance"
|
"knowledge_source_label": "Source de connaissance",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "Nom",
|
||||||
|
"description": "Description",
|
||||||
|
"type": "Type",
|
||||||
|
"required": "Requis",
|
||||||
|
"addRow": "Ajouter une ligne",
|
||||||
|
"value": "Valeur"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"paramsTabDescription": "Ces valeurs sont envoyées sous forme de corps de requête.",
|
||||||
|
"searchParamsTabDescription": "Ces valeurs sont envoyées sous forme de chaîne de requête.",
|
||||||
|
"secretsTabDescription": "Ces valeurs sont envoyées sous forme de clés d'en-tête."
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "Meus cérebros",
|
"myBrains": "Meus cérebros",
|
||||||
"knowledge_source_doc": "Documentos",
|
"knowledge_source_doc": "Documentos",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "Fonte de conhecimento"
|
"knowledge_source_label": "Fonte de conhecimento",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "Name",
|
||||||
|
"description": "Description",
|
||||||
|
"type": "Type",
|
||||||
|
"required": "Required",
|
||||||
|
"addRow": "Add row",
|
||||||
|
"value": "Value"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "Secrets",
|
||||||
|
"paramsTabDescription": "Estes valores são enviados como corpo da solicitação.",
|
||||||
|
"searchParamsTabDescription": "Estes valores são enviados como string de consulta.",
|
||||||
|
"secretsTabDescription": "Estes valores são enviados como chaves de cabeçalho"
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "Мои мозги",
|
"myBrains": "Мои мозги",
|
||||||
"knowledge_source_doc": "Документы",
|
"knowledge_source_doc": "Документы",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "Источник знаний"
|
"knowledge_source_label": "Источник знаний",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "Название",
|
||||||
|
"description": "Описание",
|
||||||
|
"type": "Тип",
|
||||||
|
"required": "Обязательно",
|
||||||
|
"addRow": "Добавить строку",
|
||||||
|
"value": "Значение"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "секреты",
|
||||||
|
"paramsTabDescription": "Эти значения отправляются в теле запроса.",
|
||||||
|
"searchParamsTabDescription": "Эти значения отправляются в виде строки запроса.",
|
||||||
|
"secretsTabDescription": "Эти значения отправляются в виде ключей заголовка."
|
||||||
}
|
}
|
||||||
|
@ -49,5 +49,13 @@
|
|||||||
"myBrains": "我的大脑",
|
"myBrains": "我的大脑",
|
||||||
"knowledge_source_doc": "文档",
|
"knowledge_source_doc": "文档",
|
||||||
"knowledge_source_api": "API",
|
"knowledge_source_api": "API",
|
||||||
"knowledge_source_label": "知识来源"
|
"knowledge_source_label": "知识来源",
|
||||||
|
"api_brain":{
|
||||||
|
"name": "名称",
|
||||||
|
"description": "描述",
|
||||||
|
"type": "类型",
|
||||||
|
"required": "必填",
|
||||||
|
"addRow": "添加行",
|
||||||
|
"value": "值"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,5 +6,9 @@
|
|||||||
"params": "Params",
|
"params": "Params",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"type": "Type (string or number)",
|
"type": "Type (string or number)",
|
||||||
"description": "Description"
|
"description": "Description",
|
||||||
|
"secrets": "秘密",
|
||||||
|
"paramsTabDescription": "这些值作为请求体发送。",
|
||||||
|
"searchParamsTabDescription": "这些值作为查询字符串发送。",
|
||||||
|
"secretsTabDescription": "这些值作为头部键发送。"
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user