Skip to content
Snippets Groups Projects
Commit bbf2e2b0 authored by Embruch, Gerd's avatar Embruch, Gerd
Browse files

fixed oboarding with new chats

parent 8ef14cbb
Branches
No related tags found
No related merge requests found
......@@ -22,6 +22,30 @@ cp ./.env.template.local ./.env.production.local
- [RAGChat-API](https://gitlab.rrz.uni-hamburg.de/zbhai/ragchat-api)
- [PM2](https://pm2.keymetrics.io/)
# Routes
- [ ] check routes
- [ ] AUTH
- [ ] register
- [ ] confirm register
- [ ] resend register token
- [ ] login
- [ ] renew JWT
- [ ] logout
- [ ] request password reset
- [ ] password reset
- [ ] AI
- [ ] status
- [ ] get models
- [ ] get model
- [ ] install model [admin only]
- [ ] delete model [admin only]
- [ ] chat
- [ ] list chats
- [ ] EMBEDDINGS
- [ ] delete vector db [admin only]
- [ ] get vector db [admin only]
- [ ] update embeddings [admin only]
# Roadmap
- [ ] complete pages
- [ ] resend verification code
......@@ -29,5 +53,4 @@ cp ./.env.template.local ./.env.production.local
- [ ] admin-login
- [ ] admin-page with LLM options
- [ ] fix errors
- [ ] fix axios' JWT auto renewal
- [ ] check width of label & submit on cleanLayout
\ No newline at end of file
......@@ -387,20 +387,56 @@ cp ./.env.template.local ./.env.production.local
<li><a href="https://gitlab.rrz.uni-hamburg.de/zbhai/ragchat-api">RAGChat-API</a></li>
<li><a href="https://pm2.keymetrics.io/">PM2</a></li>
</ul>
<h1 id="routes">Routes</h1>
<ul>
<li><input type="checkbox" id="checkbox0"><label for="checkbox0">check routes</label>
<ul>
<li><input type="checkbox" id="checkbox1"><label for="checkbox1">AUTH</label>
<ul>
<li><input type="checkbox" id="checkbox2"><label for="checkbox2">register</label></li>
<li><input type="checkbox" id="checkbox3"><label for="checkbox3">confirm register</label></li>
<li><input type="checkbox" id="checkbox4"><label for="checkbox4">resend register token</label></li>
<li><input type="checkbox" id="checkbox5"><label for="checkbox5">login</label></li>
<li><input type="checkbox" id="checkbox6"><label for="checkbox6">renew JWT</label></li>
<li><input type="checkbox" id="checkbox7"><label for="checkbox7">logout</label></li>
<li><input type="checkbox" id="checkbox8"><label for="checkbox8">request password reset</label></li>
<li><input type="checkbox" id="checkbox9"><label for="checkbox9">password reset</label></li>
</ul>
</li>
<li><input type="checkbox" id="checkbox10"><label for="checkbox10">AI</label>
<ul>
<li><input type="checkbox" id="checkbox11"><label for="checkbox11">status</label></li>
<li><input type="checkbox" id="checkbox12"><label for="checkbox12">get models</label></li>
<li><input type="checkbox" id="checkbox13"><label for="checkbox13">get model</label></li>
<li><input type="checkbox" id="checkbox14"><label for="checkbox14">install model [admin only]</label></li>
<li><input type="checkbox" id="checkbox15"><label for="checkbox15">delete model [admin only]</label></li>
<li><input type="checkbox" id="checkbox16"><label for="checkbox16">chat</label></li>
<li><input type="checkbox" id="checkbox17"><label for="checkbox17">list chats</label></li>
</ul>
</li>
<li><input type="checkbox" id="checkbox18"><label for="checkbox18">EMBEDDINGS</label>
<ul>
<li><input type="checkbox" id="checkbox19"><label for="checkbox19">delete vector db [admin only]</label></li>
<li><input type="checkbox" id="checkbox20"><label for="checkbox20">get vector db [admin only]</label></li>
<li><input type="checkbox" id="checkbox21"><label for="checkbox21">update embeddings [admin only]</label></li>
</ul>
</li>
</ul>
</li>
</ul>
<h1 id="roadmap">Roadmap</h1>
<ul>
<li><input type="checkbox" id="checkbox0"><label for="checkbox0">complete pages</label>
<li><input type="checkbox" id="checkbox22"><label for="checkbox22">complete pages</label>
<ul>
<li><input type="checkbox" id="checkbox1"><label for="checkbox1">resend verification code</label></li>
<li><input type="checkbox" id="checkbox2"><label for="checkbox2">onboarding / RAGChat</label></li>
<li><input type="checkbox" id="checkbox3"><label for="checkbox3">admin-login</label></li>
<li><input type="checkbox" id="checkbox4"><label for="checkbox4">admin-page with LLM options</label></li>
<li><input type="checkbox" id="checkbox23"><label for="checkbox23">resend verification code</label></li>
<li><input type="checkbox" id="checkbox24"><label for="checkbox24">onboarding / RAGChat</label></li>
<li><input type="checkbox" id="checkbox25"><label for="checkbox25">admin-login</label></li>
<li><input type="checkbox" id="checkbox26"><label for="checkbox26">admin-page with LLM options</label></li>
</ul>
</li>
<li><input type="checkbox" id="checkbox5"><label for="checkbox5">fix errors</label>
<li><input type="checkbox" id="checkbox27"><label for="checkbox27">fix errors</label>
<ul>
<li><input type="checkbox" id="checkbox6"><label for="checkbox6">fix axios' JWT auto renewal</label></li>
<li><input type="checkbox" id="checkbox7"><label for="checkbox7">check width of label &amp; submit on cleanLayout</label></li>
<li><input type="checkbox" id="checkbox28"><label for="checkbox28">check width of label &amp; submit on cleanLayout</label></li>
</ul>
</li>
</ul>
......
......@@ -4,6 +4,7 @@ import Heading from '../font/Heading';
import { RiAddCircleLine, RiArrowLeftCircleLine, RiArrowRightCircleLine } from 'react-icons/ri';
import { useChat } from '../../contexts/Chat/ChatState';
import { useParams } from 'react-router-dom';
import { mergeBackendValidation } from '../../utils/ErrorHandling';
const Chats = () => {
// #################################
......@@ -40,7 +41,7 @@ const Chats = () => {
// on unmount abort request
controller.abort();
};
}, []);
}, [currentChatId]);
// #################################
......@@ -52,7 +53,7 @@ const Chats = () => {
// #################################
return (
<div className="row-start-2 row-span-2 border-r-2 border-UhhGrey flex flex-col">
<Heading level="6" className="text-center">Recent</Heading>
<Heading level="6" className="text-center mx-2">Recent</Heading>
{<button onClick={() => { selectChat(null); }} disabled={currentChatId ? false : true} className='text-UhhBlue disabled:text-UhhLightBlue' title='start a new chat'><RiAddCircleLine /></button>}
......@@ -63,7 +64,7 @@ const Chats = () => {
key={chat.id}
id={chat.id}
title={chat.title}
time={new Intl.DateTimeFormat(import.meta.env.VITE_LOCALE).format(new Date(chat.created))}
time={new Intl.DateTimeFormat(import.meta.env.VITE_LOCALE).format(new Date(chat.createdAt))}
/>
))
}
......
import { zodResolver } from '@hookform/resolvers/zod';
import React from 'react';
import React, { useEffect } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { RiLoopRightFill, RiSendPlane2Line } from 'react-icons/ri';
import { z } from 'zod';
......@@ -23,7 +23,7 @@ function PromptInput() {
// HOOKS
// #################################
// ### CONNECT CONTEXT
const { currentChatId, availableModels, updateChatHistory } = useChat();
const { fetchAllModels, currentChatId, availableModels, updateChatHistory, fetchAllChats } = useChat();
// ### PREPARE FORM
const methods = useForm({
......@@ -31,10 +31,32 @@ function PromptInput() {
mode: 'onSubmit',
defaultValues: {
input: '',
model: 'llama2'
model: ''
}
});
// ### FETCH MODELS;
useEffect(() => {
// ### on run exec this code
const controller = new AbortController();
const getModels = async () => {
try {
// fetch all chats
await fetchAllModels();
} catch (error) {
mergeBackendValidation(error.response.status, error.response.data);
}
};
getModels();
// ### return will be executed on unmounting this component
return () => {
// on unmount abort request
controller.abort();
};
}, []);
// #################################
// FUNCTIONS
// #################################
......@@ -46,17 +68,25 @@ function PromptInput() {
try {
// send input to api
const result = await api.post('/ai/chat', inputs);
console.log("🚀 ~ handleSendForm ~ result id:", result.data.chat.id);
if (!currentChatId) fetchAllChats(result.data.chat.id);
// update chat history
// BUG if currentChatId is null visible update fails
updateChatHistory(currentChatId, result.data.chat.chatHistory);
updateChatHistory(result.data.chat.id, result.data.chat.chatHistory);
// selectChat(currentChatId);
// clear input field
methods.resetField('input');
} catch (error) {
console.error(error);
// merge front & backend validation errors
console.log("🚀 ~ handleSendForm ~ error:", error);
mergeBackendValidation(error.response.status, error.response.data, methods.setError);
}
}
// TODO width of input field on large screens should increase
......@@ -64,10 +94,10 @@ function PromptInput() {
// OUTPUT
// #################################
return (
<div className="row-start-3 p-3 border-t-2 border-UhhGrey">
<div className="row-start-3 p-3 border-t-2 border-UhhGrey text-center">
<FormProvider {...methods} >
<form onSubmit={methods.handleSubmit(handleSendForm)}>
<div className="flex content-center h-14 relative">
<div className="flex justify-center content-center h-14 relative">
{methods.formState.isSubmitting && <div className='absolute bg-white bg-opacity-60 z-10 h-full w-full flex items-center justify-center text-2xl'><RiLoopRightFill className='animate-spin' /></div>}
<Select name="model" options={availableModels} />
......
......@@ -19,7 +19,7 @@ const chatReducer = (state, action) => {
}
case CHAT_ACTIONS.SET_MODELS: {
const models = action.payload.data;
const models = action.payload.models;
const modelNames = models.map(model => {
return { title: model.name, _id: model.name };
});
......
......@@ -37,10 +37,11 @@ function ChatState({ children }) {
// select chat if id is provided
if (id) selectChat(id);
// fetch available models
const models = await api.post('/ai/models', { filter: '' });
dispatchAvailableModels({ type: CHAT_ACTIONS.SET_MODELS, payload: models });
// const models = await api.post('/ai/models', { filter: '' });
// dispatchAvailableModels({ type: CHAT_ACTIONS.SET_MODELS, payload: models });
} catch (error) {
// display errors
console.error(error);
mergeBackendValidation(error.response.status, error.response.data);
}
}
......@@ -74,10 +75,12 @@ function ChatState({ children }) {
const isSelectedChatId = element => element.id === id;
// get index of matching item
const index = chats.findIndex(isSelectedChatId);
// update chat history
if (index > -1) {
chats[index].chatHistory = history;
dispatchChatHistory({ type: CHAT_ACTIONS.SET_HISTORY, payload: { id, chats } });
}
}
// ### SELECT CHAT
......@@ -87,6 +90,19 @@ function ChatState({ children }) {
// save chat id in state
dispatchCurrentChatId({ type: CHAT_ACTIONS.UPDATE_CHATID, payload: id });
}
// ### FETCH MODELS
async function fetchAllModels(id = null) {
try {
// fetch available models
const response = await api.post('/ai/models', { filter: '' });
dispatchAvailableModels({ type: CHAT_ACTIONS.SET_MODELS, payload: response.data });
} catch (error) {
// display errors
console.error(error);
mergeBackendValidation(error.response.status, error.response.data);
}
}
// #################################
// OUTPUT
// #################################
......@@ -100,7 +116,8 @@ function ChatState({ children }) {
fetchChatHistory,
chatHistory,
availableModels,
updateChatHistory
updateChatHistory,
fetchAllModels
}}>
{children}
</ChatContext.Provider>
......
......@@ -49,7 +49,6 @@ api.interceptors.response.use(
try {
const result = await api.get(
'/auth',
{},
{ withCredentials: true }
);
// TODO: don't store accessToken in localStorage, keep in memory only
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment