✨ feat(chat): improve chat UI and add support for chat history display and sending messages
This commit is contained in:
parent
d1a58397da
commit
f1556f2446
2 changed files with 179 additions and 123 deletions
|
|
@ -31,136 +31,143 @@ export default function ChatMessage({
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"w-full py-2 pl-2 flex",
|
"w-full flex",
|
||||||
chat.isSend
|
chat.isSend ? "justify-end" : "justify-start"
|
||||||
? "bg-background dark:bg-gray-900 "
|
|
||||||
: "bg-input dark:bg-gray-800"
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"rounded-full overflow-hidden w-8 h-8 flex items-center my-3 justify-center"
|
"w-3/4 py-2 px-2 mb-4 flex",
|
||||||
|
chat.isSend
|
||||||
|
? "bg-input pl-4 flex-row-reverse rounded-xl rounded-tr-none dark:bg-gray-900 "
|
||||||
|
: "bg-foreground pr-4 rounded-xl rounded-tl-none dark:bg-gray-800"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{!chat.isSend && (
|
<div
|
||||||
<div className="relative w-8 h-8">
|
className={classNames(
|
||||||
<img
|
"rounded-full overflow-hidden w-8 h-8 flex items-center my-3 mx-3 justify-center"
|
||||||
className={
|
)}
|
||||||
"absolute transition-opacity duration-500 scale-150 " +
|
>
|
||||||
(lockChat ? "opacity-100" : "opacity-0")
|
{!chat.isSend && (
|
||||||
}
|
<div className="relative w-8 h-8">
|
||||||
src={lastMessage ? AiIcon : AiIconStill}
|
<img
|
||||||
/>
|
className={
|
||||||
<img
|
"absolute transition-opacity duration-500 scale-150 " +
|
||||||
className={
|
(lockChat ? "opacity-100" : "opacity-0")
|
||||||
"absolute transition-opacity duration-500 scale-150 " +
|
}
|
||||||
(lockChat ? "opacity-0" : "opacity-100")
|
src={lastMessage ? AiIcon : AiIconStill}
|
||||||
}
|
/>
|
||||||
src={AiIconStill}
|
<img
|
||||||
/>
|
className={
|
||||||
</div>
|
"absolute transition-opacity duration-500 scale-150 " +
|
||||||
)}
|
(lockChat ? "opacity-0" : "opacity-100")
|
||||||
{chat.isSend && (
|
}
|
||||||
<User2 className="w-6 h-6 -mb-1 text-gray-800 dark:text-gray-200" />
|
src={AiIconStill}
|
||||||
)}
|
/>
|
||||||
</div>
|
</div>
|
||||||
{!chat.isSend ? (
|
)}
|
||||||
<div className="w-full text-start flex items-center">
|
{chat.isSend && (
|
||||||
<div className="w-full relative text-start inline-block text-gray-600 dark:text-gray-300 text-sm font-normal">
|
<User2 className="w-6 h-6 text-gray-800 dark:text-gray-200" />
|
||||||
{hidden && chat.thought && chat.thought !== "" && (
|
)}
|
||||||
<div
|
</div>
|
||||||
onClick={() => setHidden((prev) => !prev)}
|
{!chat.isSend ? (
|
||||||
className="absolute -top-1 -left-2 cursor-pointer"
|
<div className="w-full text-start flex items-center">
|
||||||
>
|
<div className="w-full relative text-start inline-block text-background text-sm font-normal">
|
||||||
<MessageCircle className="w-5 h-5 animate-bounce dark:text-white" />
|
{hidden && chat.thought && chat.thought !== "" && (
|
||||||
</div>
|
<div
|
||||||
)}
|
onClick={() => setHidden((prev) => !prev)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && (
|
className="absolute -top-1 -left-2 cursor-pointer"
|
||||||
<div
|
>
|
||||||
onClick={() => setHidden((prev) => !prev)}
|
<MessageCircle className="w-5 h-5 animate-bounce dark:text-white" />
|
||||||
className=" text-start inline-block rounded-md text-gray-600 dark:text-gray-200 h-full border border-gray-300 dark:border-gray-500
|
</div>
|
||||||
|
)}
|
||||||
|
{chat.thought && chat.thought !== "" && !hidden && (
|
||||||
|
<div
|
||||||
|
onClick={() => setHidden((prev) => !prev)}
|
||||||
|
className=" text-start inline-block rounded-md text-background h-full border border-gray-300 dark:border-gray-500
|
||||||
bg-muted dark:bg-gray-800 w-[95%] pb-3 pt-3 px-2 ml-3 cursor-pointer scrollbar-hide overflow-scroll"
|
bg-muted dark:bg-gray-800 w-[95%] pb-3 pt-3 px-2 ml-3 cursor-pointer scrollbar-hide overflow-scroll"
|
||||||
dangerouslySetInnerHTML={{
|
dangerouslySetInnerHTML={{
|
||||||
__html: convert.toHtml(chat.thought),
|
__html: convert.toHtml(chat.thought),
|
||||||
}}
|
}}
|
||||||
></div>
|
></div>
|
||||||
)}
|
)}
|
||||||
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
{chat.thought && chat.thought !== "" && !hidden && <br></br>}
|
||||||
<div className="w-full px-4 pb-3 pt-3 pr-8">
|
<div className="w-full pb-3 pt-3">
|
||||||
<div className="dark:text-white w-full">
|
<div className="dark:text-white w-full">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm, remarkMath]}
|
remarkPlugins={[remarkGfm, remarkMath]}
|
||||||
rehypePlugins={[rehypeMathjax]}
|
rehypePlugins={[rehypeMathjax]}
|
||||||
className="markdown prose dark:prose-invert text-gray-600 dark:text-gray-200"
|
className="markdown prose dark:prose-invert text-background"
|
||||||
components={{
|
components={{
|
||||||
code({ node, inline, className, children, ...props }) {
|
code({ node, inline, className, children, ...props }) {
|
||||||
if (children.length) {
|
if (children.length) {
|
||||||
if (children[0] == "▍") {
|
if (children[0] == "▍") {
|
||||||
return (
|
return (
|
||||||
<span className="animate-pulse cursor-default mt-1">
|
<span className="animate-pulse cursor-default mt-1">
|
||||||
▍
|
▍
|
||||||
</span>
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
children[0] = (children[0] as string).replace(
|
||||||
|
"`▍`",
|
||||||
|
"▍"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
children[0] = (children[0] as string).replace(
|
const match = /language-(\w+)/.exec(className || "");
|
||||||
"`▍`",
|
|
||||||
"▍"
|
return !inline ? (
|
||||||
|
<CodeBlock
|
||||||
|
key={Math.random()}
|
||||||
|
language={(match && match[1]) || ""}
|
||||||
|
value={String(children).replace(/\n$/, "")}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<code className={className} {...props}>
|
||||||
|
{children}
|
||||||
|
</code>
|
||||||
);
|
);
|
||||||
}
|
},
|
||||||
|
}}
|
||||||
const match = /language-(\w+)/.exec(className || "");
|
>
|
||||||
|
{message}
|
||||||
return !inline ? (
|
</ReactMarkdown>
|
||||||
<CodeBlock
|
|
||||||
key={Math.random()}
|
|
||||||
language={(match && match[1]) || ""}
|
|
||||||
value={String(children).replace(/\n$/, "")}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<code className={className} {...props}>
|
|
||||||
{children}
|
|
||||||
</code>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{message}
|
|
||||||
</ReactMarkdown>
|
|
||||||
</div>
|
|
||||||
{chat.files && (
|
|
||||||
<div className="my-2 w-full">
|
|
||||||
{chat.files.map((file, index) => {
|
|
||||||
return (
|
|
||||||
<div key={index} className="my-2 w-full">
|
|
||||||
<FileCard
|
|
||||||
fileName={"Generated File"}
|
|
||||||
fileType={file.data_type}
|
|
||||||
content={file.data}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
{chat.files && (
|
||||||
|
<div className="my-2 w-full">
|
||||||
|
{chat.files.map((file, index) => {
|
||||||
|
return (
|
||||||
|
<div key={index} className="my-2 w-full">
|
||||||
|
<FileCard
|
||||||
|
fileName={"Generated File"}
|
||||||
|
fileType={file.data_type}
|
||||||
|
content={file.data}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
) : (
|
||||||
) : (
|
<div className="w-full flex items-center">
|
||||||
<div className="w-full flex items-center">
|
<div className="text-start inline-block text-gray-600 dark:text-white">
|
||||||
<div className="text-start inline-block px-3 text-gray-600 dark:text-white">
|
<span
|
||||||
<span
|
className="text-gray-600 dark:text-gray-200"
|
||||||
className="text-gray-600 dark:text-gray-200"
|
dangerouslySetInnerHTML={{
|
||||||
dangerouslySetInnerHTML={{
|
__html: message.replace(/\n/g, "<br>"),
|
||||||
__html: message.replace(/\n/g, "<br>"),
|
}}
|
||||||
}}
|
></span>
|
||||||
></span>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
)}
|
||||||
)}
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,15 @@ import { ChatMessageType } from "../../types/chat";
|
||||||
import ChatInput from "./chatInput";
|
import ChatInput from "./chatInput";
|
||||||
|
|
||||||
import _ from "lodash";
|
import _ from "lodash";
|
||||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "../../components/ui/dialog";
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
|
} from "../../components/ui/dialog";
|
||||||
import { dark } from "@mui/material/styles/createPalette";
|
import { dark } from "@mui/material/styles/createPalette";
|
||||||
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants";
|
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants";
|
||||||
import { postValidateCode } from "../../controllers/API";
|
import { postValidateCode } from "../../controllers/API";
|
||||||
|
|
@ -51,7 +59,7 @@ export default function FormModal({
|
||||||
}, [open]);
|
}, [open]);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
id.current = flow.id;
|
id.current = flow.id;
|
||||||
console.log(tabsState[flow.id])
|
console.log(tabsState[flow.id]);
|
||||||
}, [flow.id]);
|
}, [flow.id]);
|
||||||
|
|
||||||
var isStream = false;
|
var isStream = false;
|
||||||
|
|
@ -338,15 +346,56 @@ export default function FormModal({
|
||||||
</DialogHeader>
|
</DialogHeader>
|
||||||
|
|
||||||
<div className="flex h-[600px] w-full mt-2">
|
<div className="flex h-[600px] w-full mt-2">
|
||||||
<div className="w-64 h-full flex flex-col justify-start">
|
<div className="w-96 h-full flex flex-col justify-start">
|
||||||
<div className="grid w-full max-w-sm items-center gap-1.5">
|
|
||||||
<Label htmlFor="context">context</Label>
|
|
||||||
<Input placeholder="Type your message" id="context"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full pl-6">
|
<div className="w-full pl-6">
|
||||||
<div className="bg-muted rounded-md w-full h-full">
|
<div className="flex flex-col rounded-md w-full h-full">
|
||||||
teste
|
<div
|
||||||
|
ref={messagesRef}
|
||||||
|
className="w-full h-full flex-col flex items-center overflow-scroll scrollbar-hide"
|
||||||
|
>
|
||||||
|
{chatHistory.length > 0 ? (
|
||||||
|
chatHistory.map((c, i) => (
|
||||||
|
<ChatMessage
|
||||||
|
lockChat={lockChat}
|
||||||
|
chat={c}
|
||||||
|
lastMessage={chatHistory.length - 1 == i ? true : false}
|
||||||
|
key={i}
|
||||||
|
/>
|
||||||
|
))
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-col h-full text-center justify-center w-full items-center align-middle">
|
||||||
|
<span>
|
||||||
|
👋{" "}
|
||||||
|
<span className="text-gray-600 dark:text-gray-300 text-lg">
|
||||||
|
LangFlow Chat
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<br />
|
||||||
|
<div className="bg-muted dark:bg-gray-900 rounded-md w-2/4 px-6 py-8 border border-gray-200 dark:border-gray-700">
|
||||||
|
<span className="text-base text-gray-500">
|
||||||
|
Start a conversation and click the agent’s thoughts{" "}
|
||||||
|
<span>
|
||||||
|
<MessagesSquare className="w-5 h-5 inline animate-bounce mx-1 " />
|
||||||
|
</span>{" "}
|
||||||
|
to inspect the chaining process.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div ref={ref}></div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full bg-background flex-col flex items-center justify-between">
|
||||||
|
<div className="relative w-full mt-1 rounded-md shadow-sm">
|
||||||
|
<ChatInput
|
||||||
|
chatValue={chatValue}
|
||||||
|
lockChat={lockChat}
|
||||||
|
sendMessage={sendMessage}
|
||||||
|
setChatValue={setChatValue}
|
||||||
|
inputRef={ref}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue