@sinequa/assistant 3.2.2 → 3.3.0-DEV.16
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 +10 -7
- package/chat/chat-settings-v3/chat-settings-v3.component.d.ts +3 -0
- package/chat/chat.component.d.ts +36 -15
- package/chat/chat.service.d.ts +24 -2
- package/chat/saved-chats/saved-chats.component.d.ts +0 -2
- package/chat/token-progress-bar/token-progress-bar.component.d.ts +27 -0
- package/chat/types.d.ts +37 -0
- package/chat/websocket-chat.service.d.ts +1 -0
- package/esm2020/chat/chat-message/chat-message.component.mjs +18 -18
- package/esm2020/chat/chat-reference/chat-reference.component.mjs +3 -3
- package/esm2020/chat/chat-settings-v3/chat-settings-v3.component.mjs +16 -4
- package/esm2020/chat/chat.component.mjs +50 -43
- package/esm2020/chat/chat.service.mjs +46 -4
- package/esm2020/chat/rest-chat.service.mjs +10 -14
- package/esm2020/chat/saved-chats/saved-chats.component.mjs +3 -5
- package/esm2020/chat/token-progress-bar/token-progress-bar.component.mjs +54 -0
- package/esm2020/chat/types.mjs +3 -1
- package/esm2020/chat/websocket-chat.service.mjs +16 -10
- package/fesm2015/sinequa-assistant-chat.mjs +202 -99
- package/fesm2015/sinequa-assistant-chat.mjs.map +1 -1
- package/fesm2020/sinequa-assistant-chat.mjs +199 -94
- package/fesm2020/sinequa-assistant-chat.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -8,6 +8,8 @@ import { CommonModule } from '@angular/common';
|
|
|
8
8
|
import * as i2 from '@angular/forms';
|
|
9
9
|
import { FormsModule, Validators, UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
|
10
10
|
import { LoginService, AuthenticationService } from '@sinequa/core/login';
|
|
11
|
+
import { Utils } from '@sinequa/core/base';
|
|
12
|
+
import { AppService } from '@sinequa/core/app-utils';
|
|
11
13
|
import { Action } from '@sinequa/components/action';
|
|
12
14
|
import { AbstractFacet } from '@sinequa/components/facet';
|
|
13
15
|
import * as i1$1 from '@sinequa/components/search';
|
|
@@ -15,13 +17,12 @@ import { SearchService } from '@sinequa/components/search';
|
|
|
15
17
|
import { UserPreferences } from '@sinequa/components/user-settings';
|
|
16
18
|
import { NotificationsService } from '@sinequa/core/notification';
|
|
17
19
|
import { z } from 'zod';
|
|
18
|
-
import { AppService } from '@sinequa/core/app-utils';
|
|
19
20
|
import * as i6$1 from '@sinequa/core/intl';
|
|
20
21
|
import { IntlService, IntlModule } from '@sinequa/core/intl';
|
|
21
22
|
import get from 'lodash/get';
|
|
22
|
-
import { Utils } from '@sinequa/core/base';
|
|
23
23
|
import * as i1$2 from '@sinequa/core/modal';
|
|
24
24
|
import { ModalService, ModalButton, ModalModule, MODAL_MODEL } from '@sinequa/core/modal';
|
|
25
|
+
import { toDate, parseISO, isToday, isYesterday, isThisWeek, differenceInDays, endOfYesterday, isThisMonth, differenceInMonths, isThisQuarter, isThisYear, differenceInYears, format } from 'date-fns';
|
|
25
26
|
import { HttpTransportType, LogLevel } from '@microsoft/signalr';
|
|
26
27
|
import { unified } from 'unified';
|
|
27
28
|
import remarkParse from 'remark-parse';
|
|
@@ -36,7 +37,6 @@ import { RemarkModule } from 'ngx-remark';
|
|
|
36
37
|
import SafeColor from 'safecolor';
|
|
37
38
|
import 'prismjs-components-importer/esm';
|
|
38
39
|
import 'prismjs/plugins/autoloader/prism-autoloader';
|
|
39
|
-
import { parseISO, isToday, isYesterday, isThisWeek, differenceInDays, endOfYesterday, isThisMonth, differenceInMonths, isThisQuarter, isThisYear, differenceInYears, format } from 'date-fns';
|
|
40
40
|
import * as i4 from '@sinequa/components/modal';
|
|
41
41
|
import { BsModalModule } from '@sinequa/components/modal';
|
|
42
42
|
import * as i5$1 from '@sinequa/core/validation';
|
|
@@ -96,6 +96,7 @@ class ChatSettingsV3Component {
|
|
|
96
96
|
this.loginService = inject(LoginService);
|
|
97
97
|
this.instanceManagerService = inject(InstanceManagerService);
|
|
98
98
|
this.principalService = inject(PrincipalWebService);
|
|
99
|
+
this.appService = inject(AppService);
|
|
99
100
|
}
|
|
100
101
|
ngOnInit() {
|
|
101
102
|
this.subscription.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig)).subscribe(_ => {
|
|
@@ -151,9 +152,19 @@ class ChatSettingsV3Component {
|
|
|
151
152
|
}
|
|
152
153
|
/**
|
|
153
154
|
* Save the new chat config in the chat service and the user preferences
|
|
155
|
+
* If the user has never modified the default values, we need to save the hash of the standard default values, as defined by the admin, in order to properly track changes afterwards.
|
|
154
156
|
*/
|
|
155
157
|
save() {
|
|
156
|
-
|
|
158
|
+
var _a, _b, _c;
|
|
159
|
+
const userSettingsConfig = this.chatService.assistants[this.instanceId] || {};
|
|
160
|
+
if (!userSettingsConfig.defaultValues) { // At this point, it is the very first time the user makes changes to the default values
|
|
161
|
+
const standardChatConfig = (_c = (_b = (_a = this.appService.app) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.assistants) === null || _c === void 0 ? void 0 : _c[this.instanceId];
|
|
162
|
+
const hashes = Object.assign(Object.assign({}, userSettingsConfig.hashes), { "applied-defaultValues-hash": Utils.sha512(JSON.stringify(standardChatConfig.defaultValues)) });
|
|
163
|
+
this.chatService.updateChatConfig(this.config, hashes);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
this.chatService.updateChatConfig(this.config);
|
|
167
|
+
}
|
|
157
168
|
this._update.emit(this.config);
|
|
158
169
|
}
|
|
159
170
|
/**
|
|
@@ -164,10 +175,10 @@ class ChatSettingsV3Component {
|
|
|
164
175
|
}
|
|
165
176
|
}
|
|
166
177
|
ChatSettingsV3Component.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
167
|
-
ChatSettingsV3Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatSettingsV3Component, isStandalone: true, selector: "sq-chat-settings-v3", inputs: { instanceId: "instanceId" }, outputs: { _update: "update", _cancel: "cancel" }, ngImport: i0, template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\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: 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.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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"] }] });
|
|
178
|
+
ChatSettingsV3Component.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatSettingsV3Component, isStandalone: true, selector: "sq-chat-settings-v3", inputs: { instanceId: "instanceId" }, outputs: { _update: "update", _cancel: "cancel" }, ngImport: i0, template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light me-1\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\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: 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.RangeValueAccessor, selector: "input[type=range][formControlName],input[type=range][formControl],input[type=range][ngModel]" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { 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"] }] });
|
|
168
179
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, decorators: [{
|
|
169
180
|
type: Component,
|
|
170
|
-
args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"] }]
|
|
181
|
+
args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\" *ngIf=\"isAdmin || config.uiSettings.display\">\n <div class=\"settings-panel card-body small\" *ngIf=\"config\">\n\n <h5 *ngIf=\"hasModel\">Model</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.servicesModels\">\n <label for=\"gllmModel\" class=\"form-label\">Model</label>\n <select class=\"form-select\" id=\"gllmModel\" [(ngModel)]=\"selectedModel\" (ngModelChange)=\"onChatModelChange($event)\">\n <option *ngFor=\"let model of chatService.models\" [ngValue]=\"model\">{{model.displayName}}</option>\n </select>\n </div>\n\n <div class=\"mb-4\" *ngIf=\"isAdmin || config.uiSettings.functions\">\n <label for=\"gllmFunctions\" class=\"form-label\">Functions</label>\n <div id=\"gllmFunctions\" *ngFor=\"let func of functions\" class=\"multi-option form-check form-switch\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" [id]=\"func.name\" [(ngModel)]=\"func.enabled\"\n (ngModelChange)=\"toggleFunctionsSelection(func.name)\">\n <label class=\"form-check-label\" [for]=\"func.name\" [title]=\"getFunctionDescription(func.name)\">{{ func.name }}</label>\n </div>\n </div>\n\n <div class=\"form-check form-switch mb-2\" *ngIf=\"isAdmin || config.uiSettings.debug\">\n <input class=\"form-check-input\" type=\"checkbox\" role=\"switch\" id=\"debug\" [(ngModel)]=\"config.defaultValues.debug\">\n <label class=\"form-check-label\" for=\"debug\">Debug</label>\n </div>\n\n <details *ngIf=\"hasAdvancedParameters\">\n <summary>Advanced parameters</summary>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.temperature\">\n <label for=\"temperature\" class=\"form-label\">Temperature: {{config.defaultValues.temperature}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"2\" step=\"0.1\" id=\"temperature\"\n [(ngModel)]=\"config.defaultValues.temperature\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.top_p\">\n <label for=\"top-p\" class=\"form-label\">Top P: {{config.defaultValues.top_p}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"0\" max=\"1\" step=\"0.05\" id=\"top-p\"\n [(ngModel)]=\"config.defaultValues.top_p\">\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.max_tokens\">\n <label for=\"max-tokens\" class=\"form-label\">Max generated tokens per answer:\n {{config.defaultValues.max_tokens}}</label>\n <input type=\"range\" class=\"form-range form-range-sm\" min=\"1\" max=\"2048\" step=\"1\" id=\"max-tokens\"\n [(ngModel)]=\"config.defaultValues.max_tokens\">\n </div>\n </details>\n\n <hr>\n\n <h5 *ngIf=\"hasPrompts\">Prompts</h5>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displaySystemPrompt\">\n <label for=\"initialSystemPrompt\" class=\"form-label\">System prompt (hidden)</label>\n <textarea class=\"form-control\" id=\"initialSystemPrompt\" [(ngModel)]=\"config.defaultValues.systemPrompt\"></textarea>\n </div>\n <div class=\"mb-2\" *ngIf=\"isAdmin || config.uiSettings.displayUserPrompt\">\n <label for=\"initialUserPrompt\" class=\"form-label\">Initial user prompt</label>\n <textarea class=\"form-control\" id=\"initialUserPrompt\" [(ngModel)]=\"config.defaultValues.userPrompt\"></textarea>\n </div>\n\n </div>\n\n <div class=\"buttons-panel d-flex justify-content-end\">\n <button class=\"btn btn-light me-1\" (click)=\"cancel()\">Cancel</button>\n <button class=\"btn btn-primary\" *ngIf=\"config\" (click)=\"save()\">Save</button>\n </div>\n\n</div>\n", styles: [":host{display:block;width:var(--ast-chat-settings-width, 100%);max-width:100%;height:100%;margin-left:auto;margin-right:auto;padding-top:var(--ast-chat-settings-padding-top, 0);padding-bottom:var(--ast-chat-settings-padding-bottom, 0)}.sq-chat-settings{display:flex;flex-direction:column;height:100%}.sq-chat-settings .settings-panel{flex-grow:1;overflow:auto}.sq-chat-settings .buttons-panel{padding-top:.5rem}\n"] }]
|
|
171
182
|
}], propDecorators: { instanceId: [{
|
|
172
183
|
type: Input
|
|
173
184
|
}], _update: [{
|
|
@@ -246,6 +257,8 @@ const savedChatSettingsSchema = z.object({
|
|
|
246
257
|
// Define the Zod representation for the globalSettings object
|
|
247
258
|
const globalSettingsSchema = z.object({
|
|
248
259
|
disclaimer: z.string().optional(),
|
|
260
|
+
displayUserQuotaConsumption: z.boolean().optional(),
|
|
261
|
+
displayChatTokensConsumption: z.boolean().optional()
|
|
249
262
|
});
|
|
250
263
|
// Define the Zod representation for the entire ChatConfig object
|
|
251
264
|
const chatConfigSchema = z.object({
|
|
@@ -272,6 +285,14 @@ class ChatService {
|
|
|
272
285
|
this.savedChats$ = new BehaviorSubject([]);
|
|
273
286
|
/** Emit the saved chat to load */
|
|
274
287
|
this.loadSavedChat$ = new BehaviorSubject(undefined);
|
|
288
|
+
/** Emit the quota each time the chat is invoked */
|
|
289
|
+
this.quota$ = new BehaviorSubject(undefined);
|
|
290
|
+
/** Emit the calculated user's token consumption based on the quota */
|
|
291
|
+
this.userTokenConsumption$ = new BehaviorSubject(undefined);
|
|
292
|
+
/** Emit the chat usage metrics each time the generation of the assistant response is completed */
|
|
293
|
+
this.chatUsageMetrics$ = new BehaviorSubject(undefined);
|
|
294
|
+
/** Emit the calculated chat's token consumption based on the chat usage metrics */
|
|
295
|
+
this.chatTokenConsumption$ = new BehaviorSubject(undefined);
|
|
275
296
|
this.userSettingsService = inject(UserSettingsWebService);
|
|
276
297
|
this.notificationsService = inject(NotificationsService);
|
|
277
298
|
this.auditService = inject(AuditWebService);
|
|
@@ -357,7 +378,7 @@ class ChatService {
|
|
|
357
378
|
confirmType: 2 /* ConfirmType.Warning */
|
|
358
379
|
}).then(res => {
|
|
359
380
|
if (res === -1 /* ModalResult.OK */) {
|
|
360
|
-
const hashes = { "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
|
|
381
|
+
const hashes = Object.assign(Object.assign({}, userSettingsConfig.hashes), { "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined });
|
|
361
382
|
// Update the chat config and store its defaultValues in the user preferences
|
|
362
383
|
this.updateChatConfig(Object.assign({}, standardChatConfig), hashes, true);
|
|
363
384
|
this.initConfig$.next(true);
|
|
@@ -389,6 +410,7 @@ class ChatService {
|
|
|
389
410
|
/**
|
|
390
411
|
* Update the chat config and store its defaultValues in the user preferences
|
|
391
412
|
* @param config The updated chat config
|
|
413
|
+
* @param hashes The updated hashes to store in the user preferences
|
|
392
414
|
* @param notify Whether to notify the user about the update
|
|
393
415
|
* @param successCallback The callback to execute if the update is successful
|
|
394
416
|
* @param errorCallback The callback to execute if the update fails
|
|
@@ -396,7 +418,9 @@ class ChatService {
|
|
|
396
418
|
updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
|
|
397
419
|
this.chatConfig$.next(config);
|
|
398
420
|
const assistants = Object.assign({}, this.assistants);
|
|
399
|
-
assistants[this.chatInstanceId] = Object.assign(Object.assign({}, assistants[this.chatInstanceId]), { defaultValues: config.defaultValues
|
|
421
|
+
assistants[this.chatInstanceId] = Object.assign(Object.assign({}, assistants[this.chatInstanceId]), { defaultValues: config.defaultValues });
|
|
422
|
+
if (hashes)
|
|
423
|
+
assistants[this.chatInstanceId].hashes = hashes;
|
|
400
424
|
this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
|
|
401
425
|
if (notify) {
|
|
402
426
|
errorCallback ? errorCallback() : this.notificationsService.error(`The update of the assistant instance '${this.chatInstanceId}' configuration failed`);
|
|
@@ -408,6 +432,35 @@ class ChatService {
|
|
|
408
432
|
}
|
|
409
433
|
});
|
|
410
434
|
}
|
|
435
|
+
/**
|
|
436
|
+
* A handler for quota updates each time the chat is invoked.
|
|
437
|
+
* It emits the updated quota to the quota$ subject, emits accordingly the updated user's tokens consumption and notifies the user if the max quota is reached.
|
|
438
|
+
* @param quota The updated quota
|
|
439
|
+
* @param propagateError Whether to propagate the error to the caller
|
|
440
|
+
*/
|
|
441
|
+
updateQuota(quota, propagateError = false) {
|
|
442
|
+
this.quota$.next(quota);
|
|
443
|
+
const nextResetDate = this.formatDateTime(quota.nextResetUTC + "+00:00"); // This +00:00 is to ensure dates will be properly converted to local time
|
|
444
|
+
const consumptionPercentage = Math.round((quota.tokenCount * 100 / quota.periodTokens) * 100) / 100;
|
|
445
|
+
this.userTokenConsumption$.next({ percentage: consumptionPercentage, nextResetDate });
|
|
446
|
+
if (quota.maxQuotaReached) {
|
|
447
|
+
const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${nextResetDate}.`;
|
|
448
|
+
this.notificationsService.error(msg);
|
|
449
|
+
if (propagateError)
|
|
450
|
+
throw new Error(msg);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* A handler for chat usage metrics each time the generation of the assistant response is completed.
|
|
455
|
+
* It emits the chat usage metrics to the chatUsageMetrics$ subject, emits accordingly the updated chat's tokens consumption
|
|
456
|
+
* @param chatUsageMetrics The chat usage metrics
|
|
457
|
+
*/
|
|
458
|
+
updateChatUsageMetrics(chatUsageMetrics) {
|
|
459
|
+
this.chatUsageMetrics$.next(chatUsageMetrics);
|
|
460
|
+
const currentModel = this.getModel(this.chatConfig$.value.defaultValues.service_id, this.chatConfig$.value.defaultValues.model_id);
|
|
461
|
+
const consumptionPercentage = Math.round((chatUsageMetrics.totalTokenCount * 100 / (currentModel.contextWindowSize - currentModel.maxGenerationSize)) * 100) / 100;
|
|
462
|
+
this.chatTokenConsumption$.next({ percentage: consumptionPercentage });
|
|
463
|
+
}
|
|
411
464
|
/**
|
|
412
465
|
* Get the model description for the given (serviceId + modelId)
|
|
413
466
|
* If a model is not found, an error message is returned
|
|
@@ -453,7 +506,8 @@ class ChatService {
|
|
|
453
506
|
* @returns A formatted local date string
|
|
454
507
|
*/
|
|
455
508
|
formatDateTime(value) {
|
|
456
|
-
|
|
509
|
+
const localDate = toDate(parseISO(value));
|
|
510
|
+
return this.intlService["formatTime"](localDate, { day: "numeric", month: "short", year: "numeric", timeZoneName: 'short' });
|
|
457
511
|
}
|
|
458
512
|
/**
|
|
459
513
|
* Takes a text prompt that may contain placeholders for variables
|
|
@@ -486,6 +540,7 @@ class WebSocketChatService extends ChatService {
|
|
|
486
540
|
this._progress = undefined;
|
|
487
541
|
this._content = "";
|
|
488
542
|
this._attachments = [];
|
|
543
|
+
this._suggestedActions = [];
|
|
489
544
|
this.signalRService = inject(SignalRWebService);
|
|
490
545
|
this.authenticationService = inject(AuthenticationService);
|
|
491
546
|
}
|
|
@@ -617,6 +672,7 @@ class WebSocketChatService extends ChatService {
|
|
|
617
672
|
this._content = ""; // Clear the _content
|
|
618
673
|
this._progress = undefined; // Clear the _progress
|
|
619
674
|
this._attachments = []; // Clear the _attachments
|
|
675
|
+
this._suggestedActions = []; // Clear the _suggestedActions
|
|
620
676
|
this._executionTime = ""; // Clear the _executionTime
|
|
621
677
|
completion$.next(); // Emit a signal to complete the observables
|
|
622
678
|
completion$.complete(); // Complete the subject
|
|
@@ -636,9 +692,9 @@ class WebSocketChatService extends ChatService {
|
|
|
636
692
|
});
|
|
637
693
|
})
|
|
638
694
|
: undefined;
|
|
639
|
-
// As soon as the first _content
|
|
640
|
-
if (!!this._content || this._progress || this._attachments.length > 0) {
|
|
641
|
-
response = Object.assign(Object.assign({}, response), { content: this._content, additionalProperties: Object.assign(Object.assign({}, response.additionalProperties), { $progress: this._progress, $attachment: this._attachments }) });
|
|
695
|
+
// As soon as the first _content, $progress, _attachments or __suggestedActions is defined and not empty, the assistant is considered as streaming
|
|
696
|
+
if (!!this._content || this._progress || this._attachments.length > 0 || this._suggestedActions.length > 0) {
|
|
697
|
+
response = Object.assign(Object.assign({}, response), { content: this._content, additionalProperties: Object.assign(Object.assign({}, response.additionalProperties), { $progress: this._progress, $attachment: this._attachments, $suggestedAction: this._suggestedActions }) });
|
|
642
698
|
}
|
|
643
699
|
// Return the result
|
|
644
700
|
return { history: [...messages, response], executionTime: this._executionTime };
|
|
@@ -776,6 +832,9 @@ class WebSocketChatService extends ChatService {
|
|
|
776
832
|
// Re-attach the $progress and $attachment of the last response to the last assistant's response in the chat history
|
|
777
833
|
this.chatHistory.at(-1).additionalProperties.$progress = this._progress;
|
|
778
834
|
this.chatHistory.at(-1).additionalProperties.$attachment = this._attachments;
|
|
835
|
+
this.chatHistory.at(-1).additionalProperties.$suggestedAction = this._suggestedActions;
|
|
836
|
+
// Emit the updated chat usage metrics once the generation of the assistant response is completed
|
|
837
|
+
this.updateChatUsageMetrics(this.chatHistory.at(-1).additionalProperties.usageMetrics);
|
|
779
838
|
// Save/update the chat if savedChat enabled
|
|
780
839
|
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => { var _a; return ((_a = msg.additionalProperties) === null || _a === void 0 ? void 0 : _a.isUserInput) === true; })) {
|
|
781
840
|
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
@@ -793,14 +852,15 @@ class WebSocketChatService extends ChatService {
|
|
|
793
852
|
isGlobalHandler: true
|
|
794
853
|
});
|
|
795
854
|
this.addMessageHandler("Quota", {
|
|
855
|
+
handler: (message) => this.updateQuota(message.quota),
|
|
856
|
+
isGlobalHandler: true
|
|
857
|
+
});
|
|
858
|
+
this.addMessageHandler("SuggestedActions", {
|
|
796
859
|
handler: (message) => {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
console.error(msg);
|
|
800
|
-
this.notificationsService.error(msg);
|
|
801
|
-
}
|
|
860
|
+
// Suggested actions are concatenated to the existing ones in case of multiple events "SuggestedActions"
|
|
861
|
+
this._suggestedActions = this._suggestedActions.concat(message.suggestedActions);
|
|
802
862
|
},
|
|
803
|
-
isGlobalHandler:
|
|
863
|
+
isGlobalHandler: false
|
|
804
864
|
});
|
|
805
865
|
}
|
|
806
866
|
/**
|
|
@@ -1189,10 +1249,10 @@ class ChatReferenceComponent {
|
|
|
1189
1249
|
}
|
|
1190
1250
|
}
|
|
1191
1251
|
ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1192
|
-
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.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></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>", 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{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"] }] });
|
|
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.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></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>", 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"] }] });
|
|
1193
1253
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
|
|
1194
1254
|
type: Component,
|
|
1195
|
-
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.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></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>", 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{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"] }]
|
|
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.record)\" [sqTooltip]=\"!partId ? 'Open document' : ''\"></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>", 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"] }]
|
|
1196
1256
|
}], propDecorators: { reference: [{
|
|
1197
1257
|
type: Input
|
|
1198
1258
|
}], attachment: [{
|
|
@@ -1215,13 +1275,15 @@ class ChatMessageComponent {
|
|
|
1215
1275
|
this.canEdit = false;
|
|
1216
1276
|
this.canRegenerate = false;
|
|
1217
1277
|
this.canCopy = false;
|
|
1218
|
-
this.
|
|
1278
|
+
this.openDocument = new EventEmitter();
|
|
1279
|
+
this.openPreview = new EventEmitter();
|
|
1280
|
+
this.suggestAction = new EventEmitter();
|
|
1219
1281
|
this.edit = new EventEmitter();
|
|
1220
1282
|
this.regenerate = new EventEmitter();
|
|
1221
|
-
this.openPreview = new EventEmitter();
|
|
1222
1283
|
this.references = [];
|
|
1223
1284
|
this.referenceMap = new Map();
|
|
1224
1285
|
this.showReferences = true;
|
|
1286
|
+
this.iconSize = 24;
|
|
1225
1287
|
/**
|
|
1226
1288
|
* This Unified plugin looks a text nodes and replaces any reference in the
|
|
1227
1289
|
* form [1], [2.3], etc. with custom nodes of type "chat-reference".
|
|
@@ -1286,17 +1348,17 @@ class ChatMessageComponent {
|
|
|
1286
1348
|
: this.principalService.principal['fullName'] || this.principalService.principal.name;
|
|
1287
1349
|
}
|
|
1288
1350
|
ngOnChanges(changes) {
|
|
1289
|
-
var _a;
|
|
1351
|
+
var _a, _b;
|
|
1290
1352
|
if (changes.streaming) {
|
|
1291
1353
|
this.collapseProgress = !this.streaming;
|
|
1292
1354
|
}
|
|
1293
|
-
if (changes.message && this.message.role === "assistant") {
|
|
1355
|
+
if (changes.message && ((_a = this.message) === null || _a === void 0 ? void 0 : _a.role) === "assistant") {
|
|
1294
1356
|
this.references = [];
|
|
1295
1357
|
this.referenceMap.clear();
|
|
1296
1358
|
for (let m of this.conversation) {
|
|
1297
1359
|
if (m.additionalProperties.$attachment) {
|
|
1298
1360
|
for (const attachment of m.additionalProperties.$attachment) {
|
|
1299
|
-
this.referenceMap.set('' + attachment.contextId, Object.assign(Object.assign({}, attachment), { $partId: (
|
|
1361
|
+
this.referenceMap.set('' + attachment.contextId, Object.assign(Object.assign({}, attachment), { $partId: (_b = attachment.parts) === null || _b === void 0 ? void 0 : _b[0].partId }));
|
|
1300
1362
|
for (let i = 0; i < attachment.parts.length; i++) {
|
|
1301
1363
|
const refId = `${attachment.contextId}.${attachment.parts[i].partId}`;
|
|
1302
1364
|
this.referenceMap.set(refId, Object.assign(Object.assign({}, attachment), { $partId: attachment.parts[i].partId }));
|
|
@@ -1317,14 +1379,6 @@ class ChatMessageComponent {
|
|
|
1317
1379
|
var _a;
|
|
1318
1380
|
(_a = Prism === null || Prism === void 0 ? void 0 : Prism.highlightAllUnder) === null || _a === void 0 ? void 0 : _a.call(Prism, this.el.nativeElement);
|
|
1319
1381
|
}
|
|
1320
|
-
openDocument(record) {
|
|
1321
|
-
const url = record.url1 || record.originalUrl;
|
|
1322
|
-
if (url) {
|
|
1323
|
-
// Open the URL in a new tab
|
|
1324
|
-
window.open(url, '_blank');
|
|
1325
|
-
}
|
|
1326
|
-
this.referenceClicked.emit(record);
|
|
1327
|
-
}
|
|
1328
1382
|
getLinkText(node) {
|
|
1329
1383
|
if (node.text) {
|
|
1330
1384
|
return node.text; // Return directly if text is provided in node.text ([Example link](https://example.com))
|
|
@@ -1362,16 +1416,20 @@ class ChatMessageComponent {
|
|
|
1362
1416
|
}
|
|
1363
1417
|
}
|
|
1364
1418
|
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 });
|
|
1365
|
-
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", assistantIcon: "assistantIcon", streaming: "streaming", canEdit: "canEdit", canRegenerate: "canRegenerate", canCopy: "canCopy" }, outputs: { referenceClicked: "referenceClicked", edit: "edit", regenerate: "regenerate", openPreview: "openPreview" }, usesOnChanges: true, ngImport: i0, template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\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(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($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\">\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 <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($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%}.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{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}.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 });
|
|
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 });
|
|
1366
1420
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
1367
1421
|
type: Component,
|
|
1368
1422
|
args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
|
|
1369
|
-
InitialsAvatarComponent, ChatReferenceComponent], template: "<!-- Message icon -->\n<span class=\"message-icon\" [title]=\"message.role\">\n <i [ngClass]=\"assistantIcon\" [style.--sq-size.px]=\"24\" *ngIf=\"message.role === 'assistant'\"></i>\n <sq-initials-avatar [fullName]=\"name\" *ngIf=\"message.role !== 'assistant'\"></sq-initials-avatar>\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(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($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\">\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 <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($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%}.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{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}.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"] }]
|
|
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"] }]
|
|
1370
1424
|
}], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
|
|
1371
1425
|
type: Input
|
|
1372
1426
|
}], conversation: [{
|
|
1373
1427
|
type: Input
|
|
1374
|
-
}],
|
|
1428
|
+
}], suggestedActions: [{
|
|
1429
|
+
type: Input
|
|
1430
|
+
}], assistantMessageIcon: [{
|
|
1431
|
+
type: Input
|
|
1432
|
+
}], userMessageIcon: [{
|
|
1375
1433
|
type: Input
|
|
1376
1434
|
}], streaming: [{
|
|
1377
1435
|
type: Input
|
|
@@ -1381,14 +1439,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1381
1439
|
type: Input
|
|
1382
1440
|
}], canCopy: [{
|
|
1383
1441
|
type: Input
|
|
1384
|
-
}],
|
|
1442
|
+
}], openDocument: [{
|
|
1443
|
+
type: Output
|
|
1444
|
+
}], openPreview: [{
|
|
1445
|
+
type: Output
|
|
1446
|
+
}], suggestAction: [{
|
|
1385
1447
|
type: Output
|
|
1386
1448
|
}], edit: [{
|
|
1387
1449
|
type: Output
|
|
1388
1450
|
}], regenerate: [{
|
|
1389
1451
|
type: Output
|
|
1390
|
-
}], openPreview: [{
|
|
1391
|
-
type: Output
|
|
1392
1452
|
}] } });
|
|
1393
1453
|
|
|
1394
1454
|
class RestChatService extends ChatService {
|
|
@@ -1474,13 +1534,7 @@ class RestChatService extends ChatService {
|
|
|
1474
1534
|
data.savedChatId = this.savedChatId;
|
|
1475
1535
|
}
|
|
1476
1536
|
// Request the Chat endpoint
|
|
1477
|
-
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(tap((res) => {
|
|
1478
|
-
if (res.quota.maxQuotaReached) {
|
|
1479
|
-
const msg = `Sorry, you have exceeded the allowed quota. Please retry starting from ${this.formatDateTime(res.quota.nextResetUTC)}.`;
|
|
1480
|
-
this.notificationsService.error(msg);
|
|
1481
|
-
throw new Error(msg);
|
|
1482
|
-
}
|
|
1483
|
-
}), map((res) => {
|
|
1537
|
+
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(tap((res) => this.updateQuota(res.quota, true)), map((res) => {
|
|
1484
1538
|
var _a;
|
|
1485
1539
|
// Define $progress from the actions property of the response
|
|
1486
1540
|
let $progress;
|
|
@@ -1499,14 +1553,16 @@ class RestChatService extends ChatService {
|
|
|
1499
1553
|
});
|
|
1500
1554
|
});
|
|
1501
1555
|
}
|
|
1502
|
-
//
|
|
1503
|
-
const response = Object.assign(
|
|
1504
|
-
if ($progress)
|
|
1556
|
+
// Re-attach the $progress and $attachment of the last response to the last assistant's response in the chat history
|
|
1557
|
+
const response = Object.assign({}, res.history.at(-1));
|
|
1558
|
+
if ($progress)
|
|
1505
1559
|
response.additionalProperties.$progress = $progress;
|
|
1506
|
-
|
|
1507
|
-
if (res.context) {
|
|
1560
|
+
if (res.context)
|
|
1508
1561
|
response.additionalProperties.$attachment = res.context.map((ctx) => ctx.additionalProperties);
|
|
1509
|
-
|
|
1562
|
+
if (res.suggestedActions)
|
|
1563
|
+
response.additionalProperties.$suggestedAction = res.suggestedActions;
|
|
1564
|
+
// Emit the updated chat usage metrics once the generation of the assistant response is completed
|
|
1565
|
+
this.updateChatUsageMetrics(response.additionalProperties.usageMetrics);
|
|
1510
1566
|
// Update the chat history with the incoming history property of the res AND the processed response message
|
|
1511
1567
|
this.chatHistory = res.history;
|
|
1512
1568
|
this.chatHistory[this.chatHistory.length - 1] = response;
|
|
@@ -1595,6 +1651,51 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1595
1651
|
type: Injectable
|
|
1596
1652
|
}], ctorParameters: function () { return []; } });
|
|
1597
1653
|
|
|
1654
|
+
class TokenProgressBarComponent {
|
|
1655
|
+
constructor() {
|
|
1656
|
+
this.subscription = new Subscription();
|
|
1657
|
+
this.loginService = inject(LoginService);
|
|
1658
|
+
this.instanceManagerService = inject(InstanceManagerService);
|
|
1659
|
+
}
|
|
1660
|
+
ngOnInit() {
|
|
1661
|
+
this.subscription.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), switchMap(_ => this.chatService.initProcess$), filter(success => !!success), tap(_ => {
|
|
1662
|
+
this.config = this.chatService.chatConfig$.value;
|
|
1663
|
+
this.onUserTokensConsumption();
|
|
1664
|
+
this.onChatTokensConsumption();
|
|
1665
|
+
})).subscribe());
|
|
1666
|
+
}
|
|
1667
|
+
ngOnDestroy() {
|
|
1668
|
+
this.subscription.unsubscribe();
|
|
1669
|
+
}
|
|
1670
|
+
instantiateChatService() {
|
|
1671
|
+
this.chatService = this.instanceManagerService.getInstance(this.instanceId);
|
|
1672
|
+
}
|
|
1673
|
+
onUserTokensConsumption() {
|
|
1674
|
+
this.subscription.add(this.chatService.userTokenConsumption$.subscribe((data) => {
|
|
1675
|
+
if (data) {
|
|
1676
|
+
this.userPercentage = data.percentage;
|
|
1677
|
+
this.userTitle = `Max generation allowed: ${this.userPercentage}% consumed. Resets at ${data.nextResetDate}`;
|
|
1678
|
+
}
|
|
1679
|
+
}));
|
|
1680
|
+
}
|
|
1681
|
+
onChatTokensConsumption() {
|
|
1682
|
+
this.subscription.add(this.chatService.chatTokenConsumption$.subscribe((data) => {
|
|
1683
|
+
if (data) {
|
|
1684
|
+
this.chatPercentage = data.percentage;
|
|
1685
|
+
this.chatTitle = `Max length of conversation: ${this.chatPercentage}% reached.`;
|
|
1686
|
+
}
|
|
1687
|
+
}));
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
TokenProgressBarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: TokenProgressBarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1691
|
+
TokenProgressBarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: TokenProgressBarComponent, isStandalone: true, selector: "sq-token-progress-bar", inputs: { instanceId: "instanceId" }, ngImport: i0, template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
|
|
1692
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: TokenProgressBarComponent, decorators: [{
|
|
1693
|
+
type: Component,
|
|
1694
|
+
args: [{ selector: 'sq-token-progress-bar', standalone: true, imports: [CommonModule, UtilsModule], template: "<div class=\"bars-container d-flex flex-row gap-2 p-2 me-4\" *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined) || (config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\">\n <div *ngIf=\"(config?.globalSettings?.displayUserQuotaConsumption && userPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"userTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + userPercentage + '%, #0040BF 0)'\">\n </div>\n <div *ngIf=\"(config?.globalSettings?.displayChatTokensConsumption && chatPercentage !== undefined)\" class=\"token-progress-bar\" [sqTooltip]=\"chatTitle\"\n [style.background]=\"'radial-gradient(closest-side, var(--ast-primary-bg, #F8F8F8) 70%, transparent 75% 100%), conic-gradient(#FF854A ' + chatPercentage + '%, #0040BF 0)'\">\n </div>\n</div>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-btn{border:0;text-align:left;padding-top:.5rem;padding-bottom:.5rem;display:flex;align-items:center}.dark{--ast-primary-bg: #0d0701;--ast-primary-color: #008cd1;--ast-secondary-bg: #00070e;--ast-secondary-color: #ffa258;--ast-input-bg: #070707;--ast-input-color: rgba(222, 218, 218, .75);--ast-muted-color: rgba(222, 218, 218, .75);--ast-saved-chat-hover-background: #262421;--ast-message-table-border-color: #333333;--ast-message-table-tr-bg: #070707;--ast-message-table-tr-border-color: #222222;--ast-reference-icon-color: white;--ast-reference-icon-active-color: black;--ast-reference-passages-color: white;--ast-reference-expanded-hover-bg: #262421;--ast-message-reference-color: black}.bars-container{background-color:var(--ast-primary-bg, #f2f8fe);border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.token-progress-bar{width:1.5rem;height:1.5rem;border-radius:50%}\n"] }]
|
|
1695
|
+
}], propDecorators: { instanceId: [{
|
|
1696
|
+
type: Input
|
|
1697
|
+
}] } });
|
|
1698
|
+
|
|
1598
1699
|
class ChatComponent extends AbstractFacet {
|
|
1599
1700
|
constructor() {
|
|
1600
1701
|
super();
|
|
@@ -1613,12 +1714,19 @@ class ChatComponent extends AbstractFacet {
|
|
|
1613
1714
|
this.messageHandlers = new Map();
|
|
1614
1715
|
/** When the assistant answer a user question, automatically scroll down to the bottom of the discussion */
|
|
1615
1716
|
this.automaticScrollToLastResponse = false;
|
|
1616
|
-
|
|
1717
|
+
/** Icon to use for the assistant messages */
|
|
1718
|
+
this.assistantMessageIcon = 'sq-sinequa';
|
|
1719
|
+
/** Event emitter triggered each time the assistant updates the current chat */
|
|
1617
1720
|
this.data = new EventEmitter();
|
|
1618
|
-
|
|
1721
|
+
/** Event emitter triggered when the user clicks to open the original document representing the context attachment*/
|
|
1722
|
+
this.openDocument = new EventEmitter();
|
|
1723
|
+
/** Event emitter triggered when the user clicks to open the preview of a document representing the context attachment */
|
|
1619
1724
|
this.openPreview = new EventEmitter();
|
|
1725
|
+
/** Event emitter triggered when the user clicks on a suggested action */
|
|
1726
|
+
this.suggestAction = new EventEmitter();
|
|
1727
|
+
/** Event emitter triggered when the chat is loading new content */
|
|
1620
1728
|
this.loading$ = new EventEmitter(false);
|
|
1621
|
-
|
|
1729
|
+
/** Emits the assistant configuration used when instantiating the component */
|
|
1622
1730
|
this._config = new EventEmitter();
|
|
1623
1731
|
this.messages$ = new BehaviorSubject(undefined);
|
|
1624
1732
|
this.question = '';
|
|
@@ -1636,13 +1744,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
1636
1744
|
}));
|
|
1637
1745
|
}
|
|
1638
1746
|
ngOnInit() {
|
|
1639
|
-
this.sub.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), map(_ => this.chatService.initChatConfig()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig), switchMap(_ => this.chatService.init()), filter(success => !!success), tap(_ => this.onLoadChat()), switchMap(_ => this.chatService.chatConfig$), tap(config => {
|
|
1747
|
+
this.sub.add(this.loginService.events.pipe(filter(e => e.type === 'login-complete'), tap(_ => this.instantiateChatService()), map(_ => this.chatService.initChatConfig()), switchMap(() => this.chatService.initConfig$), filter(initConfig => !!initConfig), switchMap(_ => this.chatService.init()), switchMap(_ => this.chatService.initProcess$), filter(success => !!success), tap(_ => this.onLoadChat()), switchMap(_ => this.chatService.chatConfig$), tap(config => {
|
|
1640
1748
|
this.config = config;
|
|
1641
1749
|
this.enabledUserInput = this.config.modeSettings.enabledUserInput;
|
|
1642
1750
|
this._config.emit(config);
|
|
1643
1751
|
try {
|
|
1644
1752
|
this.updateModelDescription();
|
|
1645
1753
|
if (!this.firstChangesHandled) {
|
|
1754
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query)); // Initialize the previous query
|
|
1646
1755
|
this.handleChanges();
|
|
1647
1756
|
this.addScrollListener();
|
|
1648
1757
|
this.firstChangesHandled = true;
|
|
@@ -1665,6 +1774,10 @@ class ChatComponent extends AbstractFacet {
|
|
|
1665
1774
|
this.sub.unsubscribe();
|
|
1666
1775
|
(_a = this.dataSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
1667
1776
|
}
|
|
1777
|
+
/**
|
|
1778
|
+
* Instantiate the chat service based on the provided @input protocol
|
|
1779
|
+
* The chat service instance will then be stored in the instanceManagerService with provided @input instanceId as a key
|
|
1780
|
+
*/
|
|
1668
1781
|
instantiateChatService() {
|
|
1669
1782
|
switch (this.protocol) {
|
|
1670
1783
|
case 'REST':
|
|
@@ -1705,11 +1818,10 @@ class ChatComponent extends AbstractFacet {
|
|
|
1705
1818
|
* Otherwise, the chat should be reloaded by default
|
|
1706
1819
|
*/
|
|
1707
1820
|
if (this.firstChangesHandled && (changes === null || changes === void 0 ? void 0 : changes.query) && this.config.modeSettings.initialization.event === 'Query') {
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(previousQuery, currentQuery) : true) {
|
|
1711
|
-
this.triggerReloadAfterQueryChange(currentQuery);
|
|
1821
|
+
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(this._previousQuery, this.query) : true) {
|
|
1822
|
+
this.triggerReloadAfterQueryChange(this.query);
|
|
1712
1823
|
}
|
|
1824
|
+
this._previousQuery = JSON.parse(JSON.stringify(this.query)); // Update the previous query
|
|
1713
1825
|
}
|
|
1714
1826
|
}
|
|
1715
1827
|
triggerReloadAfterQueryChange(query) {
|
|
@@ -1735,23 +1847,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1735
1847
|
}));
|
|
1736
1848
|
}
|
|
1737
1849
|
updateModelDescription() {
|
|
1738
|
-
var _a;
|
|
1739
1850
|
this.modelDescription = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
|
|
1740
|
-
this.assistantIcon = !!this.customAssistantIcon ? this.customAssistantIcon : 'sq-sinequa';
|
|
1741
|
-
switch ((_a = this.modelDescription) === null || _a === void 0 ? void 0 : _a.provider) {
|
|
1742
|
-
case 'Google':
|
|
1743
|
-
this.privacyUrl = '';
|
|
1744
|
-
break;
|
|
1745
|
-
case 'AzureOpenAI':
|
|
1746
|
-
this.privacyUrl = 'https://learn.microsoft.com/en-us/legal/cognitive-services/openai/data-privacy';
|
|
1747
|
-
break;
|
|
1748
|
-
case 'OpenAI':
|
|
1749
|
-
this.privacyUrl = 'https://openai.com/enterprise-privacy';
|
|
1750
|
-
break;
|
|
1751
|
-
case 'Cohere':
|
|
1752
|
-
this.privacyUrl = 'https://cohere.com/security';
|
|
1753
|
-
break;
|
|
1754
|
-
}
|
|
1755
1851
|
this.cdr.detectChanges();
|
|
1756
1852
|
}
|
|
1757
1853
|
submitQuestion() {
|
|
@@ -1777,8 +1873,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1777
1873
|
this.fetch(messages);
|
|
1778
1874
|
}
|
|
1779
1875
|
/**
|
|
1780
|
-
* Given a list of messages,
|
|
1781
|
-
* the list of messages accordingly.
|
|
1876
|
+
* Given a list of messages, the chat endpoint is invoked for a continuation and updates the list of messages accordingly.
|
|
1782
1877
|
* @param messages
|
|
1783
1878
|
*/
|
|
1784
1879
|
fetch(messages) {
|
|
@@ -1789,10 +1884,8 @@ class ChatComponent extends AbstractFacet {
|
|
|
1789
1884
|
this.dataSubscription = this.chatService.fetch(messages, this.query)
|
|
1790
1885
|
.subscribe({
|
|
1791
1886
|
next: res => this.updateData(res.history),
|
|
1792
|
-
error:
|
|
1887
|
+
error: () => {
|
|
1793
1888
|
this.terminateFetch();
|
|
1794
|
-
console.error(err);
|
|
1795
|
-
this.error.emit(err);
|
|
1796
1889
|
},
|
|
1797
1890
|
complete: () => {
|
|
1798
1891
|
this.terminateFetch();
|
|
@@ -1892,10 +1985,11 @@ class ChatComponent extends AbstractFacet {
|
|
|
1892
1985
|
this.updateData(messages); // If the last message if from the assistant, we can load the conversation right away
|
|
1893
1986
|
this.terminateFetch();
|
|
1894
1987
|
}
|
|
1988
|
+
this.addScrollListener();
|
|
1895
1989
|
}
|
|
1896
1990
|
/**
|
|
1897
|
-
* Reset the chat by clearing the
|
|
1898
|
-
* The
|
|
1991
|
+
* Reset the chat by clearing the chat history and the UI accordingly
|
|
1992
|
+
* The user input will be cleared
|
|
1899
1993
|
* The fetch subscription will be terminated
|
|
1900
1994
|
*/
|
|
1901
1995
|
resetChat() {
|
|
@@ -1916,18 +2010,24 @@ class ChatComponent extends AbstractFacet {
|
|
|
1916
2010
|
(_a = this.dataSubscription) === null || _a === void 0 ? void 0 : _a.unsubscribe();
|
|
1917
2011
|
this.dataSubscription = undefined;
|
|
1918
2012
|
this.loading$.next(false);
|
|
1919
|
-
setTimeout(() => {
|
|
1920
|
-
var _a;
|
|
1921
|
-
(_a = this.questionInput) === null || _a === void 0 ? void 0 : _a.nativeElement.focus();
|
|
1922
|
-
});
|
|
1923
2013
|
this.cdr.detectChanges();
|
|
1924
2014
|
}
|
|
2015
|
+
/**
|
|
2016
|
+
* Copy a previous user message of the chat history to the chat user input.
|
|
2017
|
+
* Thus, the user can edit and resubmit the message.
|
|
2018
|
+
* Once the edited message is submitted, all subsequent messages starting from @param index will be removed from the history and the UI will be updated accordingly.
|
|
2019
|
+
* The assistant will regenerate a new answer based on the updated chat history.
|
|
2020
|
+
* @param index The index of the user's message to edit
|
|
2021
|
+
*/
|
|
1925
2022
|
editMessage(index) {
|
|
1926
|
-
var _a;
|
|
1927
2023
|
this.messageToEdit = index;
|
|
1928
2024
|
this.question = this.chatService.chatHistory[index].content;
|
|
1929
|
-
(_a = this.questionInput) === null || _a === void 0 ? void 0 : _a.nativeElement.focus();
|
|
1930
2025
|
}
|
|
2026
|
+
/**
|
|
2027
|
+
* Starting from the provided index, remove all subsequent messages from the chat history and the UI accordingly.
|
|
2028
|
+
* The assistant will regenerate a new answer based on the updated chat history.
|
|
2029
|
+
* @param index The index of the assistant's message to regenerate
|
|
2030
|
+
*/
|
|
1931
2031
|
regenerateMessage(index) {
|
|
1932
2032
|
// Define the chat history based on which the assistant will generate a new answer
|
|
1933
2033
|
const slicedMessages = this.chatService.chatHistory.slice(0, index);
|
|
@@ -1942,8 +2042,10 @@ class ChatComponent extends AbstractFacet {
|
|
|
1942
2042
|
this.calculateHeight();
|
|
1943
2043
|
break;
|
|
1944
2044
|
case 'Enter':
|
|
1945
|
-
if (!event.shiftKey)
|
|
2045
|
+
if (!event.shiftKey) {
|
|
2046
|
+
event.preventDefault();
|
|
1946
2047
|
this.submitQuestion();
|
|
2048
|
+
}
|
|
1947
2049
|
this.calculateHeight();
|
|
1948
2050
|
break;
|
|
1949
2051
|
default:
|
|
@@ -1960,16 +2062,16 @@ class ChatComponent extends AbstractFacet {
|
|
|
1960
2062
|
}
|
|
1961
2063
|
}
|
|
1962
2064
|
ChatComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1963
|
-
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",
|
|
2065
|
+
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: [
|
|
1964
2066
|
RestChatService,
|
|
1965
2067
|
WebSocketChatService
|
|
1966
|
-
], 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\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
|
|
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 });
|
|
1967
2069
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
1968
2070
|
type: Component,
|
|
1969
2071
|
args: [{ selector: 'sq-chat-v3', providers: [
|
|
1970
2072
|
RestChatService,
|
|
1971
2073
|
WebSocketChatService
|
|
1972
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent], template: "\n<ng-container *ngIf=\"!initializationError\">\n <div *ngIf=\"messages$ | async as messages; else loadingTpl || loadingTplDefault\" class=\"h-100 d-flex flex-column\">\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
|
|
2074
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, FormsModule, ChatMessageComponent, TokenProgressBarComponent], 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"] }]
|
|
1973
2075
|
}], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
|
|
1974
2076
|
type: Input
|
|
1975
2077
|
}], query: [{
|
|
@@ -1984,19 +2086,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1984
2086
|
type: Input
|
|
1985
2087
|
}], chat: [{
|
|
1986
2088
|
type: Input
|
|
1987
|
-
}],
|
|
2089
|
+
}], assistantMessageIcon: [{
|
|
2090
|
+
type: Input
|
|
2091
|
+
}], userMessageIcon: [{
|
|
1988
2092
|
type: Input
|
|
1989
2093
|
}], data: [{
|
|
1990
2094
|
type: Output
|
|
1991
|
-
}],
|
|
2095
|
+
}], openDocument: [{
|
|
1992
2096
|
type: Output
|
|
1993
2097
|
}], openPreview: [{
|
|
1994
2098
|
type: Output
|
|
2099
|
+
}], suggestAction: [{
|
|
2100
|
+
type: Output
|
|
1995
2101
|
}], loading$: [{
|
|
1996
2102
|
type: Output,
|
|
1997
2103
|
args: ["loading"]
|
|
1998
|
-
}], error: [{
|
|
1999
|
-
type: Output
|
|
2000
2104
|
}], _config: [{
|
|
2001
2105
|
type: Output,
|
|
2002
2106
|
args: ["config"]
|
|
@@ -2019,7 +2123,6 @@ class SavedChatsComponent {
|
|
|
2019
2123
|
this.groupedSavedChats$ = new BehaviorSubject([]);
|
|
2020
2124
|
this.loginService = inject(LoginService);
|
|
2021
2125
|
this.instanceManagerService = inject(InstanceManagerService);
|
|
2022
|
-
this.auditService = inject(AuditWebService);
|
|
2023
2126
|
this.modalService = inject(ModalService);
|
|
2024
2127
|
this.notificationsService = inject(NotificationsService);
|
|
2025
2128
|
}
|
|
@@ -2101,7 +2204,7 @@ class SavedChatsComponent {
|
|
|
2101
2204
|
savedChats
|
|
2102
2205
|
.sort((a, b) => parseISO(b.modifiedUTC).getTime() - parseISO(a.modifiedUTC).getTime())
|
|
2103
2206
|
.forEach(savedChat => {
|
|
2104
|
-
const groupKey = this._getTimeKey(parseISO(savedChat.modifiedUTC));
|
|
2207
|
+
const groupKey = this._getTimeKey(toDate(parseISO(savedChat.modifiedUTC))); // Must convert the UTC date to local date before passing to _getTimeKey
|
|
2105
2208
|
if (!groupedSavedChats.has(groupKey)) {
|
|
2106
2209
|
groupedSavedChats.set(groupKey, []);
|
|
2107
2210
|
}
|