mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-02-20 13:54:36 +01:00
Improve UI handling
This commit is contained in:
@@ -1,9 +0,0 @@
|
||||
import ReactMarkdown from "react-markdown";
|
||||
|
||||
type AssistantMessageProps = {
|
||||
content: string;
|
||||
};
|
||||
|
||||
export function AssistantMessage({ content }: AssistantMessageProps) {
|
||||
return <ReactMarkdown>{content}</ReactMarkdown>;
|
||||
}
|
||||
24
web/src/components/chat/ChatMessage.tsx
Normal file
24
web/src/components/chat/ChatMessage.tsx
Normal file
@@ -0,0 +1,24 @@
|
||||
import ReactMarkdown from "react-markdown";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type MessageBubbleProps = {
|
||||
role: "user" | "assistant";
|
||||
content: string;
|
||||
};
|
||||
|
||||
export function MessageBubble({ role, content }: MessageBubbleProps) {
|
||||
const isUser = role === "user";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"rounded-lg px-3 py-2",
|
||||
isUser
|
||||
? "self-end bg-primary text-primary-foreground"
|
||||
: "self-start bg-muted",
|
||||
)}
|
||||
>
|
||||
{isUser ? content : <ReactMarkdown>{content}</ReactMarkdown>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { FaArrowUpLong } from "react-icons/fa6";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useState, useCallback } from "react";
|
||||
import axios from "axios";
|
||||
import { AssistantMessage } from "@/components/chat/AssistantMessage";
|
||||
import { MessageBubble } from "@/components/chat/ChatMessage";
|
||||
import { ToolCallBubble } from "@/components/chat/ToolCallBubble";
|
||||
import type { ChatMessage, ToolCall } from "@/types/chat";
|
||||
|
||||
@@ -52,63 +52,53 @@ export default function ChatPage() {
|
||||
}, [input, isLoading, messages, t]);
|
||||
|
||||
return (
|
||||
<div className="flex size-full flex-col items-center p-2">
|
||||
<div className="flex min-h-0 w-full flex-1 flex-col gap-2 overflow-y-auto xl:w-[50%]">
|
||||
{messages.map((msg, i) => (
|
||||
<div key={i} className="flex flex-col gap-2">
|
||||
{msg.role === "assistant" && msg.toolCalls && (
|
||||
<>
|
||||
{msg.toolCalls.map((tc, tcIdx) => (
|
||||
<div key={tcIdx} className="flex flex-col gap-2">
|
||||
<ToolCallBubble
|
||||
name={tc.name}
|
||||
arguments={tc.arguments}
|
||||
side="left"
|
||||
/>
|
||||
{tc.response && (
|
||||
<div className="flex size-full justify-center p-2">
|
||||
<div className="flex size-full flex-col xl:w-[50%] 3xl:w-[35%]">
|
||||
<div className="flex min-h-0 w-full flex-1 flex-col gap-2 overflow-y-auto">
|
||||
{messages.map((msg, i) => (
|
||||
<div key={i} className="flex flex-col gap-2">
|
||||
{msg.role === "assistant" && msg.toolCalls && (
|
||||
<>
|
||||
{msg.toolCalls.map((tc, tcIdx) => (
|
||||
<div key={tcIdx} className="flex flex-col gap-2">
|
||||
<ToolCallBubble
|
||||
name={tc.name}
|
||||
response={tc.response}
|
||||
side="right"
|
||||
arguments={tc.arguments}
|
||||
side="left"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
<div
|
||||
className={
|
||||
msg.role === "user"
|
||||
? "self-end rounded-lg bg-primary px-3 py-2 text-primary-foreground"
|
||||
: "self-start rounded-lg bg-muted px-3 py-2"
|
||||
}
|
||||
>
|
||||
{msg.role === "assistant" ? (
|
||||
<AssistantMessage content={msg.content} />
|
||||
) : (
|
||||
msg.content
|
||||
{tc.response && (
|
||||
<ToolCallBubble
|
||||
name={tc.name}
|
||||
response={tc.response}
|
||||
side="right"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
<MessageBubble role={msg.role} content={msg.content} />
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
{isLoading && (
|
||||
<div className="self-start rounded-lg bg-muted px-3 py-2 text-muted-foreground">
|
||||
{t("processing")}
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<p className="self-start text-sm text-destructive" role="alert">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
))}
|
||||
{isLoading && (
|
||||
<div className="self-start rounded-lg bg-muted px-3 py-2 text-muted-foreground">
|
||||
{t("processing")}
|
||||
</div>
|
||||
)}
|
||||
{error && (
|
||||
<p className="self-start text-sm text-destructive" role="alert">
|
||||
{error}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
<ChatEntry
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
sendMessage={sendMessage}
|
||||
isLoading={isLoading}
|
||||
placeholder={t("placeholder")}
|
||||
/>
|
||||
</div>
|
||||
<ChatEntry
|
||||
input={input}
|
||||
setInput={setInput}
|
||||
sendMessage={sendMessage}
|
||||
isLoading={isLoading}
|
||||
placeholder={t("placeholder")}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -136,7 +126,7 @@ function ChatEntry({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full flex-col items-center justify-center rounded-xl bg-secondary p-2 xl:w-[50%]">
|
||||
<div className="flex w-full flex-col items-center justify-center rounded-xl bg-secondary p-2">
|
||||
<div className="flex w-full flex-row items-center gap-2">
|
||||
<Input
|
||||
className="w-full flex-1 border-transparent bg-transparent shadow-none focus-visible:ring-0 dark:bg-transparent"
|
||||
|
||||
Reference in New Issue
Block a user