Mamadou DICKO 2023-11-22 11:15:14 +01:00 committed by GitHub
parent 1a4c6c8741
commit d9a72b368a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 267 additions and 223 deletions

View File

@ -54,6 +54,19 @@ class ApiBrainDefinitions(Repository):
return None return None
return ApiBrainDefinition(**response.data[0]) return ApiBrainDefinition(**response.data[0])
def update_api_brain_definition(
self, brain_id: UUID, api_brain_definition: ApiBrainDefinition
) -> Optional[ApiBrainDefinition]:
response = (
self.db.table("api_brain_definition")
.update(api_brain_definition.dict(exclude={"brain_id"}))
.filter("brain_id", "eq", str(brain_id))
.execute()
)
if len(response.data) == 0:
return None
return ApiBrainDefinition(**response.data[0])
def delete_api_brain_definition(self, brain_id: UUID) -> None: def delete_api_brain_definition(self, brain_id: UUID) -> None:
self.db.table("api_brain_definition").delete().filter( self.db.table("api_brain_definition").delete().filter(
"brain_id", "eq", str(brain_id) "brain_id", "eq", str(brain_id)

View File

@ -2,6 +2,7 @@ from typing import Optional
from uuid import UUID from uuid import UUID
from logger import get_logger from logger import get_logger
from models.ApiBrainDefinition import ApiBrainDefinition
from models.brain_entity import ( from models.brain_entity import (
BrainEntity, BrainEntity,
BrainType, BrainType,
@ -45,6 +46,7 @@ class BrainUpdatableProperties(BaseModel):
max_tokens: Optional[int] max_tokens: Optional[int]
status: Optional[str] status: Optional[str]
prompt_id: Optional[UUID] prompt_id: Optional[UUID]
brain_definition: Optional[ApiBrainDefinition]
def dict(self, *args, **kwargs): def dict(self, *args, **kwargs):
brain_dict = super().dict(*args, **kwargs) brain_dict = super().dict(*args, **kwargs)

View File

@ -0,0 +1,13 @@
from typing import Optional
from uuid import UUID
from models.ApiBrainDefinition import ApiBrainDefinition
from models.settings import get_supabase_db
def update_api_brain_definition(
brain_id: UUID, api_brain_definition: ApiBrainDefinition
) -> Optional[ApiBrainDefinition]:
supabase_db = get_supabase_db()
return supabase_db.update_api_brain_definition(brain_id, api_brain_definition)

View File

@ -8,7 +8,7 @@ from repository.api_brain_definition.delete_api_brain_definition import (
delete_api_brain_definition, delete_api_brain_definition,
) )
from repository.brain import get_brain_by_id from repository.brain import get_brain_by_id
from repository.brain.delete_brain_secrets import delete_brain_secrets from repository.brain.delete_brain_secrets import delete_brain_secrets_values
from repository.knowledge.remove_brain_all_knowledge import ( from repository.knowledge.remove_brain_all_knowledge import (
remove_brain_all_knowledge, remove_brain_all_knowledge,
) )
@ -22,7 +22,7 @@ def delete_brain(brain_id: UUID) -> dict[str, str]:
raise HTTPException(status_code=404, detail="Brain not found.") raise HTTPException(status_code=404, detail="Brain not found.")
if brain_to_delete.brain_type == BrainType.API: if brain_to_delete.brain_type == BrainType.API:
delete_brain_secrets( delete_brain_secrets_values(
brain_id=brain_id, brain_id=brain_id,
) )
delete_api_brain_definition(brain_id=brain_id) delete_api_brain_definition(brain_id=brain_id)

View File

@ -9,7 +9,7 @@ from repository.api_brain_definition.get_api_brain_definition import (
from repository.external_api_secret import delete_secret from repository.external_api_secret import delete_secret
def delete_brain_secrets(brain_id: UUID) -> None: def delete_brain_secrets_values(brain_id: UUID) -> None:
supabase_db = get_supabase_db() supabase_db = get_supabase_db()
brain_definition = get_api_brain_definition(brain_id=brain_id) brain_definition = get_api_brain_definition(brain_id=brain_id)

View File

@ -1,18 +1,77 @@
from uuid import UUID from uuid import UUID
from fastapi import HTTPException
from models import BrainEntity, get_supabase_db from models import BrainEntity, get_supabase_db
from models.brain_entity import BrainType
from models.databases.supabase.brains import BrainUpdatableProperties from models.databases.supabase.brains import BrainUpdatableProperties
from repository.api_brain_definition.update_api_brain_definition import (
update_api_brain_definition,
)
from repository.brain.delete_brain_secrets import delete_brain_secrets_values
from repository.brain.update_brain_last_update_time import update_brain_last_update_time from repository.brain.update_brain_last_update_time import update_brain_last_update_time
def update_brain_by_id(brain_id: UUID, brain: BrainUpdatableProperties) -> BrainEntity: def update_brain_by_id(
brain_id: UUID, brain_new_values: BrainUpdatableProperties
) -> BrainEntity:
"""Update a prompt by id""" """Update a prompt by id"""
supabase_db = get_supabase_db() supabase_db = get_supabase_db()
brain_update_answer = supabase_db.update_brain_by_id(brain_id, brain) existing_brain = supabase_db.get_brain_by_id(brain_id)
if existing_brain is None:
raise HTTPException(
status_code=404,
detail=f"Brain with id {brain_id} not found",
)
brain_update_answer = supabase_db.update_brain_by_id(
brain_id,
brain=BrainUpdatableProperties(
**brain_new_values.dict(exclude={"brain_definition"})
),
)
if brain_update_answer is None: if brain_update_answer is None:
raise Exception("Brain not found") raise HTTPException(
status_code=404,
detail=f"Brain with id {brain_id} not found",
)
if (
brain_update_answer.brain_type == BrainType.API
and brain_new_values.brain_definition
):
existing_brain_secrets_definition = (
existing_brain.brain_definition.secrets
if existing_brain.brain_definition
else None
)
brain_new_values_secrets_definition = (
brain_new_values.brain_definition.secrets
if brain_new_values.brain_definition
else None
)
should_remove_existing_secrets_values = (
existing_brain_secrets_definition
and brain_new_values_secrets_definition
and existing_brain_secrets_definition != brain_new_values_secrets_definition
)
if should_remove_existing_secrets_values:
delete_brain_secrets_values(brain_id=brain_id)
update_api_brain_definition(
brain_id,
api_brain_definition=brain_new_values.brain_definition,
)
if brain_update_answer is None:
raise HTTPException(
status_code=404,
detail=f"Brain with id {brain_id} not found",
)
update_brain_last_update_time(brain_id) update_brain_last_update_time(brain_id)
return brain_update_answer return brain_update_answer

View File

@ -4,7 +4,7 @@ from repository.external_api_secret.create_secret import create_secret
from repository.external_api_secret.delete_secret import delete_secret from repository.external_api_secret.delete_secret import delete_secret
def update_secret( def update_secret_value(
user_id: UUID, user_id: UUID,
brain_id: UUID, brain_id: UUID,
secret_name: str, secret_name: str,

View File

@ -26,7 +26,9 @@ from repository.brain import (
update_brain_by_id, update_brain_by_id,
) )
from repository.brain.get_brain_for_user import get_brain_for_user from repository.brain.get_brain_for_user import get_brain_for_user
from repository.external_api_secret.update_secret import update_secret from repository.external_api_secret.update_secret_value import (
update_secret_value,
)
from repository.prompt import delete_prompt_by_id, get_prompt_by_id from repository.prompt import delete_prompt_by_id, get_prompt_by_id
from routes.authorizations.brain_authorization import has_brain_authorization from routes.authorizations.brain_authorization import has_brain_authorization
@ -156,7 +158,7 @@ async def update_existing_brain(
@brain_router.put( @brain_router.put(
"/brains/{brain_id}/secrets", "/brains/{brain_id}/secrets-values",
dependencies=[ dependencies=[
Depends(AuthBearer()), Depends(AuthBearer()),
], ],
@ -206,7 +208,7 @@ async def update_existing_brain_secrets(
detail=f"Secret {key} is not a valid secret.", detail=f"Secret {key} is not a valid secret.",
) )
if value: if value:
update_secret( update_secret_value(
user_id=current_user.id, user_id=current_user.id,
brain_id=brain_id, brain_id=brain_id,
secret_name=key, secret_name=key,

View File

@ -6,16 +6,14 @@ import { useTranslation } from "react-i18next";
import { FaSpinner } from "react-icons/fa"; import { FaSpinner } from "react-icons/fa";
import { Divider } from "@/lib/components/ui/Divider"; import { Divider } from "@/lib/components/ui/Divider";
import { defaultBrainConfig } from "@/lib/config/defaultBrainConfig"; import { Brain } from "@/lib/context/BrainProvider/types";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { BrainConfig } from "@/lib/types/brainConfig";
import { GeneralInformation, ModelSelection, Prompt } from "./components"; import { GeneralInformation, ModelSelection, Prompt } from "./components";
import { AccessConfirmationModal } from "./components/PrivateAccessConfirmationModal/AccessConfirmationModal"; import { AccessConfirmationModal } from "./components/PrivateAccessConfirmationModal/AccessConfirmationModal";
import { useAccessConfirmationModal } from "./components/PrivateAccessConfirmationModal/hooks/useAccessConfirmationModal"; import { useAccessConfirmationModal } from "./components/PrivateAccessConfirmationModal/hooks/useAccessConfirmationModal";
import { usePermissionsController } from "./hooks/usePermissionsController";
import { UsePromptProps } from "./hooks/usePrompt"; import { UsePromptProps } from "./hooks/usePrompt";
import { useSettingsTab } from "./hooks/useSettingsTab"; import { useSettingsTab } from "./hooks/useSettingsTab";
import { getBrainPermissions } from "../../utils/getBrainPermissions";
type SettingsTabProps = { type SettingsTabProps = {
brainId: UUID; brainId: UUID;
@ -44,12 +42,9 @@ export const SettingsTabContent = ({
const { onCancel, isAccessModalOpened, closeModal } = const { onCancel, isAccessModalOpened, closeModal } =
useAccessConfirmationModal(); useAccessConfirmationModal();
const { allBrains } = useBrainContext();
const { hasEditRights, isOwnedByCurrentUser, isPublicBrain } = const { hasEditRights, isOwnedByCurrentUser, isPublicBrain } =
getBrainPermissions({ usePermissionsController({
brainId, brainId,
userAccessibleBrains: allBrains,
}); });
return ( return (
@ -57,7 +52,7 @@ export const SettingsTabContent = ({
<form <form
onSubmit={(e) => { onSubmit={(e) => {
e.preventDefault(); e.preventDefault();
void handleSubmit(true); void handleSubmit();
}} }}
className="my-10 mb-0 flex flex-col items-center gap-2" className="my-10 mb-0 flex flex-col items-center gap-2"
ref={formRef} ref={formRef}
@ -103,9 +98,7 @@ export const SettingsTabContent = ({
}; };
export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => { export const SettingsTab = ({ brainId }: SettingsTabProps): JSX.Element => {
const methods = useForm<BrainConfig>({ const methods = useForm<Brain>();
defaultValues: defaultBrainConfig,
});
return ( return (
<FormProvider {...methods}> <FormProvider {...methods}>

View File

@ -1,15 +1,14 @@
/* eslint max-lines:["error", 150] */ /* eslint max-lines:["error", 150] */
// TODO: useFormContext to avoid passing too many props
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ApiRequestDefinition } from "@/lib/components/ApiRequestDefinition";
import Button from "@/lib/components/ui/Button"; import Button from "@/lib/components/ui/Button";
import { Chip } from "@/lib/components/ui/Chip"; import { Chip } from "@/lib/components/ui/Chip";
import Field from "@/lib/components/ui/Field"; import Field from "@/lib/components/ui/Field";
import { Radio } from "@/lib/components/ui/Radio"; import { Radio } from "@/lib/components/ui/Radio";
import { TextArea } from "@/lib/components/ui/TextArea"; import { TextArea } from "@/lib/components/ui/TextArea";
import { ApiBrainDefinition } from "./components/ApiBrainDefinition";
import { useGeneralInformation } from "./hooks/useGeneralInformation"; import { useGeneralInformation } from "./hooks/useGeneralInformation";
import { useBrainFormState } from "../../hooks/useBrainFormState"; import { useBrainFormState } from "../../hooks/useBrainFormState";
@ -97,10 +96,11 @@ export const GeneralInformation = (
items={brainTypeOptions} items={brainTypeOptions}
label={t("knowledge_source_label", { ns: "brain" })} label={t("knowledge_source_label", { ns: "brain" })}
className="flex-1 justify-between w-[50%]" className="flex-1 justify-between w-[50%]"
{...register("brain_type", { disabled: true })} disabled={true}
{...register("brain_type")}
/> />
</div> </div>
<ApiBrainDefinition /> <ApiRequestDefinition />
<TextArea <TextArea
label={t("brainDescription", { ns: "brain" })} label={t("brainDescription", { ns: "brain" })}
placeholder={t("brainDescriptionPlaceholder", { ns: "brain" })} placeholder={t("brainDescriptionPlaceholder", { ns: "brain" })}

View File

@ -1,95 +0,0 @@
import { Fragment } from "react";
import { useTranslation } from "react-i18next";
import { useUrlBrain } from "@/lib/hooks/useBrainIdFromUrl";
export const ApiBrainDefinition = (): JSX.Element => {
const { brainDetails } = useUrlBrain();
const { t } = useTranslation(["external_api_definition"]);
if (brainDetails?.brain_type !== "api") {
return <Fragment />;
}
return (
<div className="w-full">
<hr className="border-t border-gray-300 w-full mb-3" />
<div className="mb-2">
<p>
<span className="font-semibold">{t("url_placeholder")}</span>
<span className="ml-2">{brainDetails.brain_definition?.url}</span>
</p>
</div>
<div className="mb-2">
<p>
<span className="font-semibold">{t("method_label")}</span>
<span className="ml-2">{brainDetails.brain_definition?.method}</span>
</p>
</div>
{(brainDetails.brain_definition?.params.properties.length ?? 0) > 0 && (
<div className="mb-3">
<p>
<span className="font-bold mr-1">{t("params")}:</span>
<span>{t("paramsTabDescription")}</span>
</p>
{brainDetails.brain_definition?.params.properties.map((param) => (
<div key={param.name}>
<span className="mr-1">-</span>
<span className="font-semibold">{param.name}:</span>
<span className="ml-2">{param.type}</span>
<span className="ml-2">
{brainDetails.brain_definition?.params.required.includes(
param.name
) ?? false
? "- Required"
: " - Optional"}
</span>
</div>
))}
</div>
)}
{(brainDetails.brain_definition?.search_params.properties.length ?? 0) >
0 && (
<div className="mb-3">
<p>
<span className="font-bold mr-1">{t("searchParams")}:</span>
<span>{t("searchParamsTabDescription")}</span>
</p>
{brainDetails.brain_definition?.search_params.properties.map(
(param) => (
<div key={param.name}>
<span className="mr-1">-</span>
<span className="font-semibold">{param.name}:</span>
<span className="ml-2">{param.type}</span>
<span className="ml-2">
{brainDetails.brain_definition?.search_params.required.includes(
param.name
) ?? false
? "- Required"
: " - Optional"}
</span>
</div>
)
)}
</div>
)}
{(brainDetails.brain_definition?.secrets?.length ?? 0) > 0 && (
<div className="mb-3">
<p>
<span className="font-bold mr-1">{t("secrets")}:</span>
<span>{t("secretsTabDescription")}</span>
</p>
{brainDetails.brain_definition?.secrets?.map((param) => (
<div key={param.name}>
<span className="mr-1">-</span>
<span className="font-bold">{param.name}:</span>
<span className="ml-2">{param.type}</span>
</div>
))}
</div>
)}
<hr className="border-t border-gray-300 w-full mt-5" />
</div>
);
};

View File

@ -23,7 +23,7 @@ export const useBrainFormState = () => {
setValue, setValue,
reset, reset,
resetField, resetField,
formState: { dirtyFields }, formState: { defaultValues, dirtyFields },
} = useFormContext<BrainConfig>(); } = useFormContext<BrainConfig>();
const { brain, refetchBrain } = useBrainFetcher({ const { brain, refetchBrain } = useBrainFetcher({
@ -54,8 +54,6 @@ export const useBrainFormState = () => {
continue; continue;
} }
// @ts-expect-error bad type inference from typescript // @ts-expect-error bad type inference from typescript
// eslint-disable-next-line // eslint-disable-next-line
if (Boolean(brain[key])) setValue(key, brain[key]); if (Boolean(brain[key])) setValue(key, brain[key]);
@ -81,6 +79,7 @@ export const useBrainFormState = () => {
isDefaultBrain, isDefaultBrain,
promptId, promptId,
openAiKey, openAiKey,
defaultValues,
dirtyFields, dirtyFields,
status, status,
register, register,

View File

@ -0,0 +1,40 @@
import { UUID } from "crypto";
import { useEffect } from "react";
import { useFormContext } from "react-hook-form";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { getBrainPermissions } from "../../../utils/getBrainPermissions";
type UsePermissionsControllerProps = {
brainId: UUID;
};
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const usePermissionsController = ({
brainId,
}: UsePermissionsControllerProps) => {
const { allBrains } = useBrainContext();
const { setValue } = useFormContext<{
isApiDefinitionReadOnly: boolean;
isUpdatingApiDefinition: boolean;
}>();
const { hasEditRights, isOwnedByCurrentUser, isPublicBrain } =
getBrainPermissions({
brainId,
userAccessibleBrains: allBrains,
});
useEffect(() => {
setValue("isApiDefinitionReadOnly", !hasEditRights);
setValue("isUpdatingApiDefinition", true);
}, [hasEditRights, setValue]);
return {
hasEditRights,
isOwnedByCurrentUser,
isPublicBrain,
};
};

View File

@ -29,15 +29,8 @@ export const useSettingsTab = ({ brainId }: UseSettingsTabProps) => {
const { fetchAllBrains, fetchDefaultBrain } = useBrainContext(); const { fetchAllBrains, fetchDefaultBrain } = useBrainContext();
const { userData } = useUserData(); const { userData } = useUserData();
const { const { getValues, maxTokens, setValue, openAiKey, model, isDefaultBrain } =
dirtyFields, useBrainFormState();
getValues,
maxTokens,
setValue,
openAiKey,
model,
isDefaultBrain,
} = useBrainFormState();
const accessibleModels = getAccessibleModels({ const accessibleModels = getAccessibleModels({
openAiKey, openAiKey,
@ -52,7 +45,7 @@ export const useSettingsTab = ({ brainId }: UseSettingsTabProps) => {
const handleKeyPress = (event: KeyboardEvent) => { const handleKeyPress = (event: KeyboardEvent) => {
if (event.key === "Enter") { if (event.key === "Enter") {
event.preventDefault(); event.preventDefault();
void handleSubmit(true); void handleSubmit();
} }
}; };
@ -93,12 +86,8 @@ export const useSettingsTab = ({ brainId }: UseSettingsTabProps) => {
} }
}; };
const handleSubmit = async (checkDirty: boolean) => { const handleSubmit = async () => {
const hasChanges = Object.keys(dirtyFields).length > 0; const { name } = getValues();
if (!hasChanges && checkDirty) {
return;
}
const { name} = getValues();
checkBrainName(name, publish, t); checkBrainName(name, publish, t);

View File

@ -10,7 +10,11 @@ import {
} from "@/lib/api/chat/chat.local"; } from "@/lib/api/chat/chat.local";
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 {
defaultMaxTokens,
defaultModel,
defaultTemperature,
} from "@/lib/config/defaultBrainConfig";
import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext"; import { useBrainContext } from "@/lib/context/BrainProvider/hooks/useBrainContext";
import { ChatConfig } from "@/lib/context/ChatProvider/types"; import { ChatConfig } from "@/lib/context/ChatProvider/types";
import { getAccessibleModels } from "@/lib/helpers/getAccessibleModels"; import { getAccessibleModels } from "@/lib/helpers/getAccessibleModels";
@ -28,13 +32,12 @@ export const useConfigModal = () => {
queryKey: [USER_DATA_KEY], queryKey: [USER_DATA_KEY],
queryFn: getUser, queryFn: getUser,
}); });
const { register, watch, setValue } = useForm<ChatConfig>({ const { register, watch, setValue } = useForm<ChatConfig>({
defaultValues: { defaultValues: {
model: defaultBrainConfig.model, model: "gpt-3.5-turbo-16k",
temperature: defaultBrainConfig.temperature, temperature: 0,
maxTokens: defaultBrainConfig.maxTokens, maxTokens: 3000,
}, },
}); });
@ -61,15 +64,12 @@ export const useConfigModal = () => {
if (relatedBrainConfig === undefined) { if (relatedBrainConfig === undefined) {
return; return;
} }
setValue("model", relatedBrainConfig.model ?? defaultBrainConfig.model); setValue("model", relatedBrainConfig.model ?? defaultModel);
setValue( setValue(
"temperature", "temperature",
relatedBrainConfig.temperature ?? defaultBrainConfig.temperature relatedBrainConfig.temperature ?? defaultTemperature
);
setValue(
"maxTokens",
relatedBrainConfig.max_tokens ?? defaultBrainConfig.maxTokens
); );
setValue("maxTokens", relatedBrainConfig.max_tokens ?? defaultMaxTokens);
} }
}, []); }, []);

View File

@ -247,7 +247,7 @@ describe("useBrainApi", () => {
await updateBrainSecrets(brainId, secrets); await updateBrainSecrets(brainId, secrets);
expect(axiosPutMock).toHaveBeenCalledTimes(1); expect(axiosPutMock).toHaveBeenCalledTimes(1);
expect(axiosPutMock).toHaveBeenCalledWith( expect(axiosPutMock).toHaveBeenCalledWith(
`/brains/${brainId}/secrets`, `/brains/${brainId}/secrets-values`,
secrets secrets
); );
}); });

View File

@ -149,5 +149,5 @@ export const updateBrainSecrets = async (
secrets: Record<string, string>, secrets: Record<string, string>,
axiosInstance: AxiosInstance axiosInstance: AxiosInstance
): Promise<void> => { ): Promise<void> => {
await axiosInstance.put(`/brains/${brainId}/secrets`, secrets); await axiosInstance.put(`/brains/${brainId}/secrets-values`, secrets);
}; };

View File

@ -1,3 +1,5 @@
import { UUID } from "crypto";
import { BrainRoleType } from "@/lib/components/BrainUsers/types"; import { BrainRoleType } from "@/lib/components/BrainUsers/types";
import { BrainStatus, BrainType, Model } from "@/lib/types/brainConfig"; import { BrainStatus, BrainType, Model } from "@/lib/types/brainConfig";
@ -28,6 +30,7 @@ export type ApiBrainDefinitionSecret = {
}; };
export type ApiBrainDefinition = { export type ApiBrainDefinition = {
brain_id: UUID;
method: AllowedRequestMethod; method: AllowedRequestMethod;
url: string; url: string;
search_params: ApiBrainDefinitionSchema; search_params: ApiBrainDefinitionSchema;
@ -44,7 +47,7 @@ export type CreateBrainInput = {
max_tokens?: number; max_tokens?: number;
prompt_id?: string | null; prompt_id?: string | null;
brain_type?: BrainType; brain_type?: BrainType;
brain_definition?: ApiBrainDefinition; brain_definition?: Omit<ApiBrainDefinition, "brain_id">;
brain_secrets_values?: Record<string, string>; brain_secrets_values?: Record<string, string>;
}; };

View File

@ -11,10 +11,10 @@ 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";
import { ApiRequestDefinition } from "../../../ApiRequestDefinition";
import { Divider } from "../../../ui/Divider"; import { Divider } from "../../../ui/Divider";
import { Radio } from "../../../ui/Radio"; import { Radio } from "../../../ui/Radio";
import { TextArea } from "../../../ui/TextArea"; import { TextArea } from "../../../ui/TextArea";
@ -114,7 +114,6 @@ export const AddBrainConfig = ({
<ApiRequestDefinition /> <ApiRequestDefinition />
</> </>
)} )}
<fieldset className="w-full flex flex-col"> <fieldset className="w-full flex flex-col">
<label className="flex-1 text-sm" htmlFor="model"> <label className="flex-1 text-sm" htmlFor="model">

View File

@ -1,3 +0,0 @@
export const apiTabs = ["params", "searchParams", "secrets"] as const;
export type ApiTab = (typeof apiTabs)[number];

View File

@ -3,20 +3,22 @@ import { Fragment } from "react";
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { allowedRequestMethods, CreateBrainInput } from "@/lib/api/brain/types"; import { allowedRequestMethods } from "@/lib/api/brain/types";
import { BrainDefinitionTabTrigger } from "./components/BrainDefinitionTabTrigger"; import { BrainDefinitionTabTrigger } from "./components/BrainDefinitionTabTrigger";
import { ParamsDefinition } from "./components/ParamsDefinition/ParamsDefinition"; import { ParamsDefinition } from "./components/ParamsDefinition/ParamsDefinition";
import { SecretsDefinition } from "./components/SecretsDefinition/SecretsDefinition"; import { SecretsDefinition } from "./components/SecretsDefinition/SecretsDefinition";
import { useApiRequestDefinition } from "./hooks/useApiRequestDefinition"; import { useApiRequestDefinition } from "./hooks/useApiRequestDefinition";
import { ApiDefinitionContextType } from "./types";
export const ApiRequestDefinition = (): JSX.Element => { export const ApiRequestDefinition = (): JSX.Element => {
const { selectedTab, setSelectedTab } = useApiRequestDefinition(); const { selectedTab, setSelectedTab } = useApiRequestDefinition();
const { t } = useTranslation(["external_api_definition"]); const { t } = useTranslation(["external_api_definition"]);
const { watch, register } = useFormContext<CreateBrainInput>(); const { watch, register } = useFormContext<ApiDefinitionContextType>();
const brainType = watch("brain_type"); const brainType = watch("brain_type");
const readOnly = watch("isApiDefinitionReadOnly") ?? false;
if (brainType !== "api") { if (brainType !== "api") {
return <Fragment />; return <Fragment />;
@ -33,6 +35,7 @@ export const ApiRequestDefinition = (): JSX.Element => {
<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"
disabled={readOnly}
{...register("brain_definition.method")} {...register("brain_definition.method")}
> >
{allowedMethodsOptions.map(({ label, value }) => ( {allowedMethodsOptions.map(({ label, value }) => (
@ -45,6 +48,7 @@ export const ApiRequestDefinition = (): JSX.Element => {
<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"
disabled={readOnly}
{...register("brain_definition.url", { required: true })} {...register("brain_definition.url", { required: true })}
/> />
</div> </div>

View File

@ -22,7 +22,7 @@ export const ParamsDefinition = ({
description, description,
}: ParamsDefinitionProps): JSX.Element => { }: ParamsDefinitionProps): JSX.Element => {
const { t } = useTranslation(["brain"]); const { t } = useTranslation(["brain"]);
const { control, register } = useParamsDefinition({ const { control, register, isApiDefinitionReadOnly } = useParamsDefinition({
name, name,
}); });
@ -61,6 +61,7 @@ export const ParamsDefinition = ({
onClick={() => { onClick={() => {
append(defaultParamDefinitionRow); append(defaultParamDefinitionRow);
}} }}
disabled={isApiDefinitionReadOnly}
className="p-2" className="p-2"
variant={"secondary"} variant={"secondary"}
> >

View File

@ -1,7 +1,8 @@
import { UseFormRegister } from "react-hook-form"; import { useFormContext, UseFormRegister } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { ApiDefinitionContextType } from "../../../types";
import { paramsNameStyle } from "../../styles"; import { paramsNameStyle } from "../../styles";
import { ParameterDefinition } from "../types"; import { ParameterDefinition } from "../types";
@ -23,6 +24,8 @@ export const ParamDefinitionRow = ({
name, name,
}: ParamDefinitionRowProps): JSX.Element => { }: ParamDefinitionRowProps): JSX.Element => {
const { t } = useTranslation(["brain"]); const { t } = useTranslation(["brain"]);
const { watch } = useFormContext<ApiDefinitionContextType>();
const isApiDefinitionReadOnly = watch("isApiDefinitionReadOnly") ?? false;
return ( return (
<div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2"> <div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2">
@ -31,6 +34,7 @@ export const ParamDefinitionRow = ({
type="text" 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" 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")} placeholder={t("api_brain.name")}
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${name}[${index}].name` as `${typeof name}.${number}.name` `${name}[${index}].name` as `${typeof name}.${number}.name`
)} )}
@ -42,6 +46,7 @@ export const ParamDefinitionRow = ({
id={`description-${index}`} 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" 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")} placeholder={t("api_brain.description")}
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${name}[${index}].description` as `${typeof name}.${number}.description` `${name}[${index}].description` as `${typeof name}.${number}.description`
)} )}
@ -51,6 +56,7 @@ export const ParamDefinitionRow = ({
<select <select
id={`type-${index}`} 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" 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"
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${name}[${index}].type` as `${typeof name}.${number}.type` `${name}[${index}].type` as `${typeof name}.${number}.type`
)} )}
@ -63,12 +69,14 @@ export const ParamDefinitionRow = ({
<input <input
type="checkbox" type="checkbox"
className="form-checkbox h-5 w-5 text-indigo-600 rounded focus:ring-2 focus:ring-indigo-400 outline-none" className="form-checkbox h-5 w-5 text-indigo-600 rounded focus:ring-2 focus:ring-indigo-400 outline-none"
disabled={isApiDefinitionReadOnly}
{...register(`${name}[${index}].required`)} {...register(`${name}[${index}].required`)}
/> />
</div> </div>
<button <button
type="button" type="button"
disabled={isApiDefinitionReadOnly}
onClick={() => remove(index)} onClick={() => remove(index)}
className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer" className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer"
> >

View File

@ -2,7 +2,7 @@ import { useEffect } from "react";
import { useForm, useFormContext, useWatch } from "react-hook-form"; import { useForm, useFormContext, useWatch } from "react-hook-form";
import { useParamsDefinitionDefaultValues } from "./useParamsDefinitionDefaultValues"; import { useParamsDefinitionDefaultValues } from "./useParamsDefinitionDefaultValues";
import { CreateBrainProps } from "../../../../../types"; import { ApiDefinitionContextType } from "../../../types";
import { ParameterDefinition } from "../types"; import { ParameterDefinition } from "../types";
import { mapParameterDefinitionToApiBrainDefinitionSchema } from "../utils/mapParameterDefinitionToApiBrainDefinitionSchema"; import { mapParameterDefinitionToApiBrainDefinitionSchema } from "../utils/mapParameterDefinitionToApiBrainDefinitionSchema";
@ -14,7 +14,8 @@ type UseParamsDefinitionProps = {
export const useParamsDefinition = ({ name }: UseParamsDefinitionProps) => { export const useParamsDefinition = ({ name }: UseParamsDefinitionProps) => {
const dataKey = `brain_definition.${name}` as const; const dataKey = `brain_definition.${name}` as const;
const { setValue: setContextValue } = useFormContext<CreateBrainProps>(); const { setValue: setContextValue, watch: watchContextValue } =
useFormContext<ApiDefinitionContextType>();
const { defaultValues } = useParamsDefinitionDefaultValues({ const { defaultValues } = useParamsDefinitionDefaultValues({
dataKey, dataKey,
@ -28,6 +29,9 @@ export const useParamsDefinition = ({ name }: UseParamsDefinitionProps) => {
}, },
}); });
const isApiDefinitionReadOnly =
watchContextValue("isApiDefinitionReadOnly") ?? false;
const params = useWatch({ const params = useWatch({
control, control,
name, name,
@ -47,5 +51,6 @@ export const useParamsDefinition = ({ name }: UseParamsDefinitionProps) => {
return { return {
control, control,
register, register,
isApiDefinitionReadOnly,
}; };
}; };

View File

@ -1,6 +1,6 @@
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form";
import { CreateBrainProps } from "../../../../../types"; import { CreateBrainProps } from "../../../../AddBrainModal/components/AddBrainConfig/types";
import { defaultParamDefinitionRow } from "../config"; import { defaultParamDefinitionRow } from "../config";
import { mapApiBrainDefinitionSchemaToParameterDefinition } from "../utils/mapApiBrainDefinitionSchemaToParameterDefinition"; import { mapApiBrainDefinitionSchemaToParameterDefinition } from "../utils/mapApiBrainDefinitionSchemaToParameterDefinition";

View File

@ -18,7 +18,12 @@ const paramsNameStyle = "flex flex-1 justify-center";
export const SecretsDefinition = (): JSX.Element => { export const SecretsDefinition = (): JSX.Element => {
const { t } = useTranslation(["brain", "external_api_definition"]); const { t } = useTranslation(["brain", "external_api_definition"]);
const { control, register } = useSecretsDefinition(); const {
control,
register,
isApiDefinitionReadOnly,
isUpdatingApiDefinition,
} = useSecretsDefinition();
const { fields, append, remove } = useFieldArray({ const { fields, append, remove } = useFieldArray({
control, control,
@ -38,7 +43,9 @@ export const SecretsDefinition = (): JSX.Element => {
<div className={paramsNameStyle}>{t("api_brain.name")}</div> <div className={paramsNameStyle}>{t("api_brain.name")}</div>
<div className={paramsNameStyle}>{t("api_brain.description")}</div> <div className={paramsNameStyle}>{t("api_brain.description")}</div>
<div className={paramsNameStyle}>{t("api_brain.type")}</div> <div className={paramsNameStyle}>{t("api_brain.type")}</div>
<div className={paramsNameStyle}>{t("api_brain.value")}</div> {!isUpdatingApiDefinition && (
<div className={paramsNameStyle}>{t("api_brain.value")}</div>
)}
</div> </div>
</div> </div>
{fields.map((field, index) => ( {fields.map((field, index) => (
@ -56,6 +63,7 @@ export const SecretsDefinition = (): JSX.Element => {
append(defaultSecretDefinitionRow); append(defaultSecretDefinitionRow);
}} }}
className="p-2" className="p-2"
disabled={isApiDefinitionReadOnly}
variant={"secondary"} variant={"secondary"}
> >
<MdAdd size={20} /> {t("api_brain.addRow")} <MdAdd size={20} /> {t("api_brain.addRow")}

View File

@ -1,7 +1,8 @@
import { UseFormRegister } from "react-hook-form"; import { useFormContext, UseFormRegister } from "react-hook-form";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { MdCancel } from "react-icons/md"; import { MdCancel } from "react-icons/md";
import { ApiDefinitionContextType } from "../../../types";
import { paramsNameStyle } from "../../styles"; import { paramsNameStyle } from "../../styles";
import { brainSecretsSchemaDefinitionKeyInForm } from "../config"; import { brainSecretsSchemaDefinitionKeyInForm } from "../config";
import { SecretDefinition } from "../types"; import { SecretDefinition } from "../types";
@ -22,6 +23,9 @@ export const SecretDefinitionRow = ({
register, register,
}: SecretDefinitionRowProps): JSX.Element => { }: SecretDefinitionRowProps): JSX.Element => {
const { t } = useTranslation(["brain"]); const { t } = useTranslation(["brain"]);
const { watch } = useFormContext<ApiDefinitionContextType>();
const isApiDefinitionReadOnly = watch("isApiDefinitionReadOnly") ?? false;
const isUpdatingApiDefinition = watch("isUpdatingApiDefinition") ?? false;
return ( return (
<div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2"> <div className="flex flex-1 justify-between items-center py-4 border-b border-gray-300 relative gap-2">
@ -30,6 +34,7 @@ export const SecretDefinitionRow = ({
type="text" 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" 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")} placeholder={t("api_brain.name")}
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${brainSecretsSchemaDefinitionKeyInForm}.${index}.name` `${brainSecretsSchemaDefinitionKeyInForm}.${index}.name`
)} )}
@ -41,6 +46,7 @@ export const SecretDefinitionRow = ({
id={`description-${index}`} 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" 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")} placeholder={t("api_brain.description")}
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${brainSecretsSchemaDefinitionKeyInForm}.${index}.description` `${brainSecretsSchemaDefinitionKeyInForm}.${index}.description`
)} )}
@ -50,6 +56,7 @@ export const SecretDefinitionRow = ({
<select <select
id={`type-${index}`} 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" 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"
disabled={isApiDefinitionReadOnly}
{...register( {...register(
`${brainSecretsSchemaDefinitionKeyInForm}.${index}.type` `${brainSecretsSchemaDefinitionKeyInForm}.${index}.type`
)} )}
@ -58,20 +65,23 @@ export const SecretDefinitionRow = ({
<option value="number">number</option> <option value="number">number</option>
</select> </select>
</div> </div>
<div className={paramsNameStyle}> {!isUpdatingApiDefinition && (
<input <div className={paramsNameStyle}>
type="text" <input
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" type="text"
placeholder={t("api_brain.value")} 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"
{...register( placeholder={t("api_brain.value")}
`${brainSecretsSchemaDefinitionKeyInForm}.${index}.value` {...register(
)} `${brainSecretsSchemaDefinitionKeyInForm}.${index}.value`
/> )}
</div> />
</div>
)}
<button <button
type="button" type="button"
onClick={() => remove(index)} onClick={() => remove(index)}
disabled={isApiDefinitionReadOnly}
className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer" className="absolute right-0 text-red-500 bg-transparent border-none cursor-pointer"
> >
<MdCancel /> <MdCancel />

View File

@ -2,7 +2,7 @@ import { useEffect } from "react";
import { useForm, useFormContext, useWatch } from "react-hook-form"; import { useForm, useFormContext, useWatch } from "react-hook-form";
import { useSecretsDefinitionDefaultValues } from "./useSecretsDefinitionDefaultValues"; import { useSecretsDefinitionDefaultValues } from "./useSecretsDefinitionDefaultValues";
import { CreateBrainProps } from "../../../../../types"; import { ApiDefinitionContextType } from "../../../types";
import { import {
brainSecretsSchemaDefinitionKeyInForm, brainSecretsSchemaDefinitionKeyInForm,
brainSecretsValueKeyInForm, brainSecretsValueKeyInForm,
@ -12,7 +12,8 @@ import { mapSecretDefinitionToApiBrainSecretsDefinitionsAndValue } from "../util
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const useSecretsDefinition = () => { export const useSecretsDefinition = () => {
const { setValue: setContextValue } = useFormContext<CreateBrainProps>(); const { setValue: setContextValue, watch: watchContextValue } =
useFormContext<ApiDefinitionContextType>();
const { defaultValues } = useSecretsDefinitionDefaultValues(); const { defaultValues } = useSecretsDefinitionDefaultValues();
const { register, control } = useForm<{ const { register, control } = useForm<{
@ -28,6 +29,11 @@ export const useSecretsDefinition = () => {
name: brainSecretsSchemaDefinitionKeyInForm, name: brainSecretsSchemaDefinitionKeyInForm,
}) as SecretDefinition[] | undefined; }) as SecretDefinition[] | undefined;
const isApiDefinitionReadOnly =
watchContextValue("isApiDefinitionReadOnly") ?? false;
const isUpdatingApiDefinition =
watchContextValue("isUpdatingApiDefinition") ?? false;
useEffect(() => { useEffect(() => {
if (secretsDefinitionSchemas === undefined) { if (secretsDefinitionSchemas === undefined) {
return; return;
@ -50,5 +56,7 @@ export const useSecretsDefinition = () => {
return { return {
control, control,
register, register,
isApiDefinitionReadOnly,
isUpdatingApiDefinition,
}; };
}; };

View File

@ -1,6 +1,6 @@
import { useFormContext } from "react-hook-form"; import { useFormContext } from "react-hook-form";
import { CreateBrainProps } from "../../../../../types"; import { CreateBrainProps } from "../../../../AddBrainModal/components/AddBrainConfig/types";
import { import {
brainSecretsValueKeyInForm, brainSecretsValueKeyInForm,
defaultSecretDefinitionRow, defaultSecretDefinitionRow,

View File

@ -0,0 +1,10 @@
import { CreateBrainInput } from "@/lib/api/brain/types";
export const apiTabs = ["params", "searchParams", "secrets"] as const;
export type ApiTab = (typeof apiTabs)[number];
export type ApiDefinitionContextType = CreateBrainInput & {
isApiDefinitionReadOnly?: boolean;
isUpdatingApiDefinition?: boolean;
};

View File

@ -1,5 +1,5 @@
import { CreateBrainInput } from "../api/brain/types"; import { CreateBrainInput } from "../api/brain/types";
import { BrainConfig } from "../types/brainConfig"; import { Model } from "../types/brainConfig";
export const addBrainDefaultValues: CreateBrainInput = { export const addBrainDefaultValues: CreateBrainInput = {
model: "gpt-3.5-turbo", model: "gpt-3.5-turbo",
@ -12,24 +12,6 @@ export const addBrainDefaultValues: CreateBrainInput = {
brain_type: "doc", brain_type: "doc",
}; };
export const defaultBrainConfig: BrainConfig = { export const defaultModel: Model = "gpt-3.5-turbo";
model: "gpt-3.5-turbo", export const defaultMaxTokens = 1000;
temperature: 0, export const defaultTemperature = 0;
maxTokens: 1000,
keepLocal: true,
anthropicKey: undefined,
backendUrl: undefined,
openAiKey: undefined,
supabaseKey: undefined,
supabaseUrl: undefined,
prompt_id: undefined,
status: "private",
prompt: {
title: "",
content: "",
},
name: "",
description: "",
setDefault: false,
brain_type: "doc",
};

View File

@ -3,7 +3,6 @@ import axios, { AxiosError, AxiosInstance } from "axios";
import { useSupabase } from "@/lib/context/SupabaseProvider"; import { useSupabase } from "@/lib/context/SupabaseProvider";
import { DEFAULT_BACKEND_URL } from "../config/CONSTANTS"; import { DEFAULT_BACKEND_URL } from "../config/CONSTANTS";
import { defaultBrainConfig } from "../config/defaultBrainConfig";
const axiosInstance = axios.create({ const axiosInstance = axios.create({
baseURL: `${process.env.NEXT_PUBLIC_BACKEND_URL ?? DEFAULT_BACKEND_URL}`, baseURL: `${process.env.NEXT_PUBLIC_BACKEND_URL ?? DEFAULT_BACKEND_URL}`,
@ -11,13 +10,10 @@ const axiosInstance = axios.create({
export const useAxios = (): { axiosInstance: AxiosInstance } => { export const useAxios = (): { axiosInstance: AxiosInstance } => {
const { session } = useSupabase(); const { session } = useSupabase();
const { backendUrl, openAiKey } = defaultBrainConfig;
axiosInstance.interceptors.request.clear(); axiosInstance.interceptors.request.clear();
axiosInstance.interceptors.request.use( axiosInstance.interceptors.request.use(
(config) => { (config) => {
config.headers["Authorization"] = `Bearer ${session?.access_token ?? ""}`; config.headers["Authorization"] = `Bearer ${session?.access_token ?? ""}`;
config.headers["Openai-Api-Key"] = openAiKey;
config.baseURL = backendUrl ?? config.baseURL;
return config; return config;
}, },

View File

@ -13,7 +13,8 @@ export const useUrlBrain = () => {
const brainId = params?.brainId as UUID | undefined; const brainId = params?.brainId as UUID | undefined;
const correspondingBrain = allBrains.find((brain) => brain.id === brainId); const correspondingBrain = allBrains.find((brain) => brain.id === brainId);
const { brain: brainDetails } = useBrainFetcher({
const { brain: brainDetails, refetchBrain } = useBrainFetcher({
brainId: brainId, brainId: brainId,
}); });
@ -21,5 +22,6 @@ export const useUrlBrain = () => {
brain: correspondingBrain, brain: correspondingBrain,
brainId, brainId,
brainDetails, brainDetails,
refetchBrain,
}; };
}; };

View File

@ -2,8 +2,6 @@ import { useEffect, useState } from "react";
import { useSupabase } from "@/lib/context/SupabaseProvider"; import { useSupabase } from "@/lib/context/SupabaseProvider";
import { defaultBrainConfig } from "../config/defaultBrainConfig";
interface FetchInstance { interface FetchInstance {
get: (url: string, headers?: HeadersInit) => Promise<Response>; get: (url: string, headers?: HeadersInit) => Promise<Response>;
post: ( post: (
@ -30,12 +28,11 @@ const fetchInstance: FetchInstance = {
export const useFetch = (): { fetchInstance: FetchInstance } => { export const useFetch = (): { fetchInstance: FetchInstance } => {
const { session } = useSupabase(); const { session } = useSupabase();
const { backendUrl: configBackendUrl, openAiKey } = defaultBrainConfig;
const [instance, setInstance] = useState(fetchInstance); const [instance, setInstance] = useState(fetchInstance);
const baseURL = `${process.env.NEXT_PUBLIC_BACKEND_URL ?? ""}`; const baseURL = `${process.env.NEXT_PUBLIC_BACKEND_URL ?? ""}`;
const backendUrl = configBackendUrl ?? baseURL; const backendUrl = baseURL;
useEffect(() => { useEffect(() => {
setInstance({ setInstance({
@ -43,29 +40,25 @@ export const useFetch = (): { fetchInstance: FetchInstance } => {
get: async (url, headers) => get: async (url, headers) =>
fetchInstance.get(`${backendUrl}${url}`, { fetchInstance.get(`${backendUrl}${url}`, {
Authorization: `Bearer ${session?.access_token ?? ""}`, Authorization: `Bearer ${session?.access_token ?? ""}`,
"Openai-Api-Key": openAiKey ?? "",
...headers, ...headers,
}), }),
post: async (url, body, headers) => post: async (url, body, headers) =>
fetchInstance.post(`${backendUrl}${url}`, body, { fetchInstance.post(`${backendUrl}${url}`, body, {
Authorization: `Bearer ${session?.access_token ?? ""}`, Authorization: `Bearer ${session?.access_token ?? ""}`,
"Openai-Api-Key": openAiKey ?? "",
...headers, ...headers,
}), }),
put: async (url, body, headers) => put: async (url, body, headers) =>
fetchInstance.put(`${backendUrl}${url}`, body, { fetchInstance.put(`${backendUrl}${url}`, body, {
Authorization: `Bearer ${session?.access_token ?? ""}`, Authorization: `Bearer ${session?.access_token ?? ""}`,
"Openai-Api-Key": openAiKey ?? "",
...headers, ...headers,
}), }),
delete: async (url, headers) => delete: async (url, headers) =>
fetchInstance.delete(`${backendUrl}${url}`, { fetchInstance.delete(`${backendUrl}${url}`, {
Authorization: `Bearer ${session?.access_token ?? ""}`, Authorization: `Bearer ${session?.access_token ?? ""}`,
"Openai-Api-Key": openAiKey ?? "",
...headers, ...headers,
}), }),
}); });
}, [session, backendUrl, openAiKey]); }, [session, backendUrl]);
return { fetchInstance: instance }; return { fetchInstance: instance };
}; };

View File

@ -1,3 +1,7 @@
import { UUID } from "crypto";
import { ApiBrainDefinition } from "../api/brain/types";
export const brainStatuses = ["private", "public"] as const; export const brainStatuses = ["private", "public"] as const;
export type BrainStatus = (typeof brainStatuses)[number]; export type BrainStatus = (typeof brainStatuses)[number];
@ -8,7 +12,9 @@ export type BrainType = (typeof brainTypes)[number];
export type Model = (typeof freeModels)[number]; export type Model = (typeof freeModels)[number];
// TODO: update this type to match the backend (antropic, openai and some other keys should be removed)
export type BrainConfig = { export type BrainConfig = {
id: UUID;
model: Model; model: Model;
temperature: number; temperature: number;
maxTokens: number; maxTokens: number;
@ -27,11 +33,8 @@ export type BrainConfig = {
}; };
name: string; name: string;
description: string; description: string;
setDefault: boolean; } & {
}; brain_definition?: ApiBrainDefinition;
export type BrainConfigContextType = {
config: BrainConfig;
}; };
export const openAiFreeModels = ["gpt-3.5-turbo","gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k"] as const; export const openAiFreeModels = ["gpt-3.5-turbo","gpt-3.5-turbo-1106", "gpt-3.5-turbo-16k"] as const;