Merge pull request #6 from danny-avila/easy-config-setup

chore: misc. fixes/improvements before containerizing
This commit is contained in:
Danny Avila 2023-03-06 09:27:14 -05:00 committed by GitHub
commit 062cd1d838
9 changed files with 43 additions and 30 deletions

View file

@ -57,12 +57,13 @@ Here are my planned/recently finished features.
- [x] AI model change handling (start new convos within existing convo)
- [x] Server convo pagination (limit fetch and load more with 'show more' button)
- [ ] Config file for easy startup
- [ ] Conversation Search (by title)
- [ ] Resubmit/edit sent messages
- [ ] Semantic Search Option (requires more tokens)
- [ ] Bing AI Styling (for suggested responses, convo end, etc.)
- [ ] Prompt Templates
- [ ] Conversation/Prompt Search
- [ ] Prompt Templates/Search
- [ ] Refactor/clean up code (tech debt)
- [ ] Mobile styling (half-finished)
- [ ] Semantic Search Option (requires more tokens)
### Features
@ -79,12 +80,18 @@ Here are my planned/recently finished features.
## Use Cases ##
![use case example](./public/use_case.png "GPT is down! Plus is too expensive!")
- One stop shop for all conversational AIs, with the added bonus of searching past conversations.
- Using the official API, you'd have to generate 7.5 million words to expense the same cost as ChatGPT Plus ($20).
- ChatGPT Free is down.
- ChatGPT/Google Bard/Bing AI conversations are lost in space or
cannot be searched past a certain timeframe.
- ChatGPT Free (at [chat.openai.com](https://chat.openai.com/chat)) is more limited than the API
![use case example](./public/use_case2.png "chat.openai.com is getting more limited by the day!")
- ChatGPT Free is down.
![use case example](./public/use_case.png "GPT is down! Plus is too expensive!")
## Origin ##
This project was originally created as a Minimum Viable Product (or MVP) for the [@HackReactor](https://github.com/hackreactor/) Bootcamp. It was built with OpenAI response streaming and most of the UI completed in under 20 hours. During the end of that time, I had most of the UI and basic functionality done. This was created without using any boilerplates or templates, including create-react-app and other toolchains. I didn't follow any 'un-official chatgpt' video tutorials, and simply referenced the official site for the UI. The purpose of the exercise was to learn setting up a full stack project from scratch. Please feel free to give feedback, suggestions, or fork the project for your own use.

View file

@ -75,13 +75,14 @@ module.exports = {
},
// getConvos: async () => await Conversation.find({}).sort({ created: -1 }).exec(),
getConvos: async (pageNumber = 1, pageSize = 12) => {
// const skip = (pageNumber - 1) * pageSize;
const limit = pageNumber * pageSize;
const skip = (pageNumber - 1) * pageSize;
// const limit = pageNumber * pageSize;
const conversations = await Conversation.find({})
.sort({ created: -1 })
// .skip(skip)
.limit(limit)
.skip(skip)
// .limit(limit)
.limit(pageSize)
.exec();
return conversations;

View file

@ -5,8 +5,10 @@
"main": "index.js",
"scripts": {
"start": "webpack-dev-server .",
"build": "Webpack . --watch",
"server": "npx nodemon server/index.js",
"build": "Webpack .",
"server": "npx node server/index.js",
"build-dev": "Webpack . --watch",
"server-dev": "npx nodemon server/index.js",
"test": "test"
},
"repository": {

BIN
public/use_case2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

View file

@ -16,7 +16,7 @@ import {
DialogTitle
} from '../ui/Dialog.tsx';
export default function ModelDialog({ mutate }) {
export default function ModelDialog({ mutate, modelMap }) {
const dispatch = useDispatch();
const [chatGptLabel, setChatGptLabel] = useState('');
const [promptPrefix, setPromptPrefix] = useState('');
@ -50,7 +50,7 @@ export default function ModelDialog({ mutate }) {
updateCustomGpt.trigger({ value, chatGptLabel, promptPrefix });
mutate();
setSaveText('Saved!');
setSaveText((prev) => prev + 'd!');
setTimeout(() => {
setSaveText('Save');
}, 2500);
@ -60,6 +60,10 @@ export default function ModelDialog({ mutate }) {
// dispatch(setDisabled(false));
};
if (modelMap[chatGptLabel.toLowerCase()] && saveText === 'Save') {
setSaveText('Update');
}
const requiredProp = required ? { required: true } : {};
return (

View file

@ -40,15 +40,12 @@ export default function ModelMenu() {
});
useEffect(() => {
trigger();
const lastSelected = JSON.parse(localStorage.getItem('model'));
if (lastSelected && lastSelected !== 'chatgptCustom' && initial[lastSelected]) {
dispatch(setModel(lastSelected));
}
const cachedModels = JSON.parse(localStorage.getItem('models'));
if (cachedModels) {
dispatch(setModels(cachedModels));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
@ -56,10 +53,6 @@ export default function ModelMenu() {
localStorage.setItem('model', JSON.stringify(model));
}, [model]);
useEffect(() => {
localStorage.setItem('models', JSON.stringify(models.slice(4)));
}, [models]);
const onChange = (value) => {
if (!value) {
return;
@ -140,7 +133,7 @@ export default function ModelMenu() {
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>
<ModelDialog mutate={trigger} />
<ModelDialog mutate={trigger} modelMap={modelMap}/>
</Dialog>
);
}

View file

@ -6,15 +6,19 @@ import NavLinks from './NavLinks';
import useDidMountEffect from '~/hooks/useDidMountEffect';
import { swr } from '~/utils/fetchers';
import { useDispatch, useSelector } from 'react-redux';
import { incrementPage } from '~/store/convoSlice';
import { incrementPage, setConvos } from '~/store/convoSlice';
export default function Nav() {
const dispatch = useDispatch();
const [isHovering, setIsHovering] = useState(false);
const { conversationId, pageNumber } = useSelector((state) => state.convo);
const { conversationId, convos, pageNumber } = useSelector((state) => state.convo);
const onSuccess = (data) => {
dispatch(setConvos(data));
};
const { data, isLoading, mutate } = swr(
`http://localhost:3050/convos?pageNumber=${pageNumber}`
);
, onSuccess);
const containerRef = useRef(null);
const scrollPositionRef = useRef(null);
@ -63,7 +67,7 @@ export default function Nav() {
<Spinner />
) : (
<Conversations
conversations={data}
conversations={convos}
conversationId={conversationId}
showMore={showMore}
pageNumber={pageNumber}

View file

@ -93,7 +93,7 @@ export default function Landing({ title }) {
</ul>
</div>
</div>
{!showingTemplates && (
{/* {!showingTemplates && (
<div className="mt-8 mb-4 flex flex-col items-center gap-3.5 md:mt-16">
<button
onClick={showTemplates}
@ -104,7 +104,7 @@ export default function Landing({ title }) {
</button>
</div>
)}
{!!showingTemplates && <Templates showTemplates={showTemplates}/>}
{!!showingTemplates && <Templates showTemplates={showTemplates}/>} */}
<div className="group h-32 w-full flex-shrink-0 dark:border-gray-900/50 dark:bg-gray-800 md:h-48" />
</div>
</div>

View file

@ -27,8 +27,10 @@ const currentSlice = createSlice({
},
incrementPage: (state) => {
state.pageNumber = state.pageNumber + 1;
}
// setConvos: (state, action) => state.convos = action.payload,
},
setConvos: (state, action) => {
state.convos = [...state.convos, ...action.payload];
},
}
});