fix: model menu key issue

This commit is contained in:
Daniel Avila 2023-03-12 16:45:44 -04:00
parent 9bc85ea83d
commit 8e513d83a5
6 changed files with 73 additions and 57 deletions

View file

@ -1,9 +1,14 @@
const express = require('express'); const express = require('express');
const router = express.Router(); const router = express.Router();
const { getCustomGpts, updateCustomGpt, updateByLabel, deleteCustomGpts } = require('../../models'); const {
getCustomGpts,
updateCustomGpt,
updateByLabel,
deleteCustomGpts
} = require('../../models');
router.get('/', async (req, res) => { router.get('/', async (req, res) => {
const models = (await getCustomGpts()).map(model => { const models = (await getCustomGpts()).map((model) => {
model = model.toObject(); model = model.toObject();
model._id = model._id.toString(); model._id = model._id.toString();
return model; return model;
@ -15,8 +20,14 @@ router.post('/delete', async (req, res) => {
const { arg } = req.body; const { arg } = req.body;
try { try {
const dbResponse = await deleteCustomGpts(arg); await deleteCustomGpts(arg);
res.status(201).send(dbResponse); const models = (await getCustomGpts()).map((model) => {
model = model.toObject();
model._id = model._id.toString();
return model;
});
res.status(201).send(models);
// res.status(201).send(dbResponse);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).send(error); res.status(500).send(error);

View file

@ -1,11 +0,0 @@
module.exports = (req, res, next) => {
let { stopStream } = req.body;
if (stopStream) {
console.log('stopStream');
res.write('event: stop\ndata:\n\n');
res.end();
return;
} else {
next();
}
};

View file

@ -4,9 +4,10 @@ import ModelItem from './ModelItem';
export default function MenuItems({ models, onSelect }) { export default function MenuItems({ models, onSelect }) {
return ( return (
<> <>
{models.map((modelItem, i) => ( {models.map((modelItem) => (
<ModelItem <ModelItem
key={i} key={modelItem._id}
id={modelItem._id}
modelName={modelItem.name} modelName={modelItem.name}
value={modelItem.value} value={modelItem.value}
onSelect={onSelect} onSelect={onSelect}

View file

@ -27,7 +27,7 @@ export default function ModelDialog({ mutate, setModelSave, handleSaveState }) {
const inputRef = useRef(null); const inputRef = useRef(null);
const updateCustomGpt = manualSWR(`/api/customGpts/`, 'post'); const updateCustomGpt = manualSWR(`/api/customGpts/`, 'post');
const submitHandler = (e) => { const selectHandler = (e) => {
if (chatGptLabel.length === 0) { if (chatGptLabel.length === 0) {
e.preventDefault(); e.preventDefault();
setRequired(true); setRequired(true);
@ -140,10 +140,10 @@ export default function ModelDialog({ mutate, setModelSave, handleSaveState }) {
{saveText} {saveText}
</Button> </Button>
<DialogClose <DialogClose
onClick={submitHandler} onClick={selectHandler}
className="inline-flex h-10 items-center justify-center rounded-md border-none bg-gray-900 py-2 px-4 text-sm font-semibold 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" className="inline-flex h-10 items-center justify-center rounded-md border-none bg-gray-900 py-2 px-4 text-sm font-semibold 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"
> >
Submit Select
</DialogClose> </DialogClose>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>

View file

@ -1,13 +1,15 @@
import React, { useState, useRef } from 'react'; import React, { useState, useRef } from 'react';
import { useSelector } from 'react-redux'; import { useDispatch, useSelector } from 'react-redux';
import { DropdownMenuRadioItem } from '../ui/DropdownMenu.tsx'; import { DropdownMenuRadioItem } from '../ui/DropdownMenu.tsx';
import { setModels } from '~/store/modelSlice';
import { Circle } from 'lucide-react'; import { Circle } from 'lucide-react';
import { DialogTrigger } from '../ui/Dialog.tsx'; import { DialogTrigger } from '../ui/Dialog.tsx';
import RenameButton from '../Conversations/RenameButton'; import RenameButton from '../Conversations/RenameButton';
import TrashIcon from '../svg/TrashIcon'; import TrashIcon from '../svg/TrashIcon';
import manualSWR from '~/utils/fetchers'; import manualSWR from '~/utils/fetchers';
export default function ModelItem({ modelName, value, onSelect }) { export default function ModelItem({ modelName, value, onSelect, id }) {
const dispatch = useDispatch();
const { customModel } = useSelector((state) => state.submit); const { customModel } = useSelector((state) => state.submit);
const { initial } = useSelector((state) => state.models); const { initial } = useSelector((state) => state.models);
const [isHovering, setIsHovering] = useState(false); const [isHovering, setIsHovering] = useState(false);
@ -16,7 +18,14 @@ export default function ModelItem({ modelName, value, onSelect }) {
const [modelInput, setModelInput] = useState(modelName); const [modelInput, setModelInput] = useState(modelName);
const inputRef = useRef(null); const inputRef = useRef(null);
const rename = manualSWR(`/api/customGpts`, 'post'); const rename = manualSWR(`/api/customGpts`, 'post');
const deleteCustom = manualSWR(`/api/customGpts/delete`, 'post'); const deleteCustom = manualSWR(`/api/customGpts/delete`, 'post', (res) => {
const fetchedModels = res.data.map((modelItem) => ({
...modelItem,
name: modelItem.chatGptLabel
}));
dispatch(setModels(fetchedModels));
});
if (value === 'chatgptCustom') { if (value === 'chatgptCustom') {
return ( return (
@ -77,8 +86,7 @@ export default function ModelItem({ modelName, value, onSelect }) {
const onDelete = async (e) => { const onDelete = async (e) => {
e.preventDefault(); e.preventDefault();
await deleteCustom.trigger({ value: currentName.toLowerCase() }); await deleteCustom.trigger({ _id: id });
// await mutate();
onSelect('chatgpt', true); onSelect('chatgpt', true);
}; };
@ -90,25 +98,24 @@ export default function ModelItem({ modelName, value, onSelect }) {
const buttonClass = { const buttonClass = {
className: className:
'z-50 rounded-md m-0 text-gray-400 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200' 'invisible group-hover:visible z-50 rounded-md m-0 text-gray-400 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
}; };
const itemClass = { const itemClass = {
className: className:
'relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none hover:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:hover:bg-slate-700 dark:font-semibold dark:text-gray-100 dark:hover:bg-gray-800' 'relative flex group cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm font-medium outline-none hover:bg-slate-100 data-[disabled]:pointer-events-none data-[disabled]:opacity-50 dark:hover:bg-slate-700 dark:font-semibold dark:text-gray-100 dark:hover:bg-gray-800'
}; };
const showButtons = isHovering && !initial[value];
return ( return (
<span <span
value={value} value={value}
className={itemClass.className} className={itemClass.className}
onClick={(e) => { onClick={(e) => {
if (isHovering) {
return;
}
onSelect(value, true); onSelect(value, true);
}} }}
onMouseOver={handleMouseOver}
onMouseOut={handleMouseOut}
> >
{customModel === value && ( {customModel === value && (
<span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center"> <span className="absolute left-2 flex h-3.5 w-3.5 items-center justify-center">
@ -118,35 +125,36 @@ export default function ModelItem({ modelName, value, onSelect }) {
{renaming === true ? ( {renaming === true ? (
<input <input
ref={inputRef} ref={inputRef}
key={id}
type="text" type="text"
className="pointer-events-auto z-50 m-0 mr-2 w-3/4 border border-blue-500 bg-transparent p-0 text-sm leading-tight outline-none" className="pointer-events-auto z-50 m-0 mr-2 w-3/4 border border-blue-500 bg-transparent p-0 text-sm leading-tight outline-none"
value={modelInput} value={modelInput}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
onChange={(e) => setModelInput(e.target.value)} onChange={(e) => setModelInput(e.target.value)}
onBlur={onRename} // onBlur={onRename}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}
/> />
) : ( ) : (
modelInput <div className="w-3/4 overflow-hidden">{modelInput}</div>
)} )}
{value === 'chatgpt' && <sup>$</sup>} {value === 'chatgpt' && <sup>$</sup>}
{showButtons && ( <RenameButton
<> twcss={`ml-auto mr-2 ${buttonClass.className}`}
<RenameButton onRename={onRename}
twcss={`ml-auto mr-2 ${buttonClass.className}`} renaming={renaming}
onRename={onRename} onMouseOver={handleMouseOver}
renaming={renaming} onMouseOut={handleMouseOut}
renameHandler={renameHandler} renameHandler={renameHandler}
/> />
<button <button
{...buttonClass} {...buttonClass}
onClick={onDelete} onMouseOver={handleMouseOver}
> onMouseOut={handleMouseOut}
<TrashIcon /> onClick={onDelete}
</button> >
</> <TrashIcon />
)} </button>
</span> </span>
); );
} }

View file

@ -1,10 +1,16 @@
import React, { useState, useEffect } from 'react'; import React, { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux'; import { useSelector, useDispatch } from 'react-redux';
import { setSubmission, setModel, setDisabled, setCustomGpt, setCustomModel } from '~/store/submitSlice'; import {
setSubmission,
setModel,
setDisabled,
setCustomGpt,
setCustomModel
} from '~/store/submitSlice';
import { setNewConvo } from '~/store/convoSlice'; import { setNewConvo } from '~/store/convoSlice';
import ModelDialog from './ModelDialog'; import ModelDialog from './ModelDialog';
import MenuItems from './MenuItems'; import MenuItems from './MenuItems';
import manualSWR from '~/utils/fetchers'; import { swr } from '~/utils/fetchers';
import { setModels } from '~/store/modelSlice'; import { setModels } from '~/store/modelSlice';
import GPTIcon from '../svg/GPTIcon'; import GPTIcon from '../svg/GPTIcon';
import BingIcon from '../svg/BingIcon'; import BingIcon from '../svg/BingIcon';
@ -27,7 +33,7 @@ export default function ModelMenu() {
const [menuOpen, setMenuOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false);
const { model, customModel } = useSelector((state) => state.submit); const { model, customModel } = useSelector((state) => state.submit);
const { models, modelMap, initial } = useSelector((state) => state.models); const { models, modelMap, initial } = useSelector((state) => state.models);
const { trigger } = manualSWR(`/api/customGpts`, 'get', (res) => { const { data, isLoading, mutate } = swr(`/api/customGpts`, (res) => {
const fetchedModels = res.map((modelItem) => ({ const fetchedModels = res.map((modelItem) => ({
...modelItem, ...modelItem,
name: modelItem.chatGptLabel name: modelItem.chatGptLabel
@ -37,7 +43,7 @@ export default function ModelMenu() {
}); });
useEffect(() => { useEffect(() => {
trigger(); mutate();
const lastSelected = JSON.parse(localStorage.getItem('model')); const lastSelected = JSON.parse(localStorage.getItem('model'));
if (lastSelected && lastSelected !== 'chatgptCustom' && initial[lastSelected]) { if (lastSelected && lastSelected !== 'chatgptCustom' && initial[lastSelected]) {
dispatch(setModel(lastSelected)); dispatch(setModel(lastSelected));
@ -51,6 +57,9 @@ export default function ModelMenu() {
}, [model]); }, [model]);
const onChange = (value, custom = false) => { const onChange = (value, custom = false) => {
// if (custom) {
// mutate();
// }
if (!value) { if (!value) {
return; return;
} else if (value === 'chatgptCustom') { } else if (value === 'chatgptCustom') {
@ -59,9 +68,6 @@ export default function ModelMenu() {
dispatch(setModel(value)); dispatch(setModel(value));
dispatch(setDisabled(false)); dispatch(setDisabled(false));
dispatch(setCustomModel(null)); dispatch(setCustomModel(null));
if (custom) {
trigger();
}
} else if (!initial[value]) { } else if (!initial[value]) {
const chatGptLabel = modelMap[value]?.chatGptLabel; const chatGptLabel = modelMap[value]?.chatGptLabel;
const promptPrefix = modelMap[value]?.promptPrefix; const promptPrefix = modelMap[value]?.promptPrefix;
@ -81,6 +87,7 @@ export default function ModelMenu() {
}; };
const onOpenChange = (open) => { const onOpenChange = (open) => {
mutate();
if (!open) { if (!open) {
setModelSave(false); setModelSave(false);
} }
@ -157,7 +164,7 @@ export default function ModelMenu() {
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
<ModelDialog <ModelDialog
mutate={trigger} mutate={mutate}
modelMap={modelMap} modelMap={modelMap}
setModelSave={setModelSave} setModelSave={setModelSave}
handleSaveState={handleSaveState} handleSaveState={handleSaveState}