ui: add duration for msgs
This commit is contained in:
parent
f1e9546429
commit
3d3079fece
7 changed files with 60 additions and 13 deletions
|
|
@ -34,7 +34,7 @@ export default class KaiService extends AiService {
|
|||
return true;
|
||||
}
|
||||
|
||||
getKaiChat = async (projectId: string, userId: string, threadId: string): Promise<{ role: string, content: string, message_id: any }[]> => {
|
||||
getKaiChat = async (projectId: string, userId: string, threadId: string): Promise<{ role: string, content: string, message_id: any, duration?: number }[]> => {
|
||||
const jwt = window.env.KAI_TESTING // this.client.getJwt()
|
||||
const r = await fetch(`http://localhost:8700/kai/${projectId}/chats/${threadId}?user_id=${userId}`, {
|
||||
method: 'GET',
|
||||
|
|
|
|||
|
|
@ -99,6 +99,7 @@ class KaiStore {
|
|||
text: m.content,
|
||||
isUser: isUser,
|
||||
messageId: m.message_id,
|
||||
duration: m.duration,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
|
@ -121,7 +122,12 @@ class KaiStore {
|
|||
msgCallback: (msg) => {
|
||||
if ('state' in msg) {
|
||||
if (msg.state === 'running') {
|
||||
this.setProcessingStage({ content: 'Processing your request...', stage: 'chart', messageId: Date.now().toPrecision() })
|
||||
this.setProcessingStage({
|
||||
content: 'Processing your request...',
|
||||
stage: 'chart',
|
||||
messageId: Date.now().toPrecision(),
|
||||
duration: msg.start_time ? Date.now() - msg.start_time : 0
|
||||
})
|
||||
} else {
|
||||
this.setProcessingStage(null)
|
||||
}
|
||||
|
|
@ -140,6 +146,7 @@ class KaiStore {
|
|||
text: msg.content,
|
||||
isUser: false,
|
||||
messageId: msg.messageId,
|
||||
duration: msg.duration
|
||||
}
|
||||
this.addMessage(msgObj);
|
||||
this.setProcessingStage(null);
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export class ChatManager {
|
|||
msgCallback,
|
||||
titleCallback,
|
||||
}: {
|
||||
msgCallback: (msg: BotChunk | { state: string, type: 'state' }) => void;
|
||||
msgCallback: (msg: BotChunk | { state: string, type: 'state', start_time?: number }) => void;
|
||||
titleCallback: (title: string) => void;
|
||||
}) => {
|
||||
this.socket.on('chunk', (msg: BotChunk) => {
|
||||
|
|
@ -63,8 +63,8 @@ export class ChatManager {
|
|||
console.log('Received title:', msg);
|
||||
titleCallback(msg.content);
|
||||
});
|
||||
this.socket.on('state', (state: { message: 'idle' | 'running' }) => {
|
||||
msgCallback({ state: state.message, type: 'state' })
|
||||
this.socket.on('state', (state: { message: 'idle' | 'running', start_time: number }) => {
|
||||
msgCallback({ state: state.message, type: 'state', start_time: state.start_time })
|
||||
})
|
||||
};
|
||||
|
||||
|
|
@ -77,11 +77,13 @@ export interface BotChunk {
|
|||
stage: 'start' | 'chart' | 'final' | 'title';
|
||||
content: string;
|
||||
messageId: string;
|
||||
duration?: number;
|
||||
}
|
||||
export interface Message {
|
||||
text: string;
|
||||
isUser: boolean;
|
||||
messageId: string;
|
||||
duration?: number;
|
||||
}
|
||||
|
||||
export interface SentMessage extends Message {
|
||||
|
|
|
|||
|
|
@ -72,10 +72,11 @@ function ChatLog({
|
|||
userName={userLetter}
|
||||
messageId={msg.messageId}
|
||||
isLast={index === lastHumanMsgInd}
|
||||
duration={msg.duration}
|
||||
/>
|
||||
))}
|
||||
{processingStage ? (
|
||||
<ChatNotice content={processingStage.content} />
|
||||
<ChatNotice content={processingStage.content} duration={processingStage.duration} />
|
||||
) : null}
|
||||
</div>
|
||||
<div className={'sticky bottom-0 pt-6 w-2/3'}>
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import { Icon, CopyButton } from 'UI';
|
|||
import cn from 'classnames';
|
||||
import Markdown from 'react-markdown';
|
||||
import remarkGfm from 'remark-gfm'
|
||||
import { Loader, ThumbsUp, ThumbsDown, ListRestart, FileDown } from 'lucide-react';
|
||||
import { Loader, ThumbsUp, ThumbsDown, ListRestart, FileDown, Clock } from 'lucide-react';
|
||||
import { Button, Tooltip } from 'antd';
|
||||
import { kaiStore } from '../KaiStore';
|
||||
import { toast } from 'react-toastify';
|
||||
import { durationFormatted } from 'App/date';
|
||||
|
||||
export function ChatMsg({
|
||||
text,
|
||||
|
|
@ -14,12 +15,14 @@ export function ChatMsg({
|
|||
userName,
|
||||
messageId,
|
||||
isLast,
|
||||
duration,
|
||||
}: {
|
||||
text: string;
|
||||
isUser: boolean;
|
||||
messageId: string;
|
||||
userName?: string;
|
||||
isLast?: boolean;
|
||||
duration?: number;
|
||||
}) {
|
||||
const [isProcessing, setIsProcessing] = React.useState(false);
|
||||
const bodyRef = React.useRef<HTMLDivElement>(null);
|
||||
|
|
@ -78,7 +81,7 @@ export function ChatMsg({
|
|||
<Icon name={'kai_colored'} size={18} />
|
||||
</div>
|
||||
)}
|
||||
<div className={'mt-1'}>
|
||||
<div className={'mt-1 flex flex-col'}>
|
||||
<div className='markdown-body' ref={bodyRef}>
|
||||
<Markdown remarkPlugins={[remarkGfm]}>{text}</Markdown>
|
||||
</div>
|
||||
|
|
@ -96,6 +99,10 @@ export function ChatMsg({
|
|||
) : null
|
||||
) : (
|
||||
<div className={'flex items-center gap-2'}>
|
||||
{duration ? (
|
||||
<MsgDuration duration={duration} />
|
||||
) : null}
|
||||
<div className='ml-auto' />
|
||||
<IconButton tooltip="Like this answer" onClick={() => onFeedback('like', messageId)}>
|
||||
<ThumbsUp size={16} />
|
||||
</IconButton>
|
||||
|
|
@ -131,13 +138,36 @@ function IconButton({
|
|||
);
|
||||
}
|
||||
|
||||
export function ChatNotice({ content }: { content: string }) {
|
||||
export function ChatNotice({ content, duration }: { content: string, duration?: number }) {
|
||||
const startTime = React.useRef(duration ? Date.now() - duration : Date.now());
|
||||
const [activeDuration, setDuration] = React.useState(duration ?? 0);
|
||||
|
||||
React.useEffect(() => {
|
||||
const interval = setInterval(() => {
|
||||
setDuration(Math.round((Date.now() - startTime.current)));
|
||||
}, 250);
|
||||
return () => clearInterval(interval);
|
||||
}, []);
|
||||
return (
|
||||
<div className="flex items-center gap-2 p-2 rounded-lg bg-gray-lightest border-gray-light w-fit">
|
||||
<div className={'animate-spin'}>
|
||||
<Loader size={14} />
|
||||
<div className='flex flex-col gap-1 items-start p-2 rounded-lg bg-gray-lightest border-gray-light w-fit '>
|
||||
<div className="flex gap-2 items-start">
|
||||
<div className={'animate-spin mt-1'}>
|
||||
<Loader size={14} />
|
||||
</div>
|
||||
<div className={'animate-pulse'}>{content}</div>
|
||||
</div>
|
||||
<div className={'animate-pulse text-disabled-text'}>{content}</div>
|
||||
<MsgDuration duration={activeDuration} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function MsgDuration({ duration }: { duration: number }) {
|
||||
return (
|
||||
<div className="text-disabled-text text-sm flex items-center gap-1">
|
||||
<Clock size={14} />
|
||||
<span className="leading-none">
|
||||
{durationFormatted(duration)}
|
||||
</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@
|
|||
.fill-glassLavander { fill: var(--color-glassLavander) }
|
||||
.fill-blueLight { fill: var(--color-blueLight) }
|
||||
.fill-offWhite { fill: var(--color-offWhite) }
|
||||
.fill-disabled-text { fill: var(--color-disabled-text) }
|
||||
.fill-figmaColors-accent-secondary { fill: var(--color-figmaColors-accent-secondary) }
|
||||
.fill-figmaColors-main { fill: var(--color-figmaColors-main) }
|
||||
.fill-figmaColors-primary-outlined-hover-background { fill: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
@ -112,6 +113,7 @@
|
|||
.hover-fill-glassLavander:hover svg { fill: var(--color-glassLavander) }
|
||||
.hover-fill-blueLight:hover svg { fill: var(--color-blueLight) }
|
||||
.hover-fill-offWhite:hover svg { fill: var(--color-offWhite) }
|
||||
.hover-fill-disabled-text:hover svg { fill: var(--color-disabled-text) }
|
||||
.hover-fill-figmaColors-accent-secondary:hover svg { fill: var(--color-figmaColors-accent-secondary) }
|
||||
.hover-fill-figmaColors-main:hover svg { fill: var(--color-figmaColors-main) }
|
||||
.hover-fill-figmaColors-primary-outlined-hover-background:hover svg { fill: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
@ -174,6 +176,7 @@
|
|||
.color-glassLavander { color: var(--color-glassLavander) }
|
||||
.color-blueLight { color: var(--color-blueLight) }
|
||||
.color-offWhite { color: var(--color-offWhite) }
|
||||
.color-disabled-text { color: var(--color-disabled-text) }
|
||||
.color-figmaColors-accent-secondary { color: var(--color-figmaColors-accent-secondary) }
|
||||
.color-figmaColors-main { color: var(--color-figmaColors-main) }
|
||||
.color-figmaColors-primary-outlined-hover-background { color: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
@ -236,6 +239,7 @@
|
|||
.hover-glassLavander:hover { color: var(--color-glassLavander) }
|
||||
.hover-blueLight:hover { color: var(--color-blueLight) }
|
||||
.hover-offWhite:hover { color: var(--color-offWhite) }
|
||||
.hover-disabled-text:hover { color: var(--color-disabled-text) }
|
||||
.hover-figmaColors-accent-secondary:hover { color: var(--color-figmaColors-accent-secondary) }
|
||||
.hover-figmaColors-main:hover { color: var(--color-figmaColors-main) }
|
||||
.hover-figmaColors-primary-outlined-hover-background:hover { color: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
@ -298,6 +302,7 @@
|
|||
.border-glassLavander { border-color: var(--color-glassLavander) }
|
||||
.border-blueLight { border-color: var(--color-blueLight) }
|
||||
.border-offWhite { border-color: var(--color-offWhite) }
|
||||
.border-disabled-text { border-color: var(--color-disabled-text) }
|
||||
.border-figmaColors-accent-secondary { border-color: var(--color-figmaColors-accent-secondary) }
|
||||
.border-figmaColors-main { border-color: var(--color-figmaColors-main) }
|
||||
.border-figmaColors-primary-outlined-hover-background { border-color: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
@ -360,6 +365,7 @@
|
|||
.bg-glassLavander { background-color: var(--color-glassLavander) }
|
||||
.bg-blueLight { background-color: var(--color-blueLight) }
|
||||
.bg-offWhite { background-color: var(--color-offWhite) }
|
||||
.bg-disabled-text { background-color: var(--color-disabled-text) }
|
||||
.bg-figmaColors-accent-secondary { background-color: var(--color-figmaColors-accent-secondary) }
|
||||
.bg-figmaColors-main { background-color: var(--color-figmaColors-main) }
|
||||
.bg-figmaColors-primary-outlined-hover-background { background-color: var(--color-figmaColors-primary-outlined-hover-background) }
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ module.exports = {
|
|||
glassLavander: 'rgba(243, 241, 255, 0.5)',
|
||||
blueLight: 'rgba(235, 235, 255, 1)',
|
||||
offWhite: 'rgba(250, 250, 255, 1)',
|
||||
'disabled-text': 'rgba(0,0,0, 0.38)',
|
||||
|
||||
figmaColors: {
|
||||
'accent-secondary': 'rgba(62, 170, 175, 1)',
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue