7 Commits

Author SHA1 Message Date
ItzCrazyKns
9b088cd161 feat(package): bump version 2024-05-05 16:35:06 +05:30
ItzCrazyKns
94ea6c372a feat(chat-window): clear storage after error 2024-05-05 16:29:40 +05:30
ItzCrazyKns
6e61c88c9e feat(error-object): add key 2024-05-05 16:28:46 +05:30
ItzCrazyKns
ba7b92ffde feat(providers): add Content-Type header 2024-05-05 10:53:27 +05:30
ItzCrazyKns
f8fd2a6fb0 feat(package): bump version 2024-05-04 15:04:43 +05:30
ItzCrazyKns
0440a810f5 feat(http-headers): add Content-Type 2024-05-04 15:01:53 +05:30
ItzCrazyKns
e3fef3a1be feat(chat-window): add error handling 2024-05-04 14:56:54 +05:30
9 changed files with 85 additions and 12 deletions

View File

@ -1,6 +1,6 @@
{ {
"name": "perplexica-backend", "name": "perplexica-backend",
"version": "1.3.0", "version": "1.3.2",
"license": "MIT", "license": "MIT",
"author": "ItzCrazyKns", "author": "ItzCrazyKns",
"scripts": { "scripts": {

View File

@ -90,7 +90,11 @@ export const getAvailableChatModelProviders = async () => {
if (ollamaEndpoint) { if (ollamaEndpoint) {
try { try {
const response = await fetch(`${ollamaEndpoint}/api/tags`); const response = await fetch(`${ollamaEndpoint}/api/tags`, {
headers: {
'Content-Type': 'application/json',
},
});
const { models: ollamaModels } = (await response.json()) as any; const { models: ollamaModels } = (await response.json()) as any;
@ -137,7 +141,11 @@ export const getAvailableEmbeddingModelProviders = async () => {
if (ollamaEndpoint) { if (ollamaEndpoint) {
try { try {
const response = await fetch(`${ollamaEndpoint}/api/tags`); const response = await fetch(`${ollamaEndpoint}/api/tags`, {
headers: {
'Content-Type': 'application/json',
},
});
const { models: ollamaModels } = (await response.json()) as any; const { models: ollamaModels } = (await response.json()) as any;

View File

@ -70,7 +70,8 @@ export const handleConnection = async (
ws.send( ws.send(
JSON.stringify({ JSON.stringify({
type: 'error', type: 'error',
data: 'Invalid LLM or embeddings model selected', data: 'Invalid LLM or embeddings model selected, please refresh the page and try again.',
key: 'INVALID_MODEL_SELECTED',
}), }),
); );
ws.close(); ws.close();

View File

@ -57,7 +57,13 @@ const handleEmitterEvents = (
}); });
emitter.on('error', (data) => { emitter.on('error', (data) => {
const parsedData = JSON.parse(data); const parsedData = JSON.parse(data);
ws.send(JSON.stringify({ type: 'error', data: parsedData.data })); ws.send(
JSON.stringify({
type: 'error',
data: parsedData.data,
key: 'CHAIN_ERROR',
}),
);
}); });
}; };
@ -73,7 +79,11 @@ export const handleMessage = async (
if (!parsedMessage.content) if (!parsedMessage.content)
return ws.send( return ws.send(
JSON.stringify({ type: 'error', data: 'Invalid message format' }), JSON.stringify({
type: 'error',
data: 'Invalid message format',
key: 'INVALID_FORMAT',
}),
); );
const history: BaseMessage[] = parsedMessage.history.map((msg) => { const history: BaseMessage[] = parsedMessage.history.map((msg) => {
@ -99,11 +109,23 @@ export const handleMessage = async (
); );
handleEmitterEvents(emitter, ws, id); handleEmitterEvents(emitter, ws, id);
} else { } else {
ws.send(JSON.stringify({ type: 'error', data: 'Invalid focus mode' })); ws.send(
JSON.stringify({
type: 'error',
data: 'Invalid focus mode',
key: 'INVALID_FOCUS_MODE',
}),
);
} }
} }
} catch (err) { } catch (err) {
ws.send(JSON.stringify({ type: 'error', data: 'Invalid message format' })); ws.send(
JSON.stringify({
type: 'error',
data: 'Invalid message format',
key: 'INVALID_FORMAT',
}),
);
logger.error(`Failed to handle message: ${err}`); logger.error(`Failed to handle message: ${err}`);
} }
}; };

View File

@ -3,6 +3,7 @@ import { Montserrat } from 'next/font/google';
import './globals.css'; import './globals.css';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import Sidebar from '@/components/Sidebar'; import Sidebar from '@/components/Sidebar';
import { Toaster } from 'sonner';
const montserrat = Montserrat({ const montserrat = Montserrat({
weight: ['300', '400', '500', '700'], weight: ['300', '400', '500', '700'],
@ -26,6 +27,15 @@ export default function RootLayout({
<html className="h-full" lang="en"> <html className="h-full" lang="en">
<body className={cn('h-full', montserrat.className)}> <body className={cn('h-full', montserrat.className)}>
<Sidebar>{children}</Sidebar> <Sidebar>{children}</Sidebar>
<Toaster
toastOptions={{
unstyled: true,
classNames: {
toast:
'bg-[#111111] text-white rounded-lg p-4 flex flex-row items-center space-x-2',
},
}}
/>
</body> </body>
</html> </html>
); );

View File

@ -5,6 +5,7 @@ import { Document } from '@langchain/core/documents';
import Navbar from './Navbar'; import Navbar from './Navbar';
import Chat from './Chat'; import Chat from './Chat';
import EmptyChat from './EmptyChat'; import EmptyChat from './EmptyChat';
import { toast } from 'sonner';
export type Message = { export type Message = {
id: string; id: string;
@ -35,6 +36,11 @@ const useSocket = (url: string) => {
) { ) {
const providers = await fetch( const providers = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/models`, `${process.env.NEXT_PUBLIC_API_URL}/models`,
{
headers: {
'Content-Type': 'application/json',
},
},
).then(async (res) => await res.json()); ).then(async (res) => await res.json());
const chatModelProviders = providers.chatModelProviders; const chatModelProviders = providers.chatModelProviders;
@ -92,17 +98,27 @@ const useSocket = (url: string) => {
wsURL.search = searchParams.toString(); wsURL.search = searchParams.toString();
const ws = new WebSocket(wsURL.toString()); const ws = new WebSocket(wsURL.toString());
ws.onopen = () => { ws.onopen = () => {
console.log('[DEBUG] open'); console.log('[DEBUG] open');
setWs(ws); setWs(ws);
}; };
ws.onmessage = (e) => {
const parsedData = JSON.parse(e.data);
if (parsedData.type === 'error') {
toast.error(parsedData.data);
if (parsedData.key === 'INVALID_MODEL_SELECTED') {
localStorage.clear();
}
}
};
}; };
connectWs(); connectWs();
} }
return () => { return () => {
1;
ws?.close(); ws?.close();
console.log('[DEBUG] closed'); console.log('[DEBUG] closed');
}; };
@ -150,6 +166,12 @@ const ChatWindow = () => {
const messageHandler = (e: MessageEvent) => { const messageHandler = (e: MessageEvent) => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.type === 'error') {
toast.error(data.data);
setLoading(false);
return;
}
if (data.type === 'sources') { if (data.type === 'sources') {
sources = data.data; sources = data.data;
if (!added) { if (!added) {

View File

@ -46,7 +46,11 @@ const SettingsDialog = ({
if (isOpen) { if (isOpen) {
const fetchConfig = async () => { const fetchConfig = async () => {
setIsLoading(true); setIsLoading(true);
const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/config`); const res = await fetch(`${process.env.NEXT_PUBLIC_API_URL}/config`, {
headers: {
'Content-Type': 'application/json',
},
});
const data = await res.json(); const data = await res.json();
setConfig(data); setConfig(data);
setIsLoading(false); setIsLoading(false);
@ -251,7 +255,7 @@ const SettingsDialog = ({
</> </>
)} )}
{/* Embedding models */} {/* Embedding models */}
{config.chatModelProviders && ( {config.embeddingModelProviders && (
<div className="flex flex-col space-y-1"> <div className="flex flex-col space-y-1">
<p className="text-white/70 text-sm"> <p className="text-white/70 text-sm">
Embedding model Provider Embedding model Provider

View File

@ -1,6 +1,6 @@
{ {
"name": "perplexica-frontend", "name": "perplexica-frontend",
"version": "1.3.0", "version": "1.3.2",
"license": "MIT", "license": "MIT",
"author": "ItzCrazyKns", "author": "ItzCrazyKns",
"scripts": { "scripts": {
@ -24,6 +24,7 @@
"react-dom": "^18", "react-dom": "^18",
"react-text-to-speech": "^0.14.5", "react-text-to-speech": "^0.14.5",
"react-textarea-autosize": "^8.5.3", "react-textarea-autosize": "^8.5.3",
"sonner": "^1.4.41",
"tailwind-merge": "^2.2.2", "tailwind-merge": "^2.2.2",
"yet-another-react-lightbox": "^3.17.2", "yet-another-react-lightbox": "^3.17.2",
"zod": "^3.22.4" "zod": "^3.22.4"

View File

@ -2839,6 +2839,11 @@ slash@^3.0.0:
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==
sonner@^1.4.41:
version "1.4.41"
resolved "https://registry.yarnpkg.com/sonner/-/sonner-1.4.41.tgz#ff085ae4f4244713daf294959beaa3e90f842d2c"
integrity sha512-uG511ggnnsw6gcn/X+YKkWPo5ep9il9wYi3QJxHsYe7yTZ4+cOd1wuodOUmOpFuXL+/RE3R04LczdNCDygTDgQ==
source-map-js@^1.0.2, source-map-js@^1.2.0: source-map-js@^1.0.2, source-map-js@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af"