θΏ™ζ˜―indexlocζδΎ›ηš„ζœεŠ‘οΌŒδΈθ¦θΎ“ε…₯任何密码
Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ export default function ChatHistory({ settings = {}, history = [] }) {
message={props.content}
role={props.role}
sources={props.sources}
chatId={props.chatId}
feedbackScore={props.feedbackScore}
error={props.error}
/>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,105 @@
import React, { memo, useState } from "react";
import useCopyText from "@/hooks/useCopyText";
import { Check, ClipboardText } from "@phosphor-icons/react";
import { memo } from "react";
import {
Check,
ClipboardText,
ThumbsUp,
ThumbsDown,
} from "@phosphor-icons/react";
import { Tooltip } from "react-tooltip";
import Workspace from "@/models/workspace";

const Actions = ({ message, feedbackScore, chatId, slug }) => {
const [selectedFeedback, setSelectedFeedback] = useState(feedbackScore);

const handleFeedback = async (newFeedback) => {
const updatedFeedback =
selectedFeedback === newFeedback ? null : newFeedback;
await Workspace.updateChatFeedback(chatId, slug, updatedFeedback);
setSelectedFeedback(updatedFeedback);
};

const Actions = ({ message }) => {
return (
<div className="flex justify-start items-center gap-x-4">
<CopyMessage message={message} />
{/* Other actions to go here later. */}
{chatId && (
<>
<FeedbackButton
isSelected={selectedFeedback === true}
handleFeedback={() => handleFeedback(true)}
tooltipId={`${chatId}-thumbs-up`}
tooltipContent="Good response"
IconComponent={ThumbsUp}
/>
<FeedbackButton
isSelected={selectedFeedback === false}
handleFeedback={() => handleFeedback(false)}
tooltipId={`${chatId}-thumbs-down`}
tooltipContent="Bad response"
IconComponent={ThumbsDown}
/>
</>
)}
</div>
);
};

function FeedbackButton({
isSelected,
handleFeedback,
tooltipId,
tooltipContent,
IconComponent,
}) {
return (
<div className="mt-3 relative">
<button
onClick={handleFeedback}
data-tooltip-id={tooltipId}
data-tooltip-content={tooltipContent}
className="text-zinc-300"
>
<IconComponent
size={18}
className="mb-1"
weight={isSelected ? "fill" : "regular"}
/>
</button>
<Tooltip
id={tooltipId}
place="bottom"
delayShow={300}
className="tooltip !text-xs"
/>
</div>
);
}

function CopyMessage({ message }) {
const { copied, copyText } = useCopyText();

return (
<>
<div className="mt-3 relative">
<button
onClick={() => copyText(message)}
data-tooltip-id="copy-assistant-text"
data-tooltip-content="Copy"
className="text-zinc-300"
onClick={() => copyText(message)}
>
{copied ? (
<Check size={18} className="mb-1" />
) : (
<ClipboardText size={18} className="mb-1" />
)}
</button>
<Tooltip
id="copy-assistant-text"
place="bottom"
delayShow={300}
className="tooltip !text-xs"
/>
</div>
<Tooltip
id="copy-assistant-text"
place="bottom"
delayShow={300}
className="tooltip !text-xs"
/>
</>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { memo, forwardRef } from "react";
import React, { memo } from "react";
import { Warning } from "@phosphor-icons/react";
import Jazzicon from "../../../../UserIcon";
import Actions from "./Actions";
Expand All @@ -10,64 +10,70 @@ import { v4 } from "uuid";
import createDOMPurify from "dompurify";

const DOMPurify = createDOMPurify(window);
const HistoricalMessage = forwardRef(
(
{ uuid = v4(), message, role, workspace, sources = [], error = false },
ref
) => {
return (
const HistoricalMessage = ({
uuid = v4(),
message,
role,
workspace,
sources = [],
error = false,
feedbackScore = null,
chatId = null,
}) => {
return (
<div
key={uuid}
className={`flex justify-center items-end w-full ${
role === "user" ? USER_BACKGROUND_COLOR : AI_BACKGROUND_COLOR
}`}
>
<div
key={uuid}
ref={ref}
className={`flex justify-center items-end w-full ${
role === "user" ? USER_BACKGROUND_COLOR : AI_BACKGROUND_COLOR
}`}
className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col`}
>
<div
className={`py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col`}
>
<div className="flex gap-x-5">
<Jazzicon
size={36}
user={{
uid:
role === "user"
? userFromStorage()?.username
: workspace.slug,
}}
role={role}
/>
<div className="flex gap-x-5">
<Jazzicon
size={36}
user={{
uid:
role === "user" ? userFromStorage()?.username : workspace.slug,
}}
role={role}
/>

{error ? (
<div className="p-2 rounded-lg bg-red-50 text-red-500">
<span className={`inline-block `}>
<Warning className="h-4 w-4 mb-1 inline-block" /> Could not
respond to message.
</span>
<p className="text-xs font-mono mt-2 border-l-2 border-red-300 pl-2 bg-red-200 p-2 rounded-sm">
{error}
</p>
</div>
) : (
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(renderMarkdown(message)),
}}
/>
)}
</div>
{role === "assistant" && !error && (
<div className="flex gap-x-5">
<div className="relative w-[35px] h-[35px] rounded-full flex-shrink-0 overflow-hidden" />
<Actions message={DOMPurify.sanitize(message)} />
{error ? (
<div className="p-2 rounded-lg bg-red-50 text-red-500">
<span className={`inline-block `}>
<Warning className="h-4 w-4 mb-1 inline-block" /> Could not
respond to message.
</span>
<p className="text-xs font-mono mt-2 border-l-2 border-red-300 pl-2 bg-red-200 p-2 rounded-sm">
{error}
</p>
</div>
) : (
<span
className={`whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
dangerouslySetInnerHTML={{
__html: DOMPurify.sanitize(renderMarkdown(message)),
}}
/>
)}
{role === "assistant" && <Citations sources={sources} />}
</div>
{role === "assistant" && !error && (
<div className="flex gap-x-5">
<div className="relative w-[35px] h-[35px] rounded-full flex-shrink-0 overflow-hidden" />
<Actions
message={DOMPurify.sanitize(message)}
feedbackScore={feedbackScore}
chatId={chatId}
slug={workspace?.slug}
/>
</div>
)}
{role === "assistant" && <Citations sources={sources} />}
</div>
);
}
);
</div>
);
};

export default memo(HistoricalMessage);
Original file line number Diff line number Diff line change
@@ -1,67 +1,44 @@
import { forwardRef, memo } from "react";
import { memo } from "react";
import { Warning } from "@phosphor-icons/react";
import Jazzicon from "../../../../UserIcon";
import renderMarkdown from "@/utils/chat/markdown";
import Citations from "../Citation";

const PromptReply = forwardRef(
(
{ uuid, reply, pending, error, workspace, sources = [], closed = true },
ref
) => {
const assistantBackgroundColor = "bg-historical-msg-system";
const PromptReply = ({
uuid,
reply,
pending,
error,
workspace,
sources = [],
closed = true,
}) => {
const assistantBackgroundColor = "bg-historical-msg-system";

if (!reply && sources.length === 0 && !pending && !error) return null;
if (!reply && sources.length === 0 && !pending && !error) return null;

if (pending) {
return (
<div
ref={ref}
className={`flex justify-center items-end w-full ${assistantBackgroundColor}`}
>
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
<div className="flex gap-x-5">
<Jazzicon
size={36}
user={{ uid: workspace.slug }}
role="assistant"
/>
<div className="mt-3 ml-5 dot-falling"></div>
</div>
</div>
</div>
);
}

if (error) {
return (
<div
className={`flex justify-center items-end w-full ${assistantBackgroundColor}`}
>
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
<div className="flex gap-x-5">
<Jazzicon
size={36}
user={{ uid: workspace.slug }}
role="assistant"
/>
<span
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
>
<Warning className="h-4 w-4 mb-1 inline-block" /> Could not
respond to message.
<span className="text-xs">Reason: {error || "unknown"}</span>
</span>
</div>
if (pending) {
return (
<div
className={`flex justify-center items-end w-full ${assistantBackgroundColor}`}
>
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
<div className="flex gap-x-5">
<Jazzicon
size={36}
user={{ uid: workspace.slug }}
role="assistant"
/>
<div className="mt-3 ml-5 dot-falling"></div>
</div>
</div>
);
}
</div>
);
}

if (error) {
return (
<div
key={uuid}
ref={ref}
className={`flex justify-center items-end w-full ${assistantBackgroundColor}`}
>
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
Expand All @@ -72,15 +49,35 @@ const PromptReply = forwardRef(
role="assistant"
/>
<span
className={`reply whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
/>
className={`inline-block p-2 rounded-lg bg-red-50 text-red-500`}
>
<Warning className="h-4 w-4 mb-1 inline-block" /> Could not
respond to message.
<span className="text-xs">Reason: {error || "unknown"}</span>
</span>
</div>
<Citations sources={sources} />
</div>
</div>
);
}
);

return (
<div
key={uuid}
className={`flex justify-center items-end w-full ${assistantBackgroundColor}`}
>
<div className="py-8 px-4 w-full flex gap-x-5 md:max-w-[800px] flex-col">
<div className="flex gap-x-5">
<Jazzicon size={36} user={{ uid: workspace.slug }} role="assistant" />
<span
className={`reply whitespace-pre-line text-white font-normal text-sm md:text-sm flex flex-col gap-y-1 mt-2`}
dangerouslySetInnerHTML={{ __html: renderMarkdown(reply) }}
/>
</div>
<Citations sources={sources} />
</div>
</div>
);
};

export default memo(PromptReply);
Loading