@sinequa/assistant 3.6.2 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat/chat-message/chat-message.component.d.ts +4 -2
- package/chat/chat.component.d.ts +56 -17
- package/chat/chat.service.d.ts +23 -1
- package/chat/rest-chat.service.d.ts +1 -0
- package/chat/saved-chats/saved-chats.component.d.ts +2 -2
- package/chat/styles/assistant.scss +5 -0
- package/chat/types.d.ts +128 -3
- package/chat/websocket-chat.service.d.ts +6 -6
- package/esm2020/chat/chat-message/chat-message.component.mjs +9 -4
- package/esm2020/chat/chat-reference/chat-reference.component.mjs +3 -3
- package/esm2020/chat/chat.component.mjs +262 -60
- package/esm2020/chat/chat.service.mjs +49 -3
- package/esm2020/chat/debug-message/debug-message.component.mjs +3 -3
- package/esm2020/chat/rest-chat.service.mjs +8 -3
- package/esm2020/chat/saved-chats/saved-chats.component.mjs +16 -5
- package/esm2020/chat/token-progress-bar/token-progress-bar.component.mjs +3 -3
- package/esm2020/chat/types.mjs +11 -3
- package/esm2020/chat/websocket-chat.service.mjs +191 -99
- package/fesm2015/sinequa-assistant-chat.mjs +552 -178
- package/fesm2015/sinequa-assistant-chat.mjs.map +1 -1
- package/fesm2020/sinequa-assistant-chat.mjs +542 -175
- package/fesm2020/sinequa-assistant-chat.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { Injectable, EventEmitter, inject, Component, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ContentChild, Inject } from '@angular/core';
|
|
3
|
-
import { Subscription, filter, tap, switchMap, BehaviorSubject, forkJoin, map, catchError, throwError, shareReplay, Subject, fromEvent, merge, takeUntil, Observable, take, finalize } from 'rxjs';
|
|
3
|
+
import { Subscription, filter, tap, switchMap, BehaviorSubject, forkJoin, map, catchError, throwError, shareReplay, Subject, fromEvent, mergeMap, of, merge, takeUntil, Observable, take, finalize, combineLatest } from 'rxjs';
|
|
4
4
|
import * as i3 from '@sinequa/core/web-services';
|
|
5
5
|
import { PrincipalWebService, UserSettingsWebService, AuditWebService, SignalRWebService, JsonMethodPluginService } from '@sinequa/core/web-services';
|
|
6
6
|
import * as i1 from '@angular/common';
|
|
@@ -196,7 +196,8 @@ const connectionSettingsSchema = z.object({
|
|
|
196
196
|
restEndpoint: z.string().optional(),
|
|
197
197
|
websocketEndpoint: z.string().optional(),
|
|
198
198
|
signalRTransport: z.enum(["WebSockets", "ServerSentEvents", "LongPolling", "None"]),
|
|
199
|
-
signalRLogLevel: z.enum(["Critical", "Debug", "Error", "Information", "None", "Trace", "Warning"])
|
|
199
|
+
signalRLogLevel: z.enum(["Critical", "Debug", "Error", "Information", "None", "Trace", "Warning"]),
|
|
200
|
+
signalRServerTimeoutInMilliseconds: z.number().optional()
|
|
200
201
|
}).refine(data => (!!data.restEndpoint || !!data.websocketEndpoint), {
|
|
201
202
|
message: "Based on the provided input() protocol ('REST' or 'WEBSOCKET') to the Chat Component, either 'restEndpoint' or 'websocketEndpoint' property should be provided in the 'globalSettings' of the assistant instance.",
|
|
202
203
|
});
|
|
@@ -224,6 +225,10 @@ const uiSettingsSchema = z.object({
|
|
|
224
225
|
displaySystemPrompt: z.boolean(),
|
|
225
226
|
displayUserPrompt: z.boolean()
|
|
226
227
|
});
|
|
228
|
+
// Define the Zod representation for the chatStarter object
|
|
229
|
+
const chatStarterSchema = z.object({
|
|
230
|
+
text: z.string()
|
|
231
|
+
});
|
|
227
232
|
// Define the Zod representation for the defaultValues object
|
|
228
233
|
const defaultValuesSchema = z.object({
|
|
229
234
|
service_id: z.string(),
|
|
@@ -243,7 +248,8 @@ const defaultValuesSchema = z.object({
|
|
|
243
248
|
const initializationSchema = z.object({
|
|
244
249
|
event: z.enum(['Query', 'Prompt']),
|
|
245
250
|
forcedWorkflow: z.string().optional(),
|
|
246
|
-
displayUserQuery: z.boolean().optional(),
|
|
251
|
+
displayUserQuery: z.boolean().optional(),
|
|
252
|
+
chatStarters: z.array(chatStarterSchema).optional(), // Optional for event 'Prompt'
|
|
247
253
|
}).refine(data => ((data.event === "Query") ? (!!data.forcedWorkflow && data.displayUserQuery !== undefined && data.displayUserQuery !== null) : true), {
|
|
248
254
|
message: "The 'forcedWorkflow' and 'displayUserQuery' properties must be provided when the initialization's event is 'Query'.",
|
|
249
255
|
});
|
|
@@ -252,6 +258,8 @@ const modeSettingsSchema = z.object({
|
|
|
252
258
|
displayUserPrompt: z.boolean(),
|
|
253
259
|
sendUserPrompt: z.boolean(),
|
|
254
260
|
initialization: initializationSchema
|
|
261
|
+
}).refine(data => !(data.initialization.chatStarters?.length && (data.sendUserPrompt || data.displayUserPrompt || data.initialization.event === 'Query')), {
|
|
262
|
+
message: "Incompatible configuration for using chatStarters ('sendUserPrompt' and 'displayUserPrompt' must be false, 'initialization.event' must not be 'Query')",
|
|
255
263
|
});
|
|
256
264
|
// Define the Zod representation for the savedChatSettings object
|
|
257
265
|
const savedChatSettingsSchema = z.object({
|
|
@@ -291,7 +299,11 @@ class ChatService {
|
|
|
291
299
|
this.initConfig$ = new BehaviorSubject(false);
|
|
292
300
|
/** Global configuration of the chat. */
|
|
293
301
|
this.chatConfig$ = new BehaviorSubject(undefined);
|
|
294
|
-
/**
|
|
302
|
+
/**
|
|
303
|
+
* Emit true if the fetch of an assistant's response is ongoing (it includes Streaming status of the chat endpoint AND saving the discussion if save Chat is enabled).
|
|
304
|
+
* This is used to prevent multiple fetches at the same time.
|
|
305
|
+
* Typically, there is no problem chaining fetches, but when forcing a reload after query changes cases, it can't be allowed because it breaks the whole business logic.
|
|
306
|
+
*/
|
|
295
307
|
this.streaming$ = new BehaviorSubject(false);
|
|
296
308
|
/** List of saved chats. */
|
|
297
309
|
this.savedChats$ = new BehaviorSubject([]);
|
|
@@ -305,6 +317,8 @@ class ChatService {
|
|
|
305
317
|
this.chatUsageMetrics$ = new BehaviorSubject(undefined);
|
|
306
318
|
/** Emit the calculated chat's token consumption based on the chat usage metrics. */
|
|
307
319
|
this.chatTokenConsumption$ = new BehaviorSubject(undefined);
|
|
320
|
+
/** Emit true if "CancelTasks" is ongoing. */
|
|
321
|
+
this.stoppingGeneration$ = new BehaviorSubject(false);
|
|
308
322
|
this.userSettingsService = inject(UserSettingsWebService);
|
|
309
323
|
this.notificationsService = inject(NotificationsService);
|
|
310
324
|
this.auditService = inject(AuditWebService);
|
|
@@ -431,7 +445,7 @@ class ChatService {
|
|
|
431
445
|
}
|
|
432
446
|
}
|
|
433
447
|
catch (error) {
|
|
434
|
-
this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'
|
|
448
|
+
this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'. See the browser console messages for details on the missing or incorrect properties.`);
|
|
435
449
|
throw new Error(`Missing valid configuration for the assistant instance '${key}' . \n ${JSON.stringify(error.issues, null, 2)}`);
|
|
436
450
|
}
|
|
437
451
|
}
|
|
@@ -472,6 +486,7 @@ class ChatService {
|
|
|
472
486
|
const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
|
|
473
487
|
this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
|
|
474
488
|
if (quota.maxQuotaReached) {
|
|
489
|
+
this.generateAuditEvent('quota.exceeded', {});
|
|
475
490
|
const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
|
|
476
491
|
this.notificationsService.error(msg);
|
|
477
492
|
if (propagateError)
|
|
@@ -530,6 +545,45 @@ class ChatService {
|
|
|
530
545
|
};
|
|
531
546
|
this.auditService.notify(audit);
|
|
532
547
|
}
|
|
548
|
+
/**
|
|
549
|
+
* Traverse the array from the end and track the first 'assistant' message among the last group of "assistant" messages where display is true
|
|
550
|
+
* @param array The array of ChatMessage to traverse
|
|
551
|
+
* @returns The index of the first visible assistant message among the last group of "assistant" messages in the array
|
|
552
|
+
*/
|
|
553
|
+
firstVisibleAssistantMessageIndex(array) {
|
|
554
|
+
if (!array) {
|
|
555
|
+
return -1;
|
|
556
|
+
}
|
|
557
|
+
let index = array.length - 1;
|
|
558
|
+
let firstVisibleAssistantMessageIndex = -1;
|
|
559
|
+
while (index >= 0 && array[index].role === 'assistant') {
|
|
560
|
+
if (array[index].additionalProperties.display === true) {
|
|
561
|
+
firstVisibleAssistantMessageIndex = index;
|
|
562
|
+
}
|
|
563
|
+
index--;
|
|
564
|
+
}
|
|
565
|
+
return firstVisibleAssistantMessageIndex;
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* Traverse the array from the end and pick the last 'assistant' message among the last group of "assistant" messages where display is true
|
|
569
|
+
* @param array The array of ChatMessage to traverse
|
|
570
|
+
* @returns The index of the last visible assistant message among the last group of "assistant" messages in the array
|
|
571
|
+
*/
|
|
572
|
+
lastVisibleAssistantMessageIndex(array) {
|
|
573
|
+
if (!array) {
|
|
574
|
+
return -1;
|
|
575
|
+
}
|
|
576
|
+
let index = array.length - 1;
|
|
577
|
+
let lastVisibleAssistantMessageIndex = -1;
|
|
578
|
+
while (index >= 0 && array[index].role === 'assistant') {
|
|
579
|
+
if (array[index].additionalProperties.display === true) {
|
|
580
|
+
lastVisibleAssistantMessageIndex = index;
|
|
581
|
+
break;
|
|
582
|
+
}
|
|
583
|
+
index--;
|
|
584
|
+
}
|
|
585
|
+
return lastVisibleAssistantMessageIndex;
|
|
586
|
+
}
|
|
533
587
|
/**
|
|
534
588
|
* Format a date string in UTC to a local date string
|
|
535
589
|
* @param value Date string in UTC to format
|
|
@@ -560,10 +614,8 @@ class WebSocketChatService extends ChatService {
|
|
|
560
614
|
this._messageHandlers = new Map();
|
|
561
615
|
this._actionMap = new Map();
|
|
562
616
|
this._progress = undefined;
|
|
563
|
-
this._content = "";
|
|
564
617
|
this._attachments = [];
|
|
565
|
-
this.
|
|
566
|
-
this._debugMessages = undefined;
|
|
618
|
+
this._debugMessages = [];
|
|
567
619
|
this.signalRService = inject(SignalRWebService);
|
|
568
620
|
this.authenticationService = inject(AuthenticationService);
|
|
569
621
|
}
|
|
@@ -613,36 +665,36 @@ class WebSocketChatService extends ChatService {
|
|
|
613
665
|
}
|
|
614
666
|
}
|
|
615
667
|
listModels() {
|
|
616
|
-
const modelsSubject = new Subject();
|
|
668
|
+
const modelsSubject$ = new Subject();
|
|
617
669
|
this.connection.on('ListModels', (res) => {
|
|
618
670
|
this.models = res.models?.filter(model => !!model.enable);
|
|
619
|
-
modelsSubject
|
|
620
|
-
modelsSubject
|
|
671
|
+
modelsSubject$.next(this.models);
|
|
672
|
+
modelsSubject$.complete();
|
|
621
673
|
});
|
|
622
674
|
// Send the request to get the list of models
|
|
623
675
|
this.connection.invoke('ListModels', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
624
676
|
.catch(error => {
|
|
625
677
|
console.error('Error invoking ListModels:', error);
|
|
626
|
-
modelsSubject
|
|
627
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
678
|
+
modelsSubject$.error(new Error(error));
|
|
679
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
628
680
|
});
|
|
629
|
-
return modelsSubject
|
|
681
|
+
return modelsSubject$.asObservable();
|
|
630
682
|
}
|
|
631
683
|
listFunctions() {
|
|
632
|
-
const functionsSubject = new Subject();
|
|
684
|
+
const functionsSubject$ = new Subject();
|
|
633
685
|
this.connection.on('ListFunctions', (res) => {
|
|
634
686
|
this.functions = res.functions?.filter(func => func.enabled);
|
|
635
|
-
functionsSubject
|
|
636
|
-
functionsSubject
|
|
687
|
+
functionsSubject$.next(this.functions);
|
|
688
|
+
functionsSubject$.complete();
|
|
637
689
|
});
|
|
638
690
|
// Send the request to get the list of functions
|
|
639
691
|
this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
640
692
|
.catch(error => {
|
|
641
693
|
console.error('Error invoking ListFunctions:', error);
|
|
642
|
-
functionsSubject
|
|
643
|
-
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
694
|
+
functionsSubject$.error(new Error(error));
|
|
695
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
644
696
|
});
|
|
645
|
-
return functionsSubject
|
|
697
|
+
return functionsSubject$.asObservable();
|
|
646
698
|
}
|
|
647
699
|
fetch(messages, query) {
|
|
648
700
|
// Start streaming by invoking the Chat method
|
|
@@ -670,7 +722,8 @@ class WebSocketChatService extends ChatService {
|
|
|
670
722
|
data.instanceId = this.chatInstanceId;
|
|
671
723
|
data.savedChatId = this.savedChatId;
|
|
672
724
|
}
|
|
673
|
-
|
|
725
|
+
// Initialize the response with an empty assistant message
|
|
726
|
+
this._response = [{ role: "assistant", content: "", additionalProperties: { display: true } }]; // here display: true is needed in order to be able to show the progress
|
|
674
727
|
// Create a Subject to signal completion
|
|
675
728
|
const completion$ = new Subject();
|
|
676
729
|
// Create observables for each non-global handler in the _messageHandlers map (default and eventual custom ones) once it is triggered by the hub connection
|
|
@@ -678,8 +731,19 @@ class WebSocketChatService extends ChatService {
|
|
|
678
731
|
.from(this._messageHandlers.entries())
|
|
679
732
|
.filter(([eventName, eventHandler]) => !eventHandler.isGlobalHandler)
|
|
680
733
|
.map(([eventName, eventHandler]) => {
|
|
681
|
-
return fromEvent(this.connection, eventName).pipe(
|
|
682
|
-
|
|
734
|
+
return fromEvent(this.connection, eventName).pipe(mergeMap((event) => {
|
|
735
|
+
// Wrap the handler in a try-catch block to prevent the entire stream from failing if an error occurs in a single handler
|
|
736
|
+
try {
|
|
737
|
+
// Execute the handler and emit the result
|
|
738
|
+
// NB: here we could use [eventHandler.handler(event)] which behind the scenes mergeMap interprets this array as an observable sequence with one item, which it then emits
|
|
739
|
+
return of(eventHandler.handler(event));
|
|
740
|
+
}
|
|
741
|
+
catch (error) {
|
|
742
|
+
console.error(`Error in event handler for ${eventName}:`, error);
|
|
743
|
+
// Use throwError to propagate the error downstream
|
|
744
|
+
return throwError(() => new Error(`Error in event handler for ${eventName}: ${error}`));
|
|
745
|
+
}
|
|
746
|
+
}));
|
|
683
747
|
});
|
|
684
748
|
// Then merge them into a single observable in order to simulate the streaming behavior
|
|
685
749
|
const combined$ = merge(...observables).pipe(map(() => {
|
|
@@ -693,37 +757,74 @@ class WebSocketChatService extends ChatService {
|
|
|
693
757
|
time: a.executionTime,
|
|
694
758
|
}))
|
|
695
759
|
: undefined;
|
|
696
|
-
//
|
|
697
|
-
|
|
698
|
-
|
|
760
|
+
// Always update ONLY the first assistant message of the _response with the new $progress, $attachment and $debug
|
|
761
|
+
// Assuming that the first assistant message is always visible since the hub does not send hidden messages by design
|
|
762
|
+
// So even if the first assistant message is hidden (display: false), the _response[0] will and should contain :
|
|
763
|
+
// - $progress, $attachment and $debug
|
|
764
|
+
// - the content of the first visible assistant message in the workflow
|
|
765
|
+
// This is mandatory in order to match the behavior of consecutive messages and maintain consistency with the chatHistory
|
|
766
|
+
if (!!this._progress || this._attachments.length > 0 || this._debugMessages.length > 0) {
|
|
767
|
+
this._response[0].additionalProperties.$progress = this._progress;
|
|
768
|
+
this._response[0].additionalProperties.$attachment = this._attachments;
|
|
769
|
+
this._response[0].additionalProperties.$debug = this._debugMessages;
|
|
699
770
|
}
|
|
700
771
|
// Return the result
|
|
701
|
-
return { history: [...messages,
|
|
772
|
+
return { history: [...messages, ...this._response], executionTime: this._executionTime };
|
|
702
773
|
}), takeUntil(completion$));
|
|
703
774
|
// return a new Observable that emits the result of the combined stream and handles the eventual errors of the invocation of the Chat method
|
|
704
775
|
return new Observable(observer => {
|
|
705
776
|
// Subscribe to combined stream
|
|
706
777
|
combined$.subscribe({
|
|
707
778
|
next: (value) => observer.next(value),
|
|
708
|
-
error: (err) => observer.error(err)
|
|
709
|
-
complete: () => observer.complete(),
|
|
779
|
+
error: (err) => observer.error(err)
|
|
710
780
|
});
|
|
711
781
|
// Invoke the Chat method and handle errors
|
|
712
782
|
this.connection.invoke('Chat', data)
|
|
783
|
+
.then(() => {
|
|
784
|
+
// If a valid assistant message with (display: true) was found, update it
|
|
785
|
+
// and it should always the case
|
|
786
|
+
const index = this.firstVisibleAssistantMessageIndex(this.chatHistory);
|
|
787
|
+
if (index !== -1) {
|
|
788
|
+
this.chatHistory[index].additionalProperties.$progress = this._progress;
|
|
789
|
+
this.chatHistory[index].additionalProperties.$attachment = this._attachments;
|
|
790
|
+
this.chatHistory[index].additionalProperties.$debug = this._debugMessages;
|
|
791
|
+
}
|
|
792
|
+
// Save/update the chat if savedChat enabled
|
|
793
|
+
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
794
|
+
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory).pipe(tap(() => this.listSavedChat())) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
795
|
+
action.pipe(take(1)).subscribe({
|
|
796
|
+
next: () => { },
|
|
797
|
+
error: (error) => {
|
|
798
|
+
this.streaming$.next(false);
|
|
799
|
+
observer.error(error);
|
|
800
|
+
},
|
|
801
|
+
complete: () => {
|
|
802
|
+
this.streaming$.next(false);
|
|
803
|
+
observer.complete();
|
|
804
|
+
}
|
|
805
|
+
});
|
|
806
|
+
}
|
|
807
|
+
else {
|
|
808
|
+
this.streaming$.next(false);
|
|
809
|
+
observer.complete();
|
|
810
|
+
}
|
|
811
|
+
})
|
|
713
812
|
.catch(error => {
|
|
714
813
|
console.error('Error invoking Chat:', error);
|
|
814
|
+
this.streaming$.next(false);
|
|
715
815
|
// Emit the error to the newly created observable
|
|
716
816
|
observer.error(error);
|
|
717
817
|
// Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
718
818
|
return Promise.resolve();
|
|
719
819
|
})
|
|
720
820
|
.finally(() => {
|
|
721
|
-
|
|
821
|
+
// This block concerns ONLY the completion of the "Chat" method invocation.
|
|
822
|
+
// This means the completion of the combined$ stream.
|
|
823
|
+
// It does not take into account the completion of the entire fetch method (the observable returned by fetch) and which depends on the completion of the save chat action if enabled
|
|
824
|
+
this._response = []; // Clear the _response
|
|
722
825
|
this._actionMap.clear(); // Clear the _actionMap
|
|
723
|
-
this._content = ""; // Clear the _content
|
|
724
826
|
this._progress = undefined; // Clear the _progress
|
|
725
827
|
this._attachments = []; // Clear the _attachments
|
|
726
|
-
this._suggestedActions = []; // Clear the _suggestedActions
|
|
727
828
|
this._debugMessages = []; // Clear the _debugMessages
|
|
728
829
|
this._executionTime = ""; // Clear the _executionTime
|
|
729
830
|
completion$.next(); // Emit a signal to complete the observables
|
|
@@ -731,6 +832,33 @@ class WebSocketChatService extends ChatService {
|
|
|
731
832
|
});
|
|
732
833
|
});
|
|
733
834
|
}
|
|
835
|
+
stopGeneration() {
|
|
836
|
+
// Start stopping generation by invoking the CancelTasks method
|
|
837
|
+
this.stoppingGeneration$.next(true);
|
|
838
|
+
// Create a Subject to hold the result of the CancelTasks method
|
|
839
|
+
const stopGenerationSubject$ = new Subject();
|
|
840
|
+
this.connection.on('CancelTasks', (res) => {
|
|
841
|
+
// When the generation is stopped before streaming any VISIBLE assistant message, this means that $progress, $attachment and $debug properties will be lost.
|
|
842
|
+
// However, the "ContextMessage" frames will be persisted in the chatHistory and the assistant may reference them in the next generation.
|
|
843
|
+
// This leads to the problem of referencing undisplayed attachments in the next generation.
|
|
844
|
+
// To solve this problem, we need to persist $progress, $attachment and $debug properties by adding a new assistant message with empty content and these properties.
|
|
845
|
+
if (this._response.length === 1 && this._response[0].content === "") {
|
|
846
|
+
this.chatHistory?.push({ role: "assistant", content: "", additionalProperties: { display: true, $progress: this._progress, $attachment: this._attachments, $debug: this._debugMessages } });
|
|
847
|
+
}
|
|
848
|
+
stopGenerationSubject$.next(!!res); // Emit the result of the CancelTasks method
|
|
849
|
+
stopGenerationSubject$.complete(); // Complete the subject
|
|
850
|
+
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
851
|
+
});
|
|
852
|
+
// Invoke the CancelTasks method and handle errors
|
|
853
|
+
this.connection.invoke('CancelTasks')
|
|
854
|
+
.catch(error => {
|
|
855
|
+
console.error('Error invoking CancelTasks:', error);
|
|
856
|
+
stopGenerationSubject$.error(new Error(error));
|
|
857
|
+
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
858
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
859
|
+
});
|
|
860
|
+
return stopGenerationSubject$.asObservable();
|
|
861
|
+
}
|
|
734
862
|
listSavedChat() {
|
|
735
863
|
if (!this.chatConfig$.value.savedChatSettings.enabled) {
|
|
736
864
|
return;
|
|
@@ -750,27 +878,27 @@ class WebSocketChatService extends ChatService {
|
|
|
750
878
|
});
|
|
751
879
|
}
|
|
752
880
|
getSavedChat(id) {
|
|
753
|
-
const savedChatSubject = new Subject();
|
|
881
|
+
const savedChatSubject$ = new Subject();
|
|
754
882
|
const data = {
|
|
755
883
|
instanceId: this.chatInstanceId,
|
|
756
884
|
savedChatId: id,
|
|
757
885
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
758
886
|
};
|
|
759
887
|
this.connection.on('SavedChatGet', (res) => {
|
|
760
|
-
savedChatSubject
|
|
761
|
-
savedChatSubject
|
|
888
|
+
savedChatSubject$.next(res.savedChat);
|
|
889
|
+
savedChatSubject$.complete();
|
|
762
890
|
});
|
|
763
891
|
// Invoke the method SavedChatGet
|
|
764
892
|
this.connection.invoke('SavedChatGet', data)
|
|
765
893
|
.catch(error => {
|
|
766
894
|
console.error('Error invoking SavedChatGet:', error);
|
|
767
|
-
savedChatSubject
|
|
768
|
-
return Promise.resolve();
|
|
895
|
+
savedChatSubject$.error(new Error(error));
|
|
896
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
769
897
|
});
|
|
770
|
-
return savedChatSubject
|
|
898
|
+
return savedChatSubject$.asObservable();
|
|
771
899
|
}
|
|
772
900
|
addSavedChat(messages) {
|
|
773
|
-
const addSavedChatSubject = new Subject();
|
|
901
|
+
const addSavedChatSubject$ = new Subject();
|
|
774
902
|
const data = {
|
|
775
903
|
instanceId: this.chatInstanceId,
|
|
776
904
|
savedChatId: this.chatId,
|
|
@@ -780,20 +908,20 @@ class WebSocketChatService extends ChatService {
|
|
|
780
908
|
this.connection.on('SavedChatAdd', (res) => {
|
|
781
909
|
this.setSavedChatId(res.savedChat.id); // Persist the savedChatId
|
|
782
910
|
this.generateAuditEvent('saved-chat.add', {}, res.savedChat.id); // Generate audit event
|
|
783
|
-
addSavedChatSubject
|
|
784
|
-
addSavedChatSubject
|
|
911
|
+
addSavedChatSubject$.next(res.savedChat);
|
|
912
|
+
addSavedChatSubject$.complete();
|
|
785
913
|
});
|
|
786
914
|
// Invoke the method SavedChatAdd
|
|
787
915
|
this.connection.invoke('SavedChatAdd', data)
|
|
788
916
|
.catch(error => {
|
|
789
917
|
console.error('Error invoking SavedChatAdd:', error);
|
|
790
|
-
addSavedChatSubject
|
|
791
|
-
return Promise.resolve();
|
|
918
|
+
addSavedChatSubject$.error(new Error(error));
|
|
919
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
792
920
|
});
|
|
793
|
-
return addSavedChatSubject
|
|
921
|
+
return addSavedChatSubject$.asObservable();
|
|
794
922
|
}
|
|
795
923
|
updateSavedChat(id, name, messages) {
|
|
796
|
-
const updateSavedChatSubject = new Subject();
|
|
924
|
+
const updateSavedChatSubject$ = new Subject();
|
|
797
925
|
const data = {
|
|
798
926
|
instanceId: this.chatInstanceId,
|
|
799
927
|
savedChatId: id,
|
|
@@ -804,45 +932,64 @@ class WebSocketChatService extends ChatService {
|
|
|
804
932
|
if (messages)
|
|
805
933
|
data["history"] = messages;
|
|
806
934
|
this.connection.on('SavedChatUpdate', (res) => {
|
|
807
|
-
updateSavedChatSubject
|
|
808
|
-
updateSavedChatSubject
|
|
935
|
+
updateSavedChatSubject$.next(res.savedChat);
|
|
936
|
+
updateSavedChatSubject$.complete();
|
|
809
937
|
});
|
|
810
938
|
// Invoke the method SavedChatUpdate
|
|
811
939
|
this.connection.invoke('SavedChatUpdate', data)
|
|
812
940
|
.catch(error => {
|
|
813
941
|
console.error('Error invoking SavedChatUpdate:', error);
|
|
814
|
-
updateSavedChatSubject
|
|
815
|
-
return Promise.resolve();
|
|
942
|
+
updateSavedChatSubject$.error(new Error(error));
|
|
943
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
816
944
|
});
|
|
817
|
-
return updateSavedChatSubject
|
|
945
|
+
return updateSavedChatSubject$.asObservable();
|
|
818
946
|
}
|
|
819
947
|
deleteSavedChat(ids) {
|
|
820
|
-
const deleteSavedChatSubject = new Subject();
|
|
948
|
+
const deleteSavedChatSubject$ = new Subject();
|
|
821
949
|
const data = {
|
|
822
950
|
instanceId: this.chatInstanceId,
|
|
823
951
|
SavedChatIds: ids,
|
|
824
952
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
825
953
|
};
|
|
826
954
|
this.connection.on('SavedChatDelete', (res) => {
|
|
827
|
-
deleteSavedChatSubject
|
|
828
|
-
deleteSavedChatSubject
|
|
955
|
+
deleteSavedChatSubject$.next(res.deleteCount);
|
|
956
|
+
deleteSavedChatSubject$.complete();
|
|
829
957
|
});
|
|
830
958
|
// Invoke the method SavedChatDelete
|
|
831
959
|
this.connection.invoke('SavedChatDelete', data)
|
|
832
960
|
.catch(error => {
|
|
833
961
|
console.error('Error invoking SavedChatDelete:', error);
|
|
834
|
-
deleteSavedChatSubject
|
|
835
|
-
return Promise.resolve();
|
|
962
|
+
deleteSavedChatSubject$.error(new Error(error));
|
|
963
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
836
964
|
});
|
|
837
|
-
return deleteSavedChatSubject
|
|
965
|
+
return deleteSavedChatSubject$.asObservable();
|
|
838
966
|
}
|
|
839
967
|
/**
|
|
840
968
|
* Initialize out-of-the-box handlers
|
|
841
|
-
* It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with
|
|
969
|
+
* It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with frame message(s)
|
|
842
970
|
*/
|
|
843
971
|
initMessageHandlers() {
|
|
844
|
-
this.addMessageHandler("
|
|
845
|
-
|
|
972
|
+
this.addMessageHandler("Error", {
|
|
973
|
+
handler: (error) => {
|
|
974
|
+
console.error(error);
|
|
975
|
+
this.notificationsService.error(error);
|
|
976
|
+
},
|
|
977
|
+
isGlobalHandler: true
|
|
978
|
+
});
|
|
979
|
+
this.addMessageHandler("Quota", {
|
|
980
|
+
handler: (message) => {
|
|
981
|
+
try {
|
|
982
|
+
this.updateQuota(message.quota);
|
|
983
|
+
}
|
|
984
|
+
catch (error) {
|
|
985
|
+
console.error(error);
|
|
986
|
+
}
|
|
987
|
+
},
|
|
988
|
+
isGlobalHandler: true
|
|
989
|
+
});
|
|
990
|
+
this.addMessageHandler("Debug", { handler: () => { },
|
|
991
|
+
isGlobalHandler: true
|
|
992
|
+
});
|
|
846
993
|
this.addMessageHandler("ActionStart", { handler: (action) => this._actionMap.set(action.guid, action),
|
|
847
994
|
isGlobalHandler: false });
|
|
848
995
|
this.addMessageHandler("ActionResult", {
|
|
@@ -858,35 +1005,48 @@ class WebSocketChatService extends ChatService {
|
|
|
858
1005
|
isGlobalHandler: false
|
|
859
1006
|
});
|
|
860
1007
|
this.addMessageHandler("Message", {
|
|
861
|
-
handler: (message) => this.
|
|
1008
|
+
handler: (message) => this._response.at(-1).content += message ?? "",
|
|
862
1009
|
isGlobalHandler: false
|
|
863
1010
|
});
|
|
864
1011
|
this.addMessageHandler("History", {
|
|
865
1012
|
handler: (history) => {
|
|
866
|
-
|
|
867
|
-
//
|
|
868
|
-
this.chatHistory
|
|
869
|
-
|
|
870
|
-
this.chatHistory.at(-1).additionalProperties.$suggestedAction = this._suggestedActions;
|
|
871
|
-
this.chatHistory.at(-1).additionalProperties.$debug = this._debugMessages;
|
|
872
|
-
// Emit the updated chat usage metrics once the generation of the assistant response is completed
|
|
1013
|
+
// The ChatHistory is updated: it is the current copy concatenated with the new items ONLY (it can have multiple messages: the context messages + the response message)
|
|
1014
|
+
// This is mandatory to not lose the previous updates of the chatHistory when the assistant is streaming multiple message steps
|
|
1015
|
+
this.chatHistory = [...this.chatHistory, ...(history.history.slice(this.chatHistory.length))];
|
|
1016
|
+
// Emit the updated chat usage metrics
|
|
873
1017
|
if (!!this.chatHistory.at(-1)?.additionalProperties.usageMetrics) {
|
|
874
1018
|
this.updateChatUsageMetrics(this.chatHistory.at(-1).additionalProperties.usageMetrics);
|
|
875
1019
|
}
|
|
876
|
-
// Save/update the chat if savedChat enabled
|
|
877
|
-
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
878
|
-
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
879
|
-
action.pipe(take(1)).subscribe();
|
|
880
|
-
}
|
|
881
1020
|
this._executionTime = history.executionTime;
|
|
1021
|
+
},
|
|
1022
|
+
isGlobalHandler: false
|
|
1023
|
+
});
|
|
1024
|
+
this.addMessageHandler("SuggestedActions", {
|
|
1025
|
+
handler: (message) => {
|
|
1026
|
+
// Since after the "History" and "MessageBreak" that this event is caught,
|
|
1027
|
+
// $suggestedAction needs to be updated directly to the last visible "assistant" message in the _response and the chatHistory
|
|
1028
|
+
this._response.at(-1).additionalProperties.$suggestedAction = (this._response.at(-1).additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
1029
|
+
const index = this.lastVisibleAssistantMessageIndex(this.chatHistory);
|
|
1030
|
+
if (index !== -1) {
|
|
1031
|
+
this.chatHistory[index].additionalProperties.$suggestedAction = (this.chatHistory[index].additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
isGlobalHandler: false
|
|
1035
|
+
});
|
|
1036
|
+
this.addMessageHandler("DebugDisplay", {
|
|
1037
|
+
handler: (message) => this._debugMessages = this._debugMessages.concat(message),
|
|
1038
|
+
isGlobalHandler: false
|
|
1039
|
+
});
|
|
1040
|
+
this.addMessageHandler("MessageBreak", {
|
|
1041
|
+
handler: () => {
|
|
882
1042
|
// Generate audit event
|
|
883
1043
|
const details = {
|
|
884
1044
|
'duration': this._executionTime,
|
|
885
1045
|
'text': this.chatHistory.at(-1).content,
|
|
886
1046
|
'role': this.chatHistory.at(-1).role,
|
|
887
1047
|
'rank': this.chatHistory.length - 1,
|
|
888
|
-
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics
|
|
889
|
-
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics
|
|
1048
|
+
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.completionTokenCount,
|
|
1049
|
+
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.promptTokenCount,
|
|
890
1050
|
'attachments': JSON.stringify(this._attachments.map(({ recordId, contextId, parts, type }) => ({
|
|
891
1051
|
recordId,
|
|
892
1052
|
contextId,
|
|
@@ -895,31 +1055,13 @@ class WebSocketChatService extends ChatService {
|
|
|
895
1055
|
})))
|
|
896
1056
|
};
|
|
897
1057
|
this.generateAuditEvent('message', details);
|
|
1058
|
+
// Push a new assistant message to the _response array ONLY if the content of the last message is not empty
|
|
1059
|
+
if (this._response.at(-1).content !== "") {
|
|
1060
|
+
this._response.push({ role: "assistant", content: "", additionalProperties: { display: true } });
|
|
1061
|
+
}
|
|
898
1062
|
},
|
|
899
1063
|
isGlobalHandler: false
|
|
900
1064
|
});
|
|
901
|
-
this.addMessageHandler("Error", {
|
|
902
|
-
handler: (error) => {
|
|
903
|
-
console.error(error);
|
|
904
|
-
this.notificationsService.error(error);
|
|
905
|
-
},
|
|
906
|
-
isGlobalHandler: true
|
|
907
|
-
});
|
|
908
|
-
this.addMessageHandler("Quota", {
|
|
909
|
-
handler: (message) => this.updateQuota(message.quota),
|
|
910
|
-
isGlobalHandler: true
|
|
911
|
-
});
|
|
912
|
-
this.addMessageHandler("SuggestedActions", {
|
|
913
|
-
handler: (message) => {
|
|
914
|
-
// Suggested actions are concatenated to the existing ones in case of multiple events "SuggestedActions"
|
|
915
|
-
this._suggestedActions = this._suggestedActions.concat(message.suggestedActions);
|
|
916
|
-
},
|
|
917
|
-
isGlobalHandler: false
|
|
918
|
-
});
|
|
919
|
-
this.addMessageHandler("DebugDisplay", {
|
|
920
|
-
handler: (message) => this._debugMessages = this._debugMessages ? this._debugMessages.concat(message) : [message],
|
|
921
|
-
isGlobalHandler: false
|
|
922
|
-
});
|
|
923
1065
|
}
|
|
924
1066
|
/**
|
|
925
1067
|
* Override and register the entire _messageHandlers map by merging the provided map with the default one
|
|
@@ -934,7 +1076,7 @@ class WebSocketChatService extends ChatService {
|
|
|
934
1076
|
});
|
|
935
1077
|
// Merge the new event handlers with the existing ones
|
|
936
1078
|
this._messageHandlers = new Map([...this._messageHandlers, ..._messageHandlers]);
|
|
937
|
-
// Register the global
|
|
1079
|
+
// Register the global handlers among the merged map
|
|
938
1080
|
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
939
1081
|
if (eventHandler.isGlobalHandler) {
|
|
940
1082
|
this.registerMessageHandler(eventName, eventHandler);
|
|
@@ -944,7 +1086,7 @@ class WebSocketChatService extends ChatService {
|
|
|
944
1086
|
/**
|
|
945
1087
|
* Add a listener for a specific event.
|
|
946
1088
|
* If a listener for this same event already exists, it will be overridden.
|
|
947
|
-
* If the listener has "
|
|
1089
|
+
* If the listener has "isGlobalHandler" set to true, it will be registered to the hub connection.
|
|
948
1090
|
* @param eventName Name of the event to register a listener for
|
|
949
1091
|
* @param eventHandler The handler to be called when the event is received
|
|
950
1092
|
*/
|
|
@@ -998,8 +1140,12 @@ class WebSocketChatService extends ChatService {
|
|
|
998
1140
|
reject(new Error("No endpoint provided to connect the websocket to"));
|
|
999
1141
|
return;
|
|
1000
1142
|
}
|
|
1001
|
-
const logLevel = this.
|
|
1143
|
+
const logLevel = this._getLogLevel();
|
|
1002
1144
|
this.connection = this.signalRService.buildConnection(this.REQUEST_URL, { ...this.defaultOptions, ...options }, logLevel, true);
|
|
1145
|
+
const signalRServerTimeoutInMilliseconds = this.chatConfig$.value?.connectionSettings.signalRServerTimeoutInMilliseconds;
|
|
1146
|
+
if (signalRServerTimeoutInMilliseconds) {
|
|
1147
|
+
this.connection.serverTimeoutInMilliseconds = signalRServerTimeoutInMilliseconds;
|
|
1148
|
+
}
|
|
1003
1149
|
resolve();
|
|
1004
1150
|
});
|
|
1005
1151
|
}
|
|
@@ -1017,7 +1163,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1017
1163
|
stopConnection() {
|
|
1018
1164
|
return this.signalRService.stopConnection(this.connection);
|
|
1019
1165
|
}
|
|
1020
|
-
|
|
1166
|
+
_getTransports() {
|
|
1021
1167
|
switch (this.chatConfig$.value?.connectionSettings.signalRTransport) {
|
|
1022
1168
|
case "WebSockets":
|
|
1023
1169
|
return HttpTransportType.WebSockets;
|
|
@@ -1029,7 +1175,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1029
1175
|
return HttpTransportType.None;
|
|
1030
1176
|
}
|
|
1031
1177
|
}
|
|
1032
|
-
|
|
1178
|
+
_getLogLevel() {
|
|
1033
1179
|
switch (this.chatConfig$.value?.connectionSettings.signalRLogLevel) {
|
|
1034
1180
|
case "Critical":
|
|
1035
1181
|
return LogLevel.Critical; // Log level for diagnostic messages that indicate a failure that will terminate the entire application.
|
|
@@ -1063,7 +1209,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1063
1209
|
// as far as we know, signalR only lets us tweak the request with this access token factory
|
|
1064
1210
|
// so we pass along the Sinequa CSRF token to pass the CSRF check..
|
|
1065
1211
|
return {
|
|
1066
|
-
transport: this.
|
|
1212
|
+
transport: this._getTransports(),
|
|
1067
1213
|
withCredentials: true,
|
|
1068
1214
|
headers,
|
|
1069
1215
|
accessTokenFactory: () => this.authenticationService.processedCredentials?.data?.csrfToken || ""
|
|
@@ -1304,10 +1450,10 @@ class ChatReferenceComponent {
|
|
|
1304
1450
|
}
|
|
1305
1451
|
}
|
|
1306
1452
|
ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1307
|
-
ChatReferenceComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatReferenceComponent, isStandalone: true, selector: "sq-chat-reference", inputs: { reference: "reference", attachment: "attachment", partId: "partId" }, outputs: { openDocument: "openDocument", openPreview: "openPreview" }, ngImport: i0, template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\" (click)=\"expandAttachment()\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"$event.stopPropagation(); openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"$event.stopPropagation(); openDocument.emit(attachment)\" [sqTooltip]=\"!partId ? 'Open document' : ''\">\n </i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem);cursor:pointer}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{white-space:nowrap;margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "component", type: FormatIconComponent, selector: "sq-format-icon", inputs: ["extension"] }] });
|
|
1453
|
+
ChatReferenceComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatReferenceComponent, isStandalone: true, selector: "sq-chat-reference", inputs: { reference: "reference", attachment: "attachment", partId: "partId" }, outputs: { openDocument: "openDocument", openPreview: "openPreview" }, ngImport: i0, template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\" (click)=\"expandAttachment()\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"$event.stopPropagation(); openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"$event.stopPropagation(); openDocument.emit(attachment)\" [sqTooltip]=\"!partId ? 'Open document' : ''\">\n </i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span class=\"w-100 pe-2\" [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem);cursor:pointer}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{white-space:nowrap;margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "component", type: FormatIconComponent, selector: "sq-format-icon", inputs: ["extension"] }] });
|
|
1308
1454
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
|
|
1309
1455
|
type: Component,
|
|
1310
|
-
args: [{ selector: 'sq-chat-reference', standalone: true, imports: [CommonModule, UtilsModule, FormatIconComponent], template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\" (click)=\"expandAttachment()\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"$event.stopPropagation(); openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"$event.stopPropagation(); openDocument.emit(attachment)\" [sqTooltip]=\"!partId ? 'Open document' : ''\">\n </i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem);cursor:pointer}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{white-space:nowrap;margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"] }]
|
|
1456
|
+
args: [{ selector: 'sq-chat-reference', standalone: true, imports: [CommonModule, UtilsModule, FormatIconComponent], template: "<div [class.reference-tooltip]=\"!!partId\">\n <div class=\"reference-data\" [class.expanded]=\"attachment['$expanded'] || !!partId\" (click)=\"expandAttachment()\">\n <span class=\"reference me-1\">{{reference}}</span>\n <sq-format-icon [extension]=\"attachment.record.fileext\"></sq-format-icon>\n <a [id]=\"'attachment-'+attachment.recordId\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"$event.stopPropagation(); openPreview.emit(attachment)\" [sqTooltip]=\"!partId ? 'Preview document' : ''\"></i>\n <i class=\"fas fa-arrow-up-right-from-square\" *ngIf=\"attachment.record.url1 || attachment.record.originalUrl\"\n (click)=\"$event.stopPropagation(); openDocument.emit(attachment)\" [sqTooltip]=\"!partId ? 'Open document' : ''\">\n </i>\n </div>\n <div class=\"reference-passages\" *ngIf=\"!!partId || (attachment['$expanded']) && parts.length\">\n <div class=\"reference-passage\" *ngFor=\"let part of parts\">\n <span class=\"reference me-1\">{{reference}}.{{part.partId}}</span>\n <span class=\"w-100 pe-2\" [innerHTML]=\"part.text\"></span>\n </div>\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{display:block}:host.expanded,:host:hover{background-color:var(--ast-reference-expanded-hover-bg, white)}.reference-data{display:flex;flex-direction:row;align-items:baseline;padding:var(--ast-size-1, .25rem);cursor:pointer}.reference-data a{color:var(--ast-secondary-color, #FF732E);flex-grow:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-weight:var(--font-weight-bold, 500);cursor:pointer}.reference-data i{padding:var(--ast-size-1, .25rem);margin-left:var(--ast-size-1, .25rem);cursor:pointer;color:var(--ast-reference-icon-color, black)}.reference-data i.active{color:var(--ast-reference-icon-active-color, white);background-color:var(--ast-secondary-color, #FF732E)}.reference-data:not(.expanded) i{opacity:0}.reference-data:not(.expanded):hover i{opacity:1}.reference-passages{white-space:normal;font-style:italic;font-weight:400;padding:1rem 0;color:var(--ast-reference-passages-color, black)}.reference-passages .reference-passage{display:flex;align-items:baseline;padding-left:2.5rem;padding-right:1rem;word-wrap:break-word}.reference-passages .reference-passage+.reference-passage{padding-top:1rem}.reference-passages .reference-passage .reference{white-space:nowrap;margin-right:var(--ast-size-2, .5rem)}sq-format-icon{margin-left:var(--ast-size-1, .25rem);margin-right:var(--ast-size-2, .5rem);color:var(--ast-secondary-color, #FF732E)}.reference-tooltip{max-width:600px!important;box-shadow:0 .5rem 1rem #00000026;padding:.5rem;font-size:.875rem}\n"] }]
|
|
1311
1457
|
}], propDecorators: { reference: [{
|
|
1312
1458
|
type: Input
|
|
1313
1459
|
}], attachment: [{
|
|
@@ -1372,6 +1518,7 @@ class ChatMessageComponent {
|
|
|
1372
1518
|
this.openDocument = new EventEmitter();
|
|
1373
1519
|
this.openPreview = new EventEmitter();
|
|
1374
1520
|
this.suggestAction = new EventEmitter();
|
|
1521
|
+
this.chatStarterClicked = new EventEmitter();
|
|
1375
1522
|
this.edit = new EventEmitter();
|
|
1376
1523
|
this.copy = new EventEmitter();
|
|
1377
1524
|
this.regenerate = new EventEmitter();
|
|
@@ -1447,7 +1594,7 @@ class ChatMessageComponent {
|
|
|
1447
1594
|
if (changes.streaming) {
|
|
1448
1595
|
this.collapseProgress = !this.streaming;
|
|
1449
1596
|
}
|
|
1450
|
-
if (
|
|
1597
|
+
if (this.message?.role === "assistant") {
|
|
1451
1598
|
this.references = [];
|
|
1452
1599
|
this.referenceMap.clear();
|
|
1453
1600
|
for (let m of this.conversation) {
|
|
@@ -1547,17 +1694,19 @@ class ChatMessageComponent {
|
|
|
1547
1694
|
}
|
|
1548
1695
|
}
|
|
1549
1696
|
ChatMessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, deps: [{ token: i1$1.SearchService }, { token: i2$1.UIService }, { token: i3.PrincipalWebService }, { token: i0.ChangeDetectorRef }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1550
|
-
ChatMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatMessageComponent, isStandalone: true, selector: "sq-chat-message", inputs: { message: "message", conversation: "conversation", suggestedActions: "suggestedActions", assistantMessageIcon: "assistantMessageIcon", userMessageIcon: "userMessageIcon", connectionErrorMessageIcon: "connectionErrorMessageIcon", searchWarningMessageIcon: "searchWarningMessageIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy", canDebug: "canDebug", canLike: "canLike", canDislike: "canDislike" }, outputs: { openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", edit: "edit", copy: "copy", regenerate: "regenerate", like: "like", dislike: "dislike", debug: "debug" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <ng-container [ngSwitch]=\"message?.role\">\n <!-- For 'assistant' -->\n <i *ngSwitchCase=\"'assistant'\" [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <!-- For 'user' -->\n <ng-container *ngSwitchCase=\"'user'\">\n <i *ngIf=\"!!userMessageIcon; else initialsAvatar\" [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\n <!-- For 'connection-error' -->\n <ng-container *ngSwitchCase=\"'connection-error'\">\n <i *ngIf=\"!!connectionErrorMessageIcon; else defaultErrorIcon\" [ngClass]=\"connectionErrorMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultErrorIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"connection-error\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\n <path fill=\"currentColor\" d=\"M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zM256 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n <!-- For 'search-warning' -->\n <ng-container *ngSwitchCase=\"'search-warning'\">\n <i *ngIf=\"!!searchWarningMessageIcon; else defaultWarningIcon\" [ngClass]=\"searchWarningMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultWarningIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"search-warning\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\n <path fill=\"currentColor\" d=\"M272 384c9.6-31.9 29.5-59.1 49.2-86.2c0 0 0 0 0 0c5.2-7.1 10.4-14.2 15.4-21.4c19.8-28.5 31.4-63 31.4-100.3C368 78.8 289.2 0 192 0S16 78.8 16 176c0 37.3 11.6 71.9 31.4 100.3c5 7.2 10.2 14.3 15.4 21.4c0 0 0 0 0 0c19.8 27.1 39.7 54.4 49.2 86.2l160 0zM192 512c44.2 0 80-35.8 80-80l0-16-160 0 0 16c0 44.2 35.8 80 80 80zm0-448c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM160 288a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n </ng-container>\n\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <div *ngIf=\"message?.role === 'assistant' && message.messageType === 'CHART'\">\n <sq-assistant-chart [rawChartData]=\"message.content\"></sq-assistant-chart>\n </div>\n\n <remark *ngIf=\"(message?.role === 'assistant' && message.messageType === 'MARKDOWN') || message?.role === 'connection-error' || message?.role === 'search-warning'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}\n </a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyCode(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n <ng-template remarkTemplate=\"link\" let-node>\n <a [href]=\"node.url\" target=\"_blank\" rel=\"noopener noreferrer\">{{getLinkText(node)}}</a>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message?.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference\n [class.expanded]=\"attachment.$expanded\"\n [attachment]=\"attachment\"\n [reference]=\"reference\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (openDocument)=\"openOriginalAttachment($event)\">\n </sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-actions\" *ngIf=\"message\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\" (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy text\" (click)=\"copyMessage(message)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\" (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n <button class=\"btn btn-sm\" [class.bounce]=\"liked\" *ngIf=\"canLike\" sqTooltip=\"Like the answer\" (click)=\"like.emit(message); liked = true;\">\n <i class=\"far fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm bounce\" [class.bounce]=\"disliked\" *ngIf=\"canDislike\" sqTooltip=\"Report an issue\" (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canDebug && !!message.additionalProperties.$debug && message.additionalProperties.$debug?.length > 0\" sqTooltip=\"Show Log Information\" (click)=\"debug.emit(message);\">\n <i class=\"far fa-list-alt\"></i>\n </button>\n </div>\n\n <!-- List of suggested actions, if any -->\n <div *ngIf=\"suggestedActions\" class=\"mt-2 message-suggestion\">\n <div class=\"suggested-action\" *ngFor=\"let suggestedAction of suggestedActions\" (click)=\"suggestAction.emit(suggestedAction)\">\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{suggestedAction.content}}</p>\n </div>\n </div>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference\n *ngIf=\"!hiddenTooltip\"\n class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openAttachmentPreview($event, ref.$partId)\"\n (openDocument)=\"openOriginalAttachment($event, ref.$partId)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host{display:flex}:host:not(:hover):not(.last-message) .sq-chat-message-actions{visibility:hidden}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:table;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-content ::ng-deep ul,.message-content ::ng-deep ol{display:flex;flex-direction:column;gap:.5rem;padding-right:2rem;margin-left:0;margin-right:0;padding-left:40px;unicode-bidi:-webkit-isolate;unicode-bidi:isolate;list-style:disc}.message-content ::ng-deep p:not(:first-child){margin-top:.5rem}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-connection-error .message-content{background:var(--ast-error-bg, rgba(249, 58, 55, .2))}.message-search-warning .message-content{background:var(--ast-warning-bg, #fff1b8)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.message-user .message-content p{white-space:pre-line}.message-suggestion .message-content{background:var(--ast-input-bg, #F8F8F8);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500));transition:background-color .5s ease,color .5s ease}.message-suggestion .message-content:hover{background:var(--ast-primary-bg, #f2f8fe);color:var(--ast-primary-color, #005DA7)}.message-suggestion .message-content p{white-space:pre-line}.message-suggestion .suggested-action{cursor:pointer}.message-suggestion .suggested-action+.suggested-action{margin-top:var(--ast-size-2, .5rem)}.sq-chat-message-actions{position:absolute;bottom:calc(0rem - var(--ast-size-3, .75rem));display:flex;z-index:999}.sq-chat-message-actions button{font-size:.75rem}.sq-chat-message-actions button:hover{color:var(--ast-primary-color, #005DA7)}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}.connection-error{height:var(--sq-size);width:var(--sq-size);color:var(--ast-error-color, rgba(249, 58, 55, .7))}.search-warning{height:var(--sq-size);width:var(--sq-size);color:var(--ast-warning-color, #fed86f)}.bounce{animation:bounce 2s ease}@keyframes bounce{10%{transform:translateY(0)}20%{transform:translateY(-15%)}30%{transform:translateY(0)}35%{transform:translateY(-7%)}37%{transform:translateY(0)}39%{transform:translateY(-3%)}40%{transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "component", type: i5.Collapse, selector: "sq-collapse", inputs: ["collapsed"] }, { kind: "ngmodule", type: RemarkModule }, { kind: "component", type: i6.RemarkComponent, selector: "remark", inputs: ["markdown", "processor", "debug"] }, { kind: "directive", type: i6.RemarkTemplateDirective, selector: "[remarkTemplate]", inputs: ["remarkTemplate"] }, { kind: "component", type: InitialsAvatarComponent, selector: "sq-initials-avatar", inputs: ["fullName", "size"] }, { kind: "component", type: ChatReferenceComponent, selector: "sq-chat-reference", inputs: ["reference", "attachment", "partId"], outputs: ["openDocument", "openPreview"] }, { kind: "component", type: ChartComponent, selector: "sq-assistant-chart", inputs: ["rawChartData"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1697
|
+
ChatMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatMessageComponent, isStandalone: true, selector: "sq-chat-message", inputs: { message: "message", conversation: "conversation", suggestedActions: "suggestedActions", chatStarters: "chatStarters", assistantMessageIcon: "assistantMessageIcon", userMessageIcon: "userMessageIcon", connectionErrorMessageIcon: "connectionErrorMessageIcon", searchWarningMessageIcon: "searchWarningMessageIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy", canDebug: "canDebug", canLike: "canLike", canDislike: "canDislike" }, outputs: { openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", chatStarterClicked: "chatStarterClicked", edit: "edit", copy: "copy", regenerate: "regenerate", like: "like", dislike: "dislike", debug: "debug" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <ng-container [ngSwitch]=\"message?.role\">\n <!-- For 'assistant' -->\n <i *ngSwitchCase=\"'assistant'\" [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <!-- For 'user' -->\n <ng-container *ngSwitchCase=\"'user'\">\n <i *ngIf=\"!!userMessageIcon; else initialsAvatar\" [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\n <!-- For 'connection-error' -->\n <ng-container *ngSwitchCase=\"'connection-error'\">\n <i *ngIf=\"!!connectionErrorMessageIcon; else defaultErrorIcon\" [ngClass]=\"connectionErrorMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultErrorIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"connection-error\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\n <path fill=\"currentColor\" d=\"M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zM256 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n <!-- For 'search-warning' -->\n <ng-container *ngSwitchCase=\"'search-warning'\">\n <i *ngIf=\"!!searchWarningMessageIcon; else defaultWarningIcon\" [ngClass]=\"searchWarningMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultWarningIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"search-warning\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\n <path fill=\"currentColor\" d=\"M272 384c9.6-31.9 29.5-59.1 49.2-86.2c0 0 0 0 0 0c5.2-7.1 10.4-14.2 15.4-21.4c19.8-28.5 31.4-63 31.4-100.3C368 78.8 289.2 0 192 0S16 78.8 16 176c0 37.3 11.6 71.9 31.4 100.3c5 7.2 10.2 14.3 15.4 21.4c0 0 0 0 0 0c19.8 27.1 39.7 54.4 49.2 86.2l160 0zM192 512c44.2 0 80-35.8 80-80l0-16-160 0 0 16c0 44.2 35.8 80 80 80zm0-448c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM160 288a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n </ng-container>\n\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <!-- Progress steps -->\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-spinner fa-pulse step-ongoing\" *ngIf=\"!step.done && streaming\"></i>\n <i class=\"fa-solid fa-ban step-error\" *ngIf=\"!step.done && !streaming\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\" [innerHTML]=\"': ' + step.content\"></span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <!-- Message content -->\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <div *ngIf=\"message?.role === 'assistant' && message.messageType === 'CHART'\">\n <sq-assistant-chart [rawChartData]=\"message.content\"></sq-assistant-chart>\n </div>\n\n <!-- This section is responsible for customizing the template nodes used in the application.\n Template nodes are predefined structures that serve as blueprints for creating/customizing dynamic content -->\n <remark *ngIf=\"(message?.role === 'assistant' && message.messageType === 'MARKDOWN') || message?.role === 'connection-error' || message?.role === 'search-warning'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}\n </a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyCode(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n <ng-template remarkTemplate=\"link\" let-node>\n <a [href]=\"node.url\" target=\"_blank\" rel=\"noopener noreferrer\">{{getLinkText(node)}}</a>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message?.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference\n [class.expanded]=\"attachment.$expanded\"\n [attachment]=\"attachment\"\n [reference]=\"reference\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (openDocument)=\"openOriginalAttachment($event)\">\n </sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-actions\" *ngIf=\"message\">\n <!-- Common action buttons for \"user\" & \"assistant\" message -->\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy text\" (click)=\"copyMessage(message)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <!-- Action buttons for \"user\" message -->\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\" (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <!-- Action buttons for \"assistant\" message -->\n <button class=\"btn btn-sm\" [class.bounce]=\"liked\" *ngIf=\"canLike\" sqTooltip=\"Like the answer\" (click)=\"like.emit(message); liked = true;\">\n <i class=\"far fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm bounce\" [class.bounce]=\"disliked\" *ngIf=\"canDislike\" sqTooltip=\"Report an issue\" (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\" (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canDebug\" sqTooltip=\"Show Log Information\" (click)=\"debug.emit(message);\">\n <i class=\"far fa-list-alt\"></i>\n </button>\n </div>\n\n <!-- List of suggested actions, if any -->\n <div *ngIf=\"suggestedActions\" class=\"mt-2 message-suggestion\">\n <div class=\"suggested-action\" *ngFor=\"let suggestedAction of suggestedActions\" (click)=\"suggestAction.emit(suggestedAction)\">\n <div class=\"message-icon\" [style.width.px]=\"iconSize\"></div>\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{suggestedAction.content}}</p>\n </div>\n </div>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference\n *ngIf=\"!hiddenTooltip\"\n class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openAttachmentPreview($event, ref.$partId)\"\n (openDocument)=\"openOriginalAttachment($event, ref.$partId)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n\n <!-- List of chat starters, if any -->\n <div *ngIf=\"chatStarters?.length\" class=\"mt-2 message-suggestion chat-starter\" [style.bottom.rem]=\"-(3.5*chatStarters!.length)\">\n <div class=\"suggested-action\" *ngFor=\"let chatStarter of chatStarters\" (click)=\"chatStarterClicked.emit(chatStarter)\">\n <div class=\"message-icon\" [style.width.px]=\"iconSize\"></div>\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{chatStarter.text}}</p>\n </div>\n </div>\n </div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host{display:flex}:host:not(:hover):not(.last-message) .sq-chat-message-actions{visibility:hidden}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:table;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-content ::ng-deep ul,.message-content ::ng-deep ol{display:flex;flex-direction:column;gap:.5rem;padding-right:2rem;margin-left:0;margin-right:0;padding-left:40px;unicode-bidi:-webkit-isolate;unicode-bidi:isolate;list-style:disc}.message-content ::ng-deep p:not(:first-child){margin-top:.5rem}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-connection-error .message-content{background:var(--ast-error-bg, rgba(249, 58, 55, .2))}.message-search-warning .message-content{background:var(--ast-warning-bg, #fff1b8);color:var(--ast-message-reference-color, inherit)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.message-user .message-content p{white-space:pre-line}.message-suggestion .message-content{background:var(--ast-input-bg, #F8F8F8);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500));transition:background-color .5s ease,color .5s ease}.message-suggestion .message-content:hover{background:var(--ast-primary-bg, #f2f8fe);color:var(--ast-primary-color, #005DA7)}.message-suggestion .message-content p{white-space:pre-line}.message-suggestion .suggested-action{display:flex;cursor:pointer}.message-suggestion .suggested-action+.suggested-action{margin-top:var(--ast-size-2, .5rem)}.chat-starter{position:absolute}.sq-chat-message-actions{position:absolute;bottom:calc(0rem - var(--ast-size-3, .75rem));display:flex;z-index:999}.sq-chat-message-actions button{font-size:.75rem;color:var(--ast-action-buttons-color, #212529)}.sq-chat-message-actions button:hover{color:var(--ast-action-buttons-hover-color, var(--ast-primary-color, #005DA7))}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}.connection-error{height:var(--sq-size);width:var(--sq-size);color:var(--ast-error-color, rgba(249, 58, 55, .7))}.search-warning{height:var(--sq-size);width:var(--sq-size);color:var(--ast-warning-color, #fed86f)}.step-success{color:var(--ast-primary-color, #005DA7)}.step-ongoing{color:var(--ast-secondary-color, #FF732E)}.step-error{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.bounce{animation:bounce 2s ease}@keyframes bounce{10%{transform:translateY(0)}20%{transform:translateY(-15%)}30%{transform:translateY(0)}35%{transform:translateY(-7%)}37%{transform:translateY(0)}39%{transform:translateY(-3%)}40%{transform:translateY(0)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }, { kind: "ngmodule", type: CollapseModule }, { kind: "component", type: i5.Collapse, selector: "sq-collapse", inputs: ["collapsed"] }, { kind: "ngmodule", type: RemarkModule }, { kind: "component", type: i6.RemarkComponent, selector: "remark", inputs: ["markdown", "processor", "debug"] }, { kind: "directive", type: i6.RemarkTemplateDirective, selector: "[remarkTemplate]", inputs: ["remarkTemplate"] }, { kind: "component", type: InitialsAvatarComponent, selector: "sq-initials-avatar", inputs: ["fullName", "size"] }, { kind: "component", type: ChatReferenceComponent, selector: "sq-chat-reference", inputs: ["reference", "attachment", "partId"], outputs: ["openDocument", "openPreview"] }, { kind: "component", type: ChartComponent, selector: "sq-assistant-chart", inputs: ["rawChartData"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1551
1698
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
1552
1699
|
type: Component,
|
|
1553
1700
|
args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
|
|
1554
|
-
InitialsAvatarComponent, ChatReferenceComponent, ChartComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <ng-container [ngSwitch]=\"message?.role\">\n <!-- For 'assistant' -->\n <i *ngSwitchCase=\"'assistant'\" [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <!-- For 'user' -->\n <ng-container *ngSwitchCase=\"'user'\">\n <i *ngIf=\"!!userMessageIcon; else initialsAvatar\" [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\n <!-- For 'connection-error' -->\n <ng-container *ngSwitchCase=\"'connection-error'\">\n <i *ngIf=\"!!connectionErrorMessageIcon; else defaultErrorIcon\" [ngClass]=\"connectionErrorMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultErrorIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"connection-error\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\n <path fill=\"currentColor\" d=\"M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zM256 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n <!-- For 'search-warning' -->\n <ng-container *ngSwitchCase=\"'search-warning'\">\n <i *ngIf=\"!!searchWarningMessageIcon; else defaultWarningIcon\" [ngClass]=\"searchWarningMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultWarningIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"search-warning\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\n <path fill=\"currentColor\" d=\"M272 384c9.6-31.9 29.5-59.1 49.2-86.2c0 0 0 0 0 0c5.2-7.1 10.4-14.2 15.4-21.4c19.8-28.5 31.4-63 31.4-100.3C368 78.8 289.2 0 192 0S16 78.8 16 176c0 37.3 11.6 71.9 31.4 100.3c5 7.2 10.2 14.3 15.4 21.4c0 0 0 0 0 0c19.8 27.1 39.7 54.4 49.2 86.2l160 0zM192 512c44.2 0 80-35.8 80-80l0-16-160 0 0 16c0 44.2 35.8 80 80 80zm0-448c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM160 288a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n </ng-container>\n\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-fw fa-spin fa-circle-notch\" *ngIf=\"!step.done\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\">: {{step.content}}</span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <div *ngIf=\"message?.role === 'assistant' && message.messageType === 'CHART'\">\n <sq-assistant-chart [rawChartData]=\"message.content\"></sq-assistant-chart>\n </div>\n\n <remark *ngIf=\"(message?.role === 'assistant' && message.messageType === 'MARKDOWN') || message?.role === 'connection-error' || message?.role === 'search-warning'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}\n </a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyCode(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n <ng-template remarkTemplate=\"link\" let-node>\n <a [href]=\"node.url\" target=\"_blank\" rel=\"noopener noreferrer\">{{getLinkText(node)}}</a>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message?.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference\n [class.expanded]=\"attachment.$expanded\"\n [attachment]=\"attachment\"\n [reference]=\"reference\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (openDocument)=\"openOriginalAttachment($event)\">\n </sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-actions\" *ngIf=\"message\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\" (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy text\" (click)=\"copyMessage(message)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\" (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n <button class=\"btn btn-sm\" [class.bounce]=\"liked\" *ngIf=\"canLike\" sqTooltip=\"Like the answer\" (click)=\"like.emit(message); liked = true;\">\n <i class=\"far fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm bounce\" [class.bounce]=\"disliked\" *ngIf=\"canDislike\" sqTooltip=\"Report an issue\" (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canDebug && !!message.additionalProperties.$debug && message.additionalProperties.$debug?.length > 0\" sqTooltip=\"Show Log Information\" (click)=\"debug.emit(message);\">\n <i class=\"far fa-list-alt\"></i>\n </button>\n </div>\n\n <!-- List of suggested actions, if any -->\n <div *ngIf=\"suggestedActions\" class=\"mt-2 message-suggestion\">\n <div class=\"suggested-action\" *ngFor=\"let suggestedAction of suggestedActions\" (click)=\"suggestAction.emit(suggestedAction)\">\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{suggestedAction.content}}</p>\n </div>\n </div>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference\n *ngIf=\"!hiddenTooltip\"\n class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openAttachmentPreview($event, ref.$partId)\"\n (openDocument)=\"openOriginalAttachment($event, ref.$partId)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host{display:flex}:host:not(:hover):not(.last-message) .sq-chat-message-actions{visibility:hidden}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:table;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-content ::ng-deep ul,.message-content ::ng-deep ol{display:flex;flex-direction:column;gap:.5rem;padding-right:2rem;margin-left:0;margin-right:0;padding-left:40px;unicode-bidi:-webkit-isolate;unicode-bidi:isolate;list-style:disc}.message-content ::ng-deep p:not(:first-child){margin-top:.5rem}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-connection-error .message-content{background:var(--ast-error-bg, rgba(249, 58, 55, .2))}.message-search-warning .message-content{background:var(--ast-warning-bg, #fff1b8)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.message-user .message-content p{white-space:pre-line}.message-suggestion .message-content{background:var(--ast-input-bg, #F8F8F8);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500));transition:background-color .5s ease,color .5s ease}.message-suggestion .message-content:hover{background:var(--ast-primary-bg, #f2f8fe);color:var(--ast-primary-color, #005DA7)}.message-suggestion .message-content p{white-space:pre-line}.message-suggestion .suggested-action{cursor:pointer}.message-suggestion .suggested-action+.suggested-action{margin-top:var(--ast-size-2, .5rem)}.sq-chat-message-actions{position:absolute;bottom:calc(0rem - var(--ast-size-3, .75rem));display:flex;z-index:999}.sq-chat-message-actions button{font-size:.75rem}.sq-chat-message-actions button:hover{color:var(--ast-primary-color, #005DA7)}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}.connection-error{height:var(--sq-size);width:var(--sq-size);color:var(--ast-error-color, rgba(249, 58, 55, .7))}.search-warning{height:var(--sq-size);width:var(--sq-size);color:var(--ast-warning-color, #fed86f)}.bounce{animation:bounce 2s ease}@keyframes bounce{10%{transform:translateY(0)}20%{transform:translateY(-15%)}30%{transform:translateY(0)}35%{transform:translateY(-7%)}37%{transform:translateY(0)}39%{transform:translateY(-3%)}40%{transform:translateY(0)}}\n"] }]
|
|
1701
|
+
InitialsAvatarComponent, ChatReferenceComponent, ChartComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <ng-container [ngSwitch]=\"message?.role\">\n <!-- For 'assistant' -->\n <i *ngSwitchCase=\"'assistant'\" [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <!-- For 'user' -->\n <ng-container *ngSwitchCase=\"'user'\">\n <i *ngIf=\"!!userMessageIcon; else initialsAvatar\" [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\n <!-- For 'connection-error' -->\n <ng-container *ngSwitchCase=\"'connection-error'\">\n <i *ngIf=\"!!connectionErrorMessageIcon; else defaultErrorIcon\" [ngClass]=\"connectionErrorMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultErrorIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"connection-error\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 512 512\">\n <path fill=\"currentColor\" d=\"M17.1 292c-12.9-22.3-12.9-49.7 0-72L105.4 67.1c12.9-22.3 36.6-36 62.4-36l176.6 0c25.7 0 49.5 13.7 62.4 36L494.9 220c12.9 22.3 12.9 49.7 0 72L406.6 444.9c-12.9 22.3-36.6 36-62.4 36l-176.6 0c-25.7 0-49.5-13.7-62.4-36L17.1 292zM256 128c-13.3 0-24 10.7-24 24l0 112c0 13.3 10.7 24 24 24s24-10.7 24-24l0-112c0-13.3-10.7-24-24-24zm32 224a32 32 0 1 0 -64 0 32 32 0 1 0 64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n <!-- For 'search-warning' -->\n <ng-container *ngSwitchCase=\"'search-warning'\">\n <i *ngIf=\"!!searchWarningMessageIcon; else defaultWarningIcon\" [ngClass]=\"searchWarningMessageIcon\" [style.--sq-size.px]=\"iconSize\"></i>\n <ng-template #defaultWarningIcon>\n <svg [style.--sq-size.px]=\"iconSize\" class=\"search-warning\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 384 512\">\n <path fill=\"currentColor\" d=\"M272 384c9.6-31.9 29.5-59.1 49.2-86.2c0 0 0 0 0 0c5.2-7.1 10.4-14.2 15.4-21.4c19.8-28.5 31.4-63 31.4-100.3C368 78.8 289.2 0 192 0S16 78.8 16 176c0 37.3 11.6 71.9 31.4 100.3c5 7.2 10.2 14.3 15.4 21.4c0 0 0 0 0 0c19.8 27.1 39.7 54.4 49.2 86.2l160 0zM192 512c44.2 0 80-35.8 80-80l0-16-160 0 0 16c0 44.2 35.8 80 80 80zm0-448c13.3 0 24 10.7 24 24l0 112c0 13.3-10.7 24-24 24s-24-10.7-24-24l0-112c0-13.3 10.7-24 24-24zM160 288a32 32 0 1 1 64 0 32 32 0 1 1 -64 0z\"/>\n </svg>\n </ng-template>\n </ng-container>\n </ng-container>\n\n</span>\n\n<!-- Message body -->\n<div class=\"flex-grow-1\" style=\"min-width: 0;\" [ngClass]=\"'message-'+message.role\">\n\n <!-- Progress steps -->\n <div *ngIf=\"message.additionalProperties.$progress as progress\" class=\"small ms-3 mb-2\">\n <a href=\"#\" (click)=\"collapseProgress = !collapseProgress; false\" class=\"text-muted\">\n View progress\n <i class=\"fas fa-chevron-{{collapseProgress? 'right' : 'down'}}\"></i>\n </a>\n <sq-collapse [collapsed]=\"collapseProgress\">\n <ng-template>\n <ul class=\"list-unstyled\">\n <li *ngFor=\"let step of progress\">\n <i class=\"fas fa-fw fa-check text-success\" *ngIf=\"step.done\"></i>\n <i class=\"fas fa-spinner fa-pulse step-ongoing\" *ngIf=\"!step.done && streaming\"></i>\n <i class=\"fa-solid fa-ban step-error\" *ngIf=\"!step.done && !streaming\"></i>\n <span class=\"ms-2 fw-bold\">{{step.title}}</span>\n <span *ngIf=\"step.content\" [innerHTML]=\"': ' + step.content\"></span>\n </li>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n <!-- Message content -->\n <div class=\"message-content\" *ngIf=\"message.content\">\n\n <div *ngIf=\"message?.role === 'assistant' && message.messageType === 'CHART'\">\n <sq-assistant-chart [rawChartData]=\"message.content\"></sq-assistant-chart>\n </div>\n\n <!-- This section is responsible for customizing the template nodes used in the application.\n Template nodes are predefined structures that serve as blueprints for creating/customizing dynamic content -->\n <remark *ngIf=\"(message?.role === 'assistant' && message.messageType === 'MARKDOWN') || message?.role === 'connection-error' || message?.role === 'search-warning'\" [markdown]=\"message.content\" [processor]=\"processor\">\n\n <ng-template remarkTemplate=\"chat-reference\" let-ref>\n\n <a *ngIf=\"referenceMap.get(ref.refId) as attachment; else staticRefTpl\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}\n </a>\n\n <ng-template #staticRefTpl>\n <span class=\"reference\">{{ref.refId}}</span>\n </ng-template>\n\n </ng-template>\n\n <ng-template remarkTemplate=\"streaming-placeholder\">\n <span class=\"placeholder-glow\" *ngIf=\"streaming\">\n <span class=\"placeholder ms-1\"></span>\n </span>\n </ng-template>\n\n <ng-template remarkTemplate=\"code\" let-node>\n <div class=\"card mb-2\">\n <div class=\"card-header d-flex justify-content-between align-items-center\">\n <span>{{node.lang}}</span>\n <button class=\"btn btn-light btn-sm\" (click)=\"copyCode(node.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-{{node.lang}} my-0 rounded-0 rounded-bottom\"><code class=\"language-{{node.lang}}\">{{node.value}}</code></pre>\n </div>\n </ng-template>\n\n <ng-template remarkTemplate=\"link\" let-node>\n <a [href]=\"node.url\" target=\"_blank\" rel=\"noopener noreferrer\">{{getLinkText(node)}}</a>\n </ng-template>\n\n </remark>\n\n <p *ngIf=\"message?.role === 'user'\">{{message.content}}</p>\n\n <!-- List of reference, if any -->\n <div *ngIf=\"references?.length\" class=\"references\">\n <span class=\"references-title\">References</span> <i class=\"fas references-collapse\" [class.fa-chevron-down]=\"showReferences\" [class.fa-chevron-right]=\"!showReferences\" (click)=\"showReferences=!showReferences\"></i>\n <sq-collapse [collapsed]=\"!showReferences\">\n <ng-template>\n <ul>\n <ng-container *ngFor=\"let reference of references\">\n <li *ngIf=\"referenceMap.get(reference) as attachment\" class=\"text-truncate\">\n <sq-chat-reference\n [class.expanded]=\"attachment.$expanded\"\n [attachment]=\"attachment\"\n [reference]=\"reference\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (openDocument)=\"openOriginalAttachment($event)\">\n </sq-chat-reference>\n </li>\n </ng-container>\n </ul>\n </ng-template>\n </sq-collapse>\n </div>\n\n </div>\n\n <!-- Edit / Regenerate floating actions -->\n <div class=\"sq-chat-message-actions\" *ngIf=\"message\">\n <!-- Common action buttons for \"user\" & \"assistant\" message -->\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy text\" (click)=\"copyMessage(message)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <!-- Action buttons for \"user\" message -->\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\" (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <!-- Action buttons for \"assistant\" message -->\n <button class=\"btn btn-sm\" [class.bounce]=\"liked\" *ngIf=\"canLike\" sqTooltip=\"Like the answer\" (click)=\"like.emit(message); liked = true;\">\n <i class=\"far fa-thumbs-up\"></i>\n </button>\n <button class=\"btn btn-sm bounce\" [class.bounce]=\"disliked\" *ngIf=\"canDislike\" sqTooltip=\"Report an issue\" (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\" (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-alt\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canDebug\" sqTooltip=\"Show Log Information\" (click)=\"debug.emit(message);\">\n <i class=\"far fa-list-alt\"></i>\n </button>\n </div>\n\n <!-- List of suggested actions, if any -->\n <div *ngIf=\"suggestedActions\" class=\"mt-2 message-suggestion\">\n <div class=\"suggested-action\" *ngFor=\"let suggestedAction of suggestedActions\" (click)=\"suggestAction.emit(suggestedAction)\">\n <div class=\"message-icon\" [style.width.px]=\"iconSize\"></div>\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{suggestedAction.content}}</p>\n </div>\n </div>\n </div>\n\n <ng-template #tooltipTpl let-ref>\n <sq-chat-reference\n *ngIf=\"!hiddenTooltip\"\n class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openAttachmentPreview($event, ref.$partId)\"\n (openDocument)=\"openOriginalAttachment($event, ref.$partId)\">\n </sq-chat-reference>\n </ng-template>\n\n</div>\n\n <!-- List of chat starters, if any -->\n <div *ngIf=\"chatStarters?.length\" class=\"mt-2 message-suggestion chat-starter\" [style.bottom.rem]=\"-(3.5*chatStarters!.length)\">\n <div class=\"suggested-action\" *ngFor=\"let chatStarter of chatStarters\" (click)=\"chatStarterClicked.emit(chatStarter)\">\n <div class=\"message-icon\" [style.width.px]=\"iconSize\"></div>\n <div class=\"message-content\">\n <p><i class=\"fas fa-clipboard-question\"></i> {{chatStarter.text}}</p>\n </div>\n </div>\n </div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host{display:flex}:host:not(:hover):not(.last-message) .sq-chat-message-actions{visibility:hidden}.message-content{padding:var(--ast-message-padding, var(--ast-size-3, .75rem));border-radius:var(--ast-message-border-radius, var(--ast-size-4, 1rem));display:inline-block;max-width:100%;overflow-wrap:break-word;word-wrap:break-word;word-break:break-word}.message-content .references{margin-top:var(--ast-size-5, 1.25rem)}.message-content .references ul{border-left:.2rem solid var(--ast-secondary-color, #FF732E);padding-left:var(--ast-size-5, 1.25rem);margin-top:var(--ast-size-2, .5rem)}.message-content .references .references-title{font-weight:var(--font-weight-bold, 500)}.message-content .references .references-collapse{cursor:pointer;margin-left:var(--ast-size-2, .5rem)}.message-content ::ng-deep p:last-child{margin-bottom:0}.message-content ::ng-deep .placeholder-glow .placeholder{animation-duration:.4s;width:12px;height:var(--ast-size-4, 1rem);vertical-align:text-bottom}.message-content ::ng-deep img{max-width:100%}.message-content ::ng-deep table{display:table;border:1px solid;border-color:var(--ast-message-table-border-color, #ccc);border-collapse:collapse;margin:0;padding:0;min-width:100%;overflow-x:auto;table-layout:fixed}.message-content ::ng-deep table tr{background-color:var(--ast-message-table-tr-bg, #f8f8f8);border:1px solid;border-color:var(--ast-message-table-tr-border-color, #ddd);padding:.35em}.message-content ::ng-deep table th,.message-content ::ng-deep table td{padding:.625em;text-align:center}.message-content ::ng-deep table th{font-size:.85em;letter-spacing:.1em;text-transform:uppercase}.message-content ::ng-deep .reference{color:var(--ast-message-reference-color, black)!important}.message-content ::ng-deep ul,.message-content ::ng-deep ol{display:flex;flex-direction:column;gap:.5rem;padding-right:2rem;margin-left:0;margin-right:0;padding-left:40px;unicode-bidi:-webkit-isolate;unicode-bidi:isolate;list-style:disc}.message-content ::ng-deep p:not(:first-child){margin-top:.5rem}.message-assistant .message-content{background:var(--ast-secondary-bg, #FFF8F1)}.message-connection-error .message-content{background:var(--ast-error-bg, rgba(249, 58, 55, .2))}.message-search-warning .message-content{background:var(--ast-warning-bg, #fff1b8);color:var(--ast-message-reference-color, inherit)}.message-user .message-content{background:var(--ast-primary-bg, #f2f8fe);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500))}.message-user .message-content p{white-space:pre-line}.message-suggestion .message-content{background:var(--ast-input-bg, #F8F8F8);font-weight:var(--ast-user-font-weight, var(--font-weight-bold, 500));transition:background-color .5s ease,color .5s ease}.message-suggestion .message-content:hover{background:var(--ast-primary-bg, #f2f8fe);color:var(--ast-primary-color, #005DA7)}.message-suggestion .message-content p{white-space:pre-line}.message-suggestion .suggested-action{display:flex;cursor:pointer}.message-suggestion .suggested-action+.suggested-action{margin-top:var(--ast-size-2, .5rem)}.chat-starter{position:absolute}.sq-chat-message-actions{position:absolute;bottom:calc(0rem - var(--ast-size-3, .75rem));display:flex;z-index:999}.sq-chat-message-actions button{font-size:.75rem;color:var(--ast-action-buttons-color, #212529)}.sq-chat-message-actions button:hover{color:var(--ast-action-buttons-hover-color, var(--ast-primary-color, #005DA7))}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}.connection-error{height:var(--sq-size);width:var(--sq-size);color:var(--ast-error-color, rgba(249, 58, 55, .7))}.search-warning{height:var(--sq-size);width:var(--sq-size);color:var(--ast-warning-color, #fed86f)}.step-success{color:var(--ast-primary-color, #005DA7)}.step-ongoing{color:var(--ast-secondary-color, #FF732E)}.step-error{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.bounce{animation:bounce 2s ease}@keyframes bounce{10%{transform:translateY(0)}20%{transform:translateY(-15%)}30%{transform:translateY(0)}35%{transform:translateY(-7%)}37%{transform:translateY(0)}39%{transform:translateY(-3%)}40%{transform:translateY(0)}}\n"] }]
|
|
1555
1702
|
}], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
|
|
1556
1703
|
type: Input
|
|
1557
1704
|
}], conversation: [{
|
|
1558
1705
|
type: Input
|
|
1559
1706
|
}], suggestedActions: [{
|
|
1560
1707
|
type: Input
|
|
1708
|
+
}], chatStarters: [{
|
|
1709
|
+
type: Input
|
|
1561
1710
|
}], assistantMessageIcon: [{
|
|
1562
1711
|
type: Input
|
|
1563
1712
|
}], userMessageIcon: [{
|
|
@@ -1586,6 +1735,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1586
1735
|
type: Output
|
|
1587
1736
|
}], suggestAction: [{
|
|
1588
1737
|
type: Output
|
|
1738
|
+
}], chatStarterClicked: [{
|
|
1739
|
+
type: Output
|
|
1589
1740
|
}], edit: [{
|
|
1590
1741
|
type: Output
|
|
1591
1742
|
}], copy: [{
|
|
@@ -1732,8 +1883,8 @@ class RestChatService extends ChatService {
|
|
|
1732
1883
|
'text': response.content,
|
|
1733
1884
|
'role': response.role,
|
|
1734
1885
|
'rank': this.chatHistory.length - 1,
|
|
1735
|
-
'generation-tokencount': response.additionalProperties.usageMetrics
|
|
1736
|
-
'prompt-tokencount': response.additionalProperties.usageMetrics
|
|
1886
|
+
'generation-tokencount': response.additionalProperties.usageMetrics?.completionTokenCount,
|
|
1887
|
+
'prompt-tokencount': response.additionalProperties.usageMetrics?.promptTokenCount,
|
|
1737
1888
|
'attachments': response.additionalProperties.$attachment?.map(({ recordId, contextId, parts, type }) => ({
|
|
1738
1889
|
recordId,
|
|
1739
1890
|
contextId,
|
|
@@ -1746,6 +1897,11 @@ class RestChatService extends ChatService {
|
|
|
1746
1897
|
return { history: [...messages, response], executionTime: res.executionTime };
|
|
1747
1898
|
}), finalize(() => this.streaming$.next(false)));
|
|
1748
1899
|
}
|
|
1900
|
+
stopGeneration() {
|
|
1901
|
+
const error = new Error('Not supported in REST');
|
|
1902
|
+
console.error(error);
|
|
1903
|
+
return throwError(() => error);
|
|
1904
|
+
}
|
|
1749
1905
|
listSavedChat() {
|
|
1750
1906
|
if (!this.chatConfig$.value.savedChatSettings.enabled) {
|
|
1751
1907
|
return;
|
|
@@ -1864,10 +2020,10 @@ class TokenProgressBarComponent {
|
|
|
1864
2020
|
}
|
|
1865
2021
|
}
|
|
1866
2022
|
TokenProgressBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: TokenProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1867
|
-
TokenProgressBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: TokenProgressBarComponent, isStandalone: true, selector: "sq-token-progress-bar", inputs: { instanceId: "instanceId" }, ngImport: i0, template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
|
|
2023
|
+
TokenProgressBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: TokenProgressBarComponent, isStandalone: true, selector: "sq-token-progress-bar", inputs: { instanceId: "instanceId" }, ngImport: i0, template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
|
|
1868
2024
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: TokenProgressBarComponent, decorators: [{
|
|
1869
2025
|
type: Component,
|
|
1870
|
-
args: [{ selector: 'sq-token-progress-bar', standalone: true, imports: [CommonModule, UtilsModule], template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"] }]
|
|
2026
|
+
args: [{ selector: 'sq-token-progress-bar', standalone: true, imports: [CommonModule, UtilsModule], template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"] }]
|
|
1871
2027
|
}], propDecorators: { instanceId: [{
|
|
1872
2028
|
type: Input
|
|
1873
2029
|
}] } });
|
|
@@ -1896,10 +2052,10 @@ class DebugMessageComponent {
|
|
|
1896
2052
|
}
|
|
1897
2053
|
}
|
|
1898
2054
|
DebugMessageComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DebugMessageComponent, deps: [{ token: i2$1.UIService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1899
|
-
DebugMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: DebugMessageComponent, isStandalone: true, selector: "sq-debug-message", inputs: { data: "data", level: "level", parentColor: "parentColor" }, ngImport: i0, template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue>{{ item.data.value }}</ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name\" [class.
|
|
2055
|
+
DebugMessageComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: DebugMessageComponent, isStandalone: true, selector: "sq-debug-message", inputs: { data: "data", level: "level", parentColor: "parentColor" }, ngImport: i0, template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue><div class=\"data-value\">{{ item.data.value }}</div></ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name w-100\" [class.fw-bold]=\"level === 0\" (click)=\"item.expanded=!item.expanded\">\n <i class=\"fas\" [class.fa-chevron-up]=\"item.expanded\" [class.fa-chevron-down]=\"!item.expanded\"></i>\n {{ item.name }}\n </div>\n <div class=\"list-items w-100\" *ngIf=\"item.expanded\">\n <sq-debug-message [data]=\"item.items\" [level]=\"level + 1\" [parentColor]=\"getRowClass(item, i)\"></sq-debug-message>\n </div>\n </div>\n </ng-container>\n</div>\n", styles: [".table-root{display:flex;flex-direction:column;border:1px solid #ccc;width:100%;border-spacing:0}.table-row{display:flex;width:100%}.list-name{width:15%;cursor:pointer}.list-items{width:85%}.kv-key,.kv-value,.list-name{padding:8px;border:1px solid #ccc;box-sizing:border-box;word-wrap:break-word}.kv-key{width:20%}.kv-value{width:80%}.kv-value .data-value{white-space:pre-line}.kv-object,.list-object{display:flex;flex:1}.list-object{flex-direction:column}.row-even{background-color:#fff}.row-odd{background-color:#f2f8fe}.row-error{background-color:#f08080}.table-row:not(:last-child){border-bottom:1px solid #ccc}.kv-key:last-child,.kv-value:last-child,.list-name:last-child{border-right:none}\n"], dependencies: [{ kind: "component", type: DebugMessageComponent, selector: "sq-debug-message", inputs: ["data", "level", "parentColor"] }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] });
|
|
1900
2056
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DebugMessageComponent, decorators: [{
|
|
1901
2057
|
type: Component,
|
|
1902
|
-
args: [{ selector: "sq-debug-message", standalone: true, imports: [CommonModule], template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue>{{ item.data.value }}</ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name\" [class.
|
|
2058
|
+
args: [{ selector: "sq-debug-message", standalone: true, imports: [CommonModule], template: "<div *ngIf=\"data\" class=\"table-root\">\n <ng-container *ngFor=\"let item of data; let i = index\">\n <div *ngIf=\"item.type === 'KV'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row kv-object\">\n <div class=\"kv-key\">{{ item.data.key }}</div>\n <div class=\"kv-value\">\n <ng-container *ngIf=\"isObject(item.data.value); else normalValue\">\n <div class=\"card mb-2\">\n <div class=\"card-header\">\n <button class=\"btn btn-light btn-sm\" (click)=\"copyToClipboard(item.data.value)\"><i class=\"far fa-fw fa-clipboard\"></i> Copy code</button>\n </div>\n <pre class=\"language-json my-0 rounded-0 rounded-bottom\"><code class=\"language-json\">{{ item.data.value | json }}</code></pre>\n </div>\n </ng-container>\n <ng-template #normalValue><div class=\"data-value\">{{ item.data.value }}</div></ng-template>\n </div>\n </div>\n <div *ngIf=\"item.type === 'LIST'\" [ngClass]=\"getRowClass(item, i)\" class=\"table-row list-object\">\n <div class=\"list-name w-100\" [class.fw-bold]=\"level === 0\" (click)=\"item.expanded=!item.expanded\">\n <i class=\"fas\" [class.fa-chevron-up]=\"item.expanded\" [class.fa-chevron-down]=\"!item.expanded\"></i>\n {{ item.name }}\n </div>\n <div class=\"list-items w-100\" *ngIf=\"item.expanded\">\n <sq-debug-message [data]=\"item.items\" [level]=\"level + 1\" [parentColor]=\"getRowClass(item, i)\"></sq-debug-message>\n </div>\n </div>\n </ng-container>\n</div>\n", styles: [".table-root{display:flex;flex-direction:column;border:1px solid #ccc;width:100%;border-spacing:0}.table-row{display:flex;width:100%}.list-name{width:15%;cursor:pointer}.list-items{width:85%}.kv-key,.kv-value,.list-name{padding:8px;border:1px solid #ccc;box-sizing:border-box;word-wrap:break-word}.kv-key{width:20%}.kv-value{width:80%}.kv-value .data-value{white-space:pre-line}.kv-object,.list-object{display:flex;flex:1}.list-object{flex-direction:column}.row-even{background-color:#fff}.row-odd{background-color:#f2f8fe}.row-error{background-color:#f08080}.table-row:not(:last-child){border-bottom:1px solid #ccc}.kv-key:last-child,.kv-value:last-child,.list-name:last-child{border-right:none}\n"] }]
|
|
1903
2059
|
}], ctorParameters: function () { return [{ type: i2$1.UIService }]; }, propDecorators: { data: [{
|
|
1904
2060
|
type: Input
|
|
1905
2061
|
}], level: [{
|
|
@@ -1927,6 +2083,8 @@ class ChatComponent extends AbstractFacet {
|
|
|
1927
2083
|
this.messageHandlers = new Map();
|
|
1928
2084
|
/** When the assistant answer a user question, automatically scroll down to the bottom of the discussion */
|
|
1929
2085
|
this.automaticScrollToLastResponse = false;
|
|
2086
|
+
/** When the assistant answer a user question, automatically focus to the chat input */
|
|
2087
|
+
this.focusAfterResponse = false;
|
|
1930
2088
|
/** Icon to use for the assistant messages */
|
|
1931
2089
|
this.assistantMessageIcon = 'sq-sinequa';
|
|
1932
2090
|
/** Event emitter triggered once the signalR connection is established */
|
|
@@ -1943,10 +2101,17 @@ class ChatComponent extends AbstractFacet {
|
|
|
1943
2101
|
this.openPreview = new EventEmitter();
|
|
1944
2102
|
/** Event emitter triggered when the user clicks on a suggested action */
|
|
1945
2103
|
this.suggestAction = new EventEmitter();
|
|
2104
|
+
/** Event emitter triggered when the user clicks on a chat starter */
|
|
2105
|
+
this.chatStarter = new EventEmitter();
|
|
1946
2106
|
this.messages$ = new BehaviorSubject(undefined);
|
|
1947
2107
|
this.question = '';
|
|
1948
2108
|
this._actions = [];
|
|
1949
|
-
this.
|
|
2109
|
+
this._resetChatAction = new Action({
|
|
2110
|
+
icon: 'fas fa-sync',
|
|
2111
|
+
title: "Reset chat",
|
|
2112
|
+
action: () => this.newChat()
|
|
2113
|
+
});
|
|
2114
|
+
this._sub = new Subscription();
|
|
1950
2115
|
this.changes$ = new BehaviorSubject(undefined);
|
|
1951
2116
|
this.firstChangesHandled = false;
|
|
1952
2117
|
this.isAtBottom = true;
|
|
@@ -1964,16 +2129,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
1964
2129
|
'Other'
|
|
1965
2130
|
];
|
|
1966
2131
|
this.issueType = '';
|
|
1967
|
-
this.
|
|
2132
|
+
this.reportType = 'dislike';
|
|
2133
|
+
this.showReport = false;
|
|
1968
2134
|
this.showDebugMessages = false;
|
|
1969
|
-
this.
|
|
1970
|
-
|
|
1971
|
-
title: 'Reset chat',
|
|
1972
|
-
action: () => this.newChat()
|
|
1973
|
-
}));
|
|
2135
|
+
this._reloadSubscription = undefined;
|
|
2136
|
+
this._actions.push(this._resetChatAction);
|
|
1974
2137
|
}
|
|
1975
2138
|
ngOnInit() {
|
|
1976
|
-
this.
|
|
2139
|
+
this._sub.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), map(_ => this.chatService.initChatConfig()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig), switchMap(_ => this.chatService.init()), switchMap(_ => this.chatService.initProcess$), filter(success => !!success), tap(_ => {
|
|
1977
2140
|
if (this.chatService instanceof WebSocketChatService) {
|
|
1978
2141
|
this.connection.emit(this.chatService.connection);
|
|
1979
2142
|
}
|
|
@@ -1997,6 +2160,12 @@ class ChatComponent extends AbstractFacet {
|
|
|
1997
2160
|
throw error;
|
|
1998
2161
|
}
|
|
1999
2162
|
})).subscribe());
|
|
2163
|
+
this._sub.add(combineLatest([
|
|
2164
|
+
this.chatService.streaming$,
|
|
2165
|
+
this.chatService.stoppingGeneration$
|
|
2166
|
+
]).pipe(map(([streaming, stoppingGeneration]) => !!(streaming || stoppingGeneration))).subscribe((result) => {
|
|
2167
|
+
this._resetChatAction.disabled = result;
|
|
2168
|
+
}));
|
|
2000
2169
|
}
|
|
2001
2170
|
ngOnChanges(changes) {
|
|
2002
2171
|
this.changes$.next(changes);
|
|
@@ -2005,12 +2174,16 @@ class ChatComponent extends AbstractFacet {
|
|
|
2005
2174
|
}
|
|
2006
2175
|
}
|
|
2007
2176
|
ngOnDestroy() {
|
|
2008
|
-
this.
|
|
2009
|
-
this.
|
|
2177
|
+
this._sub.unsubscribe();
|
|
2178
|
+
this._dataSubscription?.unsubscribe();
|
|
2179
|
+
this._reloadSubscription?.unsubscribe();
|
|
2010
2180
|
}
|
|
2011
2181
|
get isAdmin() {
|
|
2012
2182
|
return this.principalService.principal?.isAdministrator || false;
|
|
2013
2183
|
}
|
|
2184
|
+
get visibleMessagesCount() {
|
|
2185
|
+
return this.messages$.value?.filter(m => m.additionalProperties.display).length || 0;
|
|
2186
|
+
}
|
|
2014
2187
|
/**
|
|
2015
2188
|
* Instantiate the chat service based on the provided @input protocol
|
|
2016
2189
|
* This chat service instance will then be stored in the instanceManagerService with provided @input instanceId as a key
|
|
@@ -2064,9 +2237,61 @@ class ChatComponent extends AbstractFacet {
|
|
|
2064
2237
|
*/
|
|
2065
2238
|
if (this.firstChangesHandled && changes?.query && this.config.modeSettings.initialization.event === 'Query') {
|
|
2066
2239
|
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(this._previousQuery, this.query) : true) {
|
|
2067
|
-
this.
|
|
2240
|
+
if (!!this.chatService.stoppingGeneration$.value) {
|
|
2241
|
+
if (!this._reloadSubscription) {
|
|
2242
|
+
// Create a subscription to wait for both streaming$ and stoppingGeneration$ to be false
|
|
2243
|
+
this._reloadSubscription = combineLatest([
|
|
2244
|
+
this.chatService.streaming$,
|
|
2245
|
+
this.chatService.stoppingGeneration$
|
|
2246
|
+
])
|
|
2247
|
+
.pipe(filter(([streaming, stopping]) => !streaming && !stopping), // Wait until both are false
|
|
2248
|
+
take(1) // Complete after the first match
|
|
2249
|
+
).subscribe(() => {
|
|
2250
|
+
// Execute the reload after the query change
|
|
2251
|
+
this._triggerReloadAfterQueryChange();
|
|
2252
|
+
// Update _previousQuery with the current query
|
|
2253
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2254
|
+
// Clean up subscription and reset its value
|
|
2255
|
+
this._reloadSubscription = undefined;
|
|
2256
|
+
});
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
else if (!!this.chatService.streaming$.value) {
|
|
2260
|
+
if (!this._reloadSubscription) {
|
|
2261
|
+
this._reloadSubscription = this.chatService.stopGeneration()
|
|
2262
|
+
.subscribe({
|
|
2263
|
+
next: () => { },
|
|
2264
|
+
error: () => {
|
|
2265
|
+
// Clean up subscription and reset its value
|
|
2266
|
+
this._reloadSubscription?.unsubscribe();
|
|
2267
|
+
this._reloadSubscription = undefined;
|
|
2268
|
+
},
|
|
2269
|
+
complete: () => {
|
|
2270
|
+
// Wait for the ongoing fetch to complete, then trigger the reload
|
|
2271
|
+
this.chatService.streaming$.pipe(filter((streaming) => !streaming), take(1)).subscribe(() => {
|
|
2272
|
+
// Execute the reload after the query change
|
|
2273
|
+
this._triggerReloadAfterQueryChange();
|
|
2274
|
+
// Update _previousQuery with the current query
|
|
2275
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2276
|
+
// Clean up subscription and reset its value
|
|
2277
|
+
this._reloadSubscription.unsubscribe();
|
|
2278
|
+
this._reloadSubscription = undefined;
|
|
2279
|
+
});
|
|
2280
|
+
}
|
|
2281
|
+
});
|
|
2282
|
+
}
|
|
2283
|
+
}
|
|
2284
|
+
else {
|
|
2285
|
+
// Execute the reload after the query change
|
|
2286
|
+
this._triggerReloadAfterQueryChange();
|
|
2287
|
+
// Update _previousQuery with the current query
|
|
2288
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
else {
|
|
2292
|
+
// Update _previousQuery with the current query
|
|
2293
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2068
2294
|
}
|
|
2069
|
-
this._previousQuery = JSON.parse(JSON.stringify(this.query)); // Update the previous query
|
|
2070
2295
|
}
|
|
2071
2296
|
}
|
|
2072
2297
|
_triggerReloadAfterQueryChange() {
|
|
@@ -2078,7 +2303,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
2078
2303
|
this._handleQueryMode(systemMsg, userMsg);
|
|
2079
2304
|
}
|
|
2080
2305
|
_addScrollListener() {
|
|
2081
|
-
this.
|
|
2306
|
+
this._sub.add(merge(this.loading$, this.messages$, this.chatService.streaming$, fromEvent(this.messageList.nativeElement, 'scroll')).subscribe(() => {
|
|
2082
2307
|
this.isAtBottom = this._toggleScrollButtonVisibility();
|
|
2083
2308
|
this.cdr.detectChanges();
|
|
2084
2309
|
}));
|
|
@@ -2088,14 +2313,18 @@ class ChatComponent extends AbstractFacet {
|
|
|
2088
2313
|
this.cdr.detectChanges();
|
|
2089
2314
|
}
|
|
2090
2315
|
submitQuestion() {
|
|
2316
|
+
if (this.chatService.streaming$.value) {
|
|
2317
|
+
return;
|
|
2318
|
+
}
|
|
2091
2319
|
if (this.question.trim() && this.messages$.value && this.chatService.chatHistory) {
|
|
2092
2320
|
// When the user submits a question, if the user is editing a previous message, remove all subsequent messages from the chat history
|
|
2093
2321
|
if (this.messageToEdit !== undefined) {
|
|
2094
2322
|
// Update the messages in the UI
|
|
2095
2323
|
this.messages$.next(this.messages$.value.slice(0, this.messageToEdit));
|
|
2096
2324
|
// Update the raw messages in the chat history which is the clean version used to make the next request
|
|
2097
|
-
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, this.
|
|
2325
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, this.remappedMessageToEdit);
|
|
2098
2326
|
this.messageToEdit = undefined;
|
|
2327
|
+
this.remappedMessageToEdit = undefined;
|
|
2099
2328
|
}
|
|
2100
2329
|
// Remove the search warning message if exists
|
|
2101
2330
|
if (this.chatService.chatHistory.at(-1)?.role === 'search-warning') {
|
|
@@ -2126,8 +2355,8 @@ class ChatComponent extends AbstractFacet {
|
|
|
2126
2355
|
this.cdr.detectChanges();
|
|
2127
2356
|
if (this.isConnected) {
|
|
2128
2357
|
this.loading$.next(true);
|
|
2129
|
-
this.
|
|
2130
|
-
this.
|
|
2358
|
+
this._dataSubscription?.unsubscribe();
|
|
2359
|
+
this._dataSubscription = this.chatService.fetch(messages, this.query)
|
|
2131
2360
|
.subscribe({
|
|
2132
2361
|
next: res => this.updateData(res.history),
|
|
2133
2362
|
error: () => {
|
|
@@ -2139,6 +2368,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
2139
2368
|
this.terminateFetch();
|
|
2140
2369
|
},
|
|
2141
2370
|
complete: () => {
|
|
2371
|
+
// Remove the last message if it's an empty message
|
|
2372
|
+
// This is due to the manner in which the chat service handles consecutive messages
|
|
2373
|
+
const lastMessage = this.messages$.value?.at(-1);
|
|
2374
|
+
if (lastMessage?.role === 'assistant' && lastMessage?.content === ""
|
|
2375
|
+
&& !lastMessage?.additionalProperties?.$attachment && !lastMessage?.additionalProperties?.$progress
|
|
2376
|
+
&& !lastMessage?.additionalProperties?.$debug && !lastMessage?.additionalProperties?.$suggestedAction) {
|
|
2377
|
+
this.messages$.next(this.messages$.value?.slice(0, -1));
|
|
2378
|
+
}
|
|
2142
2379
|
this.terminateFetch();
|
|
2143
2380
|
}
|
|
2144
2381
|
});
|
|
@@ -2162,10 +2399,21 @@ class ChatComponent extends AbstractFacet {
|
|
|
2162
2399
|
if (this.chatService instanceof WebSocketChatService) {
|
|
2163
2400
|
// A one-time listener for reconnected event
|
|
2164
2401
|
const onReconnectedHandler = () => {
|
|
2402
|
+
// Get the messages without the last one (the connection error message)
|
|
2165
2403
|
const messages = this.messages$.value.slice(0, -1);
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2404
|
+
// Find the last "user" message in the messages list
|
|
2405
|
+
let index = messages.length - 1;
|
|
2406
|
+
while (index >= 0 && messages[index].role !== 'user') {
|
|
2407
|
+
index--;
|
|
2408
|
+
}
|
|
2409
|
+
// If a user message is found (and it should always be the case), remove all subsequent messages from the chat history
|
|
2410
|
+
// Update the messages in the UI
|
|
2411
|
+
// and fetch the answer from the assistant
|
|
2412
|
+
if (index >= 0) {
|
|
2413
|
+
this.messages$.next(this.messages$.value.slice(0, index + 1));
|
|
2414
|
+
const remappedIndex = this._remapIndexInChatHistory(index);
|
|
2415
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, remappedIndex + 1);
|
|
2416
|
+
this.fetch(this.chatService.chatHistory);
|
|
2169
2417
|
}
|
|
2170
2418
|
this.retrialAttempts = undefined; // Reset the number of retrial attempts
|
|
2171
2419
|
/**
|
|
@@ -2244,6 +2492,9 @@ class ChatComponent extends AbstractFacet {
|
|
|
2244
2492
|
* If the savedChat feature is enabled, the list of saved chats will be refreshed
|
|
2245
2493
|
*/
|
|
2246
2494
|
newChat() {
|
|
2495
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2496
|
+
return;
|
|
2497
|
+
}
|
|
2247
2498
|
this.chatService.setSavedChatId(undefined); // Reset the savedChatId
|
|
2248
2499
|
this.chatService.generateChatId(); // Generate a new chatId
|
|
2249
2500
|
this.chatService.listSavedChat(); // Refresh the list of saved chats
|
|
@@ -2344,14 +2595,22 @@ class ChatComponent extends AbstractFacet {
|
|
|
2344
2595
|
}
|
|
2345
2596
|
onLoadChat() {
|
|
2346
2597
|
this.loading$.next(true);
|
|
2347
|
-
this.
|
|
2598
|
+
this._sub.add(this.chatService.loadSavedChat$
|
|
2348
2599
|
.pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.history, savedChatHistory.id))).subscribe());
|
|
2349
2600
|
}
|
|
2601
|
+
stopGeneration() {
|
|
2602
|
+
this.chatService.stopGeneration().subscribe(() => this.terminateFetch());
|
|
2603
|
+
}
|
|
2350
2604
|
terminateFetch() {
|
|
2351
|
-
this.
|
|
2352
|
-
this.
|
|
2605
|
+
this._dataSubscription?.unsubscribe();
|
|
2606
|
+
this._dataSubscription = undefined;
|
|
2353
2607
|
this.loading$.next(false);
|
|
2354
2608
|
this.cdr.detectChanges();
|
|
2609
|
+
if (this.focusAfterResponse) {
|
|
2610
|
+
setTimeout(() => {
|
|
2611
|
+
this.questionInput?.nativeElement.focus();
|
|
2612
|
+
});
|
|
2613
|
+
}
|
|
2355
2614
|
}
|
|
2356
2615
|
/**
|
|
2357
2616
|
* Copy a previous user message of the chat history to the chat user input.
|
|
@@ -2362,15 +2621,18 @@ class ChatComponent extends AbstractFacet {
|
|
|
2362
2621
|
*/
|
|
2363
2622
|
editMessage(index) {
|
|
2364
2623
|
this.messageToEdit = index;
|
|
2365
|
-
this.
|
|
2366
|
-
this.chatService.
|
|
2624
|
+
this.remappedMessageToEdit = this._remapIndexInChatHistory(index);
|
|
2625
|
+
this.question = this.chatService.chatHistory[this._remapIndexInChatHistory(index)].content;
|
|
2626
|
+
this.chatService.generateAuditEvent('edit.click', { 'rank': this._remapIndexInChatHistory(index) });
|
|
2367
2627
|
}
|
|
2368
2628
|
/**
|
|
2369
2629
|
* Copy a previous assistant message of the chat history to the clipboard.
|
|
2370
2630
|
* @param index The index of the assistant's message to edit
|
|
2371
2631
|
*/
|
|
2372
2632
|
copyMessage(index) {
|
|
2373
|
-
|
|
2633
|
+
// Remap the index in the chat history
|
|
2634
|
+
const idx = this._remapIndexInChatHistory(index);
|
|
2635
|
+
this.chatService.generateAuditEvent('copy.click', { 'rank': idx });
|
|
2374
2636
|
}
|
|
2375
2637
|
/**
|
|
2376
2638
|
* Starting from the provided index, remove all subsequent messages from the chat history and the UI accordingly.
|
|
@@ -2378,13 +2640,45 @@ class ChatComponent extends AbstractFacet {
|
|
|
2378
2640
|
* @param index The index of the assistant's message to regenerate
|
|
2379
2641
|
*/
|
|
2380
2642
|
regenerateMessage(index) {
|
|
2381
|
-
//
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2643
|
+
// Update the messages in the UI by removing all subsequent 'assistant' messages starting from the provided index until the first previous 'user' message
|
|
2644
|
+
let i = index;
|
|
2645
|
+
while (i >= 0 && (this.messages$.value)[i].role !== 'user') {
|
|
2646
|
+
i--;
|
|
2647
|
+
}
|
|
2648
|
+
// It should always be the case that i > 0
|
|
2649
|
+
if (i >= 0) {
|
|
2650
|
+
this.messages$.next(this.messages$.value.slice(0, i + 1));
|
|
2651
|
+
// Remap the index of this found first previous 'user' message in the chat history
|
|
2652
|
+
const idx = this._remapIndexInChatHistory(i);
|
|
2653
|
+
// Define and Update the chat history based on which the assistant will generate a new answer
|
|
2654
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, idx + 1);
|
|
2655
|
+
// Fetch the answer
|
|
2656
|
+
this.fetch(this.chatService.chatHistory);
|
|
2657
|
+
this.chatService.generateAuditEvent('regenerate.click', { 'rank': idx });
|
|
2658
|
+
}
|
|
2659
|
+
}
|
|
2660
|
+
/**
|
|
2661
|
+
* Remaps the index in the chat history.
|
|
2662
|
+
* The chat history is a list of messages where some messages can be hidden (display set to false).
|
|
2663
|
+
* The index provided as input is the index of the message in the chat history displayed in the UI.
|
|
2664
|
+
* This function should be removed once the backend is updated to add the ids of the messages in the chat history
|
|
2665
|
+
* @param index - The index to be remapped.
|
|
2666
|
+
*/
|
|
2667
|
+
_remapIndexInChatHistory(index) {
|
|
2668
|
+
// a copy of the chat history is created to avoid modifying the original chat history. Additionally, a rank is giving to each message.
|
|
2669
|
+
const history = this.chatService.chatHistory.slice().map((message, idx) => {
|
|
2670
|
+
return { ...message, additionalProperties: { ...message.additionalProperties, rank: idx } };
|
|
2671
|
+
});
|
|
2672
|
+
// Count the number of hidden messages in messages$ before the provided index
|
|
2673
|
+
// This is mandatory to get the correct rank of the message in the chat history
|
|
2674
|
+
// Since some hidden messages (like 'system' messages) are not displayed in the UI but have been counted in the provided index
|
|
2675
|
+
const numberOfHiddenMessagesInMessages$BeforeIndex = this.messages$.value.slice(0, index).filter(message => !message.additionalProperties.display).length;
|
|
2676
|
+
// remove all messages that have display set to false
|
|
2677
|
+
// this is mandatory since at the point of time when the assistant answers a question,
|
|
2678
|
+
// it might have some hidden messages (for example contextMessages) that are available in the chat history but don't figure in messages$ unless a new question is asked
|
|
2679
|
+
const filteredHistory = history.filter(message => message.additionalProperties.display);
|
|
2680
|
+
// return the index of the message in the filtered history
|
|
2681
|
+
return filteredHistory[index - numberOfHiddenMessagesInMessages$BeforeIndex].additionalProperties.rank;
|
|
2388
2682
|
}
|
|
2389
2683
|
onKeyUp(event) {
|
|
2390
2684
|
switch (event.key) {
|
|
@@ -2415,43 +2709,59 @@ class ChatComponent extends AbstractFacet {
|
|
|
2415
2709
|
}
|
|
2416
2710
|
/**
|
|
2417
2711
|
* Send a "like" event on clicking on the thumb-up icon of an assistant's message
|
|
2712
|
+
* @param message The assistant message to like
|
|
2418
2713
|
* @param rank The rank of the message to like
|
|
2419
2714
|
*/
|
|
2420
|
-
onLike(rank) {
|
|
2421
|
-
|
|
2715
|
+
onLike(message, rank) {
|
|
2716
|
+
// Remap the index in the chat history
|
|
2717
|
+
const idx = this._remapIndexInChatHistory(rank);
|
|
2718
|
+
this.chatService.generateAuditEvent('thumb-up.click', { rank: idx });
|
|
2719
|
+
this.reportType = 'like';
|
|
2720
|
+
this.messageToReport = message;
|
|
2721
|
+
this.reportComment = undefined;
|
|
2722
|
+
this.reportRank = rank;
|
|
2723
|
+
this.showReport = true;
|
|
2422
2724
|
}
|
|
2423
2725
|
/**
|
|
2424
2726
|
* Send a "dislike" event on clicking on the thumb-down icon of an assistant's message.
|
|
2425
2727
|
* It also opens the issue reporting dialog.
|
|
2426
2728
|
* @param message The assistant message to dislike
|
|
2427
|
-
* @param
|
|
2729
|
+
* @param index The rank of the message to dislike
|
|
2428
2730
|
*/
|
|
2429
2731
|
onDislike(message, rank) {
|
|
2430
|
-
|
|
2431
|
-
|
|
2732
|
+
// Remap the index in the chat history
|
|
2733
|
+
const idx = this._remapIndexInChatHistory(rank);
|
|
2734
|
+
this.chatService.generateAuditEvent('thumb-down.click', { rank: idx });
|
|
2735
|
+
this.reportType = 'dislike';
|
|
2736
|
+
this.messageToReport = message;
|
|
2432
2737
|
this.issueType = '';
|
|
2433
|
-
this.
|
|
2434
|
-
this.
|
|
2435
|
-
this.
|
|
2738
|
+
this.reportComment = undefined;
|
|
2739
|
+
this.reportRank = rank;
|
|
2740
|
+
this.showReport = true;
|
|
2436
2741
|
}
|
|
2437
2742
|
/**
|
|
2438
2743
|
* Report an issue related to the assistant's message.
|
|
2439
2744
|
*/
|
|
2440
|
-
|
|
2745
|
+
sendReport() {
|
|
2441
2746
|
const details = {
|
|
2442
|
-
'
|
|
2443
|
-
'
|
|
2444
|
-
'
|
|
2445
|
-
'rank': this.issueRank,
|
|
2747
|
+
'comment': this.reportComment,
|
|
2748
|
+
'text': this.messageToReport.content,
|
|
2749
|
+
'rank': this.reportRank,
|
|
2446
2750
|
};
|
|
2447
|
-
this.
|
|
2448
|
-
|
|
2751
|
+
if (this.reportType === 'dislike') {
|
|
2752
|
+
details['report-type'] = this.issueType;
|
|
2753
|
+
this.chatService.generateAuditEvent('negative-report.send', details);
|
|
2754
|
+
}
|
|
2755
|
+
else {
|
|
2756
|
+
this.chatService.generateAuditEvent('positive-report.send', details);
|
|
2757
|
+
}
|
|
2758
|
+
this.showReport = false;
|
|
2449
2759
|
}
|
|
2450
2760
|
/**
|
|
2451
|
-
* Close the
|
|
2761
|
+
* Close the reporting dialog.
|
|
2452
2762
|
*/
|
|
2453
|
-
|
|
2454
|
-
this.
|
|
2763
|
+
ignoreReport() {
|
|
2764
|
+
this.showReport = false;
|
|
2455
2765
|
}
|
|
2456
2766
|
/**
|
|
2457
2767
|
* Handle the click on a reference's 'open preview'.
|
|
@@ -2496,27 +2806,69 @@ class ChatComponent extends AbstractFacet {
|
|
|
2496
2806
|
this.suggestAction.emit(action);
|
|
2497
2807
|
this.chatService.generateAuditEvent('suggestedAction.click', { 'text': action.content, 'suggestedAction-type': action.type });
|
|
2498
2808
|
}
|
|
2809
|
+
/**
|
|
2810
|
+
* Handle the click on a chat starter.
|
|
2811
|
+
* @param starter the chat starter.
|
|
2812
|
+
*/
|
|
2813
|
+
chatStarterClick(starter) {
|
|
2814
|
+
this.chatStarter.emit(starter);
|
|
2815
|
+
}
|
|
2816
|
+
/**
|
|
2817
|
+
* It looks for the debug messages available in the current group of "assistant" messages.
|
|
2818
|
+
* By design, the debug messages are only available in the first visible message among the group "assistant" messages.
|
|
2819
|
+
* @param index The rank of the message
|
|
2820
|
+
* @returns The debug messages available in the current group of "assistant" messages
|
|
2821
|
+
*/
|
|
2822
|
+
getDebugMessages(index) {
|
|
2823
|
+
// If it is not an assistant message, return
|
|
2824
|
+
if ((this.messages$.value)[index].role !== 'assistant') {
|
|
2825
|
+
return [];
|
|
2826
|
+
}
|
|
2827
|
+
// Get the array of messages up to the indicated index
|
|
2828
|
+
const array = this.messages$.value.slice(0, index + 1);
|
|
2829
|
+
// If it is an assistant message, look for the debug messages available in the current group of "assistant" messages
|
|
2830
|
+
// By design, the debug messages are only available in the first visible message among the group "assistant" messages.
|
|
2831
|
+
const idx = this.chatService.firstVisibleAssistantMessageIndex(array);
|
|
2832
|
+
if (idx > -1) {
|
|
2833
|
+
return (this.messages$.value)[idx].additionalProperties.$debug || [];
|
|
2834
|
+
}
|
|
2835
|
+
return [];
|
|
2836
|
+
}
|
|
2499
2837
|
/**
|
|
2500
2838
|
* Handle the click on the 'show log info' button of a message.
|
|
2501
|
-
* @param
|
|
2839
|
+
* @param index The rank of the message
|
|
2502
2840
|
*/
|
|
2503
|
-
showDebug(
|
|
2504
|
-
this.debugMessages =
|
|
2841
|
+
showDebug(index) {
|
|
2842
|
+
this.debugMessages = this.getDebugMessages(index);
|
|
2505
2843
|
this.showDebugMessages = true;
|
|
2506
2844
|
this.cdr.detectChanges();
|
|
2507
2845
|
}
|
|
2846
|
+
/**
|
|
2847
|
+
* Verify whether the current message is an assistant message and that all following messages are assistant ones
|
|
2848
|
+
* Used to keep the "View progress" opened even though the assistant is sending additional messages after the current one
|
|
2849
|
+
* @param messages the list of current messages
|
|
2850
|
+
* @param index the index of the current message
|
|
2851
|
+
* @returns if this messages and the following ones (if any) are the last ones
|
|
2852
|
+
*/
|
|
2853
|
+
isAssistantLastMessages(messages, index) {
|
|
2854
|
+
for (let i = index; i < messages.length; i++) {
|
|
2855
|
+
if (messages[i].role !== 'assistant')
|
|
2856
|
+
return false;
|
|
2857
|
+
}
|
|
2858
|
+
return true;
|
|
2859
|
+
}
|
|
2508
2860
|
}
|
|
2509
2861
|
ChatComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2510
|
-
ChatComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatComponent, isStandalone: true, selector: "sq-chat-v3", inputs: { instanceId: "instanceId", query: "query", queryChangeShouldTriggerReload: "queryChangeShouldTriggerReload", protocol: "protocol", messageHandlers: "messageHandlers", automaticScrollToLastResponse: "automaticScrollToLastResponse", chat: "chat", assistantMessageIcon: "assistantMessageIcon", userMessageIcon: "userMessageIcon", connectionErrorMessageIcon: "connectionErrorMessageIcon", searchWarningMessageIcon: "searchWarningMessageIcon" }, outputs: { connection: "connection", loading$: "loading", _config: "config", data: "data", openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction" }, providers: [
|
|
2862
|
+
ChatComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatComponent, isStandalone: true, selector: "sq-chat-v3", inputs: { instanceId: "instanceId", query: "query", queryChangeShouldTriggerReload: "queryChangeShouldTriggerReload", protocol: "protocol", messageHandlers: "messageHandlers", automaticScrollToLastResponse: "automaticScrollToLastResponse", focusAfterResponse: "focusAfterResponse", chat: "chat", assistantMessageIcon: "assistantMessageIcon", userMessageIcon: "userMessageIcon", connectionErrorMessageIcon: "connectionErrorMessageIcon", searchWarningMessageIcon: "searchWarningMessageIcon" }, outputs: { connection: "connection", loading$: "loading", _config: "config", data: "data", openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", chatStarter: "chatStarter" }, providers: [
|
|
2511
2863
|
RestChatService,
|
|
2512
2864
|
WebSocketChatService
|
|
2513
|
-
], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], descendants: true }, { propertyName: "reportIssueTpl", first: true, predicate: ["reportIssueTpl"], descendants: true }, { propertyName: "tokenConsumptionTpl", first: true, predicate: ["tokenConsumptionTpl"], descendants: true }, { propertyName: "debugMessagesTpl", first: true, predicate: ["debugMessagesTpl"], descendants: true }], viewQueries: [{ propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true }, { propertyName: "questionInput", first: true, predicate: ["questionInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <!-- Token consumption -->\n <div class=\"ms-1\" *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\">\n <ng-container *ngTemplateOutlet=\"tokenConsumptionTpl || defaultTokenConsumptionTpl; context: { $implicit: instanceId }\"></ng-container>\n </div>\n\n <!-- Chat Messages -->\n <ul class=\"list-group list-group-flush overflow-auto flex-grow-1 pe-2 pb-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" [style.--bs-list-group-item-padding-y.rem]=\"'0.6'\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role === 'user'\"\n [class.last-message]=\"last\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [suggestedActions]=\"last ? message.additionalProperties.$suggestedAction : undefined\"\n [assistantMessageIcon]=\"assistantMessageIcon\"\n [userMessageIcon]=\"userMessageIcon\"\n [connectionErrorMessageIcon]=\"connectionErrorMessageIcon\"\n [searchWarningMessageIcon]=\"searchWarningMessageIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && ((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role === 'user'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role !== 'connection-error' && message.role !== 'search-warning'\"\n [canDebug]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant' && isAdmin && message.additionalProperties.$debug\"\n [canLike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDislike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\"\n (copy)=\"copyMessage(index)\"\n (regenerate)=\"regenerateMessage(index)\"\n (openDocument)=\"openOriginalAttachment($event)\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (suggestAction)=\"suggestActionClick($event, index)\"\n (like)=\"onLike(index)\"\n (dislike)=\"onDislike($event, index)\"\n (debug)=\"showDebug($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n <!-- Loading spinner -->\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <!-- Reporting an issue form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReportIssue\">\n <ng-container *ngTemplateOutlet=\"reportIssueTpl || reportIssueTplDefault; context: { $implicit: messageRelatedIssue, rank: issueRank }\"></ng-container>\n </div>\n\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"!showReportIssue\">\n <div class=\"py-2\">\n <div [hidden]=\"!isConnected\">\n <ng-container *ngIf=\"enabledUserInput\" [ngTemplateOutlet]=\"inputTpl\"></ng-container>\n </div>\n <!-- Retry button -->\n <button [hidden]=\"isConnected\" class=\"btn mb-4 ast-error ast-btn sq-retry\" (click)=\"retryFetch()\">\n <span>Try again</span>\n <span *ngIf=\"retrialAttempts\" class=\"ms-2 attempts\">{{ retrialAttempts }}</span>\n </button>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n\n <!-- Floating scroll button -->\n <div *ngIf=\"!isAtBottom && !showReportIssue\" class=\"sq-floating-scroll\" [ngClass]=\"enabledUserInput ? 'sq-floating-scroll--when-user-input' : 'sq-floating-scroll--without-user-input'\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <button disabled class=\"btn btn-light\">\n <i class=\"fas fa-search\"></i>\n </button>\n <textarea #questionInput rows=\"1\"\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n (keydown)=\"calculateHeight($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n </textarea>\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #reportIssueTplDefault let-message let-rank=\"rank\">\n <div class=\"px-3\">\n <h5>Issue type</h5>\n <select class=\"form-select mb-4\" [(ngModel)]=\"issueType\">\n <option [value]=\"''\">Choose an issue type</option>\n <option *ngFor=\"let type of (issueTypes ?? defaultIssueTypes)\">{{type}}</option>\n </select>\n <h5>Comment (optional)</h5>\n <textarea class=\"form-control\" [(ngModel)]=\"issueComment\" placeholder=\"What was unsatisfying about this response?\"></textarea>\n <div class=\"d-flex flex-row-reverse mt-2\">\n <button class=\"btn btn-primary\" [disabled]=\"!issueType\" (click)=\"sendIssue()\">Send</button>\n <button class=\"btn btn-light\" (click)=\"ignoreIssue()\">Cancel</button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultTokenConsumptionTpl let-instanceId>\n <sq-token-progress-bar\n [instanceId]=\"instanceId\">\n </sq-token-progress-bar>\n</ng-template>\n\n<div class=\"debug-messages\" [class.displayed]=\"showDebugMessages\">\n <button *ngIf=\"showDebugMessages\" class=\"btn btn-light shadow back-btn\" (click)=\"showDebugMessages=false\">\n <i class=\"fas fa-chevron-right\"></i>\n </button>\n <ng-container *ngTemplateOutlet=\"debugMessagesTpl || defaultDebugMessagesTpl; context: { $implicit: debugMessages }\">\n </ng-container>\n</div>\n\n<ng-template #defaultDebugMessagesTpl let-debugMessages>\n <sq-debug-message [data]=\"debugMessages\"></sq-debug-message>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>.issue-report>div,:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;text-align:center}.sq-floating-scroll--when-user-input{bottom:75px}.sq-floating-scroll--without-user-input{bottom:15px}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:end;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container textarea{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem);resize:none}.ast-input-container textarea,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}sq-token-progress-bar{z-index:10;position:absolute;top:0;right:0}.debug-messages{position:fixed;z-index:999999;right:-60%;top:0;width:60%;height:100%;transition:all .5s ease;background-color:var(--bs-body-bg);overflow:auto}.debug-messages .back-btn{position:fixed;right:0%;transition:all .5s ease}.debug-messages.displayed{right:0}.debug-messages.displayed .back-btn{right:60%}.debug-messages sq-debug-message:first-of-type{display:block;width:100%}.sq-retry{display:flex;margin:auto;font-weight:var(--font-weight-bold, 500)}.sq-retry .attempts{display:flex;border-radius:100%;background:white;height:20px;width:20px;place-content:center;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ChatMessageComponent, selector: "sq-chat-message", inputs: ["message", "conversation", "suggestedActions", "assistantMessageIcon", "userMessageIcon", "connectionErrorMessageIcon", "searchWarningMessageIcon", "streaming", "canEdit", "canRegenerate", "canCopy", "canDebug", "canLike", "canDislike"], outputs: ["openDocument", "openPreview", "suggestAction", "edit", "copy", "regenerate", "like", "dislike", "debug"] }, { kind: "component", type: TokenProgressBarComponent, selector: "sq-token-progress-bar", inputs: ["instanceId"] }, { kind: "component", type: DebugMessageComponent, selector: "sq-debug-message", inputs: ["data", "level", "parentColor"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2865
|
+
], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], descendants: true }, { propertyName: "reportTpl", first: true, predicate: ["reportTpl"], descendants: true }, { propertyName: "tokenConsumptionTpl", first: true, predicate: ["tokenConsumptionTpl"], descendants: true }, { propertyName: "debugMessagesTpl", first: true, predicate: ["debugMessagesTpl"], descendants: true }], viewQueries: [{ propertyName: "messageList", first: true, predicate: ["messageList"], descendants: true }, { propertyName: "questionInput", first: true, predicate: ["questionInput"], descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <!-- Token consumption -->\n <div class=\"ms-1\" *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\">\n <ng-container *ngTemplateOutlet=\"tokenConsumptionTpl || defaultTokenConsumptionTpl; context: { $implicit: instanceId }\"></ng-container>\n </div>\n\n <!-- Chat Messages -->\n <ul class=\"list-group list-group-flush overflow-auto flex-grow-1 pe-2 pb-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\"\n *ngIf=\"message.additionalProperties.display\"\n [style.--bs-list-group-item-padding-y.rem]=\"'0.6'\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role === 'user'\"\n [class.last-message]=\"last\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [suggestedActions]=\"last ? message.additionalProperties.$suggestedAction : undefined\"\n [chatStarters]=\"visibleMessagesCount === 1 ? config.modeSettings.initialization.chatStarters : undefined\"\n [assistantMessageIcon]=\"assistantMessageIcon\"\n [userMessageIcon]=\"userMessageIcon\"\n [connectionErrorMessageIcon]=\"connectionErrorMessageIcon\"\n [searchWarningMessageIcon]=\"searchWarningMessageIcon\"\n [streaming]=\"(chatService.streaming$ | async) && (last || isAssistantLastMessages(messages, index))\"\n [canEdit]=\"(loading$ | async) === false && ((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role === 'user'\"\n [canCopy]=\"((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role !== 'connection-error' && message.role !== 'search-warning'\"\n [canLike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDislike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDebug]=\"(((chatService.streaming$ | async) === false && last) || (!last && messages[index+1].role !== 'assistant')) && message.role === 'assistant' && isAdmin && (getDebugMessages(index).length > 0) && config?.defaultValues.debug\"\n [canRegenerate]=\"(loading$ | async) === false && (((chatService.streaming$ | async) === false && last) || (!last && messages[index+1].role !== 'assistant')) && message.role === 'assistant' && messageToEdit === undefined\"\n (edit)=\"editMessage(index)\"\n (copy)=\"copyMessage(index)\"\n (regenerate)=\"regenerateMessage(index)\"\n (openDocument)=\"openOriginalAttachment($event)\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (suggestAction)=\"suggestActionClick($event, index)\"\n (chatStarterClicked)=\"chatStarterClick($event)\"\n (like)=\"onLike($event, index)\"\n (dislike)=\"onDislike($event, index)\"\n (debug)=\"showDebug(index)\">\n </sq-chat-message>\n </li>\n </ng-container>\n <!-- Loading spinner -->\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <!-- Reporting a feedback form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReport\">\n <ng-container *ngTemplateOutlet=\"reportTpl || reportTplDefault; context: { $implicit: messageToReport, rank: reportRank, type: reportType }\"></ng-container>\n </div>\n\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"!showReport\">\n <div class=\"py-2\">\n <div [hidden]=\"!isConnected\">\n <ng-container *ngIf=\"enabledUserInput\" [ngTemplateOutlet]=\"inputTpl\"></ng-container>\n </div>\n <!-- Retry button -->\n <button [hidden]=\"isConnected\" class=\"btn mb-4 ast-error ast-btn sq-retry\" (click)=\"retryFetch()\">\n <span>Try again</span>\n <span *ngIf=\"retrialAttempts\" class=\"ms-2 attempts\">{{ retrialAttempts }}</span>\n </button>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n\n <!-- Floating scroll button -->\n <div *ngIf=\"!isAtBottom && !showReport\" class=\"sq-floating-scroll\" [ngClass]=\"enabledUserInput ? 'sq-floating-scroll--when-user-input' : 'sq-floating-scroll--without-user-input'\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <button disabled class=\"btn btn-light\">\n <i class=\"fas fa-search\"></i>\n </button>\n <textarea #questionInput rows=\"1\"\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n (keydown)=\"calculateHeight($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async) || (chatService.stoppingGeneration$ | async)\">\n </textarea>\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async) && !(chatService.stoppingGeneration$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <span *ngIf=\"(chatService.streaming$ | async) && !(chatService.stoppingGeneration$ | async)\" class=\"processing ms-2\">\n Generating <i class=\"ms-1 fas fa-spinner fa-pulse\"></i>\n </span>\n <span *ngIf=\"(chatService.stoppingGeneration$ | async)\" class=\"processing ms-2\">\n Stopping <i class=\"ms-1 fas fa-spinner fa-pulse\"></i>\n </span>\n <button\n *ngIf=\"(chatService.streaming$ | async) && !(chatService.stoppingGeneration$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Stop generating\"\n (click)=\"stopGeneration()\">\n <i class=\"fas fa-stop\"></i>\n </button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #reportTplDefault let-message let-rank=\"rank\" let-type=\"type\">\n <div class=\"px-3\">\n <ng-container *ngIf=\"type === 'dislike'\">\n <h5>Issue type</h5>\n <select class=\"form-select mb-4\" [(ngModel)]=\"issueType\">\n <option [value]=\"''\">Choose an issue type</option>\n <option *ngFor=\"let type of (issueTypes ?? defaultIssueTypes)\">{{type}}</option>\n </select>\n <h5>What was unsatisfying about this response? (optional)</h5>\n </ng-container>\n <ng-container *ngIf=\"type === 'like'\">\n <h5>Why did you like this answer? (optional)</h5>\n </ng-container>\n <textarea class=\"form-control\" [(ngModel)]=\"reportComment\" placeholder=\"Write your comment\"></textarea>\n <div class=\"d-flex flex-row-reverse mt-2\">\n <button class=\"btn btn-primary\" [disabled]=\"type === 'dislike' && !issueType\" (click)=\"sendReport()\">Send</button>\n <button class=\"btn btn-light\" (click)=\"ignoreReport()\">Cancel</button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultTokenConsumptionTpl let-instanceId>\n <sq-token-progress-bar\n [instanceId]=\"instanceId\">\n </sq-token-progress-bar>\n</ng-template>\n\n<div class=\"debug-messages\" [class.displayed]=\"showDebugMessages\">\n <button *ngIf=\"showDebugMessages\" class=\"btn btn-light shadow back-btn\" (click)=\"showDebugMessages=false\">\n <i class=\"fas fa-chevron-right\"></i>\n </button>\n <ng-container *ngTemplateOutlet=\"debugMessagesTpl || defaultDebugMessagesTpl; context: { $implicit: debugMessages }\">\n </ng-container>\n</div>\n\n<ng-template #defaultDebugMessagesTpl let-debugMessages>\n <sq-debug-message [data]=\"debugMessages\"></sq-debug-message>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>.issue-report>div,:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;text-align:center}.sq-floating-scroll--when-user-input{bottom:75px}.sq-floating-scroll--without-user-input{bottom:15px}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container textarea{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem);resize:none}.ast-input-container textarea,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container .processing{display:flex;align-items:center;color:var(--ast-secondary-color, #FF732E)}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}sq-token-progress-bar{z-index:10;position:absolute;top:0;right:0}.debug-messages{position:fixed;z-index:999999;right:-60%;top:0;width:60%;height:100%;transition:all .5s ease;background-color:var(--bs-body-bg);overflow:auto}.debug-messages .back-btn{position:fixed;right:0%;transition:all .5s ease}.debug-messages.displayed{right:0}.debug-messages.displayed .back-btn{right:60%}.debug-messages sq-debug-message:first-of-type{display:block;width:100%}.sq-retry{display:flex;margin:auto;font-weight:var(--font-weight-bold, 500)}.sq-retry .attempts{display:flex;border-radius:100%;background:white;height:20px;width:20px;place-content:center;align-items:center}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ChatMessageComponent, selector: "sq-chat-message", inputs: ["message", "conversation", "suggestedActions", "chatStarters", "assistantMessageIcon", "userMessageIcon", "connectionErrorMessageIcon", "searchWarningMessageIcon", "streaming", "canEdit", "canRegenerate", "canCopy", "canDebug", "canLike", "canDislike"], outputs: ["openDocument", "openPreview", "suggestAction", "chatStarterClicked", "edit", "copy", "regenerate", "like", "dislike", "debug"] }, { kind: "component", type: TokenProgressBarComponent, selector: "sq-token-progress-bar", inputs: ["instanceId"] }, { kind: "component", type: DebugMessageComponent, selector: "sq-debug-message", inputs: ["data", "level", "parentColor"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2514
2866
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
2515
2867
|
type: Component,
|
|
2516
2868
|
args: [{ selector: 'sq-chat-v3', providers: [
|
|
2517
2869
|
RestChatService,
|
|
2518
2870
|
WebSocketChatService
|
|
2519
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, TokenProgressBarComponent, DebugMessageComponent], template: "<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <!-- Token consumption -->\n <div class=\"ms-1\" *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\">\n <ng-container *ngTemplateOutlet=\"tokenConsumptionTpl || defaultTokenConsumptionTpl; context: { $implicit: instanceId }\"></ng-container>\n </div>\n\n <!-- Chat Messages -->\n <ul class=\"list-group list-group-flush overflow-auto flex-grow-1 pe-2 pb-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\" [style.--bs-list-group-item-padding-y.rem]=\"'0.6'\" *ngIf=\"message.additionalProperties.display\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role === 'user'\"\n [class.last-message]=\"last\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [suggestedActions]=\"last ? message.additionalProperties.$suggestedAction : undefined\"\n [assistantMessageIcon]=\"assistantMessageIcon\"\n [userMessageIcon]=\"userMessageIcon\"\n [connectionErrorMessageIcon]=\"connectionErrorMessageIcon\"\n [searchWarningMessageIcon]=\"searchWarningMessageIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && ((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role === 'user'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role !== 'connection-error' && message.role !== 'search-warning'\"\n [canDebug]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant' && isAdmin && message.additionalProperties.$debug\"\n [canLike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDislike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\"\n (copy)=\"copyMessage(index)\"\n (regenerate)=\"regenerateMessage(index)\"\n (openDocument)=\"openOriginalAttachment($event)\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (suggestAction)=\"suggestActionClick($event, index)\"\n (like)=\"onLike(index)\"\n (dislike)=\"onDislike($event, index)\"\n (debug)=\"showDebug($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n <!-- Loading spinner -->\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <!-- Reporting an issue form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReportIssue\">\n <ng-container *ngTemplateOutlet=\"reportIssueTpl || reportIssueTplDefault; context: { $implicit: messageRelatedIssue, rank: issueRank }\"></ng-container>\n </div>\n\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"!showReportIssue\">\n <div class=\"py-2\">\n <div [hidden]=\"!isConnected\">\n <ng-container *ngIf=\"enabledUserInput\" [ngTemplateOutlet]=\"inputTpl\"></ng-container>\n </div>\n <!-- Retry button -->\n <button [hidden]=\"isConnected\" class=\"btn mb-4 ast-error ast-btn sq-retry\" (click)=\"retryFetch()\">\n <span>Try again</span>\n <span *ngIf=\"retrialAttempts\" class=\"ms-2 attempts\">{{ retrialAttempts }}</span>\n </button>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n\n <!-- Floating scroll button -->\n <div *ngIf=\"!isAtBottom && !showReportIssue\" class=\"sq-floating-scroll\" [ngClass]=\"enabledUserInput ? 'sq-floating-scroll--when-user-input' : 'sq-floating-scroll--without-user-input'\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <button disabled class=\"btn btn-light\">\n <i class=\"fas fa-search\"></i>\n </button>\n <textarea #questionInput rows=\"1\"\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n (keydown)=\"calculateHeight($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async)\">\n </textarea>\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <!--<button\n *ngIf=\"(chatService.streaming$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Stop generating\"\n (click)=\"terminateFetch()\">\n <i class=\"fas fa-stop\"></i>\n </button>-->\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n title=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #reportIssueTplDefault let-message let-rank=\"rank\">\n <div class=\"px-3\">\n <h5>Issue type</h5>\n <select class=\"form-select mb-4\" [(ngModel)]=\"issueType\">\n <option [value]=\"''\">Choose an issue type</option>\n <option *ngFor=\"let type of (issueTypes ?? defaultIssueTypes)\">{{type}}</option>\n </select>\n <h5>Comment (optional)</h5>\n <textarea class=\"form-control\" [(ngModel)]=\"issueComment\" placeholder=\"What was unsatisfying about this response?\"></textarea>\n <div class=\"d-flex flex-row-reverse mt-2\">\n <button class=\"btn btn-primary\" [disabled]=\"!issueType\" (click)=\"sendIssue()\">Send</button>\n <button class=\"btn btn-light\" (click)=\"ignoreIssue()\">Cancel</button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultTokenConsumptionTpl let-instanceId>\n <sq-token-progress-bar\n [instanceId]=\"instanceId\">\n </sq-token-progress-bar>\n</ng-template>\n\n<div class=\"debug-messages\" [class.displayed]=\"showDebugMessages\">\n <button *ngIf=\"showDebugMessages\" class=\"btn btn-light shadow back-btn\" (click)=\"showDebugMessages=false\">\n <i class=\"fas fa-chevron-right\"></i>\n </button>\n <ng-container *ngTemplateOutlet=\"debugMessagesTpl || defaultDebugMessagesTpl; context: { $implicit: debugMessages }\">\n </ng-container>\n</div>\n\n<ng-template #defaultDebugMessagesTpl let-debugMessages>\n <sq-debug-message [data]=\"debugMessages\"></sq-debug-message>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2))}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>.issue-report>div,:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;text-align:center}.sq-floating-scroll--when-user-input{bottom:75px}.sq-floating-scroll--without-user-input{bottom:15px}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:end;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container textarea{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem);resize:none}.ast-input-container textarea,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}sq-token-progress-bar{z-index:10;position:absolute;top:0;right:0}.debug-messages{position:fixed;z-index:999999;right:-60%;top:0;width:60%;height:100%;transition:all .5s ease;background-color:var(--bs-body-bg);overflow:auto}.debug-messages .back-btn{position:fixed;right:0%;transition:all .5s ease}.debug-messages.displayed{right:0}.debug-messages.displayed .back-btn{right:60%}.debug-messages sq-debug-message:first-of-type{display:block;width:100%}.sq-retry{display:flex;margin:auto;font-weight:var(--font-weight-bold, 500)}.sq-retry .attempts{display:flex;border-radius:100%;background:white;height:20px;width:20px;place-content:center;align-items:center}\n"] }]
|
|
2871
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, TokenProgressBarComponent, DebugMessageComponent, UtilsModule], template: "<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <!-- Token consumption -->\n <div class=\"ms-1\" *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\">\n <ng-container *ngTemplateOutlet=\"tokenConsumptionTpl || defaultTokenConsumptionTpl; context: { $implicit: instanceId }\"></ng-container>\n </div>\n\n <!-- Chat Messages -->\n <ul class=\"list-group list-group-flush overflow-auto flex-grow-1 pe-2 pb-2\" #messageList>\n <ng-container *ngFor=\"let message of messages; let index = index; let last = last\">\n <!-- Regular messages -->\n <li class=\"list-group-item\"\n *ngIf=\"message.additionalProperties.display\"\n [style.--bs-list-group-item-padding-y.rem]=\"'0.6'\"\n [class.opacity-50]=\"messageToEdit && messageToEdit < index + 1\">\n <sq-chat-message\n [class.sq-user-message]=\"message.role === 'user'\"\n [class.last-message]=\"last\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [suggestedActions]=\"last ? message.additionalProperties.$suggestedAction : undefined\"\n [chatStarters]=\"visibleMessagesCount === 1 ? config.modeSettings.initialization.chatStarters : undefined\"\n [assistantMessageIcon]=\"assistantMessageIcon\"\n [userMessageIcon]=\"userMessageIcon\"\n [connectionErrorMessageIcon]=\"connectionErrorMessageIcon\"\n [searchWarningMessageIcon]=\"searchWarningMessageIcon\"\n [streaming]=\"(chatService.streaming$ | async) && (last || isAssistantLastMessages(messages, index))\"\n [canEdit]=\"(loading$ | async) === false && ((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role === 'user'\"\n [canCopy]=\"((chatService.streaming$ | async) === false || !last) && messageToEdit === undefined && message.role !== 'connection-error' && message.role !== 'search-warning'\"\n [canLike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDislike]=\"((chatService.streaming$ | async) === false || !last) && message.role === 'assistant'\"\n [canDebug]=\"(((chatService.streaming$ | async) === false && last) || (!last && messages[index+1].role !== 'assistant')) && message.role === 'assistant' && isAdmin && (getDebugMessages(index).length > 0) && config?.defaultValues.debug\"\n [canRegenerate]=\"(loading$ | async) === false && (((chatService.streaming$ | async) === false && last) || (!last && messages[index+1].role !== 'assistant')) && message.role === 'assistant' && messageToEdit === undefined\"\n (edit)=\"editMessage(index)\"\n (copy)=\"copyMessage(index)\"\n (regenerate)=\"regenerateMessage(index)\"\n (openDocument)=\"openOriginalAttachment($event)\"\n (openPreview)=\"openAttachmentPreview($event)\"\n (suggestAction)=\"suggestActionClick($event, index)\"\n (chatStarterClicked)=\"chatStarterClick($event)\"\n (like)=\"onLike($event, index)\"\n (dislike)=\"onDislike($event, index)\"\n (debug)=\"showDebug(index)\">\n </sq-chat-message>\n </li>\n </ng-container>\n <!-- Loading spinner -->\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <!-- Reporting a feedback form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReport\">\n <ng-container *ngTemplateOutlet=\"reportTpl || reportTplDefault; context: { $implicit: messageToReport, rank: reportRank, type: reportType }\"></ng-container>\n </div>\n\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"!showReport\">\n <div class=\"py-2\">\n <div [hidden]=\"!isConnected\">\n <ng-container *ngIf=\"enabledUserInput\" [ngTemplateOutlet]=\"inputTpl\"></ng-container>\n </div>\n <!-- Retry button -->\n <button [hidden]=\"isConnected\" class=\"btn mb-4 ast-error ast-btn sq-retry\" (click)=\"retryFetch()\">\n <span>Try again</span>\n <span *ngIf=\"retrialAttempts\" class=\"ms-2 attempts\">{{ retrialAttempts }}</span>\n </button>\n <div class=\"text-end small text-muted px-3\" *ngIf=\"!!config?.globalSettings?.disclaimer\">\n {{ config?.globalSettings?.disclaimer }}\n </div>\n </div>\n </div>\n\n <!-- Floating scroll button -->\n <div *ngIf=\"!isAtBottom && !showReport\" class=\"sq-floating-scroll\" [ngClass]=\"enabledUserInput ? 'sq-floating-scroll--when-user-input' : 'sq-floating-scroll--without-user-input'\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n</ng-container>\n\n<!-- NG TEMPLATES-->\n\n<ng-template #loadingTplDefault>\n <div class=\"spinner-grow text-primary d-block mx-auto my-5\" role=\"status\">\n <span class=\"visually-hidden\">Loading...</span>\n </div>\n</ng-template>\n\n<ng-template #inputTpl>\n <div class=\"px-3 py-1\">\n <div class=\"ast-input-container\">\n <button disabled class=\"btn btn-light\">\n <i class=\"fas fa-search\"></i>\n </button>\n <textarea #questionInput rows=\"1\"\n type=\"text\" class=\"form-control\"\n placeholder=\"Ask something\" autofocus\n [(ngModel)]=\"question\"\n (keyup)=\"onKeyUp($event)\"\n (keydown)=\"calculateHeight($event)\"\n [disabled]=\"(loading$ | async) || (chatService.streaming$ | async) || (chatService.stoppingGeneration$ | async)\">\n </textarea>\n <button\n *ngIf=\"!(chatService.streaming$ | async) && !(loading$ | async) && !(chatService.stoppingGeneration$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Send message\"\n (click)=\"submitQuestion()\">\n <i class=\"fas fa-paper-plane\"></i>\n </button>\n <button\n *ngIf=\"messageToEdit\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Cancel edition\"\n (click)=\"messageToEdit = undefined; question = ''\">\n <i class=\"fas fa-undo-alt\"></i>\n </button>\n <span *ngIf=\"(chatService.streaming$ | async) && !(chatService.stoppingGeneration$ | async)\" class=\"processing ms-2\">\n Generating <i class=\"ms-1 fas fa-spinner fa-pulse\"></i>\n </span>\n <span *ngIf=\"(chatService.stoppingGeneration$ | async)\" class=\"processing ms-2\">\n Stopping <i class=\"ms-1 fas fa-spinner fa-pulse\"></i>\n </span>\n <button\n *ngIf=\"(chatService.streaming$ | async) && !(chatService.stoppingGeneration$ | async)\"\n type=\"button\"\n class=\"btn btn-light ms-2\"\n sqTooltip=\"Stop generating\"\n (click)=\"stopGeneration()\">\n <i class=\"fas fa-stop\"></i>\n </button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #reportTplDefault let-message let-rank=\"rank\" let-type=\"type\">\n <div class=\"px-3\">\n <ng-container *ngIf=\"type === 'dislike'\">\n <h5>Issue type</h5>\n <select class=\"form-select mb-4\" [(ngModel)]=\"issueType\">\n <option [value]=\"''\">Choose an issue type</option>\n <option *ngFor=\"let type of (issueTypes ?? defaultIssueTypes)\">{{type}}</option>\n </select>\n <h5>What was unsatisfying about this response? (optional)</h5>\n </ng-container>\n <ng-container *ngIf=\"type === 'like'\">\n <h5>Why did you like this answer? (optional)</h5>\n </ng-container>\n <textarea class=\"form-control\" [(ngModel)]=\"reportComment\" placeholder=\"Write your comment\"></textarea>\n <div class=\"d-flex flex-row-reverse mt-2\">\n <button class=\"btn btn-primary\" [disabled]=\"type === 'dislike' && !issueType\" (click)=\"sendReport()\">Send</button>\n <button class=\"btn btn-light\" (click)=\"ignoreReport()\">Cancel</button>\n </div>\n </div>\n</ng-template>\n\n<ng-template #defaultTokenConsumptionTpl let-instanceId>\n <sq-token-progress-bar\n [instanceId]=\"instanceId\">\n </sq-token-progress-bar>\n</ng-template>\n\n<div class=\"debug-messages\" [class.displayed]=\"showDebugMessages\">\n <button *ngIf=\"showDebugMessages\" class=\"btn btn-light shadow back-btn\" (click)=\"showDebugMessages=false\">\n <i class=\"fas fa-chevron-right\"></i>\n </button>\n <ng-container *ngTemplateOutlet=\"debugMessagesTpl || defaultDebugMessagesTpl; context: { $implicit: debugMessages }\">\n </ng-container>\n</div>\n\n<ng-template #defaultDebugMessagesTpl let-debugMessages>\n <sq-debug-message [data]=\"debugMessages\"></sq-debug-message>\n</ng-template>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference,:host ::ng-deep .attachment .reference{position:relative;bottom:var(--ast-reference-bottom, .3em);font-weight:var(--ast-reference-font-weight, bold);padding:var(--ast-reference-padding, 0 .2em);margin:var(--ast-reference-margin, 0 .1em);border-radius:var(--ast-reference-border-radius, .2em);background-color:var(--ast-reference-background-color, lightblue);color:var(--ast-reference-color, black)}:host ::ng-deep .reference,:host ::ng-deep .message-content .reference{font-size:var(--ast-reference-message-font-size, .7em)}:host ::ng-deep .attachment .reference{font-size:var(--ast-reference-attachment-font-size, 13px)}:host{font-size:.875rem}:host>div>.user-input>div:not(.progress),:host>div>.issue-report>div,:host>div>ul>li{width:var(--ast-chat-container-width, 100%);max-width:100%;margin-left:auto;margin-right:auto}:host>div>ul{padding-top:var(--ast-chat-padding-top, 0);padding-bottom:var(--ast-chat-padding-bottom, 0)}li.attachment>p{display:-webkit-box;-webkit-box-orient:vertical;overflow:hidden;-webkit-line-clamp:3}li.attachment.expanded>p{display:block}.progress{--bs-progress-height: 3px}.progress.disabled{--bs-progress-height: 20px;--bs-progress-bar-bg: var(--bs-danger)}.user-input{z-index:1}.user-input ul.list-group{max-height:30vh}.form-control:disabled{background-color:#ededed}a.disabled{cursor:default;opacity:.5}.no-max-height{max-height:initial!important}.sq-floating-scroll{position:absolute;right:50%;text-align:center}.sq-floating-scroll--when-user-input{bottom:75px}.sq-floating-scroll--without-user-input{bottom:15px}.sq-floating-scroll .btn{background-color:#fff}.sq-floating-scroll .btn:hover{background-color:#fff;opacity:.9}.ast-input-container{display:flex;align-items:center;background-color:var(--ast-input-bg, #F8F8F8);border-radius:var(--ast-size-3, .75rem)}.ast-input-container>i{padding-left:var(--ast-size-3, .75rem);color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container textarea{padding-left:var(--ast-size-3, .75rem);padding-right:var(--ast-size-3, .75rem);resize:none}.ast-input-container textarea,.ast-input-container button,.ast-input-container button:hover{background-color:transparent;border:0}.ast-input-container button:hover{color:var(--ast-primary-color, #005DA7)}.ast-input-container button:not(:hover){color:var(--ast-muted-color, rgba(33, 37, 41, .75))}.ast-input-container .processing{display:flex;align-items:center;color:var(--ast-secondary-color, #FF732E)}sq-chat-message.sq-user-message{float:var(--ast-user-message-float, none)}sq-token-progress-bar{z-index:10;position:absolute;top:0;right:0}.debug-messages{position:fixed;z-index:999999;right:-60%;top:0;width:60%;height:100%;transition:all .5s ease;background-color:var(--bs-body-bg);overflow:auto}.debug-messages .back-btn{position:fixed;right:0%;transition:all .5s ease}.debug-messages.displayed{right:0}.debug-messages.displayed .back-btn{right:60%}.debug-messages sq-debug-message:first-of-type{display:block;width:100%}.sq-retry{display:flex;margin:auto;font-weight:var(--font-weight-bold, 500)}.sq-retry .attempts{display:flex;border-radius:100%;background:white;height:20px;width:20px;place-content:center;align-items:center}\n"] }]
|
|
2520
2872
|
}], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
|
|
2521
2873
|
type: Input
|
|
2522
2874
|
}], query: [{
|
|
@@ -2529,6 +2881,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2529
2881
|
type: Input
|
|
2530
2882
|
}], automaticScrollToLastResponse: [{
|
|
2531
2883
|
type: Input
|
|
2884
|
+
}], focusAfterResponse: [{
|
|
2885
|
+
type: Input
|
|
2532
2886
|
}], chat: [{
|
|
2533
2887
|
type: Input
|
|
2534
2888
|
}], assistantMessageIcon: [{
|
|
@@ -2555,6 +2909,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2555
2909
|
type: Output
|
|
2556
2910
|
}], suggestAction: [{
|
|
2557
2911
|
type: Output
|
|
2912
|
+
}], chatStarter: [{
|
|
2913
|
+
type: Output
|
|
2558
2914
|
}], messageList: [{
|
|
2559
2915
|
type: ViewChild,
|
|
2560
2916
|
args: ['messageList']
|
|
@@ -2564,9 +2920,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2564
2920
|
}], loadingTpl: [{
|
|
2565
2921
|
type: ContentChild,
|
|
2566
2922
|
args: ['loadingTpl']
|
|
2567
|
-
}],
|
|
2923
|
+
}], reportTpl: [{
|
|
2568
2924
|
type: ContentChild,
|
|
2569
|
-
args: ['
|
|
2925
|
+
args: ['reportTpl']
|
|
2570
2926
|
}], tokenConsumptionTpl: [{
|
|
2571
2927
|
type: ContentChild,
|
|
2572
2928
|
args: ['tokenConsumptionTpl']
|
|
@@ -2604,6 +2960,9 @@ class SavedChatsComponent {
|
|
|
2604
2960
|
}));
|
|
2605
2961
|
}
|
|
2606
2962
|
onLoad(savedChat) {
|
|
2963
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2607
2966
|
this.chatService.setSavedChatId(savedChat.id);
|
|
2608
2967
|
this.chatService.generateChatId(savedChat.id);
|
|
2609
2968
|
this.chatService.loadSavedChat$.next(savedChat);
|
|
@@ -2611,7 +2970,11 @@ class SavedChatsComponent {
|
|
|
2611
2970
|
this.chatService.listSavedChat();
|
|
2612
2971
|
this.load.emit(savedChat);
|
|
2613
2972
|
}
|
|
2614
|
-
onRename(savedChat) {
|
|
2973
|
+
onRename(event, savedChat) {
|
|
2974
|
+
event.stopPropagation();
|
|
2975
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2976
|
+
return;
|
|
2977
|
+
}
|
|
2615
2978
|
const model = {
|
|
2616
2979
|
title: 'Rename saved discussion',
|
|
2617
2980
|
message: `Please enter a new name for the discussion "${savedChat.title}".`,
|
|
@@ -2637,7 +3000,11 @@ class SavedChatsComponent {
|
|
|
2637
3000
|
}
|
|
2638
3001
|
});
|
|
2639
3002
|
}
|
|
2640
|
-
onDelete(savedChat) {
|
|
3003
|
+
onDelete(event, savedChat) {
|
|
3004
|
+
event.stopPropagation();
|
|
3005
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
3006
|
+
return;
|
|
3007
|
+
}
|
|
2641
3008
|
this.modalService
|
|
2642
3009
|
.confirm({
|
|
2643
3010
|
title: "Delete saved discussion",
|
|
@@ -2714,10 +3081,10 @@ class SavedChatsComponent {
|
|
|
2714
3081
|
}
|
|
2715
3082
|
}
|
|
2716
3083
|
SavedChatsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2717
|
-
SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\"
|
|
3084
|
+
SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\"\n (click)=\"onLoad(savedChat)\"\n class=\"saved-chat p-2\"\n [class.forbidden]=\"(chatService.streaming$ | async) || (chatService.stoppingGeneration$ | async)\"\n [class.active]=\"chatService.savedChatId === savedChat.id\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"onRename($event, savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"onDelete($event, savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .saved-chat.forbidden{cursor:not-allowed}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ModalModule }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
|
|
2718
3085
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, decorators: [{
|
|
2719
3086
|
type: Component,
|
|
2720
|
-
args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\"
|
|
3087
|
+
args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\"\n (click)=\"onLoad(savedChat)\"\n class=\"saved-chat p-2\"\n [class.forbidden]=\"(chatService.streaming$ | async) || (chatService.stoppingGeneration$ | async)\"\n [class.active]=\"chatService.savedChatId === savedChat.id\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"onRename($event, savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"onDelete($event, savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-error{background-color:var(--ast-error-bg, rgba(249, 58, 55, .2));color:var(--ast-action-buttons-color, inherit)}.ast-error:hover{color:var(--ast-error-color, rgba(249, 58, 55, .7))}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black;--ast-action-buttons-color: white;--ast-action-buttons-hover-color: #6dbee6}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .saved-chat.forbidden{cursor:not-allowed}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
2721
3088
|
}], propDecorators: { instanceId: [{
|
|
2722
3089
|
type: Input
|
|
2723
3090
|
}], load: [{
|