mirror of
https://github.com/run-llama/chat-ui.git
synced 2026-07-21 03:15:21 -04:00
refactor: able to use ChatMessage independently (#23)
--------- Co-authored-by: Thuc Pham <51660321+thucpn@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
---
|
||||
'web': patch
|
||||
'@llamaindex/chat-ui': patch
|
||||
---
|
||||
|
||||
make chat message component stand alone without provider
|
||||
@@ -122,7 +122,7 @@ function Annotation({ annotations }: { annotations: any }) {
|
||||
}
|
||||
|
||||
function CustomChatMessagesList() {
|
||||
const { messages } = useChatUI()
|
||||
const { messages, isLoading, append } = useChatUI()
|
||||
return (
|
||||
<ChatMessages.List>
|
||||
{messages.map((message, index) => (
|
||||
@@ -139,7 +139,11 @@ function CustomChatMessagesList() {
|
||||
<img alt="LlamaIndex" src="/llama.png" />
|
||||
)}
|
||||
</ChatMessage.Avatar>
|
||||
<ChatMessage.Content className="items-start">
|
||||
<ChatMessage.Content
|
||||
className="items-start"
|
||||
isLoading={isLoading}
|
||||
append={append}
|
||||
>
|
||||
<Markdown content={message.content} />
|
||||
<Annotation annotations={message.annotations} />
|
||||
</ChatMessage.Content>
|
||||
|
||||
@@ -17,24 +17,22 @@ import {
|
||||
MessageAnnotationType,
|
||||
SuggestedQuestionsData,
|
||||
} from './annotation'
|
||||
import { useChatUI } from './chat.context'
|
||||
import { Message } from './chat.interface'
|
||||
import { ChatHandler, Message } from './chat.interface'
|
||||
|
||||
export function EventAnnotations({
|
||||
message,
|
||||
isLast,
|
||||
showLoading,
|
||||
}: {
|
||||
message: Message
|
||||
isLast: boolean
|
||||
showLoading: boolean
|
||||
}) {
|
||||
const { isLoading } = useChatUI()
|
||||
const annotations = message.annotations as MessageAnnotation[] | undefined
|
||||
const eventData =
|
||||
annotations && annotations.length > 0
|
||||
? getAnnotationData<EventData>(annotations, MessageAnnotationType.EVENTS)
|
||||
: null
|
||||
if (!eventData?.length) return null
|
||||
return <ChatEvents data={eventData} isLast={isLast} isLoading={isLoading} />
|
||||
return <ChatEvents data={eventData} showLoading={showLoading} />
|
||||
}
|
||||
|
||||
export function AgentEventAnnotations({ message }: { message: Message }) {
|
||||
@@ -90,12 +88,11 @@ export function SourceAnnotations({ message }: { message: Message }) {
|
||||
|
||||
export function SuggestedQuestionsAnnotations({
|
||||
message,
|
||||
isLast,
|
||||
append,
|
||||
}: {
|
||||
message: Message
|
||||
isLast: boolean
|
||||
append: ChatHandler['append']
|
||||
}) {
|
||||
const { append } = useChatUI()
|
||||
const annotations = message.annotations as MessageAnnotation[] | undefined
|
||||
const suggestedQuestionsData =
|
||||
annotations && annotations.length > 0
|
||||
@@ -104,12 +101,8 @@ export function SuggestedQuestionsAnnotations({
|
||||
MessageAnnotationType.SUGGESTED_QUESTIONS
|
||||
)
|
||||
: null
|
||||
if (!suggestedQuestionsData) return null
|
||||
return suggestedQuestionsData[0] ? (
|
||||
<SuggestedQuestions
|
||||
questions={suggestedQuestionsData[0]}
|
||||
append={append}
|
||||
isLastMessage={isLast}
|
||||
/>
|
||||
) : null
|
||||
if (!suggestedQuestionsData?.[0]) return null
|
||||
return (
|
||||
<SuggestedQuestions questions={suggestedQuestionsData[0]} append={append} />
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,12 +13,14 @@ import {
|
||||
SourceAnnotations,
|
||||
SuggestedQuestionsAnnotations,
|
||||
} from './chat-annotations'
|
||||
import { Message } from './chat.interface'
|
||||
import { ChatHandler, Message } from './chat.interface'
|
||||
|
||||
interface ChatMessageProps extends React.PropsWithChildren {
|
||||
message: Message
|
||||
isLast: boolean
|
||||
className?: string
|
||||
isLoading?: boolean
|
||||
append?: ChatHandler['append']
|
||||
}
|
||||
|
||||
interface ChatMessageAvatarProps extends React.PropsWithChildren {
|
||||
@@ -53,6 +55,8 @@ type ContentDisplayConfig = {
|
||||
interface ChatMessageContentProps extends React.PropsWithChildren {
|
||||
className?: string
|
||||
content?: ContentDisplayConfig[]
|
||||
isLoading?: boolean
|
||||
append?: ChatHandler['append']
|
||||
}
|
||||
|
||||
interface ChatMessageActionsProps extends React.PropsWithChildren {
|
||||
@@ -79,7 +83,7 @@ function ChatMessage(props: ChatMessageProps) {
|
||||
const children = props.children ?? (
|
||||
<>
|
||||
<ChatMessageAvatar />
|
||||
<ChatMessageContent />
|
||||
<ChatMessageContent isLoading={props.isLoading} append={props.append} />
|
||||
<ChatMessageActions />
|
||||
</>
|
||||
)
|
||||
@@ -123,7 +127,10 @@ function ChatMessageContent(props: ChatMessageContentProps) {
|
||||
[key in ContentPosition]?: React.ReactNode | null
|
||||
} = {
|
||||
[ContentPosition.CHAT_EVENTS]: (
|
||||
<EventAnnotations message={message} isLast={isLast} />
|
||||
<EventAnnotations
|
||||
message={message}
|
||||
showLoading={(isLast && props.isLoading) ?? false}
|
||||
/>
|
||||
),
|
||||
[ContentPosition.CHAT_AGENT_EVENTS]: (
|
||||
<AgentEventAnnotations message={message} />
|
||||
@@ -141,9 +148,16 @@ function ChatMessageContent(props: ChatMessageContentProps) {
|
||||
<DocumentFileAnnotations message={message} />
|
||||
),
|
||||
[ContentPosition.CHAT_SOURCES]: <SourceAnnotations message={message} />,
|
||||
[ContentPosition.SUGGESTED_QUESTIONS]: (
|
||||
<SuggestedQuestionsAnnotations message={message} isLast={isLast} />
|
||||
),
|
||||
...(isLast &&
|
||||
props.append && {
|
||||
// show suggested questions only on the last message
|
||||
[ContentPosition.SUGGESTED_QUESTIONS]: (
|
||||
<SuggestedQuestionsAnnotations
|
||||
message={message}
|
||||
append={props.append}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
}
|
||||
|
||||
// Override the default display map with the custom content
|
||||
@@ -155,7 +169,14 @@ function ChatMessageContent(props: ChatMessageContentProps) {
|
||||
position: parseInt(position),
|
||||
component,
|
||||
}))
|
||||
}, [annotations, isLast, message, props.content])
|
||||
}, [
|
||||
annotations,
|
||||
isLast,
|
||||
message,
|
||||
props.append,
|
||||
props.content,
|
||||
props.isLoading,
|
||||
])
|
||||
|
||||
const children = props.children ?? (
|
||||
<>
|
||||
|
||||
@@ -84,7 +84,7 @@ function ChatMessages(props: ChatMessagesProps) {
|
||||
|
||||
function ChatMessagesList(props: ChatMessagesListProps) {
|
||||
const scrollableChatContainerRef = useRef<HTMLDivElement>(null)
|
||||
const { messages } = useChatUI()
|
||||
const { messages, isLoading, append } = useChatUI()
|
||||
const { lastMessage, messageLength } = useChatMessages()
|
||||
|
||||
const scrollToBottom = () => {
|
||||
@@ -106,6 +106,8 @@ function ChatMessagesList(props: ChatMessagesListProps) {
|
||||
key={index}
|
||||
message={message}
|
||||
isLast={index === messageLength - 1}
|
||||
isLoading={isLoading}
|
||||
append={append}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
|
||||
@@ -10,16 +10,13 @@ import { EventData } from '../chat/annotation'
|
||||
|
||||
export function ChatEvents({
|
||||
data,
|
||||
isLast,
|
||||
isLoading,
|
||||
showLoading,
|
||||
}: {
|
||||
data: EventData[]
|
||||
isLast: boolean
|
||||
isLoading: boolean
|
||||
showLoading: boolean
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false)
|
||||
|
||||
const showLoading = isLast && isLoading
|
||||
const buttonLabel = isOpen ? 'Hide events' : 'Show events'
|
||||
|
||||
const EventIcon = isOpen ? (
|
||||
|
||||
@@ -4,16 +4,13 @@ import { ChatHandler } from '../chat/chat.interface'
|
||||
export function SuggestedQuestions({
|
||||
questions,
|
||||
append,
|
||||
isLastMessage,
|
||||
}: {
|
||||
questions: SuggestedQuestionsData
|
||||
append?: Pick<ChatHandler, 'append'>['append']
|
||||
isLastMessage: boolean
|
||||
append: ChatHandler['append']
|
||||
}) {
|
||||
const showQuestions = isLastMessage && questions.length > 0
|
||||
const showQuestions = questions.length > 0
|
||||
return (
|
||||
showQuestions &&
|
||||
append !== undefined && (
|
||||
showQuestions && (
|
||||
<div className="flex flex-col space-y-2">
|
||||
{questions.map((question, index) => (
|
||||
<a
|
||||
|
||||
Reference in New Issue
Block a user