Mamadou DICKO 2023-12-06 15:59:59 +01:00 committed by GitHub
parent 90c4a44525
commit d9f6ce4e68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 175 additions and 14 deletions

View File

@ -49,6 +49,7 @@ export type CreateBrainInput = {
brain_type?: BrainType;
brain_definition?: Omit<ApiBrainDefinition, "brain_id">;
brain_secrets_values?: Record<string, string>;
connected_brains_ids?: UUID[];
};
export type UpdateBrainInput = Partial<CreateBrainInput>;

View File

@ -6,6 +6,7 @@ import { ApiRequestDefinition } from "@/lib/components/ApiRequestDefinition";
import Button from "@/lib/components/ui/Button";
import { BrainType } from "@/lib/types/brainConfig";
import { CompositeBrainConnections } from "./components/CompositeBrainConnections/CompositeBrainConnections";
import { KnowledgeToFeedInput } from "./components/KnowledgeToFeedInput";
import { useBrainCreationHandler } from "./hooks/useBrainCreationHandler";
import { useBrainKnowledgeStep } from "./hooks/useBrainKnowledgeStep";
@ -30,7 +31,7 @@ export const BrainKnowledgeStep = ({
const brainTypeToKnowledgeComponent: Record<BrainType, JSX.Element> = {
doc: <KnowledgeToFeedInput />,
api: <ApiRequestDefinition />,
chatflow: <div>Coming soon</div>,
composite: <CompositeBrainConnections />,
};
if (currentStep !== "KNOWLEDGE" || brainType === undefined) {

View File

@ -0,0 +1,35 @@
import { Checkbox } from "@/lib/components/ui/Checkbox";
import { MinimalBrainForUser } from "@/lib/context/BrainProvider/types";
import { useConnectableBrain } from "./hooks/useConnectableBrain";
type ConnectableBrainProps = {
brain: MinimalBrainForUser;
};
export const ConnectableBrain = ({
brain,
}: ConnectableBrainProps): JSX.Element => {
const { onCheckedChange } = useConnectableBrain();
return (
<div className="flex flex-row items-center gap-2">
<Checkbox
className="text-white"
onCheckedChange={(checked) =>
onCheckedChange({
brainId: brain.id,
checked,
})
}
id={`connected_brains_ids-${brain.id}`}
/>
<label
htmlFor={`connected_brains_ids-${brain.id}`}
className="text-md font-medium leading-none cursor-pointer"
>
{brain.name}
</label>
</div>
);
};

View File

@ -0,0 +1,35 @@
import { CheckedState } from "@radix-ui/react-checkbox";
import { UUID } from "crypto";
import { useFormContext } from "react-hook-form";
import { CreateBrainProps } from "@/lib/components/AddBrainModal/types";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useConnectableBrain = () => {
const { setValue, getValues } = useFormContext<CreateBrainProps>();
const onCheckedChange = ({
checked,
brainId,
}: {
checked: CheckedState;
brainId: UUID;
}) => {
if (checked === "indeterminate") {
return;
}
const connected_brains_ids = getValues("connected_brains_ids") ?? [];
if (checked) {
setValue("connected_brains_ids", [...connected_brains_ids, brainId]);
} else {
setValue(
"connected_brains_ids",
connected_brains_ids.filter((id) => id !== brainId)
);
}
};
return {
onCheckedChange,
};
};

View File

@ -0,0 +1,24 @@
import { useTranslation } from "react-i18next";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { ConnectableBrain } from "./Components/ConnectableBrain/ConnectableBrain";
export const CompositeBrainConnections = (): JSX.Element => {
const { allBrains } = useBrainContext();
const sortedBrains = allBrains.sort((a, b) => a.name.localeCompare(b.name));
const { t } = useTranslation("brain");
return (
<div className="px-10">
<p className="text-center mb-8 italic text-sm w-full">
{t("composite_brain_composition_invitation")}
</p>
<div className="w-full flex flex-col gap-2">
{sortedBrains.map((brain) => (
<ConnectableBrain key={brain.id} brain={brain} />
))}
</div>
</div>
);
};

View File

@ -49,6 +49,7 @@ export const useBrainCreationApi = ({
brain_secrets_values,
status,
brain_type,
connected_brains_ids,
} = getValues();
const createdBrainId = await createBrainApi({
@ -59,6 +60,8 @@ export const useBrainCreationApi = ({
brain_definition: brain_type === "api" ? brain_definition : undefined,
brain_secrets_values:
brain_type === "api" ? brain_secrets_values : undefined,
connected_brains_ids:
brain_type === "composite" ? connected_brains_ids : undefined,
});
if (createdBrainId === undefined) {
@ -92,6 +95,12 @@ export const useBrainCreationApi = ({
text: t("brainCreated", { ns: "brain" }),
});
},
onError: () => {
publish({
variant: "danger",
text: t("errorCreatingBrain", { ns: "brain" }),
});
},
});
return {

View File

@ -7,13 +7,15 @@ export const useBrainKnowledgeStep = () => {
const { watch } = useFormContext<CreateBrainProps>();
const brainType = watch("brain_type");
const url = watch("brain_definition.url");
const compositeBrainConnections = watch("connected_brains_ids") ?? [];
const isApiBrain = brainType === "api";
const isChatflowBrain = brainType === "chatflow";
const isCompositeBrain = brainType === "composite";
const isApiBrainDefinitionsFilled = url !== "";
const isSubmitButtonDisabled =
isChatflowBrain || (isApiBrain && !isApiBrainDefinitionsFilled);
(isCompositeBrain && compositeBrainConnections.length === 0) ||
(isApiBrain && !isApiBrainDefinitionsFilled);
return {
brainType,

View File

@ -1,3 +1,4 @@
import { useFeatureIsOn } from "@growthbook/growthbook-react";
import { useTranslation } from "react-i18next";
import { BrainType } from "@/lib/types/brainConfig";
@ -5,6 +6,7 @@ import { BrainType } from "@/lib/types/brainConfig";
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useKnowledgeSourceLabel = () => {
const { t } = useTranslation(["translation", "brain", "config"]);
const isCompositeBrainActivated = useFeatureIsOn("agent-brain");
const knowledgeSourceOptions: {
label: string;
@ -18,12 +20,15 @@ export const useKnowledgeSourceLabel = () => {
label: t("knowledge_source_api", { ns: "brain" }),
value: "api",
},
{
label: t("knowledge_source_chatflow", { ns: "brain" }),
value: "chatflow",
},
];
if (isCompositeBrainActivated) {
knowledgeSourceOptions.push({
label: t("knowledge_source_composite_brain", { ns: "brain" }),
value: "composite",
});
}
return {
knowledgeSourceOptions,
};

View File

@ -0,0 +1,26 @@
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import * as React from "react";
import { LuCheck } from "react-icons/lu";
import { cn } from "@/lib/utils";
export const Checkbox = React.forwardRef<
React.ElementRef<typeof CheckboxPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
>(({ className, ...props }, ref) => (
<CheckboxPrimitive.Root
ref={ref}
className={cn(
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
className
)}
{...props}
>
<CheckboxPrimitive.Indicator
className={cn("flex items-center justify-center text-current")}
>
<LuCheck className="h-4 w-4" />
</CheckboxPrimitive.Indicator>
</CheckboxPrimitive.Root>
));
Checkbox.displayName = CheckboxPrimitive.Root.displayName;

View File

@ -23,6 +23,7 @@ export const addBrainDefaultValues: CreateBrainInput = {
},
secrets: [],
},
connected_brains_ids: [],
};
export const defaultModel: Model = "gpt-3.5-turbo";

View File

@ -6,7 +6,7 @@ export const brainStatuses = ["private", "public"] as const;
export type BrainStatus = (typeof brainStatuses)[number];
export const brainTypes = ["doc", "api", "chatflow"] as const;
export const brainTypes = ["doc", "api", "composite"] as const;
export type BrainType = (typeof brainTypes)[number];

View File

@ -23,6 +23,7 @@
"@growthbook/growthbook-react": "^0.17.0",
"@june-so/analytics-next": "^2.0.0",
"@radix-ui/react-accordion": "^1.1.2",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dialog": "^1.0.3",
"@radix-ui/react-popover": "^1.0.6",
"@radix-ui/react-radio-group": "^1.1.3",

View File

@ -13,6 +13,7 @@
"shareBrainUsers": "Users with access",
"shareBrainLink": "Click to copy link to share your brain",
"copiedToClipboard": "Copied to clipboard",
"composite_brain_composition_invitation": "Connect your new brain to other existing brains from your library by selecting them.",
"inviteUsers": "Add new users",
"usersInvited": "Users successfully invited",
"errorSendingInvitation": "An error occurred while sending invitations",
@ -50,7 +51,7 @@
"knowledge_source_doc": "Documents",
"knowledge_source_api": "App (Through API)",
"knowledge_source_label": "Knowledge source",
"knowledge_source_chatflow":"Agent",
"knowledge_source_composite_brain":"Agent",
"api_brain": {
"name": "Name",
"description": "Description",

View File

@ -6,6 +6,7 @@
"brainNamePlaceholder": "Ejemplo: Anotaciones de historia",
"brainUndefined": "Cerebro no definido",
"copiedToClipboard": "Copiado al portapeles",
"composite_brain_composition_invitation": "Conecta tu nuevo cerebro a otros cerebros existentes de tu biblioteca seleccionándolos.",
"defaultBrain": "Cerebro por defecto",
"errorCreatingBrain": "Error al crear cerebro",
"errorFetchingBrainUsers": "Error al obtener usuarios del cerebro",
@ -49,7 +50,7 @@
"myBrains": "Mis cerebros",
"knowledge_source_doc": "Documentos",
"knowledge_source_api": "API",
"knowledge_source_chatflow": "Agente",
"knowledge_source_composite_brain": "Agente",
"knowledge_source_label": "Fuente de conocimiento",
"api_brain":{
"name": "Nombre",

View File

@ -6,6 +6,7 @@
"brainNamePlaceholder": "Ex. Notes d'histoire",
"brainUndefined": "Cerveau non défini",
"copiedToClipboard": "Copié dans le presse-papier",
"composite_brain_composition_invitation":"Connectez votre nouveau cerveau à d'autres cerveaux existants de votre librairie en les sélectionnant.",
"defaultBrain": "Cerveau par défaut",
"errorCreatingBrain": "Une erreur s'est produite lors de la création d'un cerveau",
"errorFetchingBrainUsers": "Une erreur s'est produite lors de la récupération des utilisateurs du cerveau",
@ -49,7 +50,7 @@
"myBrains": "Mes cerveaux",
"knowledge_source_doc": "Documents",
"knowledge_source_api": "API",
"knowledge_source_chatflow": "Agent",
"knowledge_source_composite_brain": "Agent",
"knowledge_source_label": "Source de connaissance",
"api_brain": {
"name": "Nom",

View File

@ -13,6 +13,7 @@
"shareBrainUsers": "Usuários com acesso",
"shareBrainLink": "Clique para copiar o link de compartilhamento",
"copiedToClipboard": "Copiado para a área de transferência",
"composite_brain_composition_invitation": "Conecte seu novo cérebro a outros cérebros existentes em sua biblioteca selecionando-os.",
"inviteUsers": "Adicionar novos usuários",
"usersInvited": "Usuários convidados com sucesso",
"errorSendingInvitation": "Um erro ocorreu ao enviar o(s) convite(s)",
@ -49,7 +50,7 @@
"myBrains": "Meus cérebros",
"knowledge_source_doc": "Documentos",
"knowledge_source_api": "API",
"knowledge_source_chatflow": "Agente",
"knowledge_source_composite_brain": "Agente",
"knowledge_source_label": "Fonte de conhecimento",
"api_brain":{
"name": "Name",

View File

@ -13,6 +13,7 @@
"shareBrainUsers": "Пользователи с доступом",
"shareBrainLink": "Нажмите, чтобы скопировать ссылку для совместного использования мозга",
"copiedToClipboard": "Скопировано в буфер обмена",
"composite_brain_composition_invitation": "Подключите свой новый мозг к другим существующим мозгам из вашей библиотеки, выбрав их.",
"inviteUsers": "Добавить новых пользователей",
"usersInvited": "Пользователи успешно приглашены",
"errorSendingInvitation": "Ошибка при отправке приглашений",
@ -49,7 +50,7 @@
"myBrains": "Мои мозги",
"knowledge_source_doc": "Документы",
"knowledge_source_api": "API",
"knowledge_source_chatflow": "Агент",
"knowledge_source_composite_brain": "Агент",
"knowledge_source_label": "Источник знаний",
"api_brain":{
"name": "Название",

View File

@ -13,6 +13,7 @@
"shareBrainUsers": "具有访问权限的用户",
"shareBrainLink": "点击复制链接来分享大脑",
"copiedToClipboard": "已复制到剪贴板",
"composite_brain_composition_invitation": "通过选择将您的新大脑连接到现有的其他大脑来进行组合。",
"inviteUsers": "添加新用户",
"usersInvited": "已成功邀请用户",
"errorSendingInvitation": "发送邀请时发生错误",
@ -49,7 +50,7 @@
"myBrains": "我的大脑",
"knowledge_source_doc": "文档",
"knowledge_source_api": "API",
"knowledge_source_chatflow": "代理",
"knowledge_source_composite_brain": "代理",
"knowledge_source_label": "知识来源",
"api_brain":{
"name": "名称",

View File

@ -816,6 +816,21 @@
"@babel/runtime" "^7.13.10"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-checkbox@^1.0.4":
version "1.0.4"
resolved "https://registry.yarnpkg.com/@radix-ui/react-checkbox/-/react-checkbox-1.0.4.tgz#98f22c38d5010dd6df4c5744cac74087e3275f4b"
integrity sha512-CBuGQa52aAYnADZVt/KBQzXrwx6TqnlwtcIPGtVt5JkkzQwMOLJjPukimhfKEr4GQNd43C+djUh5Ikopj8pSLg==
dependencies:
"@babel/runtime" "^7.13.10"
"@radix-ui/primitive" "1.0.1"
"@radix-ui/react-compose-refs" "1.0.1"
"@radix-ui/react-context" "1.0.1"
"@radix-ui/react-presence" "1.0.1"
"@radix-ui/react-primitive" "1.0.3"
"@radix-ui/react-use-controllable-state" "1.0.1"
"@radix-ui/react-use-previous" "1.0.1"
"@radix-ui/react-use-size" "1.0.1"
"@radix-ui/react-collapsible@1.0.3":
version "1.0.3"
resolved "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.0.3.tgz"