Skip to content

Commit

Permalink
Disable sending when answer is generating, try to get new token if re…
Browse files Browse the repository at this point in the history
…quest has failed due to token expiring
  • Loading branch information
ninori9 committed Nov 4, 2024
1 parent 3871b35 commit 29ed147
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 16 deletions.
3 changes: 3 additions & 0 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,8 @@
}
}
}
},
"cli": {
"analytics": false
}
}
13 changes: 8 additions & 5 deletions src/app/chat/chat.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ <h2>CIT Chatbot</h2>
</div>

<div class="study-program-dropdown">
<label for="studyProgramSelect" class="dropdown-label">Select Study Program:</label>
<label for="studyProgramSelect" class="dropdown-label">{{ dropdownLabel }}</label>
<ng-select class="select" [items]="studyPrograms" bindLabel="label" bindValue="value"
[formControl]="studyProgramControl" placeholder="Select your study program">
</ng-select>
Expand Down Expand Up @@ -45,10 +45,13 @@ <h2>CIT Chatbot</h2>
(keydown)="onKeyDown($event)"
[placeholder]="placeholderText"
rows="1"></textarea>
<button (click)="sendMessage()">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
</svg>
<button
(click)="sendMessage()"
[disabled]="disableSending"
[ngClass]="{ 'disabled': disableSending }">
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 24 24">
<path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/>
</svg>
</button>
</div>
</div>
6 changes: 6 additions & 0 deletions src/app/chat/chat.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
22 changes: 16 additions & 6 deletions src/app/chat/chat.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: `
Expand All @@ -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:`
}
};

Expand All @@ -54,13 +56,15 @@ export class ChatComponent implements OnInit, AfterViewChecked {
placeholderText: string = '';
welcomeMessage: string = '';
errorMessage: string = '';
dropdownLabel: string = '';

// FormControl for the study program dropdown
studyProgramControl = new FormControl('');
studyPrograms = studyPrograms;

language: 'en' | 'de' = 'en'; // Default language is English
private needScrollToBottom: boolean = false;
disableSending: boolean = false;

constructor(private chatbotService: ChatbotService, private route: ActivatedRoute) { }

Expand All @@ -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 {
Expand All @@ -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();
Expand All @@ -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();
Expand All @@ -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({
Expand All @@ -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);
Expand All @@ -137,6 +146,7 @@ export class ChatComponent implements OnInit, AfterViewChecked {
type: 'system'
});
this.needScrollToBottom = true;
this.disableSending = false;
}
});
}
Expand Down
48 changes: 43 additions & 5 deletions src/app/services/chatbot.service.ts
Original file line number Diff line number Diff line change
@@ -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';

Expand All @@ -22,14 +22,52 @@ export class ChatbotService {

getBotResponse(chatHistory: ChatMessage[], study_program: string): Observable<any> {
const token = this.authService.getToken();

const makeRequest = (authToken: string): Observable<any> => {
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);
})
);
}
Expand Down

0 comments on commit 29ed147

Please sign in to comment.