@sinequa/assistant 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat/chat-message/chat-message.component.d.ts +15 -106
- package/chat/chat-reference/chat-reference.component.d.ts +1 -105
- package/chat/chat.component.d.ts +72 -22
- package/chat/chat.service.d.ts +40 -22
- package/chat/types.d.ts +1 -1
- package/esm2020/chat/chat-message/chat-message.component.mjs +23 -5
- package/esm2020/chat/chat-reference/chat-reference.component.mjs +3 -3
- package/esm2020/chat/chat.component.mjs +154 -32
- package/esm2020/chat/chat.service.mjs +52 -39
- package/esm2020/chat/rest-chat.service.mjs +23 -5
- package/esm2020/chat/saved-chats/saved-chats.component.mjs +5 -1
- package/esm2020/chat/types.mjs +1 -1
- package/esm2020/chat/websocket-chat.service.mjs +19 -3
- package/fesm2015/sinequa-assistant-chat.mjs +271 -81
- package/fesm2015/sinequa-assistant-chat.mjs.map +1 -1
- package/fesm2020/sinequa-assistant-chat.mjs +270 -80
- package/fesm2020/sinequa-assistant-chat.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -273,25 +273,25 @@ const chatConfigSchema = z.object({
|
|
|
273
273
|
|
|
274
274
|
class ChatService {
|
|
275
275
|
constructor() {
|
|
276
|
-
/** Emit true once the initialization of the chat process is done*/
|
|
276
|
+
/** Emit true once the initialization of the chat process is done. */
|
|
277
277
|
this.initProcess$ = new BehaviorSubject(false);
|
|
278
|
-
/** Emit true once the initialization of the chat config is done*/
|
|
278
|
+
/** Emit true once the initialization of the chat config is done. */
|
|
279
279
|
this.initConfig$ = new BehaviorSubject(false);
|
|
280
|
-
/** Global configuration of the chat */
|
|
280
|
+
/** Global configuration of the chat. */
|
|
281
281
|
this.chatConfig$ = new BehaviorSubject(undefined);
|
|
282
|
-
/** Streaming status of the chat endpoint */
|
|
282
|
+
/** Streaming status of the chat endpoint. */
|
|
283
283
|
this.streaming$ = new BehaviorSubject(false);
|
|
284
|
-
/** List of saved chats */
|
|
284
|
+
/** List of saved chats. */
|
|
285
285
|
this.savedChats$ = new BehaviorSubject([]);
|
|
286
|
-
/** Emit the saved chat to load */
|
|
286
|
+
/** Emit the saved chat to load. */
|
|
287
287
|
this.loadSavedChat$ = new BehaviorSubject(undefined);
|
|
288
|
-
/** Emit the quota each time the chat is invoked */
|
|
288
|
+
/** Emit the quota each time the chat is invoked. */
|
|
289
289
|
this.quota$ = new BehaviorSubject(undefined);
|
|
290
|
-
/** Emit the calculated user's token consumption based on the quota */
|
|
290
|
+
/** Emit the calculated user's token consumption based on the quota. */
|
|
291
291
|
this.userTokenConsumption$ = new BehaviorSubject(undefined);
|
|
292
|
-
/** Emit the chat usage metrics each time the generation of the assistant response is completed */
|
|
292
|
+
/** Emit the chat usage metrics each time the generation of the assistant response is completed. */
|
|
293
293
|
this.chatUsageMetrics$ = new BehaviorSubject(undefined);
|
|
294
|
-
/** Emit the calculated chat's token consumption based on the chat usage metrics */
|
|
294
|
+
/** Emit the calculated chat's token consumption based on the chat usage metrics. */
|
|
295
295
|
this.chatTokenConsumption$ = new BehaviorSubject(undefined);
|
|
296
296
|
this.userSettingsService = inject(UserSettingsWebService);
|
|
297
297
|
this.notificationsService = inject(NotificationsService);
|
|
@@ -301,6 +301,7 @@ class ChatService {
|
|
|
301
301
|
this.appService = inject(AppService);
|
|
302
302
|
this.intlService = inject(IntlService);
|
|
303
303
|
this.modalService = inject(ModalService);
|
|
304
|
+
this.principalService = inject(PrincipalWebService);
|
|
304
305
|
}
|
|
305
306
|
get assistants() {
|
|
306
307
|
if (!this.userSettingsService.userSettings)
|
|
@@ -337,6 +338,21 @@ class ChatService {
|
|
|
337
338
|
setSavedChatId(savedChatId) {
|
|
338
339
|
this._savedChatId = savedChatId;
|
|
339
340
|
}
|
|
341
|
+
/**
|
|
342
|
+
* Get the ID of the current chat discussion which is used to identify audit events
|
|
343
|
+
* @returns The ID of the current chat discussion
|
|
344
|
+
*/
|
|
345
|
+
get chatId() {
|
|
346
|
+
return this._chatId;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Generate an GUID for the current chat discussion which is used to identify audit events
|
|
350
|
+
* If the discussion is saved, the savedChatId is initialized with the value of this chatId
|
|
351
|
+
* @param chatId if provided, it will be considered as the ID of the current chat discussion which is used to identify audit events
|
|
352
|
+
*/
|
|
353
|
+
generateChatId(chatId) {
|
|
354
|
+
this._chatId = chatId || Utils.guid();
|
|
355
|
+
}
|
|
340
356
|
/**
|
|
341
357
|
* Initialize the chat config by managing ONLY sub-object **defaultValues** configs of the standard app config (defined in the customization json tab ) and the user preferences.
|
|
342
358
|
* To do so, a tracking mechanism is implemented to notify the user about the available updates in the defaultValues object of the standard app config.
|
|
@@ -478,27 +494,28 @@ class ChatService {
|
|
|
478
494
|
}
|
|
479
495
|
return model;
|
|
480
496
|
}
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
497
|
+
/**
|
|
498
|
+
* Generate an audit event with the given type and details. The generated audit event is sent afterwards via the AuditWebService
|
|
499
|
+
* @param type Audit event type
|
|
500
|
+
* @param details Audit event details
|
|
501
|
+
* @param id Actions (savedChat delete/rename/...) may occur on a specific chat different than the current one stored in this service, so the chat id can be provided
|
|
502
|
+
*/
|
|
503
|
+
generateAuditEvent(type, details, id) {
|
|
504
|
+
var _a;
|
|
505
|
+
const baseDetails = {
|
|
506
|
+
"url": decodeURIComponent(window.location.href),
|
|
507
|
+
"app": this.appService.appName,
|
|
508
|
+
"user-id": (_a = this.principalService.principal) === null || _a === void 0 ? void 0 : _a.userId,
|
|
509
|
+
"instance-id": this.chatInstanceId,
|
|
510
|
+
"chat-id": id || this.chatId,
|
|
511
|
+
"service-id": this.chatConfig$.value.defaultValues.service_id,
|
|
512
|
+
"model-id": this.chatConfig$.value.defaultValues.model_id,
|
|
513
|
+
};
|
|
514
|
+
const audit = {
|
|
515
|
+
type,
|
|
516
|
+
detail: Object.assign(Object.assign({}, baseDetails), details)
|
|
517
|
+
};
|
|
518
|
+
this.auditService.notify(audit);
|
|
502
519
|
}
|
|
503
520
|
/**
|
|
504
521
|
* Format a date string in UTC to a local date string
|
|
@@ -517,12 +534,6 @@ class ChatService {
|
|
|
517
534
|
static formatPrompt(prompt, context) {
|
|
518
535
|
return prompt.replace(/{{(.*?)}}/g, (match, expr) => { var _a; return (_a = get(context, expr)) !== null && _a !== void 0 ? _a : match; });
|
|
519
536
|
}
|
|
520
|
-
/**
|
|
521
|
-
* @returns A Globally Unique Identifier
|
|
522
|
-
*/
|
|
523
|
-
static generateGUID() {
|
|
524
|
-
return Utils.guid();
|
|
525
|
-
}
|
|
526
537
|
}
|
|
527
538
|
ChatService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
528
539
|
ChatService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatService });
|
|
@@ -661,7 +672,6 @@ class WebSocketChatService extends ChatService {
|
|
|
661
672
|
);
|
|
662
673
|
// Invoke the Chat method
|
|
663
674
|
this.connection.invoke('Chat', data)
|
|
664
|
-
.then(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.defaultValues.service_id)) // When the server indicates it has successfully finished invoking the method, notify the audit service with the recent chat history
|
|
665
675
|
.catch(error => {
|
|
666
676
|
console.error('Error invoking Chat:', error);
|
|
667
677
|
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
@@ -739,12 +749,13 @@ class WebSocketChatService extends ChatService {
|
|
|
739
749
|
const addSavedChatSubject = new Subject();
|
|
740
750
|
const data = {
|
|
741
751
|
instanceId: this.chatInstanceId,
|
|
742
|
-
savedChatId:
|
|
752
|
+
savedChatId: this.chatId,
|
|
743
753
|
history: messages,
|
|
744
754
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
745
755
|
};
|
|
746
756
|
this.connection.on('SavedChatAdd', (res) => {
|
|
747
757
|
this.setSavedChatId(res.savedChat.id); // Persist the savedChatId
|
|
758
|
+
this.generateAuditEvent('saved-chat.add', {}, res.savedChat.id); // Generate audit event
|
|
748
759
|
addSavedChatSubject.next(res.savedChat);
|
|
749
760
|
addSavedChatSubject.complete();
|
|
750
761
|
});
|
|
@@ -841,6 +852,22 @@ class WebSocketChatService extends ChatService {
|
|
|
841
852
|
action.pipe(take(1)).subscribe();
|
|
842
853
|
}
|
|
843
854
|
this._executionTime = history.executionTime;
|
|
855
|
+
// Generate audit event
|
|
856
|
+
const details = {
|
|
857
|
+
'duration': this._executionTime,
|
|
858
|
+
'text': this.chatHistory.at(-1).content,
|
|
859
|
+
'role': this.chatHistory.at(-1).role,
|
|
860
|
+
'rank': this.chatHistory.length - 1,
|
|
861
|
+
'generation-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics.completionTokenCount,
|
|
862
|
+
'prompt-tokencount': this.chatHistory.at(-1).additionalProperties.usageMetrics.promptTokenCount,
|
|
863
|
+
'attachments': this._attachments.map(({ recordId, contextId, parts, type }) => ({
|
|
864
|
+
recordId,
|
|
865
|
+
contextId,
|
|
866
|
+
parts: parts.map(({ partId, text }) => ({ partId, text })),
|
|
867
|
+
type
|
|
868
|
+
}))
|
|
869
|
+
};
|
|
870
|
+
this.generateAuditEvent('message', details);
|
|
844
871
|
},
|
|
845
872
|
isGlobalHandler: false
|
|
846
873
|
});
|
|
@@ -1249,10 +1276,10 @@ class ChatReferenceComponent {
|
|
|
1249
1276
|
}
|
|
1250
1277
|
}
|
|
1251
1278
|
ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1252
|
-
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\">\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\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"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)=\"openDocument.emit(attachment
|
|
1279
|
+
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\">\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\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"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)=\"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-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)}.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"] }] });
|
|
1253
1280
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
|
|
1254
1281
|
type: Component,
|
|
1255
|
-
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\">\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\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"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)=\"openDocument.emit(attachment
|
|
1282
|
+
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\">\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\" (click)=\"expandAttachment()\">\n {{attachment.record.title}}\n </a>\n <i class=\"fas fa-eye\" (click)=\"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)=\"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-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)}.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"] }]
|
|
1256
1283
|
}], propDecorators: { reference: [{
|
|
1257
1284
|
type: Input
|
|
1258
1285
|
}], attachment: [{
|
|
@@ -1279,11 +1306,16 @@ class ChatMessageComponent {
|
|
|
1279
1306
|
this.openPreview = new EventEmitter();
|
|
1280
1307
|
this.suggestAction = new EventEmitter();
|
|
1281
1308
|
this.edit = new EventEmitter();
|
|
1309
|
+
this.copy = new EventEmitter();
|
|
1282
1310
|
this.regenerate = new EventEmitter();
|
|
1311
|
+
this.like = new EventEmitter();
|
|
1312
|
+
this.dislike = new EventEmitter();
|
|
1283
1313
|
this.references = [];
|
|
1284
1314
|
this.referenceMap = new Map();
|
|
1285
1315
|
this.showReferences = true;
|
|
1286
1316
|
this.iconSize = 24;
|
|
1317
|
+
this.liked = false;
|
|
1318
|
+
this.disliked = false;
|
|
1287
1319
|
/**
|
|
1288
1320
|
* This Unified plugin looks a text nodes and replaces any reference in the
|
|
1289
1321
|
* form [1], [2.3], etc. with custom nodes of type "chat-reference".
|
|
@@ -1411,16 +1443,23 @@ class ChatMessageComponent {
|
|
|
1411
1443
|
getReferenceMatches(content) {
|
|
1412
1444
|
return Array.from(content.matchAll(/\[(\s*\d+(?:\.\d+)?\s*)\]/g));
|
|
1413
1445
|
}
|
|
1414
|
-
copyToClipboard(
|
|
1415
|
-
this.ui.copyToClipboard(
|
|
1446
|
+
copyToClipboard(message) {
|
|
1447
|
+
this.ui.copyToClipboard(message.content);
|
|
1448
|
+
this.copy.emit(message);
|
|
1449
|
+
}
|
|
1450
|
+
openAttachmentPreview(attachment, partId) {
|
|
1451
|
+
this.openPreview.emit({ reference: attachment, partId });
|
|
1452
|
+
}
|
|
1453
|
+
openOriginalAttachment(attachment, partId) {
|
|
1454
|
+
this.openDocument.emit({ reference: attachment, partId });
|
|
1416
1455
|
}
|
|
1417
1456
|
}
|
|
1418
1457
|
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 });
|
|
1419
|
-
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", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", edit: "edit", regenerate: "regenerate" }, 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 <i [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"message.role === 'assistant'\"></i>\n <ng-container *ngIf=\"message?.role === 'user'\">\n <i [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"!!userMessageIcon; else initialsAvatar\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\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 <remark *ngIf=\"message?.role === 'assistant'\" [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 (click)=\"openDocument.emit(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</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)=\"copyToClipboard(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 [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument.emit($event)\"></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-action\" *ngIf=\"message\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-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 class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument.emit($event)\">\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-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) .sq-chat-message-action{display:none}.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:block;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-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-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:0;display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\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: "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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1458
|
+
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", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", edit: "edit", copy: "copy", regenerate: "regenerate", like: "like", dislike: "dislike" }, 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 <i [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"message.role === 'assistant'\"></i>\n <ng-container *ngIf=\"message?.role === 'user'\">\n <i [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"!!userMessageIcon; else initialsAvatar\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\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 <remark *ngIf=\"message?.role === 'assistant'\" [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)=\"copyToClipboard(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\"\n (click)=\"edit.emit(message)\">\n<i class=\"fas fa-edit\"></i>\n</button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\" (click)=\"copyToClipboard(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=\"message.role === 'assistant' && !streaming\" sqTooltip=\"Like the answer\"\n (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=\"message.role === 'assistant' && !streaming\" sqTooltip=\"Report an issue\"\n (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></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 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-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:block;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-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)}.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: "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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1420
1459
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
1421
1460
|
type: Component,
|
|
1422
1461
|
args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
|
|
1423
|
-
InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <i [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"message.role === 'assistant'\"></i>\n <ng-container *ngIf=\"message?.role === 'user'\">\n <i [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"!!userMessageIcon; else initialsAvatar\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\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 <remark *ngIf=\"message?.role === 'assistant'\" [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 (click)=\"openDocument.emit(attachment.record)\"\n class=\"reference\"\n [sqTooltip]=\"attachment\"\n [sqTooltipTemplate]=\"tooltipTpl\"\n [hoverableTooltip]=\"true\"\n >{{ref.refId}}</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)=\"copyToClipboard(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 [class.expanded]=\"attachment.$expanded\" [attachment]=\"attachment\" [reference]=\"reference\"\n (openPreview)=\"openPreview.emit($event)\" (openDocument)=\"openDocument.emit($event)\"></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-action\" *ngIf=\"message\">\n <button class=\"btn btn-sm\" *ngIf=\"canEdit\" sqTooltip=\"Edit message\"\n (click)=\"edit.emit(message)\">\n <i class=\"fas fa-edit\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\"\n (click)=\"copyToClipboard(message.content)\">\n <i class=\"far fa-clipboard\"></i>\n </button>\n <button class=\"btn btn-sm\" *ngIf=\"canRegenerate\" sqTooltip=\"Regenerate message\"\n (click)=\"regenerate.emit(message)\">\n <i class=\"fas fa-sync-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 class=\"expanded\"\n [attachment]=\"ref\"\n [reference]=\"ref.contextId\"\n [partId]=\"ref.$partId\"\n (openPreview)=\"openPreview.emit($event)\"\n (openDocument)=\"openDocument.emit($event)\">\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-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) .sq-chat-message-action{display:none}.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:block;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-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-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:0;display:flex;flex-direction:column}.message-icon{margin-top:var(--ast-size-3, .75rem);margin-right:var(--ast-size-4, 1rem)}\n"] }]
|
|
1462
|
+
InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message?.role\">\n <i class=\"d-block\" [style.width.px]=\"iconSize\" *ngIf=\"!message\"></i>\n <i [ngClass]=\"assistantMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"message.role === 'assistant'\"></i>\n <ng-container *ngIf=\"message?.role === 'user'\">\n <i [ngClass]=\"userMessageIcon\" [style.--sq-size.px]=\"iconSize\" *ngIf=\"!!userMessageIcon; else initialsAvatar\"></i>\n <ng-template #initialsAvatar>\n <sq-initials-avatar [fullName]=\"name\"></sq-initials-avatar>\n </ng-template>\n </ng-container>\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 <remark *ngIf=\"message?.role === 'assistant'\" [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)=\"copyToClipboard(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\"\n (click)=\"edit.emit(message)\">\n<i class=\"fas fa-edit\"></i>\n</button>\n <button class=\"btn btn-sm\" *ngIf=\"canCopy\" sqTooltip=\"Copy to clipboard\" (click)=\"copyToClipboard(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=\"message.role === 'assistant' && !streaming\" sqTooltip=\"Like the answer\"\n (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=\"message.role === 'assistant' && !streaming\" sqTooltip=\"Report an issue\"\n (click)=\"dislike.emit(message); disliked = true;\">\n <i class=\"far fa-thumbs-down\"></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 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-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:block;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-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)}.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"] }]
|
|
1424
1463
|
}], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
|
|
1425
1464
|
type: Input
|
|
1426
1465
|
}], conversation: [{
|
|
@@ -1447,8 +1486,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1447
1486
|
type: Output
|
|
1448
1487
|
}], edit: [{
|
|
1449
1488
|
type: Output
|
|
1489
|
+
}], copy: [{
|
|
1490
|
+
type: Output
|
|
1450
1491
|
}], regenerate: [{
|
|
1451
1492
|
type: Output
|
|
1493
|
+
}], like: [{
|
|
1494
|
+
type: Output
|
|
1495
|
+
}], dislike: [{
|
|
1496
|
+
type: Output
|
|
1452
1497
|
}] } });
|
|
1453
1498
|
|
|
1454
1499
|
class RestChatService extends ChatService {
|
|
@@ -1535,7 +1580,7 @@ class RestChatService extends ChatService {
|
|
|
1535
1580
|
}
|
|
1536
1581
|
// Request the Chat endpoint
|
|
1537
1582
|
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(tap((res) => this.updateQuota(res.quota, true)), map((res) => {
|
|
1538
|
-
var _a;
|
|
1583
|
+
var _a, _b;
|
|
1539
1584
|
// Define $progress from the actions property of the response
|
|
1540
1585
|
let $progress;
|
|
1541
1586
|
if (((_a = res.actions) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
@@ -1571,9 +1616,25 @@ class RestChatService extends ChatService {
|
|
|
1571
1616
|
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
1572
1617
|
action.pipe(take(1)).subscribe();
|
|
1573
1618
|
}
|
|
1619
|
+
// Generate audit event
|
|
1620
|
+
const details = {
|
|
1621
|
+
'duration': res.executionTime,
|
|
1622
|
+
'text': response.content,
|
|
1623
|
+
'role': response.role,
|
|
1624
|
+
'rank': this.chatHistory.length - 1,
|
|
1625
|
+
'generation-tokencount': response.additionalProperties.usageMetrics.completionTokenCount,
|
|
1626
|
+
'prompt-tokencount': response.additionalProperties.usageMetrics.promptTokenCount,
|
|
1627
|
+
'attachments': (_b = response.additionalProperties.$attachment) === null || _b === void 0 ? void 0 : _b.map(({ recordId, contextId, parts, type }) => ({
|
|
1628
|
+
recordId,
|
|
1629
|
+
contextId,
|
|
1630
|
+
parts: parts.map(({ partId, text }) => ({ partId, text })),
|
|
1631
|
+
type
|
|
1632
|
+
}))
|
|
1633
|
+
};
|
|
1634
|
+
this.generateAuditEvent('message', details);
|
|
1574
1635
|
// Return the result
|
|
1575
1636
|
return { history: [...messages, response], executionTime: res.executionTime };
|
|
1576
|
-
}),
|
|
1637
|
+
}), finalize(() => this.streaming$.next(false)));
|
|
1577
1638
|
}
|
|
1578
1639
|
listSavedChat() {
|
|
1579
1640
|
const data = {
|
|
@@ -1590,12 +1651,14 @@ class RestChatService extends ChatService {
|
|
|
1590
1651
|
const data = {
|
|
1591
1652
|
action: "SavedChatAdd",
|
|
1592
1653
|
instanceId: this.chatInstanceId,
|
|
1593
|
-
savedChatId:
|
|
1654
|
+
savedChatId: this.chatId,
|
|
1594
1655
|
history: messages,
|
|
1595
1656
|
debug: this.chatConfig$.value.defaultValues.debug
|
|
1596
1657
|
};
|
|
1597
|
-
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.savedChat), tap((savedChat) =>
|
|
1598
|
-
|
|
1658
|
+
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.savedChat), tap((savedChat) => {
|
|
1659
|
+
this.setSavedChatId(savedChat.id); // Persist the savedChatId
|
|
1660
|
+
this.generateAuditEvent('saved-chat.add', {}, savedChat.id); // Generate audit event
|
|
1661
|
+
}), catchError((error) => {
|
|
1599
1662
|
console.error('Error occurred while calling the SavedChatAdd API:', error.error.errorMessage);
|
|
1600
1663
|
this.notificationsService.error('Error occurred while calling the SavedChatAdd API:', error.error.errorMessage);
|
|
1601
1664
|
return throwError(() => error);
|
|
@@ -1706,6 +1769,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1706
1769
|
this.searchService = inject(SearchService);
|
|
1707
1770
|
this.principalService = inject(PrincipalWebService);
|
|
1708
1771
|
this.cdr = inject(ChangeDetectorRef);
|
|
1772
|
+
this.appService = inject(AppService);
|
|
1709
1773
|
/** Define the query to use to fetch answers */
|
|
1710
1774
|
this.query = this.searchService.query;
|
|
1711
1775
|
/** Define the protocol to be used for this chat instance*/
|
|
@@ -1737,10 +1801,21 @@ class ChatComponent extends AbstractFacet {
|
|
|
1737
1801
|
this.isAtBottom = true;
|
|
1738
1802
|
this.initializationError = false;
|
|
1739
1803
|
this.enabledUserInput = false;
|
|
1804
|
+
// Issue reporting
|
|
1805
|
+
this.issueTypes = [
|
|
1806
|
+
'User Interface bug',
|
|
1807
|
+
'Incorrect or misleading response',
|
|
1808
|
+
'Incomplete response',
|
|
1809
|
+
'Technical issue',
|
|
1810
|
+
'Privacy/data security issue',
|
|
1811
|
+
'Other'
|
|
1812
|
+
];
|
|
1813
|
+
this.issueType = '';
|
|
1814
|
+
this.showReportIssue = false;
|
|
1740
1815
|
this._actions.push(new Action({
|
|
1741
1816
|
icon: 'fas fa-sync',
|
|
1742
1817
|
title: 'Reset chat',
|
|
1743
|
-
action: () => this.
|
|
1818
|
+
action: () => this.newChat()
|
|
1744
1819
|
}));
|
|
1745
1820
|
}
|
|
1746
1821
|
ngOnInit() {
|
|
@@ -1776,7 +1851,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1776
1851
|
}
|
|
1777
1852
|
/**
|
|
1778
1853
|
* Instantiate the chat service based on the provided @input protocol
|
|
1779
|
-
*
|
|
1854
|
+
* This chat service instance will then be stored in the instanceManagerService with provided @input instanceId as a key
|
|
1780
1855
|
*/
|
|
1781
1856
|
instantiateChatService() {
|
|
1782
1857
|
switch (this.protocol) {
|
|
@@ -1810,7 +1885,15 @@ class ChatComponent extends AbstractFacet {
|
|
|
1810
1885
|
}
|
|
1811
1886
|
this.openChat(this.chat.messages);
|
|
1812
1887
|
};
|
|
1813
|
-
this.
|
|
1888
|
+
this.chatService.generateChatId();
|
|
1889
|
+
if (this.chat) {
|
|
1890
|
+
this.chatService.generateAuditEvent('new-chat', { 'chat-init': JSON.stringify(this.chat) });
|
|
1891
|
+
openChat();
|
|
1892
|
+
}
|
|
1893
|
+
else {
|
|
1894
|
+
this.chatService.generateAuditEvent('new-chat', {});
|
|
1895
|
+
this.loadDefaultChat();
|
|
1896
|
+
}
|
|
1814
1897
|
}
|
|
1815
1898
|
/**
|
|
1816
1899
|
* If the chat is initialized, the initialization event is "Query", the query changes and the queryChangeShouldTriggerReload function is provided,
|
|
@@ -1819,26 +1902,18 @@ class ChatComponent extends AbstractFacet {
|
|
|
1819
1902
|
*/
|
|
1820
1903
|
if (this.firstChangesHandled && (changes === null || changes === void 0 ? void 0 : changes.query) && this.config.modeSettings.initialization.event === 'Query') {
|
|
1821
1904
|
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(this._previousQuery, this.query) : true) {
|
|
1822
|
-
this.
|
|
1905
|
+
this._triggerReloadAfterQueryChange();
|
|
1823
1906
|
}
|
|
1824
1907
|
this._previousQuery = JSON.parse(JSON.stringify(this.query)); // Update the previous query
|
|
1825
1908
|
}
|
|
1826
1909
|
}
|
|
1827
|
-
|
|
1910
|
+
_triggerReloadAfterQueryChange() {
|
|
1828
1911
|
const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
|
|
1829
1912
|
const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
if (!!this.query.text) {
|
|
1835
|
-
const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
|
|
1836
|
-
this.openChat(this.config.modeSettings.sendUserPrompt ? [systemMsg, userMsg, userQueryMsg] : [systemMsg, userQueryMsg]);
|
|
1837
|
-
}
|
|
1838
|
-
else {
|
|
1839
|
-
const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
|
|
1840
|
-
this.openChat([warningMsg]);
|
|
1841
|
-
}
|
|
1913
|
+
this.chatService.setSavedChatId(undefined); // Reset the savedChatId
|
|
1914
|
+
this.chatService.generateChatId(); // Generate a new chatId
|
|
1915
|
+
this.chatService.generateAuditEvent('new-chat', {}); // Generate a new chat audit event
|
|
1916
|
+
this._handleQueryMode(systemMsg, userMsg);
|
|
1842
1917
|
}
|
|
1843
1918
|
addScrollListener() {
|
|
1844
1919
|
this.sub.add(merge(this.loading$, this.messages$, this.chatService.streaming$, fromEvent(this.messageList.nativeElement, 'scroll')).subscribe(() => {
|
|
@@ -1867,10 +1942,12 @@ class ChatComponent extends AbstractFacet {
|
|
|
1867
1942
|
}
|
|
1868
1943
|
}
|
|
1869
1944
|
fetchAnswer(question, conversation) {
|
|
1945
|
+
var _a;
|
|
1870
1946
|
const userMsg = { role: 'user', content: question, additionalProperties: { display: true, isUserInput: true } };
|
|
1871
1947
|
const messages = [...conversation, userMsg];
|
|
1872
1948
|
this.messages$.next(messages);
|
|
1873
1949
|
this.fetch(messages);
|
|
1950
|
+
this.chatService.generateAuditEvent('message', Object.assign(Object.assign({}, this._defineMessageAuditDetails(userMsg, messages.length - 1)), { 'query': JSON.stringify(this.query), 'is-user-input': true, 'enabled-functions': (_a = this.config.defaultValues.functions) === null || _a === void 0 ? void 0 : _a.filter(func => func.enabled).map(func => func.name) }));
|
|
1874
1951
|
}
|
|
1875
1952
|
/**
|
|
1876
1953
|
* Given a list of messages, the chat endpoint is invoked for a continuation and updates the list of messages accordingly.
|
|
@@ -1931,9 +2008,11 @@ class ChatComponent extends AbstractFacet {
|
|
|
1931
2008
|
*/
|
|
1932
2009
|
newChat() {
|
|
1933
2010
|
this.chatService.setSavedChatId(undefined); // Reset the savedChatId
|
|
2011
|
+
this.chatService.generateChatId(); // Generate a new chatId
|
|
1934
2012
|
if (this.config.savedChatSettings.enabled) {
|
|
1935
2013
|
this.chatService.listSavedChat(); // Refresh the list of saved chats
|
|
1936
2014
|
}
|
|
2015
|
+
this.chatService.generateAuditEvent('new-chat', {}); // Generate a new chat audit event
|
|
1937
2016
|
this.loadDefaultChat(); // Start a new chat
|
|
1938
2017
|
}
|
|
1939
2018
|
/**
|
|
@@ -1941,38 +2020,67 @@ class ChatComponent extends AbstractFacet {
|
|
|
1941
2020
|
* If the chat is meant to be initialized with event === "Query", the corresponding user query message will be added to the chat history
|
|
1942
2021
|
*/
|
|
1943
2022
|
loadDefaultChat() {
|
|
2023
|
+
// Define the default system prompt and user prompt messages
|
|
1944
2024
|
const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
|
|
1945
2025
|
const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
|
|
1946
2026
|
if (this.config.modeSettings.initialization.event === 'Query') {
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
2027
|
+
this._handleQueryMode(systemMsg, userMsg);
|
|
2028
|
+
}
|
|
2029
|
+
else { // If the chat is meant to be initialized with event === "Prompt"
|
|
2030
|
+
this.openChat([systemMsg, userMsg]);
|
|
2031
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(systemMsg, 0));
|
|
2032
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(userMsg, 1));
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
/**
|
|
2036
|
+
* If the provided query text is not empty, then add the user query message to the chat history and invoke the assistant
|
|
2037
|
+
* Otherwise, just start a new chat with a warning message inviting the user to perform a full text search to retrieve some results
|
|
2038
|
+
*/
|
|
2039
|
+
_handleQueryMode(systemMsg, userMsg) {
|
|
2040
|
+
var _a, _b;
|
|
2041
|
+
if (!!this.query.text) {
|
|
2042
|
+
const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
|
|
2043
|
+
if (this.config.modeSettings.sendUserPrompt) {
|
|
2044
|
+
this.openChat([systemMsg, userMsg, userQueryMsg]);
|
|
2045
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(systemMsg, 0));
|
|
2046
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(userMsg, 1));
|
|
2047
|
+
this.chatService.generateAuditEvent('message', Object.assign(Object.assign({}, this._defineMessageAuditDetails(userQueryMsg, 2)), { 'query': JSON.stringify(this.query), 'is-user-input': true, 'forced-workflow': this.config.modeSettings.initialization.forcedWorkflow, 'enabled-functions': (_a = this.config.defaultValues.functions) === null || _a === void 0 ? void 0 : _a.filter(func => func.enabled).map(func => func.name) }));
|
|
1952
2048
|
}
|
|
1953
2049
|
else {
|
|
1954
|
-
|
|
1955
|
-
this.
|
|
2050
|
+
this.openChat([systemMsg, userQueryMsg]);
|
|
2051
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(systemMsg, 0));
|
|
2052
|
+
this.chatService.generateAuditEvent('message', Object.assign(Object.assign({}, this._defineMessageAuditDetails(userQueryMsg, 1)), { 'query': JSON.stringify(this.query), 'is-user-input': true, 'forced-workflow': this.config.modeSettings.initialization.forcedWorkflow, 'enabled-functions': (_b = this.config.defaultValues.functions) === null || _b === void 0 ? void 0 : _b.filter(func => func.enabled).map(func => func.name) }));
|
|
1956
2053
|
}
|
|
1957
2054
|
}
|
|
1958
2055
|
else {
|
|
1959
|
-
|
|
2056
|
+
const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
|
|
2057
|
+
this.openChat([warningMsg]);
|
|
2058
|
+
this.chatService.generateAuditEvent('message', this._defineMessageAuditDetails(warningMsg, 0));
|
|
1960
2059
|
}
|
|
1961
2060
|
}
|
|
2061
|
+
_defineMessageAuditDetails(message, rank) {
|
|
2062
|
+
return {
|
|
2063
|
+
'duration': 0,
|
|
2064
|
+
'text': message.content,
|
|
2065
|
+
'role': message.role,
|
|
2066
|
+
'rank': rank
|
|
2067
|
+
};
|
|
2068
|
+
}
|
|
1962
2069
|
/**
|
|
1963
2070
|
* Start/open a new chat with the provided messages and chatId
|
|
1964
2071
|
* If the last message is from the user, a request to the assistant is made to get an answer
|
|
1965
2072
|
* If the last message is from the assistant, the conversation is loaded right away
|
|
1966
2073
|
* @param messages The list of messages of the chat
|
|
1967
|
-
* @param
|
|
2074
|
+
* @param savedChatId The id of the saved chat. If provided (ie. an existing discussion in the saved chat index), update the savedChatId in the chat service for the upcoming saved chat operations
|
|
1968
2075
|
*/
|
|
1969
|
-
openChat(messages,
|
|
2076
|
+
openChat(messages, savedChatId) {
|
|
1970
2077
|
if (!messages || !Array.isArray(messages)) {
|
|
1971
2078
|
console.error('Error occurs while trying to load the chat discussion. Invalid messages received :', messages);
|
|
1972
2079
|
return;
|
|
1973
2080
|
}
|
|
1974
|
-
if (
|
|
1975
|
-
this.chatService.setSavedChatId(
|
|
2081
|
+
if (savedChatId) {
|
|
2082
|
+
this.chatService.setSavedChatId(savedChatId);
|
|
2083
|
+
this.chatService.generateChatId(savedChatId);
|
|
1976
2084
|
}
|
|
1977
2085
|
this.resetChat();
|
|
1978
2086
|
this.messages$.next(messages);
|
|
@@ -2022,6 +2130,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
2022
2130
|
editMessage(index) {
|
|
2023
2131
|
this.messageToEdit = index;
|
|
2024
2132
|
this.question = this.chatService.chatHistory[index].content;
|
|
2133
|
+
this.chatService.generateAuditEvent('edit.click', { 'rank': index });
|
|
2134
|
+
}
|
|
2135
|
+
/**
|
|
2136
|
+
* Copy a previous assistant message of the chat history to the clipboard.
|
|
2137
|
+
* @param index The index of the assistant's message to edit
|
|
2138
|
+
*/
|
|
2139
|
+
copyMessage(index) {
|
|
2140
|
+
this.chatService.generateAuditEvent('copy.click', { 'rank': index });
|
|
2025
2141
|
}
|
|
2026
2142
|
/**
|
|
2027
2143
|
* Starting from the provided index, remove all subsequent messages from the chat history and the UI accordingly.
|
|
@@ -2035,6 +2151,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
2035
2151
|
this.messages$.next(slicedMessages);
|
|
2036
2152
|
// Fetch the answer
|
|
2037
2153
|
this.fetch(slicedMessages);
|
|
2154
|
+
this.chatService.generateAuditEvent('regenerate.click', { 'rank': index });
|
|
2038
2155
|
}
|
|
2039
2156
|
onKeyUp(event) {
|
|
2040
2157
|
switch (event.key) {
|
|
@@ -2060,18 +2177,84 @@ class ChatComponent extends AbstractFacet {
|
|
|
2060
2177
|
el.style.height = `${el.scrollHeight}px`;
|
|
2061
2178
|
el.style.overflowY = el.scrollHeight >= maxHeight ? 'scroll' : 'hidden';
|
|
2062
2179
|
}
|
|
2180
|
+
/**
|
|
2181
|
+
* Send a "like" event on clicking on the thumb-up icon of an assistant's message
|
|
2182
|
+
* @param rank The rank of the message to like
|
|
2183
|
+
*/
|
|
2184
|
+
onLike(rank) {
|
|
2185
|
+
this.chatService.generateAuditEvent('thumb-up.click', { rank });
|
|
2186
|
+
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Send a "dislike" event on clicking on the thumb-down icon of an assistant's message.
|
|
2189
|
+
* It also opens the issue reporting dialog.
|
|
2190
|
+
* @param message The assistant message to dislike
|
|
2191
|
+
* @param rank The rank of the message to dislike
|
|
2192
|
+
*/
|
|
2193
|
+
onDislike(message, rank) {
|
|
2194
|
+
this.chatService.generateAuditEvent('thumb-down.click', { rank });
|
|
2195
|
+
this.messageRelatedIssue = message;
|
|
2196
|
+
this.issueType = '';
|
|
2197
|
+
this.issueComment = undefined;
|
|
2198
|
+
this.issueRank = rank;
|
|
2199
|
+
this.showReportIssue = true;
|
|
2200
|
+
}
|
|
2201
|
+
/**
|
|
2202
|
+
* Report an issue related to the assistant's message.
|
|
2203
|
+
*/
|
|
2204
|
+
sendIssue() {
|
|
2205
|
+
const details = {
|
|
2206
|
+
'report-type': this.issueType,
|
|
2207
|
+
'comment': this.issueComment,
|
|
2208
|
+
'text': this.messageRelatedIssue.content,
|
|
2209
|
+
'rank': this.issueRank,
|
|
2210
|
+
};
|
|
2211
|
+
this.chatService.generateAuditEvent('negative-report.send', details);
|
|
2212
|
+
this.showReportIssue = false;
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Close the issue reporting dialog.
|
|
2216
|
+
*/
|
|
2217
|
+
ignoreIssue() {
|
|
2218
|
+
this.showReportIssue = false;
|
|
2219
|
+
}
|
|
2220
|
+
openAttachmentPreview(data) {
|
|
2221
|
+
this.openPreview.emit(data.reference);
|
|
2222
|
+
const details = {
|
|
2223
|
+
'doc-id': data.reference.recordId,
|
|
2224
|
+
'title': data.reference.record.title,
|
|
2225
|
+
'source': data.reference.record.treepath,
|
|
2226
|
+
'collection': data.reference.record.collection,
|
|
2227
|
+
'index': data.reference.record.databasealias,
|
|
2228
|
+
};
|
|
2229
|
+
if (!!data.partId)
|
|
2230
|
+
details['part-id'] = data.partId;
|
|
2231
|
+
this.chatService.generateAuditEvent('attachment.preview.click', details);
|
|
2232
|
+
}
|
|
2233
|
+
openOriginalAttachment(data) {
|
|
2234
|
+
this.openDocument.emit(data.reference.record);
|
|
2235
|
+
const details = {
|
|
2236
|
+
'doc-id': data.reference.recordId,
|
|
2237
|
+
'title': data.reference.record.title,
|
|
2238
|
+
'source': data.reference.record.treepath,
|
|
2239
|
+
'collection': data.reference.record.collection,
|
|
2240
|
+
'index': data.reference.record.databasealias,
|
|
2241
|
+
};
|
|
2242
|
+
if (!!data.partId)
|
|
2243
|
+
details['part-id'] = data.partId;
|
|
2244
|
+
this.chatService.generateAuditEvent('attachment.link.click', details);
|
|
2245
|
+
}
|
|
2063
2246
|
}
|
|
2064
2247
|
ChatComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2065
2248
|
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" }, outputs: { data: "data", openDocument: "openDocument", openPreview: "openPreview", suggestAction: "suggestAction", loading$: "loading", _config: "config" }, providers: [
|
|
2066
2249
|
RestChatService,
|
|
2067
2250
|
WebSocketChatService
|
|
2068
|
-
], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], 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: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <sq-token-progress-bar\n *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\"\n [instanceId]=\"instanceId\"\n class=\"ms-1\">\n </sq-token-progress-bar>\n\n <ul class=\"list-group list-group-flush overflow-auto 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\" *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 [message]=\"message\"\n [conversation]=\"messages\"\n [suggestedActions]=\"last ? message.additionalProperties.$suggestedAction : undefined\"\n [assistantMessageIcon]=\"assistantMessageIcon\"\n [userMessageIcon]=\"userMessageIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'user'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && message.role === 'assistant'\"\n (edit)=\"editMessage(index)\"\n (regenerate)=\"regenerateMessage(index)\"\n (openDocument)=\"openDocument.emit($event)\"\n (openPreview)=\"openPreview.emit($event)\"\n (suggestAction)=\"suggestAction.emit($event)\">\n </sq-chat-message>\n </li>\n </ng-container>\n\n <li class=\"list-group-item\" *ngIf=\"(loading$ | async) === true\">\n <ng-container *ngTemplateOutlet=\"loadingTpl || loadingTplDefault\"></ng-container>\n </li>\n </ul>\n\n <div class=\"user-input mt-auto\" *ngIf=\"enabledUserInput\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\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 </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()\"\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 class=\"sq-floating-scroll\" *ngIf=\"!isAtBottom\">\n <button class=\"btn shadow\" (click)=\"scrollDown()\">\n <i class=\"fas fa-angle-double-down\"></i>\n </button>\n </div>\n </div>\n </div>\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-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>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%;bottom:75px;text-align:center}.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}\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: "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.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.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", "streaming", "canEdit", "canRegenerate", "canCopy"], outputs: ["openDocument", "openPreview", "suggestAction", "edit", "regenerate"] }, { kind: "component", type: TokenProgressBarComponent, selector: "sq-token-progress-bar", inputs: ["instanceId"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2251
|
+
], queries: [{ propertyName: "loadingTpl", first: true, predicate: ["loadingTpl"], descendants: true }, { propertyName: "reportIssueTpl", first: true, predicate: ["reportIssueTpl"], 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 <sq-token-progress-bar\n *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\"\n [instanceId]=\"instanceId\"\n class=\"ms-1\">\n </sq-token-progress-bar>\n\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 [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'user'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && 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)=\"suggestAction.emit($event)\"\n (like)=\"onLike(index)\"\n (dislike)=\"onDislike($event, 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 an issue form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReportIssue\">\n <ng-container *ngTemplateOutlet=\"reportIssueTpl || reportIssueTplDefault\" ></ng-container>\n </div>\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"enabledUserInput && !showReportIssue\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\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 <!-- 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()\"\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>\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\">{{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", 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-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}\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", "streaming", "canEdit", "canRegenerate", "canCopy"], outputs: ["openDocument", "openPreview", "suggestAction", "edit", "copy", "regenerate", "like", "dislike"] }, { kind: "component", type: TokenProgressBarComponent, selector: "sq-token-progress-bar", inputs: ["instanceId"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
2069
2252
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
2070
2253
|
type: Component,
|
|
2071
2254
|
args: [{ selector: 'sq-chat-v3', providers: [
|
|
2072
2255
|
RestChatService,
|
|
2073
2256
|
WebSocketChatService
|
|
2074
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, TokenProgressBarComponent], template: "
|
|
2257
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, TokenProgressBarComponent], template: "<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\n <sq-token-progress-bar\n *ngIf=\"config?.globalSettings?.displayUserQuotaConsumption || config?.globalSettings?.displayChatTokensConsumption\"\n [instanceId]=\"instanceId\"\n class=\"ms-1\">\n </sq-token-progress-bar>\n\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 [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'user'\"\n [canRegenerate]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role === 'assistant' && last\"\n [canCopy]=\"!(last && (chatService.streaming$ | async)) && messageToEdit === undefined && 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)=\"suggestAction.emit($event)\"\n (like)=\"onLike(index)\"\n (dislike)=\"onDislike($event, 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 an issue form -->\n <div class=\"issue-report bg-light pt-3 pb-2\" *ngIf=\"showReportIssue\">\n <ng-container *ngTemplateOutlet=\"reportIssueTpl || reportIssueTplDefault\" ></ng-container>\n </div>\n <!-- User text input -->\n <div class=\"user-input mt-auto\" *ngIf=\"enabledUserInput && !showReportIssue\">\n <div class=\"py-2\">\n <ng-container *ngTemplateOutlet=\"inputTpl\"></ng-container>\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 <!-- 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()\"\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>\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\">{{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", 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-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}\n"] }]
|
|
2075
2258
|
}], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
|
|
2076
2259
|
type: Input
|
|
2077
2260
|
}], query: [{
|
|
@@ -2113,6 +2296,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
2113
2296
|
}], loadingTpl: [{
|
|
2114
2297
|
type: ContentChild,
|
|
2115
2298
|
args: ['loadingTpl']
|
|
2299
|
+
}], reportIssueTpl: [{
|
|
2300
|
+
type: ContentChild,
|
|
2301
|
+
args: ['reportIssueTpl']
|
|
2116
2302
|
}] } });
|
|
2117
2303
|
|
|
2118
2304
|
class SavedChatsComponent {
|
|
@@ -2145,7 +2331,9 @@ class SavedChatsComponent {
|
|
|
2145
2331
|
}
|
|
2146
2332
|
onLoad(savedChat) {
|
|
2147
2333
|
this.chatService.setSavedChatId(savedChat.id);
|
|
2334
|
+
this.chatService.generateChatId(savedChat.id);
|
|
2148
2335
|
this.chatService.loadSavedChat$.next(savedChat);
|
|
2336
|
+
this.chatService.generateAuditEvent('saved-chat.load', {}, savedChat.id);
|
|
2149
2337
|
this.chatService.listSavedChat();
|
|
2150
2338
|
this.load.emit(savedChat);
|
|
2151
2339
|
}
|
|
@@ -2171,6 +2359,7 @@ class SavedChatsComponent {
|
|
|
2171
2359
|
this.notificationsService.error(`Error occurred while updating the saved discussion "${savedChat.title}"`);
|
|
2172
2360
|
return throwError(() => error);
|
|
2173
2361
|
})).subscribe());
|
|
2362
|
+
this.chatService.generateAuditEvent('saved-chat.rename', { 'text': model.output }, savedChat.id);
|
|
2174
2363
|
}
|
|
2175
2364
|
});
|
|
2176
2365
|
}
|
|
@@ -2196,6 +2385,7 @@ class SavedChatsComponent {
|
|
|
2196
2385
|
this.notificationsService.error(`Error occurred while deleting the saved discussion "${savedChat.title}"`);
|
|
2197
2386
|
return throwError(() => error);
|
|
2198
2387
|
})).subscribe());
|
|
2388
|
+
this.chatService.generateAuditEvent('saved-chat.delete', {}, savedChat.id);
|
|
2199
2389
|
}
|
|
2200
2390
|
});
|
|
2201
2391
|
}
|