adding responsive markdown response, error alert

pull/861/head
ManishMadan2882 4 months ago
parent f60e88573a
commit abe5f43f3d

File diff suppressed because it is too large Load Diff

@ -17,6 +17,9 @@
"clsx": "^2.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^9.0.1",
"react-syntax-highlighter": "^15.5.0",
"remark-gfm": "^4.0.0",
"tailwind-merge": "^2.2.1",
"tailwindcss-animate": "^1.0.7"
},
@ -24,6 +27,7 @@
"@types/node": "^20.11.19",
"@types/react": "^18.2.55",
"@types/react-dom": "^18.2.19",
"@types/react-syntax-highlighter": "^15.5.11",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"@vitejs/plugin-react": "^4.2.1",

@ -1,34 +1,17 @@
"use client";
import { Fragment, useEffect, useRef, useState } from 'react'
import { PaperPlaneIcon } from '@radix-ui/react-icons';
import ReactMarkdown from 'react-markdown';
import { PaperPlaneIcon, RocketIcon, ExclamationTriangleIcon } from '@radix-ui/react-icons';
import { Input } from './ui/input';
import { Button } from './ui/button';
import { ScrollArea, ScrollBar } from './ui/scroll-area'
import { ScrollArea } from './ui/scroll-area'
import { Alert, AlertTitle, AlertDescription } from './ui/alert';
import Dragon from '../assets/cute-docsgpt.svg'
import MessageIcon from '../assets/message.svg'
import Cancel from '../assets/cancel.svg'
import { Doc, Query } from '@/models/customTypes';
import { Query } from '@/models/customTypes';
import { fetchAnswerStreaming } from '@/requests/streamingApi';
//import './style.css'
interface HistoryItem {
prompt: string;
response: string;
}
interface Message {
type: 'PROMPT' | 'RESPONSE' | 'ERROR',
message: string
id: string | null
}
interface FetchAnswerStreamingProps {
question?: string;
apiKey?: string;
selectedDocs?: string;
history?: HistoryItem[];
conversationId?: string | null;
apiHost?: string;
onEvent?: (event: MessageEvent) => void;
}
import Response from './Response';
type Status = 'idle' | 'loading' | 'failed';
@ -50,28 +33,7 @@ export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', selectDo
});
const [prompt, setPrompt] = useState('');
const [status, setStatus] = useState<Status>('idle');
const [queries, setQueries] = useState<Query[]>([
{
prompt: 'dasasfafa fafajfiaf agad gagadjga gadgadgadijgaf',
response: 'dkadfafadfa fadfafa fa df adgdfaeye5uttr sr s srt rssr '
},
{
prompt: 'dasasfafa fafajfiaf agad gagadjga gadgadgadijgaf',
response: 'dkadfafadfa fadfafa fa df adgdfaeye5uttr sr s srt rssr '
},
{
prompt: 'dasasfafa fafajfiaf agad gagadjga gadgadgadijgaf',
response: 'dkadfafadfa fadfafa fa df adgdfaeye5uttr sr s srt rssr '
},
{
prompt: 'dasasfafa fafajfiaf agad gagadjga gadgadgadijgaf',
response: 'dkadfafadfa fadfafa fa df adgdfaeye5uttr sr s srt rssr '
},
{
prompt: 'LAST PROMPT',
response: 'dkadfafadfa fadfafa fa df adgdfaeye5uttr sr s srt rssr '
}
])
const [queries, setQueries] = useState<Query[]>([])
const [conversationId, setConversationId] = useState<string | null>(null)
//const selectDocs = 'local/1706.03762.pdf/'
const scrollRef = useRef<HTMLDivElement | null>(null);
@ -83,7 +45,7 @@ export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', selectDo
};
useEffect(() => {
scrollIntoView();
}, [queries.length, queries[queries.length - 1].response]);
}, [queries.length, queries[queries.length - 1]?.response]);
useEffect(() => {
localStorage.setItem('docsGPTChatState', chatState);
@ -185,7 +147,7 @@ export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', selectDo
<div className='h-full'>
<ScrollArea className='h-72 rounded-md border'>
{
queries?.map((query, index) => {
queries.length > 0 ? queries?.map((query, index) => {
return (
<Fragment key={index}>
{
@ -196,14 +158,37 @@ export const DocsGPTWidget = ({ apiHost = 'https://gptcloud.arc53.com', selectDo
</div>
}
{
query.response && <div ref={(index === queries.length - 1) ? scrollRef : null} className='flex justify-start m-2 '>
query.response ? <div ref={(index === queries.length - 1) ? scrollRef : null} className='flex justify-start m-2 '>
<p className='dark:bg-[#38383B] max-w-[80%] dark:text-white block p-2 rounded-lg'>
{query.response}
<Response message={query.response}/>
</p>
</div>
: <div className='max-w-[80%] m-2'>
{
query.error ? <Alert className='border-red-700 text-red-700' variant="destructive">
<ExclamationTriangleIcon color='red' className="h-4 w-4" />
<AlertTitle>Network Error</AlertTitle>
<AlertDescription>
Something went wrong !
</AlertDescription>
</Alert>
: <div>
add loader here
</div>
}
</div>
}
</Fragment>)
})
: <div className='absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-5/6 bg-gradient-to-br dark:from-[#5AF0EC] dark:to-[#ff1bf4] rounded-lg mx-2 p-[1px]'>
<Alert className='dark:bg-[#222327] mx-0'>
<RocketIcon className="h-4 w-4" />
<AlertTitle>Welcome to DocsGPT !</AlertTitle>
<AlertDescription>
This is a chatbot that uses the GPT-3, Faiss and LangChain to answer questions.
</AlertDescription>
</Alert>
</div>
}
</ScrollArea>
<form

@ -0,0 +1,12 @@
.list p {
display: inline;
}
.list li:not(:first-child) {
margin-top: 1em;
}
.list li > .list {
margin-top: 1em;
}

@ -0,0 +1,88 @@
import { vscDarkPlus } from 'react-syntax-highlighter/dist/cjs/styles/prism';
import remarkGfm from 'remark-gfm';
import ReactMarkdown from 'react-markdown'
import classes from './Response.module.css'
import SyntaxHighlighter from 'react-syntax-highlighter/dist/esm/light-async';
interface typeProps {
message:string
}
const Response = (props:typeProps) => {
return (
<ReactMarkdown
className="whitespace-pre-wrap break-words max-w-72"
remarkPlugins={[remarkGfm]}
components={{
code({ node, className, children, ...props }) {
const match = /language-(\w+)/.exec(className || '');
return match ? (
<SyntaxHighlighter
PreTag="div"
wrapLines={true}
lineProps={{style: {width:'',overflowX:'scroll'}}}
language={match[1]}
style={vscDarkPlus}
>
{String(children).replace(/\n$/, '')}
</SyntaxHighlighter>
) : (
<code className={className ? className : ''} {...props}>
{children}
</code>
);
},
ul({ children }) {
return (
<ul
className={`list-inside list-disc whitespace-normal pl-4 ${classes.list}`}
>
{children}
</ul>
);
},
ol({ children }) {
return (
<ol
className={`list-inside list-decimal whitespace-normal pl-4 ${classes.list}`}
>
{children}
</ol>
);
},
table({ children }) {
return (
<div className="relative overflow-x-auto rounded-lg border">
<table className="w-full text-left text-sm text-gray-700">
{children}
</table>
</div>
);
},
thead({ children }) {
return (
<thead className="text-xs uppercase text-gray-900 [&>.table-row]:bg-gray-50">
{children}
</thead>
);
},
tr({ children }) {
return (
<tr className="table-row border-b odd:bg-white even:bg-gray-50">
{children}
</tr>
);
},
td({ children }) {
return <td className="px-6 py-3">{children}</td>;
},
th({ children }) {
return <th className="px-6 py-3">{children}</th>;
},
}}
>
{props.message}
</ReactMarkdown>
)
}
export default Response

@ -0,0 +1,59 @@
import * as React from "react"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/lib/utils"
const alertVariants = cva(
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
{
variants: {
variant: {
default: "bg-background text-foreground",
destructive:
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
},
},
defaultVariants: {
variant: "default",
},
}
)
const Alert = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
>(({ className, variant, ...props }, ref) => (
<div
ref={ref}
role="alert"
className={cn(alertVariants({ variant }), className)}
{...props}
/>
))
Alert.displayName = "Alert"
const AlertTitle = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLHeadingElement>
>(({ className, ...props }, ref) => (
<h5
ref={ref}
className={cn("mb-1 font-medium leading-none tracking-tight", className)}
{...props}
/>
))
AlertTitle.displayName = "AlertTitle"
const AlertDescription = React.forwardRef<
HTMLParagraphElement,
React.HTMLAttributes<HTMLParagraphElement>
>(({ className, ...props }, ref) => (
<div
ref={ref}
className={cn("text-sm [&_p]:leading-relaxed", className)}
{...props}
/>
))
AlertDescription.displayName = "AlertDescription"
export { Alert, AlertTitle, AlertDescription }
Loading…
Cancel
Save