Moved from spinner to inline thinking indicator

This commit is contained in:
Chris Kent 2024-02-08 13:06:17 -05:00
parent 9c8bfe0c9b
commit 4ff53d4896
5 changed files with 109 additions and 15 deletions

View File

@ -3,10 +3,12 @@ import { Icon } from '@fluentui/react';
import * as React from "react";
import styles from "./ChatStreaming.module.scss";
import MarkdownContent from "./MarkdownContent";
import ThinkingIndicator from "./ThinkingIndicator";
export interface IAssistantResponseProps {
message: string;
disableMarkdown?: boolean;
thinking?: boolean;
}
export default class AssistantResponse extends React.Component<
@ -20,10 +22,13 @@ export default class AssistantResponse extends React.Component<
<Icon iconName="Robot" />
</div>
<div className={styles.messageBox}>
{this.props.disableMarkdown &&
{this.props.thinking && this.props.message.length === 0 &&
<ThinkingIndicator />
}
{this.props.disableMarkdown && this.props.message.length > 0 &&
<p className={styles.message}>{this.props.message}</p>
}
{!this.props.disableMarkdown &&
{!this.props.disableMarkdown && this.props.message.length > 0 &&
<MarkdownContent className={styles.message}>{this.props.message}</MarkdownContent>
}
<div className={styles.beak}/>

View File

@ -148,4 +148,76 @@
padding: 8px;
border-radius: 4px;
}
}
$dotSize: 8px;
$jumpHeight: 14px;
.thinkingIndicator {
padding-top: 6px;
.allDots {
margin-top: $jumpHeight;
display: flex;
gap: calc($dotSize / 2);
.dot {
position: relative;
width: $dotSize;
height: $dotSize;
border-radius: 50%;
display: inline-block;
animation: bouncedelay 2.0s infinite cubic-bezier(.62, .28, .23, .99) both;
}
.dot1 {
animation-delay: -.16s;
}
.dot2 {
animation-delay: -.08s;
}
.dot3 {
color: inherit;
}
}
}
@keyframes bouncedelay {
0% {
bottom: 0;
background-color: "[theme: themePrimary, default: #0078d4]";
}
16.66% {
bottom: $jumpHeight;
background-color: "[theme: themeDark, default: #005a9e]";
}
33.33% {
bottom: 0px;
background-color: "[theme: themeDark, default: #005a9e]";
}
50% {
bottom: $jumpHeight;
background-color: "[theme: themeLight, default: #c7e0f4]";
}
66.66% {
bottom: 0px;
background-color: "[theme: themeLight, default: #c7e0f4]";
}
83.33% {
bottom: $jumpHeight;
background-color: "[theme: themePrimary, default: #0078d4]";
}
100% {
bottom: 0;
background-color: "[theme: themePrimary, default: #0078d4]";
}
}

View File

@ -5,7 +5,7 @@ import { IChatStreamingState } from './IChatStreamingState';
import { cloneDeep } from '@microsoft/sp-lodash-subset';
import { fetchEventSource } from '@microsoft/fetch-event-source';
import CompletionsRequestBuilder from '../models/CompletionsRequestBuilder';
import { Spinner, SpinnerSize, Stack, css } from '@fluentui/react';
import { Stack, css } from '@fluentui/react';
import MessagesList from './MessagesList';
import UserMessage from './UserMessage';
import { IChatMessage } from '../models/IChatMessage';
@ -38,18 +38,8 @@ export default class ChatStreaming extends React.Component<IChatStreamingProps,
const content = this._validateWebPartProperties() ? (
<Stack className={css(styles.chatStreaming, this.props.hasTeamsContext && styles.teams)}>
<Stack.Item grow className={styles.messagesContainer}>
<MessagesList messages={this.state.sessionMessages} disableMarkdown={this.state.disableMarkdown} />
<MessagesList messages={this.state.sessionMessages} disableMarkdown={this.state.disableMarkdown} thinking={this.state.thinking} />
</Stack.Item>
{this.state.thinking && (
<Stack.Item>
<Spinner
size={SpinnerSize.large}
label="Wait till our super cool AI system answers your question..."
ariaLive="assertive"
labelPosition="right"
/>
</Stack.Item>
)}
<Stack.Item>
<UserMessage
textFieldValue={this.state.userQuery}
@ -79,6 +69,10 @@ export default class ChatStreaming extends React.Component<IChatStreamingProps,
role: 'user', text: this.state.userQuery
});
this.state.sessionMessages.push({
role: 'assistant', text: ''
});
await this._chatAsStream();
this.setState({

View File

@ -9,6 +9,7 @@ import { ScrollablePane, ScrollbarVisibility } from '@fluentui/react';
export interface IMessagesListProps {
messages: IChatMessage[];
disableMarkdown?: boolean;
thinking?: boolean;
}
export default class MessagesList extends React.Component<IMessagesListProps, {}> {
@ -28,7 +29,7 @@ export default class MessagesList extends React.Component<IMessagesListProps, {}
if (m.role === 'user') {
return <UserQuestion key={i} message={m.text} />
}
return <AssistantResponse key={i} message={m.text} disableMarkdown={this.props.disableMarkdown} />
return <AssistantResponse key={i} message={m.text} disableMarkdown={this.props.disableMarkdown} thinking={this.props.thinking} />
});
return (

View File

@ -0,0 +1,22 @@
import * as React from "react";
import styles from "./ChatStreaming.module.scss";
import { css } from "@fluentui/react";
export interface IThinkingIndicatorProps {}
export default class ThinkingIndicator extends React.Component<
IThinkingIndicatorProps,
{}
> {
public render(): React.ReactElement<IThinkingIndicatorProps> {
return (
<div className={styles.thinkingIndicator}>
<div className={styles.allDots}>
<div className={css(styles.dot, styles.dot1)} />
<div className={css(styles.dot, styles.dot2)} />
<div className={css(styles.dot, styles.dot3)} />
</div>
</div>
);
}
}