mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-18 17:30:16 +01:00
feat: export preset.
This commit is contained in:
parent
ced65f8c98
commit
15ada95249
4 changed files with 98 additions and 20 deletions
|
|
@ -39,6 +39,7 @@
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"copy-to-clipboard": "^3.3.3",
|
"copy-to-clipboard": "^3.3.3",
|
||||||
"crypto-browserify": "^3.12.0",
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"export-from-json": "^1.7.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lucide-react": "^0.113.0",
|
"lucide-react": "^0.113.0",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { useSetRecoilState, useRecoilValue } from 'recoil';
|
import { useSetRecoilState, useRecoilValue } from 'recoil';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import exportFromJSON from 'export-from-json';
|
||||||
import DialogTemplate from '../ui/DialogTemplate';
|
import DialogTemplate from '../ui/DialogTemplate';
|
||||||
import { Dialog } from '../ui/Dialog.tsx';
|
import { Dialog, DialogClose, DialogButton } from '../ui/Dialog.tsx';
|
||||||
import { Input } from '../ui/Input.tsx';
|
import { Input } from '../ui/Input.tsx';
|
||||||
import { Label } from '../ui/Label.tsx';
|
import { Label } from '../ui/Label.tsx';
|
||||||
import Dropdown from '../ui/Dropdown';
|
import Dropdown from '../ui/Dropdown';
|
||||||
|
|
@ -55,17 +56,47 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset }) => {
|
||||||
const defaultTextProps =
|
const defaultTextProps =
|
||||||
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
|
'rounded-md border border-gray-200 focus:border-slate-400 focus:bg-gray-50 bg-transparent text-sm shadow-[0_0_10px_rgba(0,0,0,0.05)] outline-none placeholder:text-gray-400 focus:outline-none focus:ring-gray-400 focus:ring-opacity-20 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-gray-500 dark:bg-gray-700 focus:dark:bg-gray-600 dark:text-gray-50 dark:shadow-[0_0_15px_rgba(0,0,0,0.10)] dark:focus:border-gray-400 dark:focus:outline-none dark:focus:ring-0 dark:focus:ring-gray-400 dark:focus:ring-offset-0';
|
||||||
|
|
||||||
|
// in order not to use wrong data from other endpoint
|
||||||
|
const clearPreset = () => {
|
||||||
|
if (preset?.endpoint === 'openAI')
|
||||||
|
return {
|
||||||
|
title: preset?.title,
|
||||||
|
endpoint: preset?.endpoint,
|
||||||
|
model: preset?.model,
|
||||||
|
chatGptLabel: preset?.chatGptLabel,
|
||||||
|
promptPrefix: preset?.promptPrefix,
|
||||||
|
temperature: preset?.temperature,
|
||||||
|
top_p: preset?.top_p,
|
||||||
|
presence_penalty: preset?.presence_penalty,
|
||||||
|
frequency_penalty: preset?.frequency_penalty
|
||||||
|
};
|
||||||
|
else
|
||||||
|
return {
|
||||||
|
title: preset?.title,
|
||||||
|
endpoint: preset?.endpoint
|
||||||
|
};
|
||||||
|
// TODO: else
|
||||||
|
};
|
||||||
|
|
||||||
const submitPreset = () => {
|
const submitPreset = () => {
|
||||||
axios({
|
axios({
|
||||||
method: 'post',
|
method: 'post',
|
||||||
url: '/api/presets',
|
url: '/api/presets',
|
||||||
data: preset,
|
data: clearPreset(),
|
||||||
withCredentials: true
|
withCredentials: true
|
||||||
}).then(res => {
|
}).then(res => {
|
||||||
setPresets(res?.data);
|
setPresets(res?.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const exportPreset = () => {
|
||||||
|
exportFromJSON({
|
||||||
|
data: clearPreset(),
|
||||||
|
fileName: `${preset?.title}.json`,
|
||||||
|
exportType: exportFromJSON.types.json
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setPreset(_preset);
|
setPreset(_preset);
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
@ -123,11 +154,26 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset }) => {
|
||||||
<div className="w-full p-0">{renderSettings()}</div>
|
<div className="w-full p-0">{renderSettings()}</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
selection={{
|
buttons={
|
||||||
selectHandler: submitPreset,
|
<>
|
||||||
selectClasses: 'bg-green-600 hover:bg-green-700 dark:hover:bg-green-800 text-white',
|
<DialogClose
|
||||||
selectText: 'Save'
|
onClick={submitPreset}
|
||||||
}}
|
className="dark:hover:gray-400 border-gray-700 bg-green-600 text-white hover:bg-green-700 dark:hover:bg-green-800"
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</DialogClose>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
leftButtons={
|
||||||
|
<>
|
||||||
|
<DialogButton
|
||||||
|
onClick={exportPreset}
|
||||||
|
className="dark:hover:gray-400 bg-red border-gray-700"
|
||||||
|
>
|
||||||
|
Export
|
||||||
|
</DialogButton>
|
||||||
|
</>
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import * as React from "react"
|
import * as React from "react"
|
||||||
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
import * as DialogPrimitive from "@radix-ui/react-dialog"
|
||||||
|
import { Button } from '../ui/Button';
|
||||||
import { X } from "lucide-react"
|
import { X } from "lucide-react"
|
||||||
|
|
||||||
import { cn } from "../../utils"
|
import { cn } from "../../utils"
|
||||||
|
|
@ -81,7 +82,7 @@ const DialogFooter = ({
|
||||||
}: React.HTMLAttributes<HTMLDivElement>) => (
|
}: React.HTMLAttributes<HTMLDivElement>) => (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
"flex flex-col-reverse sm:flex-row sm:justify-between sm:space-x-2",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
@ -132,6 +133,22 @@ const DialogClose = React.forwardRef<
|
||||||
))
|
))
|
||||||
DialogClose.displayName = DialogPrimitive.Title.displayName
|
DialogClose.displayName = DialogPrimitive.Title.displayName
|
||||||
|
|
||||||
|
const DialogButton = React.forwardRef<
|
||||||
|
React.ElementRef<typeof Button>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof Button>
|
||||||
|
>(({ className, ...props }, ref) => (
|
||||||
|
<Button
|
||||||
|
ref={ref}
|
||||||
|
variant="outline"
|
||||||
|
className={cn(
|
||||||
|
"mt-2 inline-flex h-10 items-center justify-center rounded-md border border-slate-200 bg-transparent py-2 px-4 text-sm font-semibold text-slate-900 transition-colors hover:bg-slate-100 focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:border-slate-700 dark:text-slate-100 dark:hover:bg-slate-700 dark:focus:ring-slate-400 dark:focus:ring-offset-slate-900 sm:mt-0",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
DialogButton.displayName = DialogPrimitive.Title.displayName
|
||||||
|
|
||||||
export {
|
export {
|
||||||
Dialog,
|
Dialog,
|
||||||
DialogTrigger,
|
DialogTrigger,
|
||||||
|
|
@ -141,4 +158,5 @@ export {
|
||||||
DialogTitle,
|
DialogTitle,
|
||||||
DialogDescription,
|
DialogDescription,
|
||||||
DialogClose,
|
DialogClose,
|
||||||
|
DialogButton,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,16 @@ import {
|
||||||
} from './Dialog.tsx';
|
} from './Dialog.tsx';
|
||||||
import { cn } from '~/utils/';
|
import { cn } from '~/utils/';
|
||||||
|
|
||||||
export default function DialogTemplate({ title, description, main, buttons, selection, className }) {
|
export default function DialogTemplate({
|
||||||
const { selectHandler, selectClasses, selectText } = selection;
|
title,
|
||||||
|
description,
|
||||||
|
main,
|
||||||
|
buttons,
|
||||||
|
leftButtons,
|
||||||
|
selection,
|
||||||
|
className
|
||||||
|
}) {
|
||||||
|
const { selectHandler, selectClasses, selectText } = selection || {};
|
||||||
|
|
||||||
const defaultSelect =
|
const defaultSelect =
|
||||||
'bg-gray-900 text-white transition-colors hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900';
|
'bg-gray-900 text-white transition-colors hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 dark:bg-gray-100 dark:text-gray-900 dark:hover:bg-gray-200 dark:focus:ring-gray-400 dark:focus:ring-offset-gray-900';
|
||||||
|
|
@ -43,8 +51,11 @@ export default function DialogTemplate({ title, description, main, buttons, sele
|
||||||
</div> */}
|
</div> */}
|
||||||
{main ? main : null}
|
{main ? main : null}
|
||||||
<DialogFooter>
|
<DialogFooter>
|
||||||
|
<div>{leftButtons ? leftButtons : null}</div>
|
||||||
|
<div>
|
||||||
<DialogClose className="dark:hover:gray-400 border-gray-700">Cancel</DialogClose>
|
<DialogClose className="dark:hover:gray-400 border-gray-700">Cancel</DialogClose>
|
||||||
{buttons ? buttons : null}
|
{buttons ? buttons : null}
|
||||||
|
{selection ? (
|
||||||
<DialogClose
|
<DialogClose
|
||||||
onClick={selectHandler}
|
onClick={selectHandler}
|
||||||
className={`${
|
className={`${
|
||||||
|
|
@ -53,6 +64,8 @@ export default function DialogTemplate({ title, description, main, buttons, sele
|
||||||
>
|
>
|
||||||
{selectText}
|
{selectText}
|
||||||
</DialogClose>
|
</DialogClose>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
</DialogFooter>
|
</DialogFooter>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue