From 276a13251f865c82d37ebf39af5b4f657c563b01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rodolphe=20K=C3=BCffer?= <101799433+rkuffer@users.noreply.github.com> Date: Fri, 28 Jun 2024 14:51:19 +0200 Subject: [PATCH] [Tock Studio] Filter dialogs with rag responses + Create new Faq from rag response (#1657) * dercbot-1065-1073-Filter rag dialogs and create faq from rag answer * Use of condensed question if debug enabled --- .../dialogs-list/dialogs-list.component.html | 170 +++++++++++------- .../dialogs-list/dialogs-list.component.scss | 4 - .../dialogs-list/dialogs-list.component.ts | 39 +++- .../web/src/app/analytics/dialogs/dialogs.ts | 4 +- .../app/analytics/users/users.component.ts | 8 +- .../faq-management-edit.component.spec.ts | 2 +- .../faq-management-edit.component.ts | 13 +- .../faq-management-list.component.html | 9 + .../faq-management-list.component.ts | 9 +- .../faq-management.component.ts | 36 ++-- .../chat-ui-message-debug.component.ts | 6 +- .../web/src/app/theme/styles/utilities.scss | 16 ++ 12 files changed, 205 insertions(+), 111 deletions(-) diff --git a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.html b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.html index d4d80353aa..1d72817c67 100644 --- a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.html +++ b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.html @@ -1,7 +1,7 @@ - + -
+
- - {{ c.id }} + - + {{ c.id }} + - - All - - {{ intent.name }} - - Unknown - + All + + {{ intent.name }} + + Unknown + +
- - All - + - {{ config }} - - + All + + {{ config }} + + - - Clear selection - - {{ intent }} - - + Clear selection + + {{ intent }} + + + - Rag responses only + + + Display tests + >Display tests +
@@ -111,16 +129,32 @@

- - + + +
+ +
+
+
diff --git a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.scss b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.scss index d6b167136c..824227d493 100644 --- a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.scss +++ b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.scss @@ -13,7 +13,3 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -.min-width-10 { - min-width: 25rem; -} diff --git a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.ts b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.ts index 53274a1da0..1827528ec9 100644 --- a/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.ts +++ b/bot/admin/web/src/app/analytics/dialogs/dialogs-list/dialogs-list.component.ts @@ -1,15 +1,15 @@ import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; -import { ActionReport, DialogReport } from '../../../shared/model/dialog-data'; +import { ActionReport, Debug, DialogReport, SentenceWithFootnotes } from '../../../shared/model/dialog-data'; import { ConnectorType } from '../../../core/model/configuration'; import { StateService } from '../../../core-nlp/state.service'; import { DialogReportQuery } from '../dialogs'; import { AnalyticsService } from '../../analytics.service'; import { BotConfigurationService } from '../../../core/bot-configuration.service'; -import { ActivatedRoute, UrlSegment } from '@angular/router'; +import { ActivatedRoute, Router, UrlSegment } from '@angular/router'; import { BotSharedService } from '../../../shared/bot-shared.service'; import { PaginatedQuery, SearchMark } from '../../../model/commons'; import { BehaviorSubject, Observable, Subject, filter, mergeMap, take, takeUntil } from 'rxjs'; -import { PaginatedResult } from '../../../model/nlp'; +import { PaginatedResult, Sentence } from '../../../model/nlp'; import { saveAs } from 'file-saver-es'; import { getDialogMessageUserAvatar, getDialogMessageUserQualifier } from '../../../shared/utils'; @@ -23,8 +23,8 @@ export class DialogFilter { public connectorType?: ConnectorType, public ratings?: number[], public configuration?: string, - - public intentsToHide?: string[] + public intentsToHide?: string[], + public isGenAiRagDialog?: boolean ) {} } @@ -67,7 +67,8 @@ export class DialogsListComponent implements OnInit, OnChanges, OnDestroy { private analytics: AnalyticsService, private botConfiguration: BotConfigurationService, private route: ActivatedRoute, - public botSharedService: BotSharedService + public botSharedService: BotSharedService, + private router: Router ) { this.state = state; @@ -143,7 +144,8 @@ export class DialogsListComponent implements OnInit, OnChanges, OnDestroy { this.filter.displayTests, this.ratingFilter, this.filter.configuration, - this.filter.intentsToHide + this.filter.intentsToHide, + this.filter.isGenAiRagDialog ); return this.route.queryParams.pipe( @@ -219,6 +221,29 @@ export class DialogsListComponent implements OnInit, OnChanges, OnDestroy { return getDialogMessageUserAvatar(action.isBot()); } + createFaq(action: ActionReport, actionsStack: ActionReport[]) { + const actionIndex = actionsStack.findIndex((act) => act === action); + if (actionIndex > 0) { + const answerSentence = action.message as unknown as SentenceWithFootnotes; + const answer = answerSentence.text; + + let question; + const questionAction = actionsStack[actionIndex - 1]; + + if (questionAction.message.isDebug()) { + const actionDebug = questionAction.message as unknown as Debug; + question = actionDebug.data.condense_question || actionDebug.data.user_question; + } else if (!questionAction.isBot()) { + const questionSentence = questionAction.message as unknown as Sentence; + question = questionSentence.text; + } + + if (question && answer) { + this.router.navigate(['faq/management'], { state: { question, answer } }); + } + } + } + ngOnDestroy(): void { this.destroy$.next(true); this.destroy$.complete(); diff --git a/bot/admin/web/src/app/analytics/dialogs/dialogs.ts b/bot/admin/web/src/app/analytics/dialogs/dialogs.ts index f9c649c0a2..2c0bb1f000 100644 --- a/bot/admin/web/src/app/analytics/dialogs/dialogs.ts +++ b/bot/admin/web/src/app/analytics/dialogs/dialogs.ts @@ -34,8 +34,8 @@ export class DialogReportQuery extends PaginatedQuery { public displayTests?: boolean, public ratings?: number[], public applicationId?: string, - - public intentsToHide? : string[] + public intentsToHide?: string[], + public isGenAiRagDialog?: boolean ) { super(namespace, applicationName, language, start, size); } diff --git a/bot/admin/web/src/app/analytics/users/users.component.ts b/bot/admin/web/src/app/analytics/users/users.component.ts index faac07cd4d..1d80ae8bc3 100644 --- a/bot/admin/web/src/app/analytics/users/users.component.ts +++ b/bot/admin/web/src/app/analytics/users/users.component.ts @@ -30,6 +30,10 @@ import { BotApplicationConfiguration, ConnectorType } from '../../core/model/con import { TestPlan } from '../../test/model/test'; import { getDialogMessageUserAvatar, getDialogMessageUserQualifier } from '../../shared/utils'; +export class UserFilter { + constructor(public flags: string[], public displayTests: boolean, public from?: Date, public to?: Date, public intent: string = '') {} +} + @Component({ selector: 'tock-users', templateUrl: './users.component.html', @@ -175,7 +179,3 @@ export class UsersComponent extends ScrollComponent { return user.userPreferences.picture ? user.userPreferences.picture : getDialogMessageUserAvatar(false); } } - -export class UserFilter { - constructor(public flags: string[], public displayTests: boolean, public from?: Date, public to?: Date, public intent: string = '') {} -} diff --git a/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.spec.ts b/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.spec.ts index 60187e18ce..b3a68d28d3 100644 --- a/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.spec.ts +++ b/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.spec.ts @@ -230,7 +230,7 @@ describe('FaqManagementEditComponent', () => { enabled: true, applicationName: 'app', language: 'fr', - _initUtterance: 'test' + _initQuestion: 'test' }; component.ngOnChanges({ faq: new SimpleChange(null, faq, true) }); fixture.detectChanges(); diff --git a/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.ts b/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.ts index 98223c530c..cc675f07b0 100644 --- a/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.ts +++ b/bot/admin/web/src/app/faq/faq-management/faq-management-edit/faq-management-edit.component.ts @@ -1,10 +1,9 @@ import { Component, ElementRef, EventEmitter, Input, OnChanges, Output, SimpleChanges, ViewChild } from '@angular/core'; import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms'; import { NbDialogService, NbTabComponent, NbTagComponent, NbTagInputAddEvent } from '@nebular/theme'; -import { Observable, Subscription, of } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { take } from 'rxjs/operators'; -import { DialogService } from '../../../core-nlp/dialog.service'; import { StateService } from '../../../core-nlp/state.service'; import { PaginatedQuery } from '../../../model/commons'; import { Intent, SearchQuery, SentenceStatus } from '../../../model/nlp'; @@ -120,20 +119,20 @@ export class FaqManagementEditComponent implements OnChanges { this.utterances.push(new FormControl(utterance)); }); - if (faq._initUtterance) { + if (faq._initQuestion) { this.form.markAsDirty(); this.form.markAsTouched(); this.setCurrentTab({ tabTitle: FaqTabs.QUESTION } as NbTabComponent); setTimeout(() => { - this.addUtterance(faq._initUtterance); - delete faq._initUtterance; + this.addUtterance(faq._initQuestion); + delete faq._initQuestion; }); } } - if (!faq.id && !faq._initUtterance) { + if (!faq.id && !faq._initQuestion) { this.setCurrentTab({ tabTitle: FaqTabs.INFO } as NbTabComponent); } } @@ -199,7 +198,7 @@ export class FaqManagementEditComponent implements OnChanges { this.intentNameExistInApp = undefined; } - addUtterance(utt?) { + addUtterance(utt?: string) { this.resetAlerts(); let utterance = utt || this.addUtteranceInput.nativeElement.value.trim(); diff --git a/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.html b/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.html index 765bee11b9..b043109f0c 100644 --- a/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.html +++ b/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.html @@ -34,6 +34,15 @@ First question (out of {{ faq.utterances.length }}) {{ faq.utterances[0] }} + diff --git a/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.ts b/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.ts index 27295c54e6..206c3ffa45 100644 --- a/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.ts +++ b/bot/admin/web/src/app/faq/faq-management/faq-management-list/faq-management-list.component.ts @@ -5,6 +5,8 @@ import { FaqDefinitionExtended } from '../faq-management.component'; import { StateService } from '../../../core-nlp/state.service'; import { DialogService } from '../../../core-nlp/dialog.service'; import { ConfirmDialogComponent } from '../../../shared-nlp/confirm-dialog/confirm-dialog.component'; +import { copyToClipboard } from '../../../shared/utils'; +import { NbToastrService } from '@nebular/theme'; @Component({ selector: 'tock-faq-management-list', @@ -19,7 +21,7 @@ export class FaqManagementListComponent { @Output() onDelete = new EventEmitter(); @Output() onEnable = new EventEmitter(); - constructor(private state: StateService, private dialogService: DialogService) {} + constructor(private state: StateService, private dialogService: DialogService, private toastrService: NbToastrService) {} toggleEnabled(faq: FaqDefinitionExtended) { let action = 'Enable'; @@ -68,4 +70,9 @@ export class FaqManagementListComponent { saveAs(jsonBlob, `${this.state.currentApplication.name}_${this.state.currentLocale}_faq_${faq.title}.json`); } + + copyString(str: string) { + copyToClipboard(str); + this.toastrService.success(`String copied to clipboard`, 'Clipboard'); + } } diff --git a/bot/admin/web/src/app/faq/faq-management/faq-management.component.ts b/bot/admin/web/src/app/faq/faq-management/faq-management.component.ts index 65df4ad0c4..f394de9b55 100644 --- a/bot/admin/web/src/app/faq/faq-management/faq-management.component.ts +++ b/bot/admin/web/src/app/faq/faq-management/faq-management.component.ts @@ -15,7 +15,7 @@ import { FaqManagementEditComponent } from './faq-management-edit/faq-management import { FaqManagementSettingsComponent } from './faq-management-settings/faq-management-settings.component'; import { Pagination } from '../../shared/components'; -export type FaqDefinitionExtended = FaqDefinition & { _initUtterance?: string }; +export type FaqDefinitionExtended = FaqDefinition & { _initQuestion?: string }; @Component({ selector: 'tock-faq-management', @@ -44,7 +44,8 @@ export class FaqManagementComponent implements OnInit, OnDestroy { list: false }; - initUtterance: string; + initQuestion: string; + initAnswer: string; constructor( private botConfiguration: BotConfigurationService, @@ -53,7 +54,8 @@ export class FaqManagementComponent implements OnInit, OnDestroy { private toastrService: NbToastrService, private router: Router ) { - this.initUtterance = this.router.getCurrentNavigation().extras?.state?.question; + this.initQuestion = this.router.getCurrentNavigation().extras?.state?.question; + this.initAnswer = this.router.getCurrentNavigation().extras?.state?.answer; } ngOnInit(): void { @@ -64,10 +66,20 @@ export class FaqManagementComponent implements OnInit, OnDestroy { this.search(); this.closeSidePanel(); - if (this.initUtterance) { - let initUtterance = this.initUtterance; - this.initUtterance = undefined; - this.addFaq(initUtterance); + let initQuestion; + if (this.initQuestion) { + initQuestion = this.initQuestion; + this.initQuestion = undefined; + } + + let initAnswer; + if (this.initAnswer) { + initAnswer = this.initAnswer; + this.initAnswer = undefined; + } + + if (initQuestion || initAnswer) { + this.addFaq(initQuestion, initAnswer); } } }); @@ -201,22 +213,22 @@ export class FaqManagementComponent implements OnInit, OnDestroy { } } - addFaq(initUtterance?: string) { + addFaq(initQuestion?: string, initAnswer?: string) { this.faqEdit = { id: undefined, intentId: undefined, - title: initUtterance ? initUtterance : '', + title: initQuestion || '', description: '', utterances: [], tags: [], - answer: '', + answer: initAnswer || '', enabled: true, applicationName: this.stateService.currentApplication.name, language: this.stateService.currentLocale }; - if (initUtterance) { - this.faqEdit._initUtterance = initUtterance; + if (initQuestion) { + this.faqEdit._initQuestion = initQuestion; } this.isSidePanelOpen.edit = true; diff --git a/bot/admin/web/src/app/shared/components/chat-ui/chat-ui-message/chat-ui-message-debug/chat-ui-message-debug.component.ts b/bot/admin/web/src/app/shared/components/chat-ui/chat-ui-message/chat-ui-message-debug/chat-ui-message-debug.component.ts index efec21e1c1..1e5c81c852 100644 --- a/bot/admin/web/src/app/shared/components/chat-ui/chat-ui-message/chat-ui-message-debug/chat-ui-message-debug.component.ts +++ b/bot/admin/web/src/app/shared/components/chat-ui/chat-ui-message/chat-ui-message-debug/chat-ui-message-debug.component.ts @@ -8,14 +8,10 @@ import { DebugViewerDialogComponent } from '../../../debug-viewer-dialog/debug-v templateUrl: './chat-ui-message-debug.component.html', styleUrls: ['./chat-ui-message-debug.component.scss'] }) -export class ChatUiMessageDebugComponent implements OnInit { +export class ChatUiMessageDebugComponent { @Input() message: Debug; constructor(private nbDialogService: NbDialogService) {} - ngOnInit(): void { - console.log(this.message); - } - showDebug() { this.nbDialogService.open(DebugViewerDialogComponent, { context: { diff --git a/bot/admin/web/src/app/theme/styles/utilities.scss b/bot/admin/web/src/app/theme/styles/utilities.scss index 28de36f5f7..d321584067 100644 --- a/bot/admin/web/src/app/theme/styles/utilities.scss +++ b/bot/admin/web/src/app/theme/styles/utilities.scss @@ -189,3 +189,19 @@ nb-menu { } } } + +.min-width-5 { + min-width: 5em; +} + +.min-width-10 { + min-width: 10em; +} + +.min-width-15 { + min-width: 15em; +} + +.min-width-20 { + min-width: 20em; +}