From 29ed147cb8cf830e26c623d70eed2e54e880dd06 Mon Sep 17 00:00:00 2001 From: Nino Richter Date: Mon, 4 Nov 2024 19:59:29 +0000 Subject: [PATCH] Disable sending when answer is generating, try to get new token if request has failed due to token expiring --- angular.json | 3 ++ src/app/chat/chat.component.html | 13 +++++--- src/app/chat/chat.component.scss | 6 ++++ src/app/chat/chat.component.ts | 22 +++++++++---- src/app/services/chatbot.service.ts | 48 ++++++++++++++++++++++++++--- 5 files changed, 76 insertions(+), 16 deletions(-) diff --git a/angular.json b/angular.json index 1930f4b..9fbfd88 100644 --- a/angular.json +++ b/angular.json @@ -111,5 +111,8 @@ } } } + }, + "cli": { + "analytics": false } } \ No newline at end of file diff --git a/src/app/chat/chat.component.html b/src/app/chat/chat.component.html index 6f9e8a1..c44d7e9 100644 --- a/src/app/chat/chat.component.html +++ b/src/app/chat/chat.component.html @@ -6,7 +6,7 @@

CIT Chatbot

- + @@ -45,10 +45,13 @@

CIT Chatbot

(keydown)="onKeyDown($event)" [placeholder]="placeholderText" rows="1"> -
\ No newline at end of file diff --git a/src/app/chat/chat.component.scss b/src/app/chat/chat.component.scss index 8380b12..d745164 100644 --- a/src/app/chat/chat.component.scss +++ b/src/app/chat/chat.component.scss @@ -110,6 +110,12 @@ $logo-size: 40px; &:hover { background-color: $primary-color; } + + &.disabled { + background-color: $border-color; + color: #aaa; + cursor: not-allowed; + } svg { fill: white; diff --git a/src/app/chat/chat.component.ts b/src/app/chat/chat.component.ts index 0c031fd..8be62cb 100644 --- a/src/app/chat/chat.component.ts +++ b/src/app/chat/chat.component.ts @@ -21,7 +21,8 @@ export const MESSAGES = { If you'd like program-specific advice, please select your study program from the dropdown menu at the top, and I'll provide you with the most relevant information. `, errorMessage: `Sorry, but I am currently unable to answer your questions. Please try again at a later time.`, - placeholder: `Type your message here...` + placeholder: `Type your message here...`, + dropdownLabel: `Select Study Program:` }, de: { welcomeMessage: ` @@ -32,7 +33,8 @@ export const MESSAGES = { Wenn Sie studiengangspezifische Ratschläge benötigen, wählen Sie bitte Ihr Studienprogramm aus dem Dropdown-Menü oben, und ich werde Ihnen die relevantesten Informationen bereitstellen. `, errorMessage: `Entschuldigung, aber ich kann Ihre Fragen derzeit nicht beantworten. Bitte versuchen Sie es später erneut.`, - placeholder: `Geben Sie hier Ihre Nachricht ein...` + placeholder: `Geben Sie hier Ihre Nachricht ein...`, + dropdownLabel: `Studiengang auswählen:` } }; @@ -54,6 +56,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { placeholderText: string = ''; welcomeMessage: string = ''; errorMessage: string = ''; + dropdownLabel: string = ''; // FormControl for the study program dropdown studyProgramControl = new FormControl(''); @@ -61,6 +64,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { language: 'en' | 'de' = 'en'; // Default language is English private needScrollToBottom: boolean = false; + disableSending: boolean = false; constructor(private chatbotService: ChatbotService, private route: ActivatedRoute) { } @@ -84,6 +88,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { this.welcomeMessage = MESSAGES[this.language].welcomeMessage; this.errorMessage = MESSAGES[this.language].errorMessage; this.placeholderText = MESSAGES[this.language].placeholder; + this.dropdownLabel = MESSAGES[this.language].dropdownLabel; } onKeyDown(event: KeyboardEvent): void { @@ -92,7 +97,8 @@ export class ChatComponent implements OnInit, AfterViewChecked { !event.shiftKey && !event.ctrlKey && !event.altKey && - !event.metaKey + !event.metaKey && + !this.disableSending ) { event.preventDefault(); // Prevents the default action of adding a newline this.sendMessage(); @@ -102,6 +108,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { sendMessage() { if (this.userMessage.trim()) { // Add the user's message to the messages array + this.disableSending = true; this.messages.push({ message: this.userMessage, type: 'user' }); this.userMessage = ''; this.resetTextAreaHeight(); @@ -113,9 +120,10 @@ export class ChatComponent implements OnInit, AfterViewChecked { const loadingMessage: ChatMessage = { message: '', type: 'loading' }; this.messages.push(loadingMessage); this.needScrollToBottom = true; - - // Prepare the messages to send to the bot, excluding the loading message - const messagesToSend = this.messages.filter(msg => msg.type !== 'loading'); + + const nonLoadingMessages = this.messages.filter(msg => msg.type !== 'loading'); + // Keep only the last 5 messages, if there are 5 or more + const messagesToSend = nonLoadingMessages.slice(-5); // Call the bot service with the filtered messages this.chatbotService.getBotResponse(messagesToSend, selectedProgram).subscribe({ @@ -126,6 +134,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { const formattedResponse = this.formatResponseText(response.answer); this.messages.push({ message: formattedResponse, type: 'system' }); this.needScrollToBottom = true; + this.disableSending = false; }, error: (error) => { console.error('Error fetching response:', error); @@ -137,6 +146,7 @@ export class ChatComponent implements OnInit, AfterViewChecked { type: 'system' }); this.needScrollToBottom = true; + this.disableSending = false; } }); } diff --git a/src/app/services/chatbot.service.ts b/src/app/services/chatbot.service.ts index ff416ec..4258e56 100644 --- a/src/app/services/chatbot.service.ts +++ b/src/app/services/chatbot.service.ts @@ -1,7 +1,7 @@ -import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { HttpClient, HttpErrorResponse, HttpHeaders } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { ChatMessage } from '../chat/chat.component'; -import { Observable, switchMap } from 'rxjs'; +import { catchError, Observable, switchMap, throwError } from 'rxjs'; import { environment } from '../../environments/environment'; import { AuthService } from './auth.service'; @@ -22,14 +22,52 @@ export class ChatbotService { getBotResponse(chatHistory: ChatMessage[], study_program: string): Observable { const token = this.authService.getToken(); + + const makeRequest = (authToken: string): Observable => { + return this.sendBotRequest(authToken, chatHistory, study_program); + }; + if (token) { - return this.sendBotRequest(token, chatHistory, study_program); + return makeRequest(token).pipe( + catchError((error: HttpErrorResponse) => { + if (error.status === 401 || error.status === 403) { + // Token might have expired, try to re-authenticate + return this.authService.login().pipe( + switchMap(() => { + const newToken = this.authService.getToken(); + if (newToken) { + return makeRequest(newToken); + } else { + // Login failed to return a token + return throwError(() => new Error('Failed to obtain new token after re-authentication.')); + } + }), + catchError(loginError => { + // Handle login failure + return throwError(() => loginError); + }) + ); + } else { + // Other errors + return throwError(() => error); + } + }) + ); } else { - // Login if no token is stored, then proceed with the bot request + // No token available, attempt to login return this.authService.login().pipe( switchMap(() => { const newToken = this.authService.getToken(); - return this.sendBotRequest(newToken, chatHistory, study_program); + if (newToken) { + return makeRequest(newToken); + } else { + // Login failed to return a token + return throwError(() => new Error('Failed to obtain token after login.')); + } + }), + catchError(loginError => { + // Handle login failure + return throwError(() => loginError); }) ); }