mirror of
https://github.com/StanGirard/quivr.git
synced 2024-11-24 05:55:13 +03:00
parent
537efc834d
commit
b3453157e6
54
frontend/app/config/components/BackendConfig.tsx
Normal file
54
frontend/app/config/components/BackendConfig.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
"use client";
|
||||
|
||||
import { BrainConfig } from "@/lib/context/BrainConfigProvider/types";
|
||||
import { UseFormRegister } from "react-hook-form";
|
||||
import Field from "../../components/ui/Field";
|
||||
|
||||
interface BackendConfigProps {
|
||||
register: UseFormRegister<BrainConfig>;
|
||||
}
|
||||
|
||||
export const BackendConfig = ({
|
||||
register,
|
||||
}: BackendConfigProps): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Backend config
|
||||
</p>
|
||||
</div>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Backend URL"
|
||||
className="w-full"
|
||||
label="Backend URL"
|
||||
{...register("backendUrl")}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Supabase URL"
|
||||
className="w-full"
|
||||
label="Supabase URL"
|
||||
{...register("supabaseUrl")}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Supabase key"
|
||||
className="w-full"
|
||||
label="Supabase key"
|
||||
{...register("supabaseKey")}
|
||||
/>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked
|
||||
name="keepLocal"
|
||||
onChange={() => alert("Coming soon")}
|
||||
className="form-checkbox h-5 w-5 text-indigo-600 rounded focus:ring-2 focus:ring-indigo-400"
|
||||
/>
|
||||
<span className="ml-2 text-gray-700">Keep in local</span>
|
||||
</label>
|
||||
</>
|
||||
);
|
||||
};
|
61
frontend/app/config/components/ConfigForm.tsx
Normal file
61
frontend/app/config/components/ConfigForm.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import { useRouter } from "next/navigation";
|
||||
import Button from "../../components/ui/Button";
|
||||
import { useConfig } from "../hooks/useConfig";
|
||||
import { BackendConfig } from "./BackendConfig";
|
||||
import { ModelConfig } from "./ModelConfig";
|
||||
import { UserAccountSection } from "./UserAccountSection";
|
||||
|
||||
export const ConfigForm = (): JSX.Element => {
|
||||
const {
|
||||
handleSubmit,
|
||||
isDirty,
|
||||
maxTokens,
|
||||
openAiKey,
|
||||
saveConfig,
|
||||
register,
|
||||
temperature,
|
||||
model,
|
||||
resetBrainConfig,
|
||||
} = useConfig();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
const handleDoneClick = () => {
|
||||
if (isDirty) {
|
||||
saveConfig();
|
||||
}
|
||||
router.back();
|
||||
};
|
||||
|
||||
return (
|
||||
<form
|
||||
className="flex flex-col gap-5 py-5 w-full max-w-xl"
|
||||
onSubmit={handleSubmit(handleDoneClick)}
|
||||
>
|
||||
<ModelConfig
|
||||
register={register}
|
||||
model={model}
|
||||
openAiKey={openAiKey}
|
||||
temperature={temperature}
|
||||
maxTokens={maxTokens}
|
||||
/>
|
||||
<BackendConfig register={register} />
|
||||
<div className="flex justify-between">
|
||||
<Button
|
||||
variant="danger"
|
||||
className="self-end"
|
||||
type="button"
|
||||
onClick={resetBrainConfig}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button variant="secondary" className="self-end">
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
<UserAccountSection />
|
||||
</form>
|
||||
);
|
||||
};
|
10
frontend/app/config/components/ConfigTitle.tsx
Normal file
10
frontend/app/config/components/ConfigTitle.tsx
Normal file
@ -0,0 +1,10 @@
|
||||
export const ConfigTitle = (): JSX.Element => {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<h1 className="text-3xl font-bold text-center">Configuration</h1>
|
||||
<h2 className="opacity-50 text-center">
|
||||
Here, you can choose your model, set your credentials...
|
||||
</h2>
|
||||
</div>
|
||||
);
|
||||
};
|
96
frontend/app/config/components/ModelConfig.tsx
Normal file
96
frontend/app/config/components/ModelConfig.tsx
Normal file
@ -0,0 +1,96 @@
|
||||
"use client";
|
||||
|
||||
import {
|
||||
BrainConfig,
|
||||
Model,
|
||||
anthropicModels,
|
||||
models,
|
||||
paidModels,
|
||||
} from "@/lib/context/BrainConfigProvider/types";
|
||||
import { UseFormRegister } from "react-hook-form";
|
||||
import Field from "../../components/ui/Field";
|
||||
|
||||
interface ModelConfigProps {
|
||||
register: UseFormRegister<BrainConfig>;
|
||||
model: Model;
|
||||
openAiKey: string | undefined;
|
||||
temperature: number;
|
||||
maxTokens: number;
|
||||
}
|
||||
|
||||
export const ModelConfig = ({
|
||||
register,
|
||||
model,
|
||||
openAiKey,
|
||||
temperature,
|
||||
maxTokens,
|
||||
}: ModelConfigProps): JSX.Element => {
|
||||
return (
|
||||
<>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Model config
|
||||
</p>
|
||||
</div>
|
||||
<Field
|
||||
type="password"
|
||||
placeholder="Open AI Key"
|
||||
className="w-full"
|
||||
label="Open AI Key"
|
||||
{...register("openAiKey")}
|
||||
/>
|
||||
<fieldset className="w-full flex flex-col">
|
||||
<label className="flex-1 text-sm" htmlFor="model">
|
||||
Model
|
||||
</label>
|
||||
<select
|
||||
id="model"
|
||||
{...register("model")}
|
||||
className="px-5 py-2 dark:bg-gray-700 bg-gray-200 rounded-md"
|
||||
>
|
||||
{(openAiKey ? paidModels : models).map((model) => (
|
||||
<option value={model} key={model}>
|
||||
{model}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</fieldset>
|
||||
{(anthropicModels as readonly string[]).includes(model) && (
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Anthropic API Key"
|
||||
className="w-full"
|
||||
label="Anthropic API Key"
|
||||
{...register("anthropicKey")}
|
||||
/>
|
||||
)}
|
||||
<fieldset className="w-full flex">
|
||||
<label className="flex-1" htmlFor="temp">
|
||||
Temperature: {temperature}
|
||||
</label>
|
||||
<input
|
||||
id="temp"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={temperature}
|
||||
{...register("temperature")}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset className="w-full flex">
|
||||
<label className="flex-1" htmlFor="tokens">
|
||||
Tokens: {maxTokens}
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="256"
|
||||
max="3000"
|
||||
step="1"
|
||||
value={maxTokens}
|
||||
{...register("maxTokens")}
|
||||
/>
|
||||
</fieldset>
|
||||
</>
|
||||
);
|
||||
};
|
34
frontend/app/config/components/UserAccountSection.tsx
Normal file
34
frontend/app/config/components/UserAccountSection.tsx
Normal file
@ -0,0 +1,34 @@
|
||||
"use client";
|
||||
|
||||
import { useSupabase } from "@/app/supabase-provider";
|
||||
import Link from "next/link";
|
||||
import Button from "../../components/ui/Button";
|
||||
|
||||
export const UserAccountSection = (): JSX.Element => {
|
||||
const { session } = useSupabase();
|
||||
|
||||
if (session === null) {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Your Account
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between items-center w-full">
|
||||
<span>
|
||||
Signed In as: <b>{session.user.email}</b>
|
||||
</span>
|
||||
<Link className="mt-2" href={"/logout"}>
|
||||
<Button className="px-3 py-2" variant={"danger"}>
|
||||
Logout
|
||||
</Button>
|
||||
</Link>
|
||||
{/* TODO: add functionality to change password */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
2
frontend/app/config/components/index.tsx
Normal file
2
frontend/app/config/components/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
export * from "./ConfigForm";
|
||||
export * from "./ConfigTitle";
|
@ -1,30 +1,12 @@
|
||||
"use client";
|
||||
import { redirect } from "next/navigation";
|
||||
|
||||
import {
|
||||
anthropicModels,
|
||||
models,
|
||||
paidModels,
|
||||
} from "@/lib/context/BrainConfigProvider/types";
|
||||
import Link from "next/link";
|
||||
import Button from "../components/ui/Button";
|
||||
import Field from "../components/ui/Field";
|
||||
import { useSupabase } from "../supabase-provider";
|
||||
import { useConfig } from "./hooks/useConfig";
|
||||
import { ConfigForm, ConfigTitle } from "./components";
|
||||
|
||||
export default function ExplorePage() {
|
||||
// TODO: Use states instead of NEXTJS router to open and close modal
|
||||
export default function ConfigPage() {
|
||||
const { session } = useSupabase();
|
||||
const {
|
||||
handleSubmit,
|
||||
isDirty,
|
||||
maxTokens,
|
||||
openAiKey,
|
||||
saveConfig,
|
||||
register,
|
||||
temperature,
|
||||
model,
|
||||
resetBrainConfig,
|
||||
} = useConfig();
|
||||
|
||||
if (session === null) {
|
||||
redirect("/login");
|
||||
@ -33,150 +15,8 @@ export default function ExplorePage() {
|
||||
return (
|
||||
<main className="w-full flex flex-col">
|
||||
<section className="w-full outline-none pt-10 flex flex-col gap-5 items-center justify-center p-6">
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<h1 className="text-3xl font-bold text-center">Configuration</h1>
|
||||
<h2 className="opacity-50 text-center">
|
||||
Here, you can choose your model, set your credentials...
|
||||
</h2>
|
||||
</div>
|
||||
<form
|
||||
className="flex flex-col gap-5 py-5 w-full max-w-xl"
|
||||
onSubmit={handleSubmit(saveConfig)}
|
||||
>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Model config
|
||||
</p>
|
||||
</div>
|
||||
<Field
|
||||
type="password"
|
||||
placeholder="Open AI Key"
|
||||
className="w-full"
|
||||
label="Open AI Key"
|
||||
{...register("openAiKey")}
|
||||
/>
|
||||
<fieldset className="w-full flex flex-col">
|
||||
<label className="flex-1 text-sm" htmlFor="model">
|
||||
Model
|
||||
</label>
|
||||
<select
|
||||
id="model"
|
||||
{...register("model")}
|
||||
className="px-5 py-2 dark:bg-gray-700 bg-gray-200 rounded-md"
|
||||
>
|
||||
{(openAiKey ? paidModels : models).map((model) => (
|
||||
<option value={model} key={model}>
|
||||
{model}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</fieldset>
|
||||
{(anthropicModels as readonly string[]).includes(model) && (
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Anthropic API Key"
|
||||
className="w-full"
|
||||
label="Anthropic API Key"
|
||||
{...register("anthropicKey")}
|
||||
/>
|
||||
)}
|
||||
<fieldset className="w-full flex">
|
||||
<label className="flex-1" htmlFor="temp">
|
||||
Temperature: {temperature}
|
||||
</label>
|
||||
<input
|
||||
id="temp"
|
||||
type="range"
|
||||
min="0"
|
||||
max="1"
|
||||
step="0.01"
|
||||
value={temperature}
|
||||
{...register("temperature")}
|
||||
/>
|
||||
</fieldset>
|
||||
<fieldset className="w-full flex">
|
||||
<label className="flex-1" htmlFor="tokens">
|
||||
Tokens: {maxTokens}
|
||||
</label>
|
||||
<input
|
||||
type="range"
|
||||
min="256"
|
||||
max="3000"
|
||||
step="1"
|
||||
value={maxTokens}
|
||||
{...register("maxTokens")}
|
||||
/>
|
||||
</fieldset>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Backend config
|
||||
</p>
|
||||
</div>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Backend URL"
|
||||
className="w-full"
|
||||
label="Backend URL"
|
||||
{...register("backendUrl")}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Supabase URL"
|
||||
className="w-full"
|
||||
label="Supabase URL"
|
||||
{...register("supabaseUrl")}
|
||||
/>
|
||||
<Field
|
||||
type="text"
|
||||
placeholder="Supabase key"
|
||||
className="w-full"
|
||||
label="Supabase key"
|
||||
{...register("supabaseKey")}
|
||||
/>
|
||||
<label className="flex items-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked
|
||||
name="keepLocal"
|
||||
onChange={() => alert("Coming soon")}
|
||||
className="form-checkbox h-5 w-5 text-indigo-600 rounded focus:ring-2 focus:ring-indigo-400"
|
||||
/>
|
||||
<span className="ml-2 text-gray-700">Keep in local</span>
|
||||
</label>
|
||||
<div className="flex justify-between">
|
||||
<Button
|
||||
variant="danger"
|
||||
className="self-end"
|
||||
type="button"
|
||||
onClick={resetBrainConfig}
|
||||
>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!isDirty}
|
||||
variant="secondary"
|
||||
className="self-end"
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
</div>
|
||||
<div className="border-b border-gray-300 mt-8 mb-8">
|
||||
<p className="text-center text-gray-600 uppercase tracking-wide font-semibold">
|
||||
Your Account
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex justify-between items-center w-full">
|
||||
<span>
|
||||
Signed In as: <b>{session.user.email}</b>
|
||||
</span>
|
||||
<Link className="mt-2" href={"/logout"}>
|
||||
<Button className="px-3 py-2" variant={"danger"}>
|
||||
Logout
|
||||
</Button>
|
||||
</Link>
|
||||
{/* TODO: add functionality to change password */}
|
||||
</div>
|
||||
</form>
|
||||
<ConfigTitle />
|
||||
<ConfigForm />
|
||||
</section>
|
||||
</main>
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user