Skip to content

Commit

Permalink
feat(spa): displaying the bot's reply as a streaming message
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastianmusial committed Mar 29, 2024
1 parent 399a1d2 commit 9252292
Show file tree
Hide file tree
Showing 5 changed files with 86 additions and 18 deletions.
33 changes: 26 additions & 7 deletions apps/spa/src/app/modules/+chat/shared/chat-gateway.service.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,41 @@
import { Injectable } from '@angular/core';
import { ChatEvents } from './chat.model';
import io from 'socket.io-client';
import { ChatCallDto } from '@boldare/openai-assistant';
import {
ChatCallDto,
TextCreatedPayload, TextDeltaPayload, TextDonePayload
} from '@boldare/openai-assistant';
import { Observable } from 'rxjs';
import { environment } from '../../../../environments/environment';

@Injectable({ providedIn: 'root' })
export class ChatGatewayService {
private socket = io(environment.websocketUrl);

sendMessage(payload: ChatCallDto): void {
watchEvent<T>(event: ChatEvents): Observable<T> {
return new Observable<T>(observer => {
this.socket.on(event, data => observer.next(data));
return () => this.socket.disconnect();
});
}

callStart(payload: ChatCallDto): void {
this.socket.emit(ChatEvents.CallStart, payload);
}

getMessages(): Observable<ChatCallDto> {
return new Observable<ChatCallDto>(observer => {
this.socket.on(ChatEvents.CallDone, data => observer.next(data));
return () => this.socket.disconnect();
});
callDone(): Observable<ChatCallDto> {
return this.watchEvent(ChatEvents.CallDone);
}

textCreated(): Observable<TextCreatedPayload> {
return this.watchEvent(ChatEvents.TextCreated);
}

textDelta(): Observable<TextDeltaPayload> {
return this.watchEvent(ChatEvents.TextDelta);
}

textDone(): Observable<TextDonePayload> {
return this.watchEvent(ChatEvents.TextDone);
}
}
6 changes: 3 additions & 3 deletions apps/spa/src/app/modules/+chat/shared/chat.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,12 @@ export interface ChatMessage {
export enum ChatEvents {
CallStart = 'callStart',
CallDone = 'callDone',
TextDone = 'textCreated',
TextCreated = 'textDelta',
TextDelta = 'textDone',
MessageCreated = 'messageCreated',
MessageDelta = 'messageDelta',
MessageDone = 'messageDone',
TextCreated = 'textCreated',
TextDelta = 'textDelta',
TextDone = 'textDone',
ImageFileDone = 'imageFileDone',
ToolCallCreated = 'toolCallCreated',
ToolCallDelta = 'toolCallDelta',
Expand Down
63 changes: 55 additions & 8 deletions apps/spa/src/app/modules/+chat/shared/chat.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,21 @@ export class ChatService {
) {
document.body.classList.add('ai-chat');

this.subscribeMessages();
this.setInitialValues();
this.watchMessages();
this.watchVisibility();
}

subscribeMessages(): void {
if (!environment.isStreamingEnabled) {
this.watchMessages();
} else {
this.watchTextCreated();
this.watchTextDelta();
this.watchTextDone();
}
}

isMessageInvisible(message: Message): boolean {
const metadata = message.metadata as Record<string, unknown>;
return metadata?.['status'] === ChatMessageStatus.Invisible;
Expand Down Expand Up @@ -86,11 +96,13 @@ export class ChatService {

refresh(): void {
this.isLoading$.next(true);
this.isTyping$.next(false);
this.messages$.next([]);
this.threadService.start().subscribe();
}

clear(): void {
this.isTyping$.next(false);
this.threadService.clear();
this.messages$.next([]);
}
Expand Down Expand Up @@ -119,21 +131,56 @@ export class ChatService {
const files = await this.chatFilesService.sendFiles();
this.addFileMessage(files);

this.chatGatewayService.sendMessage({
this.chatGatewayService.callStart({
content,
threadId: this.threadService.threadId$.value,
file_ids: files.map(file => file.id) || [],
});
}

watchTextCreated(): Subscription {
return this.chatGatewayService
.textCreated()
.subscribe((data) => {
this.isTyping$.next(false)
this.addMessage({ content: data.text.value, role: ChatRole.Assistant })
});
}

watchTextDelta(): Subscription {
return this.chatGatewayService
.textDelta()
.subscribe((data) => {
const length = this.messages$.value.length;
this.messages$.value[length - 1].content = data.text.value;
});
}

watchTextDone(): Subscription {
return this.chatGatewayService
.textDone()
.subscribe((data) => {
this.isTyping$.next(false);
this.messages$.next([
...this.messages$.value.slice(0, -1),
{
content: data.text.value,
role: ChatRole.Assistant,
},
]);
});
}

watchMessages(): Subscription {
return this.chatGatewayService.getMessages().subscribe(data => {
this.addMessage({
content: data.content,
role: ChatRole.Assistant,
return this.chatGatewayService
.callDone()
.subscribe(data => {
this.addMessage({
content: data.content,
role: ChatRole.Assistant,
});
this.isTyping$.next(false);
});
this.isTyping$.next(false);
});
}

sendAudio(file: Blob): void {
Expand Down
1 change: 1 addition & 0 deletions apps/spa/src/environments/environment.development.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const environment = {
isRefreshEnabled: true,
isConfigEnabled: true,
isAutoOpen: true,
isStreamingEnabled: true,
};
1 change: 1 addition & 0 deletions apps/spa/src/environments/environment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const environment = {
isRefreshEnabled: true,
isConfigEnabled: true,
isAutoOpen: true,
isStreamingEnabled: true,
};

0 comments on commit 9252292

Please sign in to comment.