diff --git a/src/app/components/chat/chat.component.html b/src/app/components/chat/chat.component.html index 7eb9b42a..c5f9ab90 100644 --- a/src/app/components/chat/chat.component.html +++ b/src/app/components/chat/chat.component.html @@ -348,7 +348,17 @@ }" > @if (message.isLoading) { - +
+ + +
} @if (message.attachments) {
diff --git a/src/app/components/chat/chat.component.scss b/src/app/components/chat/chat.component.scss index 163dee3b..278f82cd 100644 --- a/src/app/components/chat/chat.component.scss +++ b/src/app/components/chat/chat.component.scss @@ -85,11 +85,31 @@ background-color: #131314; } +.loading-container { + display: flex; + align-items: center; + width: 150px; + justify-content: space-between; +} + .loading-bar { width: 100px; margin: 15px; } +.stop-button { + width: 30px; + height: 30px; + background-color: #303030; + + .mat-icon { + font-size: 18px; + color: white; + margin-left: -20px; + margin-top: -10px; + } +} + .chat-messages { flex-grow: 1; overflow-y: auto; diff --git a/src/app/components/chat/chat.component.ts b/src/app/components/chat/chat.component.ts index e82008a0..064a8066 100644 --- a/src/app/components/chat/chat.component.ts +++ b/src/app/components/chat/chat.component.ts @@ -1389,6 +1389,10 @@ export class ChatComponent implements OnInit, AfterViewInit, OnDestroy { this.currentSessionState = session.state; } + stop() { + this.agentService.stopSse(); + } + onNewSessionClick() { this.createSession(); this.eventData.clear(); diff --git a/src/app/core/services/agent.service.ts b/src/app/core/services/agent.service.ts index 0d0791a7..2cf672af 100644 --- a/src/app/core/services/agent.service.ts +++ b/src/app/core/services/agent.service.ts @@ -31,6 +31,7 @@ export class AgentService { private _currentApp = new BehaviorSubject(''); currentApp = this._currentApp.asObservable(); private isLoading = new BehaviorSubject(false); + private abortController: AbortController | null = null; constructor( private http: HttpClient, @@ -49,9 +50,19 @@ export class AgentService { return this.isLoading; } + stopSse() { + if (this.abortController) { + this.abortController.abort(); + this.abortController = null; + } + } + runSse(req: AgentRunRequest) { const url = this.apiServerDomain + `/run_sse`; this.isLoading.next(true); + this.abortController = new AbortController(); + const signal = this.abortController.signal; + return new Observable((observer) => { const self = this; fetch(url, { @@ -61,6 +72,7 @@ export class AgentService { 'Accept': 'text/event-stream', }, body: JSON.stringify(req), + signal, }) .then((response) => { const reader = response.body?.getReader(); @@ -97,13 +109,20 @@ export class AgentService { }) .catch((err) => { self.zone.run(() => observer.error(err)); + this.isLoading.next(false); }); }; read(); }) .catch((err) => { - self.zone.run(() => observer.error(err)); + if (err.name === 'AbortError') { + // Fetch was aborted + this.isLoading.next(false); + observer.complete(); + } else { + self.zone.run(() => observer.error(err)); + } }); }); }