@sinequa/assistant 3.6.2 → 3.7.1
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 +137 -18
- 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 +189 -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 +361 -62
- package/esm2020/chat/chat.service.mjs +49 -3
- package/esm2020/chat/debug-message/debug-message.component.mjs +3 -3
- package/esm2020/chat/instance-manager.service.mjs +2 -2
- 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 +18 -4
- package/esm2020/chat/websocket-chat.service.mjs +191 -99
- package/fesm2015/sinequa-assistant-chat.mjs +660 -182
- package/fesm2015/sinequa-assistant-chat.mjs.map +1 -1
- package/fesm2020/sinequa-assistant-chat.mjs +649 -179
- 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';
|
|
@@ -66,7 +66,7 @@ class InstanceManagerService {
|
|
|
66
66
|
*/
|
|
67
67
|
getInstance(key) {
|
|
68
68
|
if (!this.checkInstance(key)) {
|
|
69
|
-
throw new Error(`No
|
|
69
|
+
throw new Error(`No assistant instance found for the given key : '${key}'`);
|
|
70
70
|
}
|
|
71
71
|
return this._serviceInstances.get(key);
|
|
72
72
|
}
|
|
@@ -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
|
});
|
|
@@ -239,11 +240,21 @@ const defaultValuesSchema = z.object({
|
|
|
239
240
|
systemPrompt: z.string(),
|
|
240
241
|
userPrompt: z.string()
|
|
241
242
|
});
|
|
243
|
+
// Define the Zod representation for the chatStarter object
|
|
244
|
+
const chatStarterSchema = z.object({
|
|
245
|
+
text: z.string()
|
|
246
|
+
});
|
|
247
|
+
// Define the Zod representation for the action object
|
|
248
|
+
const actionSchema = z.object({
|
|
249
|
+
forcedWorkflow: z.string(),
|
|
250
|
+
forcedWorkflowProperties: z.record(z.unknown()).optional() // forcedWorkflowProperties must be an object (Map equivalent)
|
|
251
|
+
});
|
|
242
252
|
// Define the Zod representation for the modeSettings object
|
|
243
253
|
const initializationSchema = z.object({
|
|
244
254
|
event: z.enum(['Query', 'Prompt']),
|
|
245
255
|
forcedWorkflow: z.string().optional(),
|
|
246
|
-
displayUserQuery: z.boolean().optional(),
|
|
256
|
+
displayUserQuery: z.boolean().optional(),
|
|
257
|
+
chatStarters: z.array(chatStarterSchema).optional(), // Optional for event 'Prompt'
|
|
247
258
|
}).refine(data => ((data.event === "Query") ? (!!data.forcedWorkflow && data.displayUserQuery !== undefined && data.displayUserQuery !== null) : true), {
|
|
248
259
|
message: "The 'forcedWorkflow' and 'displayUserQuery' properties must be provided when the initialization's event is 'Query'.",
|
|
249
260
|
});
|
|
@@ -251,7 +262,10 @@ const modeSettingsSchema = z.object({
|
|
|
251
262
|
enabledUserInput: z.boolean(),
|
|
252
263
|
displayUserPrompt: z.boolean(),
|
|
253
264
|
sendUserPrompt: z.boolean(),
|
|
254
|
-
initialization: initializationSchema
|
|
265
|
+
initialization: initializationSchema,
|
|
266
|
+
actions: z.record(actionSchema).optional()
|
|
267
|
+
}).refine(data => !(data.initialization.chatStarters?.length && (data.sendUserPrompt || data.displayUserPrompt || data.initialization.event === 'Query')), {
|
|
268
|
+
message: "Incompatible configuration for using chatStarters ('sendUserPrompt' and 'displayUserPrompt' must be false, 'initialization.event' must not be 'Query')",
|
|
255
269
|
});
|
|
256
270
|
// Define the Zod representation for the savedChatSettings object
|
|
257
271
|
const savedChatSettingsSchema = z.object({
|
|
@@ -291,7 +305,11 @@ class ChatService {
|
|
|
291
305
|
this.initConfig$ = new BehaviorSubject(false);
|
|
292
306
|
/** Global configuration of the chat. */
|
|
293
307
|
this.chatConfig$ = new BehaviorSubject(undefined);
|
|
294
|
-
/**
|
|
308
|
+
/**
|
|
309
|
+
* 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).
|
|
310
|
+
* This is used to prevent multiple fetches at the same time.
|
|
311
|
+
* 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.
|
|
312
|
+
*/
|
|
295
313
|
this.streaming$ = new BehaviorSubject(false);
|
|
296
314
|
/** List of saved chats. */
|
|
297
315
|
this.savedChats$ = new BehaviorSubject([]);
|
|
@@ -305,6 +323,8 @@ class ChatService {
|
|
|
305
323
|
this.chatUsageMetrics$ = new BehaviorSubject(undefined);
|
|
306
324
|
/** Emit the calculated chat's token consumption based on the chat usage metrics. */
|
|
307
325
|
this.chatTokenConsumption$ = new BehaviorSubject(undefined);
|
|
326
|
+
/** Emit true if "CancelTasks" is ongoing. */
|
|
327
|
+
this.stoppingGeneration$ = new BehaviorSubject(false);
|
|
308
328
|
this.userSettingsService = inject(UserSettingsWebService);
|
|
309
329
|
this.notificationsService = inject(NotificationsService);
|
|
310
330
|
this.auditService = inject(AuditWebService);
|
|
@@ -431,7 +451,7 @@ class ChatService {
|
|
|
431
451
|
}
|
|
432
452
|
}
|
|
433
453
|
catch (error) {
|
|
434
|
-
this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'
|
|
454
|
+
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
455
|
throw new Error(`Missing valid configuration for the assistant instance '${key}' . \n ${JSON.stringify(error.issues, null, 2)}`);
|
|
436
456
|
}
|
|
437
457
|
}
|
|
@@ -472,6 +492,7 @@ class ChatService {
|
|
|
472
492
|
const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
|
|
473
493
|
this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
|
|
474
494
|
if (quota.maxQuotaReached) {
|
|
495
|
+
this.generateAuditEvent('quota.exceeded', {});
|
|
475
496
|
const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
|
|
476
497
|
this.notificationsService.error(msg);
|
|
477
498
|
if (propagateError)
|
|
@@ -530,6 +551,45 @@ class ChatService {
|
|
|
530
551
|
};
|
|
531
552
|
this.auditService.notify(audit);
|
|
532
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* Traverse the array from the end and track the first 'assistant' message among the last group of "assistant" messages where display is true
|
|
556
|
+
* @param array The array of ChatMessage to traverse
|
|
557
|
+
* @returns The index of the first visible assistant message among the last group of "assistant" messages in the array
|
|
558
|
+
*/
|
|
559
|
+
firstVisibleAssistantMessageIndex(array) {
|
|
560
|
+
if (!array) {
|
|
561
|
+
return -1;
|
|
562
|
+
}
|
|
563
|
+
let index = array.length - 1;
|
|
564
|
+
let firstVisibleAssistantMessageIndex = -1;
|
|
565
|
+
while (index >= 0 && array[index].role === 'assistant') {
|
|
566
|
+
if (array[index].additionalProperties.display === true) {
|
|
567
|
+
firstVisibleAssistantMessageIndex = index;
|
|
568
|
+
}
|
|
569
|
+
index--;
|
|
570
|
+
}
|
|
571
|
+
return firstVisibleAssistantMessageIndex;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Traverse the array from the end and pick the last 'assistant' message among the last group of "assistant" messages where display is true
|
|
575
|
+
* @param array The array of ChatMessage to traverse
|
|
576
|
+
* @returns The index of the last visible assistant message among the last group of "assistant" messages in the array
|
|
577
|
+
*/
|
|
578
|
+
lastVisibleAssistantMessageIndex(array) {
|
|
579
|
+
if (!array) {
|
|
580
|
+
return -1;
|
|
581
|
+
}
|
|
582
|
+
let index = array.length - 1;
|
|
583
|
+
let lastVisibleAssistantMessageIndex = -1;
|
|
584
|
+
while (index >= 0 && array[index].role === 'assistant') {
|
|
585
|
+
if (array[index].additionalProperties.display === true) {
|
|
586
|
+
lastVisibleAssistantMessageIndex = index;
|
|
587
|
+
break;
|
|
588
|
+
}
|
|
589
|
+
index--;
|
|
590
|
+
}
|
|
591
|
+
return lastVisibleAssistantMessageIndex;
|
|
592
|
+
}
|
|
533
593
|
/**
|
|
534
594
|
* Format a date string in UTC to a local date string
|
|
535
595
|
* @param value Date string in UTC to format
|
|
@@ -560,10 +620,8 @@ class WebSocketChatService extends ChatService {
|
|
|
560
620
|
this._messageHandlers = new Map();
|
|
561
621
|
this._actionMap = new Map();
|
|
562
622
|
this._progress = undefined;
|
|
563
|
-
this._content = "";
|
|
564
623
|
this._attachments = [];
|
|
565
|
-
this.
|
|
566
|
-
this._debugMessages = undefined;
|
|
624
|
+
this._debugMessages = [];
|
|
567
625
|
this.signalRService = inject(SignalRWebService);
|
|
568
626
|
this.authenticationService = inject(AuthenticationService);
|
|
569
627
|
}
|
|
@@ -613,36 +671,36 @@ class WebSocketChatService extends ChatService {
|
|
|
613
671
|
}
|
|
614
672
|
}
|
|
615
673
|
listModels() {
|
|
616
|
-
const modelsSubject = new Subject();
|
|
674
|
+
const modelsSubject$ = new Subject();
|
|
617
675
|
this.connection.on('ListModels', (res) => {
|
|
618
676
|
this.models = res.models?.filter(model => !!model.enable);
|
|
619
|
-
modelsSubject
|
|
620
|
-
modelsSubject
|
|
677
|
+
modelsSubject$.next(this.models);
|
|
678
|
+
modelsSubject$.complete();
|
|
621
679
|
});
|
|
622
680
|
// Send the request to get the list of models
|
|
623
681
|
this.connection.invoke('ListModels', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
624
682
|
.catch(error => {
|
|
625
683
|
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
|
|
684
|
+
modelsSubject$.error(new Error(error));
|
|
685
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
628
686
|
});
|
|
629
|
-
return modelsSubject
|
|
687
|
+
return modelsSubject$.asObservable();
|
|
630
688
|
}
|
|
631
689
|
listFunctions() {
|
|
632
|
-
const functionsSubject = new Subject();
|
|
690
|
+
const functionsSubject$ = new Subject();
|
|
633
691
|
this.connection.on('ListFunctions', (res) => {
|
|
634
692
|
this.functions = res.functions?.filter(func => func.enabled);
|
|
635
|
-
functionsSubject
|
|
636
|
-
functionsSubject
|
|
693
|
+
functionsSubject$.next(this.functions);
|
|
694
|
+
functionsSubject$.complete();
|
|
637
695
|
});
|
|
638
696
|
// Send the request to get the list of functions
|
|
639
697
|
this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
640
698
|
.catch(error => {
|
|
641
699
|
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
|
|
700
|
+
functionsSubject$.error(new Error(error));
|
|
701
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
644
702
|
});
|
|
645
|
-
return functionsSubject
|
|
703
|
+
return functionsSubject$.asObservable();
|
|
646
704
|
}
|
|
647
705
|
fetch(messages, query) {
|
|
648
706
|
// Start streaming by invoking the Chat method
|
|
@@ -670,7 +728,8 @@ class WebSocketChatService extends ChatService {
|
|
|
670
728
|
data.instanceId = this.chatInstanceId;
|
|
671
729
|
data.savedChatId = this.savedChatId;
|
|
672
730
|
}
|
|
673
|
-
|
|
731
|
+
// Initialize the response with an empty assistant message
|
|
732
|
+
this._response = [{ role: "assistant", content: "", additionalProperties: { display: true } }]; // here display: true is needed in order to be able to show the progress
|
|
674
733
|
// Create a Subject to signal completion
|
|
675
734
|
const completion$ = new Subject();
|
|
676
735
|
// 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 +737,19 @@ class WebSocketChatService extends ChatService {
|
|
|
678
737
|
.from(this._messageHandlers.entries())
|
|
679
738
|
.filter(([eventName, eventHandler]) => !eventHandler.isGlobalHandler)
|
|
680
739
|
.map(([eventName, eventHandler]) => {
|
|
681
|
-
return fromEvent(this.connection, eventName).pipe(
|
|
682
|
-
|
|
740
|
+
return fromEvent(this.connection, eventName).pipe(mergeMap((event) => {
|
|
741
|
+
// Wrap the handler in a try-catch block to prevent the entire stream from failing if an error occurs in a single handler
|
|
742
|
+
try {
|
|
743
|
+
// Execute the handler and emit the result
|
|
744
|
+
// 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
|
|
745
|
+
return of(eventHandler.handler(event));
|
|
746
|
+
}
|
|
747
|
+
catch (error) {
|
|
748
|
+
console.error(`Error in event handler for ${eventName}:`, error);
|
|
749
|
+
// Use throwError to propagate the error downstream
|
|
750
|
+
return throwError(() => new Error(`Error in event handler for ${eventName}: ${error}`));
|
|
751
|
+
}
|
|
752
|
+
}));
|
|
683
753
|
});
|
|
684
754
|
// Then merge them into a single observable in order to simulate the streaming behavior
|
|
685
755
|
const combined$ = merge(...observables).pipe(map(() => {
|
|
@@ -693,37 +763,74 @@ class WebSocketChatService extends ChatService {
|
|
|
693
763
|
time: a.executionTime,
|
|
694
764
|
}))
|
|
695
765
|
: undefined;
|
|
696
|
-
//
|
|
697
|
-
|
|
698
|
-
|
|
766
|
+
// Always update ONLY the first assistant message of the _response with the new $progress, $attachment and $debug
|
|
767
|
+
// Assuming that the first assistant message is always visible since the hub does not send hidden messages by design
|
|
768
|
+
// So even if the first assistant message is hidden (display: false), the _response[0] will and should contain :
|
|
769
|
+
// - $progress, $attachment and $debug
|
|
770
|
+
// - the content of the first visible assistant message in the workflow
|
|
771
|
+
// This is mandatory in order to match the behavior of consecutive messages and maintain consistency with the chatHistory
|
|
772
|
+
if (!!this._progress || this._attachments.length > 0 || this._debugMessages.length > 0) {
|
|
773
|
+
this._response[0].additionalProperties.$progress = this._progress;
|
|
774
|
+
this._response[0].additionalProperties.$attachment = this._attachments;
|
|
775
|
+
this._response[0].additionalProperties.$debug = this._debugMessages;
|
|
699
776
|
}
|
|
700
777
|
// Return the result
|
|
701
|
-
return { history: [...messages,
|
|
778
|
+
return { history: [...messages, ...this._response], executionTime: this._executionTime };
|
|
702
779
|
}), takeUntil(completion$));
|
|
703
780
|
// 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
781
|
return new Observable(observer => {
|
|
705
782
|
// Subscribe to combined stream
|
|
706
783
|
combined$.subscribe({
|
|
707
784
|
next: (value) => observer.next(value),
|
|
708
|
-
error: (err) => observer.error(err)
|
|
709
|
-
complete: () => observer.complete(),
|
|
785
|
+
error: (err) => observer.error(err)
|
|
710
786
|
});
|
|
711
787
|
// Invoke the Chat method and handle errors
|
|
712
788
|
this.connection.invoke('Chat', data)
|
|
789
|
+
.then(() => {
|
|
790
|
+
// If a valid assistant message with (display: true) was found, update it
|
|
791
|
+
// and it should always the case
|
|
792
|
+
const index = this.firstVisibleAssistantMessageIndex(this.chatHistory);
|
|
793
|
+
if (index !== -1) {
|
|
794
|
+
this.chatHistory[index].additionalProperties.$progress = this._progress;
|
|
795
|
+
this.chatHistory[index].additionalProperties.$attachment = this._attachments;
|
|
796
|
+
this.chatHistory[index].additionalProperties.$debug = this._debugMessages;
|
|
797
|
+
}
|
|
798
|
+
// Save/update the chat if savedChat enabled
|
|
799
|
+
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
800
|
+
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory).pipe(tap(() => this.listSavedChat())) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
801
|
+
action.pipe(take(1)).subscribe({
|
|
802
|
+
next: () => { },
|
|
803
|
+
error: (error) => {
|
|
804
|
+
this.streaming$.next(false);
|
|
805
|
+
observer.error(error);
|
|
806
|
+
},
|
|
807
|
+
complete: () => {
|
|
808
|
+
this.streaming$.next(false);
|
|
809
|
+
observer.complete();
|
|
810
|
+
}
|
|
811
|
+
});
|
|
812
|
+
}
|
|
813
|
+
else {
|
|
814
|
+
this.streaming$.next(false);
|
|
815
|
+
observer.complete();
|
|
816
|
+
}
|
|
817
|
+
})
|
|
713
818
|
.catch(error => {
|
|
714
819
|
console.error('Error invoking Chat:', error);
|
|
820
|
+
this.streaming$.next(false);
|
|
715
821
|
// Emit the error to the newly created observable
|
|
716
822
|
observer.error(error);
|
|
717
823
|
// Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
718
824
|
return Promise.resolve();
|
|
719
825
|
})
|
|
720
826
|
.finally(() => {
|
|
721
|
-
|
|
827
|
+
// This block concerns ONLY the completion of the "Chat" method invocation.
|
|
828
|
+
// This means the completion of the combined$ stream.
|
|
829
|
+
// 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
|
|
830
|
+
this._response = []; // Clear the _response
|
|
722
831
|
this._actionMap.clear(); // Clear the _actionMap
|
|
723
|
-
this._content = ""; // Clear the _content
|
|
724
832
|
this._progress = undefined; // Clear the _progress
|
|
725
833
|
this._attachments = []; // Clear the _attachments
|
|
726
|
-
this._suggestedActions = []; // Clear the _suggestedActions
|
|
727
834
|
this._debugMessages = []; // Clear the _debugMessages
|
|
728
835
|
this._executionTime = ""; // Clear the _executionTime
|
|
729
836
|
completion$.next(); // Emit a signal to complete the observables
|
|
@@ -731,6 +838,33 @@ class WebSocketChatService extends ChatService {
|
|
|
731
838
|
});
|
|
732
839
|
});
|
|
733
840
|
}
|
|
841
|
+
stopGeneration() {
|
|
842
|
+
// Start stopping generation by invoking the CancelTasks method
|
|
843
|
+
this.stoppingGeneration$.next(true);
|
|
844
|
+
// Create a Subject to hold the result of the CancelTasks method
|
|
845
|
+
const stopGenerationSubject$ = new Subject();
|
|
846
|
+
this.connection.on('CancelTasks', (res) => {
|
|
847
|
+
// When the generation is stopped before streaming any VISIBLE assistant message, this means that $progress, $attachment and $debug properties will be lost.
|
|
848
|
+
// However, the "ContextMessage" frames will be persisted in the chatHistory and the assistant may reference them in the next generation.
|
|
849
|
+
// This leads to the problem of referencing undisplayed attachments in the next generation.
|
|
850
|
+
// 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.
|
|
851
|
+
if (this._response.length === 1 && this._response[0].content === "") {
|
|
852
|
+
this.chatHistory?.push({ role: "assistant", content: "", additionalProperties: { display: true, $progress: this._progress, $attachment: this._attachments, $debug: this._debugMessages } });
|
|
853
|
+
}
|
|
854
|
+
stopGenerationSubject$.next(!!res); // Emit the result of the CancelTasks method
|
|
855
|
+
stopGenerationSubject$.complete(); // Complete the subject
|
|
856
|
+
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
857
|
+
});
|
|
858
|
+
// Invoke the CancelTasks method and handle errors
|
|
859
|
+
this.connection.invoke('CancelTasks')
|
|
860
|
+
.catch(error => {
|
|
861
|
+
console.error('Error invoking CancelTasks:', error);
|
|
862
|
+
stopGenerationSubject$.error(new Error(error));
|
|
863
|
+
this.stoppingGeneration$.next(false); // Complete stopping generation
|
|
864
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
865
|
+
});
|
|
866
|
+
return stopGenerationSubject$.asObservable();
|
|
867
|
+
}
|
|
734
868
|
listSavedChat() {
|
|
735
869
|
if (!this.chatConfig$.value.savedChatSettings.enabled) {
|
|
736
870
|
return;
|
|
@@ -750,27 +884,27 @@ class WebSocketChatService extends ChatService {
|
|
|
750
884
|
});
|
|
751
885
|
}
|
|
752
886
|
getSavedChat(id) {
|
|
753
|
-
const savedChatSubject = new Subject();
|
|
887
|
+
const savedChatSubject$ = new Subject();
|
|
754
888
|
const data = {
|
|
755
889
|
instanceId: this.chatInstanceId,
|
|
756
890
|
savedChatId: id,
|
|
757
891
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
758
892
|
};
|
|
759
893
|
this.connection.on('SavedChatGet', (res) => {
|
|
760
|
-
savedChatSubject
|
|
761
|
-
savedChatSubject
|
|
894
|
+
savedChatSubject$.next(res.savedChat);
|
|
895
|
+
savedChatSubject$.complete();
|
|
762
896
|
});
|
|
763
897
|
// Invoke the method SavedChatGet
|
|
764
898
|
this.connection.invoke('SavedChatGet', data)
|
|
765
899
|
.catch(error => {
|
|
766
900
|
console.error('Error invoking SavedChatGet:', error);
|
|
767
|
-
savedChatSubject
|
|
768
|
-
return Promise.resolve();
|
|
901
|
+
savedChatSubject$.error(new Error(error));
|
|
902
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
769
903
|
});
|
|
770
|
-
return savedChatSubject
|
|
904
|
+
return savedChatSubject$.asObservable();
|
|
771
905
|
}
|
|
772
906
|
addSavedChat(messages) {
|
|
773
|
-
const addSavedChatSubject = new Subject();
|
|
907
|
+
const addSavedChatSubject$ = new Subject();
|
|
774
908
|
const data = {
|
|
775
909
|
instanceId: this.chatInstanceId,
|
|
776
910
|
savedChatId: this.chatId,
|
|
@@ -780,20 +914,20 @@ class WebSocketChatService extends ChatService {
|
|
|
780
914
|
this.connection.on('SavedChatAdd', (res) => {
|
|
781
915
|
this.setSavedChatId(res.savedChat.id); // Persist the savedChatId
|
|
782
916
|
this.generateAuditEvent('saved-chat.add', {}, res.savedChat.id); // Generate audit event
|
|
783
|
-
addSavedChatSubject
|
|
784
|
-
addSavedChatSubject
|
|
917
|
+
addSavedChatSubject$.next(res.savedChat);
|
|
918
|
+
addSavedChatSubject$.complete();
|
|
785
919
|
});
|
|
786
920
|
// Invoke the method SavedChatAdd
|
|
787
921
|
this.connection.invoke('SavedChatAdd', data)
|
|
788
922
|
.catch(error => {
|
|
789
923
|
console.error('Error invoking SavedChatAdd:', error);
|
|
790
|
-
addSavedChatSubject
|
|
791
|
-
return Promise.resolve();
|
|
924
|
+
addSavedChatSubject$.error(new Error(error));
|
|
925
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
792
926
|
});
|
|
793
|
-
return addSavedChatSubject
|
|
927
|
+
return addSavedChatSubject$.asObservable();
|
|
794
928
|
}
|
|
795
929
|
updateSavedChat(id, name, messages) {
|
|
796
|
-
const updateSavedChatSubject = new Subject();
|
|
930
|
+
const updateSavedChatSubject$ = new Subject();
|
|
797
931
|
const data = {
|
|
798
932
|
instanceId: this.chatInstanceId,
|
|
799
933
|
savedChatId: id,
|
|
@@ -804,45 +938,64 @@ class WebSocketChatService extends ChatService {
|
|
|
804
938
|
if (messages)
|
|
805
939
|
data["history"] = messages;
|
|
806
940
|
this.connection.on('SavedChatUpdate', (res) => {
|
|
807
|
-
updateSavedChatSubject
|
|
808
|
-
updateSavedChatSubject
|
|
941
|
+
updateSavedChatSubject$.next(res.savedChat);
|
|
942
|
+
updateSavedChatSubject$.complete();
|
|
809
943
|
});
|
|
810
944
|
// Invoke the method SavedChatUpdate
|
|
811
945
|
this.connection.invoke('SavedChatUpdate', data)
|
|
812
946
|
.catch(error => {
|
|
813
947
|
console.error('Error invoking SavedChatUpdate:', error);
|
|
814
|
-
updateSavedChatSubject
|
|
815
|
-
return Promise.resolve();
|
|
948
|
+
updateSavedChatSubject$.error(new Error(error));
|
|
949
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
816
950
|
});
|
|
817
|
-
return updateSavedChatSubject
|
|
951
|
+
return updateSavedChatSubject$.asObservable();
|
|
818
952
|
}
|
|
819
953
|
deleteSavedChat(ids) {
|
|
820
|
-
const deleteSavedChatSubject = new Subject();
|
|
954
|
+
const deleteSavedChatSubject$ = new Subject();
|
|
821
955
|
const data = {
|
|
822
956
|
instanceId: this.chatInstanceId,
|
|
823
957
|
SavedChatIds: ids,
|
|
824
958
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
825
959
|
};
|
|
826
960
|
this.connection.on('SavedChatDelete', (res) => {
|
|
827
|
-
deleteSavedChatSubject
|
|
828
|
-
deleteSavedChatSubject
|
|
961
|
+
deleteSavedChatSubject$.next(res.deleteCount);
|
|
962
|
+
deleteSavedChatSubject$.complete();
|
|
829
963
|
});
|
|
830
964
|
// Invoke the method SavedChatDelete
|
|
831
965
|
this.connection.invoke('SavedChatDelete', data)
|
|
832
966
|
.catch(error => {
|
|
833
967
|
console.error('Error invoking SavedChatDelete:', error);
|
|
834
|
-
deleteSavedChatSubject
|
|
835
|
-
return Promise.resolve();
|
|
968
|
+
deleteSavedChatSubject$.error(new Error(error));
|
|
969
|
+
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection when no further error handling exists downstream
|
|
836
970
|
});
|
|
837
|
-
return deleteSavedChatSubject
|
|
971
|
+
return deleteSavedChatSubject$.asObservable();
|
|
838
972
|
}
|
|
839
973
|
/**
|
|
840
974
|
* 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
|
|
975
|
+
* It is a placeholder for non-streaming scenarios, where you invoke a specific hub method, and the server responds with frame message(s)
|
|
842
976
|
*/
|
|
843
977
|
initMessageHandlers() {
|
|
844
|
-
this.addMessageHandler("
|
|
845
|
-
|
|
978
|
+
this.addMessageHandler("Error", {
|
|
979
|
+
handler: (error) => {
|
|
980
|
+
console.error(error);
|
|
981
|
+
this.notificationsService.error(error);
|
|
982
|
+
},
|
|
983
|
+
isGlobalHandler: true
|
|
984
|
+
});
|
|
985
|
+
this.addMessageHandler("Quota", {
|
|
986
|
+
handler: (message) => {
|
|
987
|
+
try {
|
|
988
|
+
this.updateQuota(message.quota);
|
|
989
|
+
}
|
|
990
|
+
catch (error) {
|
|
991
|
+
console.error(error);
|
|
992
|
+
}
|
|
993
|
+
},
|
|
994
|
+
isGlobalHandler: true
|
|
995
|
+
});
|
|
996
|
+
this.addMessageHandler("Debug", { handler: () => { },
|
|
997
|
+
isGlobalHandler: true
|
|
998
|
+
});
|
|
846
999
|
this.addMessageHandler("ActionStart", { handler: (action) => this._actionMap.set(action.guid, action),
|
|
847
1000
|
isGlobalHandler: false });
|
|
848
1001
|
this.addMessageHandler("ActionResult", {
|
|
@@ -858,35 +1011,48 @@ class WebSocketChatService extends ChatService {
|
|
|
858
1011
|
isGlobalHandler: false
|
|
859
1012
|
});
|
|
860
1013
|
this.addMessageHandler("Message", {
|
|
861
|
-
handler: (message) => this.
|
|
1014
|
+
handler: (message) => this._response.at(-1).content += message ?? "",
|
|
862
1015
|
isGlobalHandler: false
|
|
863
1016
|
});
|
|
864
1017
|
this.addMessageHandler("History", {
|
|
865
1018
|
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
|
|
1019
|
+
// 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)
|
|
1020
|
+
// This is mandatory to not lose the previous updates of the chatHistory when the assistant is streaming multiple message steps
|
|
1021
|
+
this.chatHistory = [...this.chatHistory, ...(history.history.slice(this.chatHistory.length))];
|
|
1022
|
+
// Emit the updated chat usage metrics
|
|
873
1023
|
if (!!this.chatHistory.at(-1)?.additionalProperties.usageMetrics) {
|
|
874
1024
|
this.updateChatUsageMetrics(this.chatHistory.at(-1).additionalProperties.usageMetrics);
|
|
875
1025
|
}
|
|
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
1026
|
this._executionTime = history.executionTime;
|
|
1027
|
+
},
|
|
1028
|
+
isGlobalHandler: false
|
|
1029
|
+
});
|
|
1030
|
+
this.addMessageHandler("SuggestedActions", {
|
|
1031
|
+
handler: (message) => {
|
|
1032
|
+
// Since after the "History" and "MessageBreak" that this event is caught,
|
|
1033
|
+
// $suggestedAction needs to be updated directly to the last visible "assistant" message in the _response and the chatHistory
|
|
1034
|
+
this._response.at(-1).additionalProperties.$suggestedAction = (this._response.at(-1).additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
1035
|
+
const index = this.lastVisibleAssistantMessageIndex(this.chatHistory);
|
|
1036
|
+
if (index !== -1) {
|
|
1037
|
+
this.chatHistory[index].additionalProperties.$suggestedAction = (this.chatHistory[index].additionalProperties.$suggestedAction || []).concat(message.suggestedActions);
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
isGlobalHandler: false
|
|
1041
|
+
});
|
|
1042
|
+
this.addMessageHandler("DebugDisplay", {
|
|
1043
|
+
handler: (message) => this._debugMessages = this._debugMessages.concat(message),
|
|
1044
|
+
isGlobalHandler: false
|
|
1045
|
+
});
|
|
1046
|
+
this.addMessageHandler("MessageBreak", {
|
|
1047
|
+
handler: () => {
|
|
882
1048
|
// Generate audit event
|
|
883
1049
|
const details = {
|
|
884
1050
|
'duration': this._executionTime,
|
|
885
1051
|
'text': this.chatHistory.at(-1).content,
|
|
886
1052
|
'role': this.chatHistory.at(-1).role,
|
|
887
1053
|
'rank': this.chatHistory.length - 1,
|
|
888
|
-
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics
|
|
889
|
-
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics
|
|
1054
|
+
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.completionTokenCount,
|
|
1055
|
+
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics?.promptTokenCount,
|
|
890
1056
|
'attachments': JSON.stringify(this._attachments.map(({ recordId, contextId, parts, type }) => ({
|
|
891
1057
|
recordId,
|
|
892
1058
|
contextId,
|
|
@@ -895,31 +1061,13 @@ class WebSocketChatService extends ChatService {
|
|
|
895
1061
|
})))
|
|
896
1062
|
};
|
|
897
1063
|
this.generateAuditEvent('message', details);
|
|
1064
|
+
// Push a new assistant message to the _response array ONLY if the content of the last message is not empty
|
|
1065
|
+
if (this._response.at(-1).content !== "") {
|
|
1066
|
+
this._response.push({ role: "assistant", content: "", additionalProperties: { display: true } });
|
|
1067
|
+
}
|
|
898
1068
|
},
|
|
899
1069
|
isGlobalHandler: false
|
|
900
1070
|
});
|
|
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
1071
|
}
|
|
924
1072
|
/**
|
|
925
1073
|
* Override and register the entire _messageHandlers map by merging the provided map with the default one
|
|
@@ -934,7 +1082,7 @@ class WebSocketChatService extends ChatService {
|
|
|
934
1082
|
});
|
|
935
1083
|
// Merge the new event handlers with the existing ones
|
|
936
1084
|
this._messageHandlers = new Map([...this._messageHandlers, ..._messageHandlers]);
|
|
937
|
-
// Register the global
|
|
1085
|
+
// Register the global handlers among the merged map
|
|
938
1086
|
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
939
1087
|
if (eventHandler.isGlobalHandler) {
|
|
940
1088
|
this.registerMessageHandler(eventName, eventHandler);
|
|
@@ -944,7 +1092,7 @@ class WebSocketChatService extends ChatService {
|
|
|
944
1092
|
/**
|
|
945
1093
|
* Add a listener for a specific event.
|
|
946
1094
|
* If a listener for this same event already exists, it will be overridden.
|
|
947
|
-
* If the listener has "
|
|
1095
|
+
* If the listener has "isGlobalHandler" set to true, it will be registered to the hub connection.
|
|
948
1096
|
* @param eventName Name of the event to register a listener for
|
|
949
1097
|
* @param eventHandler The handler to be called when the event is received
|
|
950
1098
|
*/
|
|
@@ -998,8 +1146,12 @@ class WebSocketChatService extends ChatService {
|
|
|
998
1146
|
reject(new Error("No endpoint provided to connect the websocket to"));
|
|
999
1147
|
return;
|
|
1000
1148
|
}
|
|
1001
|
-
const logLevel = this.
|
|
1149
|
+
const logLevel = this._getLogLevel();
|
|
1002
1150
|
this.connection = this.signalRService.buildConnection(this.REQUEST_URL, { ...this.defaultOptions, ...options }, logLevel, true);
|
|
1151
|
+
const signalRServerTimeoutInMilliseconds = this.chatConfig$.value?.connectionSettings.signalRServerTimeoutInMilliseconds;
|
|
1152
|
+
if (signalRServerTimeoutInMilliseconds) {
|
|
1153
|
+
this.connection.serverTimeoutInMilliseconds = signalRServerTimeoutInMilliseconds;
|
|
1154
|
+
}
|
|
1003
1155
|
resolve();
|
|
1004
1156
|
});
|
|
1005
1157
|
}
|
|
@@ -1017,7 +1169,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1017
1169
|
stopConnection() {
|
|
1018
1170
|
return this.signalRService.stopConnection(this.connection);
|
|
1019
1171
|
}
|
|
1020
|
-
|
|
1172
|
+
_getTransports() {
|
|
1021
1173
|
switch (this.chatConfig$.value?.connectionSettings.signalRTransport) {
|
|
1022
1174
|
case "WebSockets":
|
|
1023
1175
|
return HttpTransportType.WebSockets;
|
|
@@ -1029,7 +1181,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1029
1181
|
return HttpTransportType.None;
|
|
1030
1182
|
}
|
|
1031
1183
|
}
|
|
1032
|
-
|
|
1184
|
+
_getLogLevel() {
|
|
1033
1185
|
switch (this.chatConfig$.value?.connectionSettings.signalRLogLevel) {
|
|
1034
1186
|
case "Critical":
|
|
1035
1187
|
return LogLevel.Critical; // Log level for diagnostic messages that indicate a failure that will terminate the entire application.
|
|
@@ -1063,7 +1215,7 @@ class WebSocketChatService extends ChatService {
|
|
|
1063
1215
|
// as far as we know, signalR only lets us tweak the request with this access token factory
|
|
1064
1216
|
// so we pass along the Sinequa CSRF token to pass the CSRF check..
|
|
1065
1217
|
return {
|
|
1066
|
-
transport: this.
|
|
1218
|
+
transport: this._getTransports(),
|
|
1067
1219
|
withCredentials: true,
|
|
1068
1220
|
headers,
|
|
1069
1221
|
accessTokenFactory: () => this.authenticationService.processedCredentials?.data?.csrfToken || ""
|
|
@@ -1304,10 +1456,10 @@ class ChatReferenceComponent {
|
|
|
1304
1456
|
}
|
|
1305
1457
|
}
|
|
1306
1458
|
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"] }] });
|
|
1459
|
+
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
1460
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
|
|
1309
1461
|
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"] }]
|
|
1462
|
+
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
1463
|
}], propDecorators: { reference: [{
|
|
1312
1464
|
type: Input
|
|
1313
1465
|
}], attachment: [{
|
|
@@ -1372,6 +1524,7 @@ class ChatMessageComponent {
|
|
|
1372
1524
|
this.openDocument = new EventEmitter();
|
|
1373
1525
|
this.openPreview = new EventEmitter();
|
|
1374
1526
|
this.suggestAction = new EventEmitter();
|
|
1527
|
+
this.chatStarterClicked = new EventEmitter();
|
|
1375
1528
|
this.edit = new EventEmitter();
|
|
1376
1529
|
this.copy = new EventEmitter();
|
|
1377
1530
|
this.regenerate = new EventEmitter();
|
|
@@ -1447,7 +1600,7 @@ class ChatMessageComponent {
|
|
|
1447
1600
|
if (changes.streaming) {
|
|
1448
1601
|
this.collapseProgress = !this.streaming;
|
|
1449
1602
|
}
|
|
1450
|
-
if (
|
|
1603
|
+
if (this.message?.role === "assistant") {
|
|
1451
1604
|
this.references = [];
|
|
1452
1605
|
this.referenceMap.clear();
|
|
1453
1606
|
for (let m of this.conversation) {
|
|
@@ -1547,17 +1700,19 @@ class ChatMessageComponent {
|
|
|
1547
1700
|
}
|
|
1548
1701
|
}
|
|
1549
1702
|
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 });
|
|
1703
|
+
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
1704
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
1552
1705
|
type: Component,
|
|
1553
1706
|
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"] }]
|
|
1707
|
+
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
1708
|
}], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
|
|
1556
1709
|
type: Input
|
|
1557
1710
|
}], conversation: [{
|
|
1558
1711
|
type: Input
|
|
1559
1712
|
}], suggestedActions: [{
|
|
1560
1713
|
type: Input
|
|
1714
|
+
}], chatStarters: [{
|
|
1715
|
+
type: Input
|
|
1561
1716
|
}], assistantMessageIcon: [{
|
|
1562
1717
|
type: Input
|
|
1563
1718
|
}], userMessageIcon: [{
|
|
@@ -1586,6 +1741,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1586
1741
|
type: Output
|
|
1587
1742
|
}], suggestAction: [{
|
|
1588
1743
|
type: Output
|
|
1744
|
+
}], chatStarterClicked: [{
|
|
1745
|
+
type: Output
|
|
1589
1746
|
}], edit: [{
|
|
1590
1747
|
type: Output
|
|
1591
1748
|
}], copy: [{
|
|
@@ -1732,8 +1889,8 @@ class RestChatService extends ChatService {
|
|
|
1732
1889
|
'text': response.content,
|
|
1733
1890
|
'role': response.role,
|
|
1734
1891
|
'rank': this.chatHistory.length - 1,
|
|
1735
|
-
'generation-tokencount': response.additionalProperties.usageMetrics
|
|
1736
|
-
'prompt-tokencount': response.additionalProperties.usageMetrics
|
|
1892
|
+
'generation-tokencount': response.additionalProperties.usageMetrics?.completionTokenCount,
|
|
1893
|
+
'prompt-tokencount': response.additionalProperties.usageMetrics?.promptTokenCount,
|
|
1737
1894
|
'attachments': response.additionalProperties.$attachment?.map(({ recordId, contextId, parts, type }) => ({
|
|
1738
1895
|
recordId,
|
|
1739
1896
|
contextId,
|
|
@@ -1746,6 +1903,11 @@ class RestChatService extends ChatService {
|
|
|
1746
1903
|
return { history: [...messages, response], executionTime: res.executionTime };
|
|
1747
1904
|
}), finalize(() => this.streaming$.next(false)));
|
|
1748
1905
|
}
|
|
1906
|
+
stopGeneration() {
|
|
1907
|
+
const error = new Error('Not supported in REST');
|
|
1908
|
+
console.error(error);
|
|
1909
|
+
return throwError(() => error);
|
|
1910
|
+
}
|
|
1749
1911
|
listSavedChat() {
|
|
1750
1912
|
if (!this.chatConfig$.value.savedChatSettings.enabled) {
|
|
1751
1913
|
return;
|
|
@@ -1864,10 +2026,10 @@ class TokenProgressBarComponent {
|
|
|
1864
2026
|
}
|
|
1865
2027
|
}
|
|
1866
2028
|
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"] }] });
|
|
2029
|
+
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
2030
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: TokenProgressBarComponent, decorators: [{
|
|
1869
2031
|
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"] }]
|
|
2032
|
+
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
2033
|
}], propDecorators: { instanceId: [{
|
|
1872
2034
|
type: Input
|
|
1873
2035
|
}] } });
|
|
@@ -1896,10 +2058,10 @@ class DebugMessageComponent {
|
|
|
1896
2058
|
}
|
|
1897
2059
|
}
|
|
1898
2060
|
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.
|
|
2061
|
+
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
2062
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: DebugMessageComponent, decorators: [{
|
|
1901
2063
|
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.
|
|
2064
|
+
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
2065
|
}], ctorParameters: function () { return [{ type: i2$1.UIService }]; }, propDecorators: { data: [{
|
|
1904
2066
|
type: Input
|
|
1905
2067
|
}], level: [{
|
|
@@ -1927,6 +2089,8 @@ class ChatComponent extends AbstractFacet {
|
|
|
1927
2089
|
this.messageHandlers = new Map();
|
|
1928
2090
|
/** When the assistant answer a user question, automatically scroll down to the bottom of the discussion */
|
|
1929
2091
|
this.automaticScrollToLastResponse = false;
|
|
2092
|
+
/** When the assistant answer a user question, automatically focus to the chat input */
|
|
2093
|
+
this.focusAfterResponse = false;
|
|
1930
2094
|
/** Icon to use for the assistant messages */
|
|
1931
2095
|
this.assistantMessageIcon = 'sq-sinequa';
|
|
1932
2096
|
/** Event emitter triggered once the signalR connection is established */
|
|
@@ -1943,10 +2107,17 @@ class ChatComponent extends AbstractFacet {
|
|
|
1943
2107
|
this.openPreview = new EventEmitter();
|
|
1944
2108
|
/** Event emitter triggered when the user clicks on a suggested action */
|
|
1945
2109
|
this.suggestAction = new EventEmitter();
|
|
2110
|
+
/** Event emitter triggered when the user clicks on a chat starter */
|
|
2111
|
+
this.chatStarter = new EventEmitter();
|
|
1946
2112
|
this.messages$ = new BehaviorSubject(undefined);
|
|
1947
2113
|
this.question = '';
|
|
1948
2114
|
this._actions = [];
|
|
1949
|
-
this.
|
|
2115
|
+
this._resetChatAction = new Action({
|
|
2116
|
+
icon: 'fas fa-sync',
|
|
2117
|
+
title: "Reset assistant",
|
|
2118
|
+
action: () => this.newChat()
|
|
2119
|
+
});
|
|
2120
|
+
this._sub = new Subscription();
|
|
1950
2121
|
this.changes$ = new BehaviorSubject(undefined);
|
|
1951
2122
|
this.firstChangesHandled = false;
|
|
1952
2123
|
this.isAtBottom = true;
|
|
@@ -1964,16 +2135,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
1964
2135
|
'Other'
|
|
1965
2136
|
];
|
|
1966
2137
|
this.issueType = '';
|
|
1967
|
-
this.
|
|
2138
|
+
this.reportType = 'dislike';
|
|
2139
|
+
this.showReport = false;
|
|
1968
2140
|
this.showDebugMessages = false;
|
|
1969
|
-
this.
|
|
1970
|
-
|
|
1971
|
-
title: 'Reset chat',
|
|
1972
|
-
action: () => this.newChat()
|
|
1973
|
-
}));
|
|
2141
|
+
this._reloadSubscription = undefined;
|
|
2142
|
+
this._actions.push(this._resetChatAction);
|
|
1974
2143
|
}
|
|
1975
2144
|
ngOnInit() {
|
|
1976
|
-
this.
|
|
2145
|
+
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
2146
|
if (this.chatService instanceof WebSocketChatService) {
|
|
1978
2147
|
this.connection.emit(this.chatService.connection);
|
|
1979
2148
|
}
|
|
@@ -1997,6 +2166,12 @@ class ChatComponent extends AbstractFacet {
|
|
|
1997
2166
|
throw error;
|
|
1998
2167
|
}
|
|
1999
2168
|
})).subscribe());
|
|
2169
|
+
this._sub.add(combineLatest([
|
|
2170
|
+
this.chatService.streaming$,
|
|
2171
|
+
this.chatService.stoppingGeneration$
|
|
2172
|
+
]).pipe(map(([streaming, stoppingGeneration]) => !!(streaming || stoppingGeneration))).subscribe((result) => {
|
|
2173
|
+
this._resetChatAction.disabled = result;
|
|
2174
|
+
}));
|
|
2000
2175
|
}
|
|
2001
2176
|
ngOnChanges(changes) {
|
|
2002
2177
|
this.changes$.next(changes);
|
|
@@ -2005,12 +2180,19 @@ class ChatComponent extends AbstractFacet {
|
|
|
2005
2180
|
}
|
|
2006
2181
|
}
|
|
2007
2182
|
ngOnDestroy() {
|
|
2008
|
-
this.
|
|
2009
|
-
this.
|
|
2183
|
+
this._sub.unsubscribe();
|
|
2184
|
+
this._dataSubscription?.unsubscribe();
|
|
2185
|
+
this._reloadSubscription?.unsubscribe();
|
|
2186
|
+
if (this.chatService instanceof WebSocketChatService) {
|
|
2187
|
+
this.chatService.stopConnection();
|
|
2188
|
+
}
|
|
2010
2189
|
}
|
|
2011
2190
|
get isAdmin() {
|
|
2012
2191
|
return this.principalService.principal?.isAdministrator || false;
|
|
2013
2192
|
}
|
|
2193
|
+
get visibleMessagesCount() {
|
|
2194
|
+
return this.messages$.value?.filter(m => m.additionalProperties.display).length || 0;
|
|
2195
|
+
}
|
|
2014
2196
|
/**
|
|
2015
2197
|
* Instantiate the chat service based on the provided @input protocol
|
|
2016
2198
|
* This chat service instance will then be stored in the instanceManagerService with provided @input instanceId as a key
|
|
@@ -2030,6 +2212,17 @@ class ChatComponent extends AbstractFacet {
|
|
|
2030
2212
|
this.instanceManagerService.storeInstance(this.instanceId, this.chatService);
|
|
2031
2213
|
}
|
|
2032
2214
|
get actions() { return this._actions; }
|
|
2215
|
+
/**
|
|
2216
|
+
* Handles the changes in the chat component.
|
|
2217
|
+
* If the chat service is a WebSocketChatService, it handles the override of the message handlers if they exist.
|
|
2218
|
+
* Initializes the chat with the provided chat messages if they exist, otherwise loads the default chat.
|
|
2219
|
+
* If the chat is initialized, the initialization event is "Query", the query changes, and the queryChangeShouldTriggerReload function is provided,
|
|
2220
|
+
* then the chat should be reloaded if the function returns true. Otherwise, the chat should be reloaded by default.
|
|
2221
|
+
* It takes into account the ongoing streaming process and the ongoing stopping process to trigger that conditionally define the logic
|
|
2222
|
+
* of the reload :
|
|
2223
|
+
* - If the chat is streaming, then stop the generation and wait for the fetch to complete before reloading the chat.
|
|
2224
|
+
* - If the chat is stopping the generation, then wait for the fetch to complete before reloading the chat.
|
|
2225
|
+
*/
|
|
2033
2226
|
_handleChanges() {
|
|
2034
2227
|
const changes = this.changes$.value;
|
|
2035
2228
|
// If the chat service is a WebSocketChatService, handle the override of the message handlers if exists
|
|
@@ -2064,11 +2257,69 @@ class ChatComponent extends AbstractFacet {
|
|
|
2064
2257
|
*/
|
|
2065
2258
|
if (this.firstChangesHandled && changes?.query && this.config.modeSettings.initialization.event === 'Query') {
|
|
2066
2259
|
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(this._previousQuery, this.query) : true) {
|
|
2067
|
-
this.
|
|
2260
|
+
if (!!this.chatService.stoppingGeneration$.value) {
|
|
2261
|
+
if (!this._reloadSubscription) {
|
|
2262
|
+
// Create a subscription to wait for both streaming$ and stoppingGeneration$ to be false
|
|
2263
|
+
this._reloadSubscription = combineLatest([
|
|
2264
|
+
this.chatService.streaming$,
|
|
2265
|
+
this.chatService.stoppingGeneration$
|
|
2266
|
+
])
|
|
2267
|
+
.pipe(filter(([streaming, stopping]) => !streaming && !stopping), // Wait until both are false
|
|
2268
|
+
take(1) // Complete after the first match
|
|
2269
|
+
).subscribe(() => {
|
|
2270
|
+
// Execute the reload after the query change
|
|
2271
|
+
this._triggerReloadAfterQueryChange();
|
|
2272
|
+
// Update _previousQuery with the current query
|
|
2273
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2274
|
+
// Clean up subscription and reset its value
|
|
2275
|
+
this._reloadSubscription = undefined;
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
else if (!!this.chatService.streaming$.value) {
|
|
2280
|
+
if (!this._reloadSubscription) {
|
|
2281
|
+
this._reloadSubscription = this.chatService.stopGeneration()
|
|
2282
|
+
.subscribe({
|
|
2283
|
+
next: () => { },
|
|
2284
|
+
error: () => {
|
|
2285
|
+
// Clean up subscription and reset its value
|
|
2286
|
+
this._reloadSubscription?.unsubscribe();
|
|
2287
|
+
this._reloadSubscription = undefined;
|
|
2288
|
+
},
|
|
2289
|
+
complete: () => {
|
|
2290
|
+
// Wait for the ongoing fetch to complete, then trigger the reload
|
|
2291
|
+
this.chatService.streaming$.pipe(filter((streaming) => !streaming), take(1)).subscribe(() => {
|
|
2292
|
+
// Execute the reload after the query change
|
|
2293
|
+
this._triggerReloadAfterQueryChange();
|
|
2294
|
+
// Update _previousQuery with the current query
|
|
2295
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2296
|
+
// Clean up subscription and reset its value
|
|
2297
|
+
this._reloadSubscription.unsubscribe();
|
|
2298
|
+
this._reloadSubscription = undefined;
|
|
2299
|
+
});
|
|
2300
|
+
}
|
|
2301
|
+
});
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
else {
|
|
2305
|
+
// Execute the reload after the query change
|
|
2306
|
+
this._triggerReloadAfterQueryChange();
|
|
2307
|
+
// Update _previousQuery with the current query
|
|
2308
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
else {
|
|
2312
|
+
// Update _previousQuery with the current query
|
|
2313
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query));
|
|
2068
2314
|
}
|
|
2069
|
-
this._previousQuery = JSON.parse(JSON.stringify(this.query)); // Update the previous query
|
|
2070
2315
|
}
|
|
2071
2316
|
}
|
|
2317
|
+
/**
|
|
2318
|
+
* Triggers a reload after the query change.
|
|
2319
|
+
* This method performs the necessary operations to reload the chat after a query change.
|
|
2320
|
+
* It sets the system and user messages, resets the savedChatId, generates a new chatId,
|
|
2321
|
+
* generates a new chat audit event, and handles the query mode.
|
|
2322
|
+
*/
|
|
2072
2323
|
_triggerReloadAfterQueryChange() {
|
|
2073
2324
|
const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
|
|
2074
2325
|
const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
|
|
@@ -2077,25 +2328,48 @@ class ChatComponent extends AbstractFacet {
|
|
|
2077
2328
|
this.chatService.generateAuditEvent('new-chat', { 'configuration': JSON.stringify(this.chatService.chatConfig$.value) }); // Generate a new chat audit event
|
|
2078
2329
|
this._handleQueryMode(systemMsg, userMsg);
|
|
2079
2330
|
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Adds a scroll listener to the message list element.
|
|
2333
|
+
* The listener is triggered when any of the following events occur:
|
|
2334
|
+
* - Loading state changes
|
|
2335
|
+
* - Messages change
|
|
2336
|
+
* - Streaming state changes
|
|
2337
|
+
* - Scroll event occurs on the message list element
|
|
2338
|
+
*
|
|
2339
|
+
* When the listener is triggered, it updates the `isAtBottom` property.
|
|
2340
|
+
*/
|
|
2080
2341
|
_addScrollListener() {
|
|
2081
|
-
this.
|
|
2342
|
+
this._sub.add(merge(this.loading$, this.messages$, this.chatService.streaming$, fromEvent(this.messageList.nativeElement, 'scroll')).subscribe(() => {
|
|
2082
2343
|
this.isAtBottom = this._toggleScrollButtonVisibility();
|
|
2083
2344
|
this.cdr.detectChanges();
|
|
2084
2345
|
}));
|
|
2085
2346
|
}
|
|
2347
|
+
/**
|
|
2348
|
+
* Get the model description based on the defaultValues service_id and model_id
|
|
2349
|
+
*/
|
|
2086
2350
|
updateModelDescription() {
|
|
2087
2351
|
this.modelDescription = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
|
|
2088
2352
|
this.cdr.detectChanges();
|
|
2089
2353
|
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Submits a question from the user.
|
|
2356
|
+
* If the user is editing a previous message, removes all subsequent messages from the chat history.
|
|
2357
|
+
* Triggers the fetch of the answer for the submitted question by calling _fetchAnswer().
|
|
2358
|
+
* Clears the input value in the UI.
|
|
2359
|
+
*/
|
|
2090
2360
|
submitQuestion() {
|
|
2361
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2362
|
+
return;
|
|
2363
|
+
}
|
|
2091
2364
|
if (this.question.trim() && this.messages$.value && this.chatService.chatHistory) {
|
|
2092
2365
|
// When the user submits a question, if the user is editing a previous message, remove all subsequent messages from the chat history
|
|
2093
2366
|
if (this.messageToEdit !== undefined) {
|
|
2094
2367
|
// Update the messages in the UI
|
|
2095
2368
|
this.messages$.next(this.messages$.value.slice(0, this.messageToEdit));
|
|
2096
2369
|
// 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.
|
|
2370
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, this.remappedMessageToEdit);
|
|
2098
2371
|
this.messageToEdit = undefined;
|
|
2372
|
+
this.remappedMessageToEdit = undefined;
|
|
2099
2373
|
}
|
|
2100
2374
|
// Remove the search warning message if exists
|
|
2101
2375
|
if (this.chatService.chatHistory.at(-1)?.role === 'search-warning') {
|
|
@@ -2108,6 +2382,13 @@ class ChatComponent extends AbstractFacet {
|
|
|
2108
2382
|
this.questionInput.nativeElement.style.height = `auto`;
|
|
2109
2383
|
}
|
|
2110
2384
|
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Triggers the fetch of the answer for the given question and updates the conversation.
|
|
2387
|
+
* Generates an audit event for the user input.
|
|
2388
|
+
*
|
|
2389
|
+
* @param question - The question asked by the user.
|
|
2390
|
+
* @param conversation - The current conversation messages.
|
|
2391
|
+
*/
|
|
2111
2392
|
_fetchAnswer(question, conversation) {
|
|
2112
2393
|
const userMsg = { role: 'user', content: question, additionalProperties: { display: true, isUserInput: true, additionalWorkflowProperties: this.config.additionalWorkflowProperties } };
|
|
2113
2394
|
const messages = [...conversation, userMsg];
|
|
@@ -2119,15 +2400,15 @@ class ChatComponent extends AbstractFacet {
|
|
|
2119
2400
|
* Depending on the connection's state :
|
|
2120
2401
|
* - If connected => given a list of messages, the chat endpoint is invoked for a continuation and updates the list of messages accordingly.
|
|
2121
2402
|
* - If any other state => a connection error message is displayed in the chat.
|
|
2122
|
-
* @param messages
|
|
2403
|
+
* @param messages The list of messages to invoke the chat endpoint with
|
|
2123
2404
|
*/
|
|
2124
2405
|
fetch(messages) {
|
|
2125
2406
|
this._updateConnectionStatus();
|
|
2126
2407
|
this.cdr.detectChanges();
|
|
2127
2408
|
if (this.isConnected) {
|
|
2128
2409
|
this.loading$.next(true);
|
|
2129
|
-
this.
|
|
2130
|
-
this.
|
|
2410
|
+
this._dataSubscription?.unsubscribe();
|
|
2411
|
+
this._dataSubscription = this.chatService.fetch(messages, this.query)
|
|
2131
2412
|
.subscribe({
|
|
2132
2413
|
next: res => this.updateData(res.history),
|
|
2133
2414
|
error: () => {
|
|
@@ -2139,6 +2420,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
2139
2420
|
this.terminateFetch();
|
|
2140
2421
|
},
|
|
2141
2422
|
complete: () => {
|
|
2423
|
+
// Remove the last message if it's an empty message
|
|
2424
|
+
// This is due to the manner in which the chat service handles consecutive messages
|
|
2425
|
+
const lastMessage = this.messages$.value?.at(-1);
|
|
2426
|
+
if (lastMessage?.role === 'assistant' && lastMessage?.content === ""
|
|
2427
|
+
&& !lastMessage?.additionalProperties?.$attachment && !lastMessage?.additionalProperties?.$progress
|
|
2428
|
+
&& !lastMessage?.additionalProperties?.$debug && !lastMessage?.additionalProperties?.$suggestedAction) {
|
|
2429
|
+
this.messages$.next(this.messages$.value?.slice(0, -1));
|
|
2430
|
+
}
|
|
2142
2431
|
this.terminateFetch();
|
|
2143
2432
|
}
|
|
2144
2433
|
});
|
|
@@ -2162,10 +2451,21 @@ class ChatComponent extends AbstractFacet {
|
|
|
2162
2451
|
if (this.chatService instanceof WebSocketChatService) {
|
|
2163
2452
|
// A one-time listener for reconnected event
|
|
2164
2453
|
const onReconnectedHandler = () => {
|
|
2454
|
+
// Get the messages without the last one (the connection error message)
|
|
2165
2455
|
const messages = this.messages$.value.slice(0, -1);
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2456
|
+
// Find the last "user" message in the messages list
|
|
2457
|
+
let index = messages.length - 1;
|
|
2458
|
+
while (index >= 0 && messages[index].role !== 'user') {
|
|
2459
|
+
index--;
|
|
2460
|
+
}
|
|
2461
|
+
// If a user message is found (and it should always be the case), remove all subsequent messages from the chat history
|
|
2462
|
+
// Update the messages in the UI
|
|
2463
|
+
// and fetch the answer from the assistant
|
|
2464
|
+
if (index >= 0) {
|
|
2465
|
+
this.messages$.next(this.messages$.value.slice(0, index + 1));
|
|
2466
|
+
const remappedIndex = this._remapIndexInChatHistory(index);
|
|
2467
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, remappedIndex + 1);
|
|
2468
|
+
this.fetch(this.chatService.chatHistory);
|
|
2169
2469
|
}
|
|
2170
2470
|
this.retrialAttempts = undefined; // Reset the number of retrial attempts
|
|
2171
2471
|
/**
|
|
@@ -2224,12 +2524,18 @@ class ChatComponent extends AbstractFacet {
|
|
|
2224
2524
|
this.scrollDown();
|
|
2225
2525
|
}
|
|
2226
2526
|
}
|
|
2527
|
+
/**
|
|
2528
|
+
* @returns true if the chat discussion is scrolled down to the bottom, false otherwise
|
|
2529
|
+
*/
|
|
2227
2530
|
_toggleScrollButtonVisibility() {
|
|
2228
2531
|
if (this.messageList?.nativeElement) {
|
|
2229
2532
|
return Math.round(this.messageList?.nativeElement.scrollHeight - this.messageList?.nativeElement.scrollTop - 1) <= this.messageList?.nativeElement.clientHeight;
|
|
2230
2533
|
}
|
|
2231
2534
|
return true;
|
|
2232
2535
|
}
|
|
2536
|
+
/**
|
|
2537
|
+
* Scroll down to the bottom of the chat discussion
|
|
2538
|
+
*/
|
|
2233
2539
|
scrollDown() {
|
|
2234
2540
|
setTimeout(() => {
|
|
2235
2541
|
if (this.messageList?.nativeElement) {
|
|
@@ -2244,12 +2550,39 @@ class ChatComponent extends AbstractFacet {
|
|
|
2244
2550
|
* If the savedChat feature is enabled, the list of saved chats will be refreshed
|
|
2245
2551
|
*/
|
|
2246
2552
|
newChat() {
|
|
2553
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2554
|
+
return;
|
|
2555
|
+
}
|
|
2247
2556
|
this.chatService.setSavedChatId(undefined); // Reset the savedChatId
|
|
2248
2557
|
this.chatService.generateChatId(); // Generate a new chatId
|
|
2249
2558
|
this.chatService.listSavedChat(); // Refresh the list of saved chats
|
|
2250
2559
|
this.chatService.generateAuditEvent('new-chat', { 'configuration': JSON.stringify(this.chatService.chatConfig$.value) }); // Generate a new chat audit event
|
|
2251
2560
|
this.loadDefaultChat(); // Start a new chat
|
|
2252
2561
|
}
|
|
2562
|
+
/**
|
|
2563
|
+
* Attaches the specified document IDs to the assistant.
|
|
2564
|
+
* If the chat is streaming or stopping the generation, the operation is not allowed.
|
|
2565
|
+
* If no document IDs are provided, the operation is not allowed.
|
|
2566
|
+
* If the action for attaching a document is not defined at the application customization level, an error is logged.
|
|
2567
|
+
* @param ids - An array of document IDs to attach.
|
|
2568
|
+
*/
|
|
2569
|
+
attachToChat(ids) {
|
|
2570
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
2571
|
+
return;
|
|
2572
|
+
}
|
|
2573
|
+
if (!ids || ids?.length < 1) {
|
|
2574
|
+
return;
|
|
2575
|
+
}
|
|
2576
|
+
const attachDocAction = this.config.modeSettings.actions?.["attachDocAction"];
|
|
2577
|
+
if (!attachDocAction) {
|
|
2578
|
+
console.error(`No action is defined for attaching a document to the assistant "${this.instanceId}"`);
|
|
2579
|
+
return;
|
|
2580
|
+
}
|
|
2581
|
+
const userMsg = { role: 'user', content: '', additionalProperties: { display: false, isUserInput: false, type: "Action", forcedWorkflow: attachDocAction.forcedWorkflow, forcedWorkflowProperties: { ...(attachDocAction.forcedWorkflowProperties || {}), ids }, additionalWorkflowProperties: this.config.additionalWorkflowProperties } };
|
|
2582
|
+
const messages = [...this.chatService.chatHistory, userMsg];
|
|
2583
|
+
this.messages$.next(messages);
|
|
2584
|
+
this.fetch(messages);
|
|
2585
|
+
}
|
|
2253
2586
|
/**
|
|
2254
2587
|
* Start the default chat with the defaultValues settings
|
|
2255
2588
|
* If the chat is meant to be initialized with event === "Query", the corresponding user query message will be added to the chat history
|
|
@@ -2309,7 +2642,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
2309
2642
|
*/
|
|
2310
2643
|
openChat(messages, savedChatId) {
|
|
2311
2644
|
if (!messages || !Array.isArray(messages)) {
|
|
2312
|
-
console.error('Error occurs while trying to load the
|
|
2645
|
+
console.error('Error occurs while trying to load the discussion. Invalid messages received :', messages);
|
|
2313
2646
|
return;
|
|
2314
2647
|
}
|
|
2315
2648
|
if (savedChatId) {
|
|
@@ -2342,16 +2675,36 @@ class ChatComponent extends AbstractFacet {
|
|
|
2342
2675
|
this.question = '';
|
|
2343
2676
|
this.terminateFetch();
|
|
2344
2677
|
}
|
|
2678
|
+
/**
|
|
2679
|
+
* Fetch and Load the saved chat from the saved chat index.
|
|
2680
|
+
* If the saved chat is found, the chat discussion will be loaded with the provided messages and chatId
|
|
2681
|
+
*/
|
|
2345
2682
|
onLoadChat() {
|
|
2346
2683
|
this.loading$.next(true);
|
|
2347
|
-
this.
|
|
2684
|
+
this._sub.add(this.chatService.loadSavedChat$
|
|
2348
2685
|
.pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.history, savedChatHistory.id))).subscribe());
|
|
2349
2686
|
}
|
|
2687
|
+
/**
|
|
2688
|
+
* Stop the generation of the current assistant's answer.
|
|
2689
|
+
* The fetch subscription will be terminated.
|
|
2690
|
+
*/
|
|
2691
|
+
stopGeneration() {
|
|
2692
|
+
this.chatService.stopGeneration().subscribe(() => this.terminateFetch());
|
|
2693
|
+
}
|
|
2694
|
+
/**
|
|
2695
|
+
* Terminate the fetch process by unsubscribing from the data subscription and updating the loading status to false.
|
|
2696
|
+
* Additionally, focus on the chat input if the focusAfterResponse flag is set to true.
|
|
2697
|
+
*/
|
|
2350
2698
|
terminateFetch() {
|
|
2351
|
-
this.
|
|
2352
|
-
this.
|
|
2699
|
+
this._dataSubscription?.unsubscribe();
|
|
2700
|
+
this._dataSubscription = undefined;
|
|
2353
2701
|
this.loading$.next(false);
|
|
2354
2702
|
this.cdr.detectChanges();
|
|
2703
|
+
if (this.focusAfterResponse) {
|
|
2704
|
+
setTimeout(() => {
|
|
2705
|
+
this.questionInput?.nativeElement.focus();
|
|
2706
|
+
});
|
|
2707
|
+
}
|
|
2355
2708
|
}
|
|
2356
2709
|
/**
|
|
2357
2710
|
* Copy a previous user message of the chat history to the chat user input.
|
|
@@ -2362,15 +2715,18 @@ class ChatComponent extends AbstractFacet {
|
|
|
2362
2715
|
*/
|
|
2363
2716
|
editMessage(index) {
|
|
2364
2717
|
this.messageToEdit = index;
|
|
2365
|
-
this.
|
|
2366
|
-
this.chatService.
|
|
2718
|
+
this.remappedMessageToEdit = this._remapIndexInChatHistory(index);
|
|
2719
|
+
this.question = this.chatService.chatHistory[this._remapIndexInChatHistory(index)].content;
|
|
2720
|
+
this.chatService.generateAuditEvent('edit.click', { 'rank': this._remapIndexInChatHistory(index) });
|
|
2367
2721
|
}
|
|
2368
2722
|
/**
|
|
2369
2723
|
* Copy a previous assistant message of the chat history to the clipboard.
|
|
2370
2724
|
* @param index The index of the assistant's message to edit
|
|
2371
2725
|
*/
|
|
2372
2726
|
copyMessage(index) {
|
|
2373
|
-
|
|
2727
|
+
// Remap the index in the chat history
|
|
2728
|
+
const idx = this._remapIndexInChatHistory(index);
|
|
2729
|
+
this.chatService.generateAuditEvent('copy.click', { 'rank': idx });
|
|
2374
2730
|
}
|
|
2375
2731
|
/**
|
|
2376
2732
|
* Starting from the provided index, remove all subsequent messages from the chat history and the UI accordingly.
|
|
@@ -2378,14 +2734,50 @@ class ChatComponent extends AbstractFacet {
|
|
|
2378
2734
|
* @param index The index of the assistant's message to regenerate
|
|
2379
2735
|
*/
|
|
2380
2736
|
regenerateMessage(index) {
|
|
2381
|
-
//
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2737
|
+
// Update the messages in the UI by removing all subsequent 'assistant' messages starting from the provided index until the first previous 'user' message
|
|
2738
|
+
let i = index;
|
|
2739
|
+
while (i >= 0 && (this.messages$.value)[i].role !== 'user') {
|
|
2740
|
+
i--;
|
|
2741
|
+
}
|
|
2742
|
+
// It should always be the case that i > 0
|
|
2743
|
+
if (i >= 0) {
|
|
2744
|
+
this.messages$.next(this.messages$.value.slice(0, i + 1));
|
|
2745
|
+
// Remap the index of this found first previous 'user' message in the chat history
|
|
2746
|
+
const idx = this._remapIndexInChatHistory(i);
|
|
2747
|
+
// Define and Update the chat history based on which the assistant will generate a new answer
|
|
2748
|
+
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, idx + 1);
|
|
2749
|
+
// Fetch the answer
|
|
2750
|
+
this.fetch(this.chatService.chatHistory);
|
|
2751
|
+
this.chatService.generateAuditEvent('regenerate.click', { 'rank': idx });
|
|
2752
|
+
}
|
|
2753
|
+
}
|
|
2754
|
+
/**
|
|
2755
|
+
* Remaps the index in the chat history.
|
|
2756
|
+
* The chat history is a list of messages where some messages can be hidden (display set to false).
|
|
2757
|
+
* The index provided as input is the index of the message in the chat history displayed in the UI.
|
|
2758
|
+
* This function should be removed once the backend is updated to add the ids of the messages in the chat history
|
|
2759
|
+
* @param index - The index to be remapped.
|
|
2760
|
+
*/
|
|
2761
|
+
_remapIndexInChatHistory(index) {
|
|
2762
|
+
// a copy of the chat history is created to avoid modifying the original chat history. Additionally, a rank is giving to each message.
|
|
2763
|
+
const history = this.chatService.chatHistory.slice().map((message, idx) => {
|
|
2764
|
+
return { ...message, additionalProperties: { ...message.additionalProperties, rank: idx } };
|
|
2765
|
+
});
|
|
2766
|
+
// Count the number of hidden messages in messages$ before the provided index
|
|
2767
|
+
// This is mandatory to get the correct rank of the message in the chat history
|
|
2768
|
+
// Since some hidden messages (like 'system' messages) are not displayed in the UI but have been counted in the provided index
|
|
2769
|
+
const numberOfHiddenMessagesInMessages$BeforeIndex = this.messages$.value.slice(0, index).filter(message => !message.additionalProperties.display).length;
|
|
2770
|
+
// remove all messages that have display set to false
|
|
2771
|
+
// this is mandatory since at the point of time when the assistant answers a question,
|
|
2772
|
+
// 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
|
|
2773
|
+
const filteredHistory = history.filter(message => message.additionalProperties.display);
|
|
2774
|
+
// return the index of the message in the filtered history
|
|
2775
|
+
return filteredHistory[index - numberOfHiddenMessagesInMessages$BeforeIndex].additionalProperties.rank;
|
|
2388
2776
|
}
|
|
2777
|
+
/**
|
|
2778
|
+
* Handles the key up event for 'Backspace' and 'Enter' keys.
|
|
2779
|
+
* @param event - The keyboard event.
|
|
2780
|
+
*/
|
|
2389
2781
|
onKeyUp(event) {
|
|
2390
2782
|
switch (event.key) {
|
|
2391
2783
|
case 'Backspace':
|
|
@@ -2402,6 +2794,11 @@ class ChatComponent extends AbstractFacet {
|
|
|
2402
2794
|
break;
|
|
2403
2795
|
}
|
|
2404
2796
|
}
|
|
2797
|
+
/**
|
|
2798
|
+
* Calculates and adjusts the height of the question input element based on its content.
|
|
2799
|
+
* If the Enter key is pressed without the Shift key, it prevents the default behavior.
|
|
2800
|
+
* @param event The keyboard event
|
|
2801
|
+
*/
|
|
2405
2802
|
calculateHeight(event) {
|
|
2406
2803
|
if (event?.key === 'Enter' && !event.shiftKey) {
|
|
2407
2804
|
event?.preventDefault();
|
|
@@ -2415,43 +2812,59 @@ class ChatComponent extends AbstractFacet {
|
|
|
2415
2812
|
}
|
|
2416
2813
|
/**
|
|
2417
2814
|
* Send a "like" event on clicking on the thumb-up icon of an assistant's message
|
|
2815
|
+
* @param message The assistant message to like
|
|
2418
2816
|
* @param rank The rank of the message to like
|
|
2419
2817
|
*/
|
|
2420
|
-
onLike(rank) {
|
|
2421
|
-
|
|
2818
|
+
onLike(message, rank) {
|
|
2819
|
+
// Remap the index in the chat history
|
|
2820
|
+
const idx = this._remapIndexInChatHistory(rank);
|
|
2821
|
+
this.chatService.generateAuditEvent('thumb-up.click', { rank: idx });
|
|
2822
|
+
this.reportType = 'like';
|
|
2823
|
+
this.messageToReport = message;
|
|
2824
|
+
this.reportComment = undefined;
|
|
2825
|
+
this.reportRank = rank;
|
|
2826
|
+
this.showReport = true;
|
|
2422
2827
|
}
|
|
2423
2828
|
/**
|
|
2424
2829
|
* Send a "dislike" event on clicking on the thumb-down icon of an assistant's message.
|
|
2425
2830
|
* It also opens the issue reporting dialog.
|
|
2426
2831
|
* @param message The assistant message to dislike
|
|
2427
|
-
* @param
|
|
2832
|
+
* @param index The rank of the message to dislike
|
|
2428
2833
|
*/
|
|
2429
2834
|
onDislike(message, rank) {
|
|
2430
|
-
|
|
2431
|
-
|
|
2835
|
+
// Remap the index in the chat history
|
|
2836
|
+
const idx = this._remapIndexInChatHistory(rank);
|
|
2837
|
+
this.chatService.generateAuditEvent('thumb-down.click', { rank: idx });
|
|
2838
|
+
this.reportType = 'dislike';
|
|
2839
|
+
this.messageToReport = message;
|
|
2432
2840
|
this.issueType = '';
|
|
2433
|
-
this.
|
|
2434
|
-
this.
|
|
2435
|
-
this.
|
|
2841
|
+
this.reportComment = undefined;
|
|
2842
|
+
this.reportRank = rank;
|
|
2843
|
+
this.showReport = true;
|
|
2436
2844
|
}
|
|
2437
2845
|
/**
|
|
2438
2846
|
* Report an issue related to the assistant's message.
|
|
2439
2847
|
*/
|
|
2440
|
-
|
|
2848
|
+
sendReport() {
|
|
2441
2849
|
const details = {
|
|
2442
|
-
'
|
|
2443
|
-
'
|
|
2444
|
-
'
|
|
2445
|
-
'rank': this.issueRank,
|
|
2850
|
+
'comment': this.reportComment,
|
|
2851
|
+
'text': this.messageToReport.content,
|
|
2852
|
+
'rank': this.reportRank,
|
|
2446
2853
|
};
|
|
2447
|
-
this.
|
|
2448
|
-
|
|
2854
|
+
if (this.reportType === 'dislike') {
|
|
2855
|
+
details['report-type'] = this.issueType;
|
|
2856
|
+
this.chatService.generateAuditEvent('negative-report.send', details);
|
|
2857
|
+
}
|
|
2858
|
+
else {
|
|
2859
|
+
this.chatService.generateAuditEvent('positive-report.send', details);
|
|
2860
|
+
}
|
|
2861
|
+
this.showReport = false;
|
|
2449
2862
|
}
|
|
2450
2863
|
/**
|
|
2451
|
-
* Close the
|
|
2864
|
+
* Close the reporting dialog.
|
|
2452
2865
|
*/
|
|
2453
|
-
|
|
2454
|
-
this.
|
|
2866
|
+
ignoreReport() {
|
|
2867
|
+
this.showReport = false;
|
|
2455
2868
|
}
|
|
2456
2869
|
/**
|
|
2457
2870
|
* Handle the click on a reference's 'open preview'.
|
|
@@ -2496,27 +2909,69 @@ class ChatComponent extends AbstractFacet {
|
|
|
2496
2909
|
this.suggestAction.emit(action);
|
|
2497
2910
|
this.chatService.generateAuditEvent('suggestedAction.click', { 'text': action.content, 'suggestedAction-type': action.type });
|
|
2498
2911
|
}
|
|
2912
|
+
/**
|
|
2913
|
+
* Handle the click on a chat starter.
|
|
2914
|
+
* @param starter the chat starter.
|
|
2915
|
+
*/
|
|
2916
|
+
chatStarterClick(starter) {
|
|
2917
|
+
this.chatStarter.emit(starter);
|
|
2918
|
+
}
|
|
2919
|
+
/**
|
|
2920
|
+
* It looks for the debug messages available in the current group of "assistant" messages.
|
|
2921
|
+
* By design, the debug messages are only available in the first visible message among the group "assistant" messages.
|
|
2922
|
+
* @param index The rank of the message
|
|
2923
|
+
* @returns The debug messages available in the current group of "assistant" messages
|
|
2924
|
+
*/
|
|
2925
|
+
getDebugMessages(index) {
|
|
2926
|
+
// If it is not an assistant message, return
|
|
2927
|
+
if ((this.messages$.value)[index].role !== 'assistant') {
|
|
2928
|
+
return [];
|
|
2929
|
+
}
|
|
2930
|
+
// Get the array of messages up to the indicated index
|
|
2931
|
+
const array = this.messages$.value.slice(0, index + 1);
|
|
2932
|
+
// If it is an assistant message, look for the debug messages available in the current group of "assistant" messages
|
|
2933
|
+
// By design, the debug messages are only available in the first visible message among the group "assistant" messages.
|
|
2934
|
+
const idx = this.chatService.firstVisibleAssistantMessageIndex(array);
|
|
2935
|
+
if (idx > -1) {
|
|
2936
|
+
return (this.messages$.value)[idx].additionalProperties.$debug || [];
|
|
2937
|
+
}
|
|
2938
|
+
return [];
|
|
2939
|
+
}
|
|
2499
2940
|
/**
|
|
2500
2941
|
* Handle the click on the 'show log info' button of a message.
|
|
2501
|
-
* @param
|
|
2942
|
+
* @param index The rank of the message
|
|
2502
2943
|
*/
|
|
2503
|
-
showDebug(
|
|
2504
|
-
this.debugMessages =
|
|
2944
|
+
showDebug(index) {
|
|
2945
|
+
this.debugMessages = this.getDebugMessages(index);
|
|
2505
2946
|
this.showDebugMessages = true;
|
|
2506
2947
|
this.cdr.detectChanges();
|
|
2507
2948
|
}
|
|
2949
|
+
/**
|
|
2950
|
+
* Verify whether the current message is an assistant message and that all following messages are assistant ones
|
|
2951
|
+
* Used to keep the "View progress" opened even though the assistant is sending additional messages after the current one
|
|
2952
|
+
* @param messages the list of current messages
|
|
2953
|
+
* @param index the index of the current message
|
|
2954
|
+
* @returns if this messages and the following ones (if any) are the last ones
|
|
2955
|
+
*/
|
|
2956
|
+
isAssistantLastMessages(messages, index) {
|
|
2957
|
+
for (let i = index; i < messages.length; i++) {
|
|
2958
|
+
if (messages[i].role !== 'assistant')
|
|
2959
|
+
return false;
|
|
2960
|
+
}
|
|
2961
|
+
return true;
|
|
2962
|
+
}
|
|
2508
2963
|
}
|
|
2509
2964
|
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: [
|
|
2965
|
+
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
2966
|
RestChatService,
|
|
2512
2967
|
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 });
|
|
2968
|
+
], 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
2969
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
2515
2970
|
type: Component,
|
|
2516
2971
|
args: [{ selector: 'sq-chat-v3', providers: [
|
|
2517
2972
|
RestChatService,
|
|
2518
2973
|
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"] }]
|
|
2974
|
+
], 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
2975
|
}], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
|
|
2521
2976
|
type: Input
|
|
2522
2977
|
}], query: [{
|
|
@@ -2529,6 +2984,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2529
2984
|
type: Input
|
|
2530
2985
|
}], automaticScrollToLastResponse: [{
|
|
2531
2986
|
type: Input
|
|
2987
|
+
}], focusAfterResponse: [{
|
|
2988
|
+
type: Input
|
|
2532
2989
|
}], chat: [{
|
|
2533
2990
|
type: Input
|
|
2534
2991
|
}], assistantMessageIcon: [{
|
|
@@ -2555,6 +3012,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2555
3012
|
type: Output
|
|
2556
3013
|
}], suggestAction: [{
|
|
2557
3014
|
type: Output
|
|
3015
|
+
}], chatStarter: [{
|
|
3016
|
+
type: Output
|
|
2558
3017
|
}], messageList: [{
|
|
2559
3018
|
type: ViewChild,
|
|
2560
3019
|
args: ['messageList']
|
|
@@ -2564,9 +3023,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2564
3023
|
}], loadingTpl: [{
|
|
2565
3024
|
type: ContentChild,
|
|
2566
3025
|
args: ['loadingTpl']
|
|
2567
|
-
}],
|
|
3026
|
+
}], reportTpl: [{
|
|
2568
3027
|
type: ContentChild,
|
|
2569
|
-
args: ['
|
|
3028
|
+
args: ['reportTpl']
|
|
2570
3029
|
}], tokenConsumptionTpl: [{
|
|
2571
3030
|
type: ContentChild,
|
|
2572
3031
|
args: ['tokenConsumptionTpl']
|
|
@@ -2604,6 +3063,9 @@ class SavedChatsComponent {
|
|
|
2604
3063
|
}));
|
|
2605
3064
|
}
|
|
2606
3065
|
onLoad(savedChat) {
|
|
3066
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
3067
|
+
return;
|
|
3068
|
+
}
|
|
2607
3069
|
this.chatService.setSavedChatId(savedChat.id);
|
|
2608
3070
|
this.chatService.generateChatId(savedChat.id);
|
|
2609
3071
|
this.chatService.loadSavedChat$.next(savedChat);
|
|
@@ -2611,7 +3073,11 @@ class SavedChatsComponent {
|
|
|
2611
3073
|
this.chatService.listSavedChat();
|
|
2612
3074
|
this.load.emit(savedChat);
|
|
2613
3075
|
}
|
|
2614
|
-
onRename(savedChat) {
|
|
3076
|
+
onRename(event, savedChat) {
|
|
3077
|
+
event.stopPropagation();
|
|
3078
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
3079
|
+
return;
|
|
3080
|
+
}
|
|
2615
3081
|
const model = {
|
|
2616
3082
|
title: 'Rename saved discussion',
|
|
2617
3083
|
message: `Please enter a new name for the discussion "${savedChat.title}".`,
|
|
@@ -2637,7 +3103,11 @@ class SavedChatsComponent {
|
|
|
2637
3103
|
}
|
|
2638
3104
|
});
|
|
2639
3105
|
}
|
|
2640
|
-
onDelete(savedChat) {
|
|
3106
|
+
onDelete(event, savedChat) {
|
|
3107
|
+
event.stopPropagation();
|
|
3108
|
+
if (!!this.chatService.streaming$.value || !!this.chatService.stoppingGeneration$.value) {
|
|
3109
|
+
return;
|
|
3110
|
+
}
|
|
2641
3111
|
this.modalService
|
|
2642
3112
|
.confirm({
|
|
2643
3113
|
title: "Delete saved discussion",
|
|
@@ -2714,10 +3184,10 @@ class SavedChatsComponent {
|
|
|
2714
3184
|
}
|
|
2715
3185
|
}
|
|
2716
3186
|
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\"
|
|
3187
|
+
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
3188
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, decorators: [{
|
|
2719
3189
|
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\"
|
|
3190
|
+
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
3191
|
}], propDecorators: { instanceId: [{
|
|
2722
3192
|
type: Input
|
|
2723
3193
|
}], load: [{
|