Skip to content

Commit

Permalink
Chat: Add Angular AI And Chatbot Integration Demo (#28519)
Browse files Browse the repository at this point in the history
Co-authored-by: marker dao ® <[email protected]>
  • Loading branch information
Zedwag and marker dao ® authored Dec 10, 2024
1 parent 733a755 commit bf4ce28
Show file tree
Hide file tree
Showing 5 changed files with 459 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
.demo-container {
display: flex;
justify-content: center;
}

::ng-deep .dx-chat {
max-width: 900px;
}

::ng-deep .dx-chat-messagelist-empty-image {
display: none;
}

::ng-deep .dx-chat-messagelist-empty-message {
font-size: var(--dx-font-size-heading-5);
}

::ng-deep .dx-chat-messagebubble-content,
::ng-deep .dx-chat-messagebubble-text {
display: flex;
flex-direction: column;
}

::ng-deep .dx-bubble-button-container {
display: none;
}

::ng-deep .dx-button {
display: inline-block;
color: var(--dx-color-icon);
}

::ng-deep .dx-chat-messagegroup-alignment-start:last-child .dx-chat-messagebubble:last-child .dx-bubble-button-container {
display: flex;
gap: 4px;
margin-top: 8px;
}

::ng-deep .dx-template-wrapper > div > p:first-child {
margin-top: 0;
}

::ng-deep .dx-template-wrapper > div > p:last-child {
margin-bottom: 0;
}

::ng-deep .dx-chat-messagebubble-content ol,
::ng-deep .dx-chat-messagebubble-content ul {
white-space: normal;
}

::ng-deep .dx-chat-messagebubble-content h1,
::ng-deep .dx-chat-messagebubble-content h2,
::ng-deep .dx-chat-messagebubble-content h3,
::ng-deep .dx-chat-messagebubble-content h4,
::ng-deep .dx-chat-messagebubble-content h5,
::ng-deep .dx-chat-messagebubble-content h6 {
font-size: revert;
font-weight: revert;
}

::ng-deep .dx-chat-disabled .dx-chat-messagebox {
opacity: 0.5;
pointer-events: none;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<div class="demo-container">
<dx-chat
[class.dx-chat-disabled]="isDisabled"
[dataSource]="dataSource"
[reloadOnChange]="false"
[showAvatar]="false"
[showDayHeaders]="false"
[user]="user"
height="710"
[typingUsers]="typingUsers$ | async"
[alerts]="alerts$ | async"
(onMessageEntered)="onMessageEntered($event)"
messageTemplate="messageTemplate"
>
<div *dxTemplate="let data of 'messageTemplate'">
<ng-container *ngIf="data.message.text === regenerationText">
<span>{{ regenerationText }}</span>
</ng-container>
<ng-container *ngIf="data.message.text !== regenerationText">
<div
class="dx-chat-messagebubble-text"
[innerHTML]="convertToHtml(data.message)"
>
</div>
<div class="dx-bubble-button-container">
<dx-button
[icon]="copyButtonIcon"
stylingMode="text"
hint="Copy"
(onClick)="onCopyButtonClick(data.message)"
>
</dx-button>
<dx-button
icon="refresh"
stylingMode="text"
hint="Regenerate"
(onClick)="onRegenerateButtonClick()"
>
</dx-button>
</div>
</ng-container>
</div>
</dx-chat>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import { NgModule, Component, enableProdMode } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { DxChatModule } from 'devextreme-angular';
import { DxButtonModule } from 'devextreme-angular';
import {
User,
Alert,
Message,
MessageEnteredEvent
} from 'devextreme/ui/chat';
import { Observable } from 'rxjs';
import { AppService } from './app.service';
import { loadMessages } from 'devextreme/localization';
import { DataSource } from 'devextreme/common/data';

if (!/localhost/.test(document.location.host)) {
enableProdMode();
}

let modulePrefix = '';
// @ts-ignore
if (window && window.config.packageConfigPaths) {
modulePrefix = '/app';
}

@Component({
selector: 'demo-app',
templateUrl: `.${modulePrefix}/app.component.html`,
styleUrls: [`.${modulePrefix}/app.component.css`],
})
export class AppComponent {
dataSource: DataSource;

user: User;

typingUsers$: Observable<User[]>;

alerts$: Observable<Alert[]>;

regenerationText: string;

copyButtonIcon: string;

isDisabled: boolean;

constructor(private readonly appService: AppService) {
loadMessages(this.appService.getDictionary());

this.dataSource = this.appService.dataSource;
this.user = this.appService.user;
this.alerts$ = this.appService.alerts$;
this.typingUsers$ = this.appService.typingUsers$;
this.regenerationText = this.appService.REGENERATION_TEXT;
this.copyButtonIcon = 'copy';
this.isDisabled = false;
}

convertToHtml(message: Message): string {
return this.appService.convertToHtml(message.text);
}

toggleDisabledState(disabled: boolean, event = undefined) {
this.isDisabled = disabled;

if (disabled) {
event?.target.blur();
} else {
event?.target.focus();
}
};

async onMessageEntered(e: MessageEnteredEvent) {
if (!this.appService.alerts.length) {
this.toggleDisabledState(true, e.event);
}

try {
await this.appService.onMessageEntered(e);
} finally {
this.toggleDisabledState(false, e.event);
}
}

onCopyButtonClick(message: Message) {
navigator.clipboard?.writeText(message.text);

this.copyButtonIcon = 'check';

setTimeout(() => {
this.copyButtonIcon = 'copy';
}, 2500);
}

async onRegenerateButtonClick() {
this.appService.updateLastMessage();
this.toggleDisabledState(true);

try {
await this.appService.regenerate();
} finally {
this.toggleDisabledState(false);
}
}
}

@NgModule({
imports: [
BrowserModule,
DxChatModule,
DxButtonModule,
],
declarations: [AppComponent],
bootstrap: [AppComponent],
providers: [AppService],
})
export class AppModule { }

platformBrowserDynamic().bootstrapModule(AppModule);
Loading

0 comments on commit bf4ce28

Please sign in to comment.