Skip to content

Commit

Permalink
feat: on reaction callback
Browse files Browse the repository at this point in the history
  • Loading branch information
HuberTRoy committed Jan 3, 2025
1 parent c8c0548 commit b509f05
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 7 deletions.
9 changes: 9 additions & 0 deletions components/common/chatUi/chatUi.less
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,15 @@
}
}
}

&-reaction {
padding: 4px;
padding-left: 0;
display: flex;
align-items: center;
gap: 10px;
cursor: pointer;
}
}

&__assistant {
Expand Down
95 changes: 88 additions & 7 deletions components/common/chatUi/chatUi.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ import { v4 as uuidv4 } from 'uuid';
import { cloneDeep, isString } from 'lodash-es';
import Address from '../address';
import Markdown from '../markdown/Markdown';
import { FaRegThumbsUp, FaThumbsUp, FaRegThumbsDown, FaThumbsDown } from 'react-icons/fa';
import './chatUi.less';
import { chatWithStream, ConversationProperty, Message } from 'components/utilities/chatWithStream';
import { chatWithStream, ConversationProperty, Message, ResponseChunk } from 'components/utilities/chatWithStream';

const indexerName: { [key in string]: string } = {
'0xd0af1919af890cfdd8d12be5cf1b1421224fc29a': 'Mainnet Operator',
Expand All @@ -45,6 +46,7 @@ export interface ChatBoxProps {
model?: string;
onSendMessage?: (message: string) => void;
onChatboxOpen?: () => void;
onReaction?: (reaction: 'like' | 'dislike' | 'none', message: Message, userQuestion: Message) => void;
}

export interface ConversationItemProps {
Expand Down Expand Up @@ -98,10 +100,18 @@ export const ConversationItem: FC<ConversationItemProps> = ({ property, active,

export const ConversationMessage = forwardRef<
{ scrollToBottom: () => void },
{ property: ConversationProperty; answerStatus: ChatBotAnswerStatus; version?: 'chat' | 'chatbox' }
>(({ property, answerStatus, version = 'chat' }, ref) => {
{
property: ConversationProperty;
answerStatus: ChatBotAnswerStatus;
version?: 'chat' | 'chatbox';
onReaction?: (reaction: 'like' | 'dislike' | 'none', message: Message, userQuestion: Message) => void;
}
>(({ property, answerStatus, version = 'chat', onReaction }, ref) => {
const bem = useBem(version === 'chat' ? 'subql-chat-conversation-message' : 'subql-chatbox-conversation-message');
const outerRef = useRef<HTMLDivElement>(null);
const [reactionState, setReactionState] = useState<{
[key in string]: { status: 'like' | 'dislike' | 'none'; message: Message };
}>({});
useImperativeHandle(ref, () => ({
scrollToBottom: (onlyWhenReachBottom = false) => {
if (onlyWhenReachBottom && outerRef.current) {
Expand Down Expand Up @@ -159,6 +169,66 @@ export const ConversationMessage = forwardRef<
{/* TODO: support array */}
<div className={clsx(bem('item-span'))}>
{isString(message.content) ? <Markdown.Preview>{message.content}</Markdown.Preview> : ''}
{message.type !== 'welcome' && message.role === 'assistant' && message.content && (
<div className={clsx(bem('item-reaction'))}>
{(reactionState[message.id || '0']?.status === 'none' || !reactionState[message.id || '0']) && (
<FaRegThumbsUp
onClick={() => {
setReactionState({
...reactionState,
[message.id || '0']: {
status: 'like',
message,
},
});
onReaction?.('like', message, property.messages[index - 1]);
}}
></FaRegThumbsUp>
)}
{reactionState[message.id || '0']?.status === 'like' && (
<FaThumbsUp
// onClick={() => {
// setReactionState({
// ...reactionState,
// [message.id || '0']: {
// status: 'none',
// message,
// },
// });
// onReaction?.('none', message);
// }}
></FaThumbsUp>
)}
{reactionState[message.id || '0']?.status === 'dislike' && (
<FaThumbsDown
// onClick={() => {
// setReactionState({
// ...reactionState,
// [message.id || '0']: {
// status: 'none',
// message,
// },
// });
// onReaction?.('none', message);
// }}
></FaThumbsDown>
)}
{(reactionState[message.id || '0']?.status === 'none' || !reactionState[message.id || '0']) && (
<FaRegThumbsDown
onClick={() => {
setReactionState({
...reactionState,
[message.id || '0']: {
status: 'dislike',
message,
},
});
onReaction?.('dislike', message, property.messages[index - 1]);
}}
></FaRegThumbsDown>
)}
</div>
)}
</div>
</div>
);
Expand Down Expand Up @@ -558,7 +628,7 @@ const ChatBoxIcon: FC<{ className?: string }> = ({ className }) => (

// maybe split to other file.
export const ChatBox: FC<ChatBoxProps> = (props) => {
const { chatUrl, prompt = '', model, onSendMessage, onChatboxOpen } = props;
const { chatUrl, prompt = '', model, onSendMessage, onChatboxOpen, onReaction } = props;
const [popoverOpen, setPopoverOpen] = useState(false);
const bem = useBem('subql-chatbox');
const [currentInput, setCurrentInput] = useState('');
Expand Down Expand Up @@ -617,6 +687,8 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {
const robotAnswer: Message = {
role: 'assistant' as const,
content: '',
id: '0',
conversation_id: '0',
};

setCurrentInput('');
Expand Down Expand Up @@ -651,8 +723,10 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {
if (invalidJson) {
try {
invalidJson += part;
const parsed: { choices: { delta: { content: string } }[] } = JSON.parse(invalidJson);
const parsed: ResponseChunk = JSON.parse(invalidJson);
robotAnswer.content += parsed?.choices?.[0]?.delta?.content;
robotAnswer.id = parsed.id !== '0' ? parsed.id : '0';
robotAnswer.conversation_id = parsed.conversation_id !== '0' ? parsed.conversation_id : '0';

await pushNewMsgToChat(newChat, robotAnswer, curChat);
console.warn(messageRef);
Expand All @@ -668,8 +742,10 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {

if (partWithHandle) {
try {
const parsed: { choices: { delta: { content: string } }[] } = JSON.parse(partWithHandle);
const parsed: ResponseChunk = JSON.parse(partWithHandle);
robotAnswer.content += parsed?.choices?.[0]?.delta?.content;
robotAnswer.id = parsed.id !== '0' ? parsed.id : '0';
robotAnswer.conversation_id = parsed.conversation_id !== '0' ? parsed.conversation_id : '0';

await pushNewMsgToChat(newChat, robotAnswer, curChat);
messageRef.current?.scrollToBottom(true);
Expand All @@ -682,8 +758,10 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {

if (invalidJson) {
try {
const parsed: { choices: { delta: { content: string } }[] } = JSON.parse(invalidJson);
const parsed: ResponseChunk = JSON.parse(invalidJson);
robotAnswer.content += parsed?.choices?.[0]?.delta?.content;
robotAnswer.id = parsed.id !== '0' ? parsed.id : '0';
robotAnswer.conversation_id = parsed.conversation_id !== '0' ? parsed.conversation_id : '0';

await pushNewMsgToChat(newChat, robotAnswer, curChat);
messageRef.current?.scrollToBottom(true);
Expand All @@ -696,7 +774,9 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {
robotAnswer.content = 'Sorry, The Server is not available now.';
await pushNewMsgToChat(newChat, robotAnswer, curChat);
setAnswerStatus(ChatBotAnswerStatus.Error);
return;
}
// onResponse?.(robotAnswer);
inputRef.current?.focus();
setAnswerStatus(ChatBotAnswerStatus.Success);
} catch (e) {
Expand Down Expand Up @@ -738,6 +818,7 @@ export const ChatBox: FC<ChatBoxProps> = (props) => {
answerStatus={answerStatus}
version="chatbox"
ref={messageRef}
onReaction={onReaction}
></ConversationMessage>
</div>
<div className={clsx(bem('content-bottom'))}>
Expand Down
8 changes: 8 additions & 0 deletions components/utilities/chatWithStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,14 @@ export interface Message {
role: AiMessageRole;
content: string | Content[];
type?: 'welcome'; // welcome should filter before send
id?: string;
conversation_id?: string;
}

export interface ResponseChunk {
id?: string;
conversation_id?: string;
choices: { delta: { content: string } }[];
}

export const chatWithStream = async (url: string, body: { messages: Message[]; model?: string }) => {
Expand Down

0 comments on commit b509f05

Please sign in to comment.