@sinequa/assistant 3.1.1 → 3.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/chat/chat-message/chat-message.component.d.ts +3 -0
- package/chat/chat-settings-v3/chat-settings-v3.component.d.ts +8 -3
- package/chat/chat.component.d.ts +174 -146
- package/chat/chat.service.d.ts +31 -917
- package/chat/prompt.component.d.ts +21 -0
- package/chat/public-api.d.ts +1 -0
- package/chat/rest-chat.service.d.ts +5 -2
- package/chat/saved-chats/saved-chats.component.d.ts +4 -3
- package/chat/styles/assistant.scss +21 -1
- package/chat/types.d.ts +284 -866
- package/chat/websocket-chat.service.d.ts +16 -12
- package/esm2020/chat/chat-message/chat-message.component.mjs +25 -3
- package/esm2020/chat/chat-reference/chat-reference.component.mjs +3 -3
- package/esm2020/chat/chat-settings-v3/chat-settings-v3.component.mjs +22 -24
- package/esm2020/chat/chat.component.mjs +123 -67
- package/esm2020/chat/chat.service.mjs +68 -24
- package/esm2020/chat/prompt.component.mjs +88 -0
- package/esm2020/chat/public-api.mjs +2 -1
- package/esm2020/chat/rest-chat.service.mjs +73 -26
- package/esm2020/chat/saved-chats/saved-chats.component.mjs +37 -7
- package/esm2020/chat/types.mjs +50 -54
- package/esm2020/chat/websocket-chat.service.mjs +116 -56
- package/fesm2015/sinequa-assistant-chat.mjs +583 -251
- package/fesm2015/sinequa-assistant-chat.mjs.map +1 -1
- package/fesm2020/sinequa-assistant-chat.mjs +584 -254
- package/fesm2020/sinequa-assistant-chat.mjs.map +1 -1
- package/package.json +4 -2
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, EventEmitter, inject, Component, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ContentChild } from '@angular/core';
|
|
3
|
-
import { Subscription, filter, tap, switchMap, BehaviorSubject, Subject, forkJoin, map, catchError, throwError, shareReplay, fromEvent, merge, takeUntil, finalize } from 'rxjs';
|
|
2
|
+
import { Injectable, EventEmitter, inject, Component, Input, Output, ViewEncapsulation, ChangeDetectionStrategy, ChangeDetectorRef, ViewChild, ContentChild, Inject } from '@angular/core';
|
|
3
|
+
import { Subscription, filter, tap, switchMap, BehaviorSubject, Subject, forkJoin, map, catchError, throwError, shareReplay, fromEvent, merge, takeUntil, take, finalize } from 'rxjs';
|
|
4
4
|
import * as i3 from '@sinequa/core/web-services';
|
|
5
5
|
import { PrincipalWebService, UserSettingsWebService, AuditWebService, SignalRWebService, JsonMethodPluginService } from '@sinequa/core/web-services';
|
|
6
6
|
import * as i1 from '@angular/common';
|
|
7
7
|
import { CommonModule } from '@angular/common';
|
|
8
8
|
import * as i2 from '@angular/forms';
|
|
9
|
-
import { FormsModule } from '@angular/forms';
|
|
9
|
+
import { FormsModule, Validators, UntypedFormControl, ReactiveFormsModule } from '@angular/forms';
|
|
10
10
|
import { LoginService, AuthenticationService } from '@sinequa/core/login';
|
|
11
11
|
import { Action } from '@sinequa/components/action';
|
|
12
12
|
import { AbstractFacet } from '@sinequa/components/facet';
|
|
@@ -16,9 +16,12 @@ import { UserPreferences } from '@sinequa/components/user-settings';
|
|
|
16
16
|
import { NotificationsService } from '@sinequa/core/notification';
|
|
17
17
|
import { z } from 'zod';
|
|
18
18
|
import { AppService } from '@sinequa/core/app-utils';
|
|
19
|
-
import
|
|
19
|
+
import * as i6$1 from '@sinequa/core/intl';
|
|
20
|
+
import { IntlService, IntlModule } from '@sinequa/core/intl';
|
|
20
21
|
import get from 'lodash/get';
|
|
21
22
|
import { Utils } from '@sinequa/core/base';
|
|
23
|
+
import * as i1$2 from '@sinequa/core/modal';
|
|
24
|
+
import { ModalService, ModalButton, ModalModule, MODAL_MODEL } from '@sinequa/core/modal';
|
|
22
25
|
import { HttpTransportType, LogLevel } from '@microsoft/signalr';
|
|
23
26
|
import { unified } from 'unified';
|
|
24
27
|
import remarkParse from 'remark-parse';
|
|
@@ -31,8 +34,13 @@ import { CollapseModule } from '@sinequa/components/collapse';
|
|
|
31
34
|
import * as i6 from 'ngx-remark';
|
|
32
35
|
import { RemarkModule } from 'ngx-remark';
|
|
33
36
|
import SafeColor from 'safecolor';
|
|
34
|
-
import
|
|
37
|
+
import 'prismjs-components-importer/esm';
|
|
38
|
+
import 'prismjs/plugins/autoloader/prism-autoloader';
|
|
35
39
|
import { parseISO, isToday, isYesterday, isThisWeek, differenceInDays, endOfYesterday, isThisMonth, differenceInMonths, isThisQuarter, isThisYear, differenceInYears, format } from 'date-fns';
|
|
40
|
+
import * as i4 from '@sinequa/components/modal';
|
|
41
|
+
import { BsModalModule } from '@sinequa/components/modal';
|
|
42
|
+
import * as i5$1 from '@sinequa/core/validation';
|
|
43
|
+
import { ValidationModule } from '@sinequa/core/validation';
|
|
36
44
|
|
|
37
45
|
/**
|
|
38
46
|
* A service to create and manage instances of ChatService dynamically based on the provided component references and the implementation type (http or websocket)
|
|
@@ -83,6 +91,7 @@ class ChatSettingsV3Component {
|
|
|
83
91
|
this._update = new EventEmitter();
|
|
84
92
|
this._cancel = new EventEmitter();
|
|
85
93
|
this.subscription = new Subscription();
|
|
94
|
+
this.functions = [];
|
|
86
95
|
this.isAdmin = false;
|
|
87
96
|
this.loginService = inject(LoginService);
|
|
88
97
|
this.instanceManagerService = inject(InstanceManagerService);
|
|
@@ -93,8 +102,8 @@ class ChatSettingsV3Component {
|
|
|
93
102
|
this.isAdmin = this.principalService.principal.isAdministrator;
|
|
94
103
|
// Init config with a copy of the original chat config, so that it won't be modified by the user until he clicks on save
|
|
95
104
|
this.config = JSON.parse(JSON.stringify(this.chatService.chatConfig$.value));
|
|
96
|
-
this.selectedModel = this.chatService.getModel(this.config.
|
|
97
|
-
this.
|
|
105
|
+
this.selectedModel = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
|
|
106
|
+
this.initFunctionsList();
|
|
98
107
|
}));
|
|
99
108
|
}
|
|
100
109
|
ngOnDestroy() {
|
|
@@ -102,14 +111,14 @@ class ChatSettingsV3Component {
|
|
|
102
111
|
}
|
|
103
112
|
get hasPrompts() {
|
|
104
113
|
return this.isAdmin
|
|
105
|
-
|| !!this.config.uiSettings.
|
|
106
|
-
|| !!this.config.uiSettings.
|
|
114
|
+
|| !!this.config.uiSettings.displaySystemPrompt
|
|
115
|
+
|| !!this.config.uiSettings.displayUserPrompt;
|
|
107
116
|
}
|
|
108
117
|
get hasAdvancedParameters() {
|
|
109
118
|
return this.isAdmin
|
|
110
119
|
|| !!this.config.uiSettings.temperature
|
|
111
120
|
|| !!this.config.uiSettings.top_p
|
|
112
|
-
|| !!this.config.uiSettings.
|
|
121
|
+
|| !!this.config.uiSettings.max_tokens;
|
|
113
122
|
}
|
|
114
123
|
get hasModel() {
|
|
115
124
|
return this.isAdmin
|
|
@@ -118,49 +127,46 @@ class ChatSettingsV3Component {
|
|
|
118
127
|
|| !!this.config.uiSettings.debug
|
|
119
128
|
|| !!this.config.uiSettings.temperature
|
|
120
129
|
|| !!this.config.uiSettings.top_p
|
|
121
|
-
|| !!this.config.uiSettings.
|
|
130
|
+
|| !!this.config.uiSettings.max_tokens;
|
|
122
131
|
}
|
|
123
132
|
instantiateChatService() {
|
|
124
133
|
this.chatService = this.instanceManagerService.getInstance(this.instanceId);
|
|
125
134
|
}
|
|
126
135
|
onChatModelChange(selectedModel) {
|
|
127
136
|
// Update properties based on the selected model
|
|
128
|
-
this.config.
|
|
129
|
-
this.config.
|
|
137
|
+
this.config.defaultValues.service_id = selectedModel.serviceId;
|
|
138
|
+
this.config.defaultValues.model_id = selectedModel.modelId;
|
|
139
|
+
}
|
|
140
|
+
getFunctionDescription(name) {
|
|
141
|
+
return this.chatService.functions?.find(fn => fn.functionName === name)?.description || "";
|
|
130
142
|
}
|
|
131
143
|
toggleFunctionsSelection(name) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
else {
|
|
136
|
-
this.config.functions.push(name);
|
|
137
|
-
}
|
|
144
|
+
// Update the enabled property of the function
|
|
145
|
+
const index = this.config.defaultValues.functions.findIndex(func => func.name === name);
|
|
146
|
+
this.config.defaultValues.functions[index].enabled = this.functions[index].enabled;
|
|
138
147
|
}
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
(this.chatService.functions || []).forEach(item => {
|
|
142
|
-
item['selected'] = this.config.functions.includes(item.functionName);
|
|
143
|
-
});
|
|
148
|
+
initFunctionsList() {
|
|
149
|
+
this.functions = this.config.defaultValues.functions.filter(func => !!this.chatService.functions?.find(fn => fn.functionName === func.name));
|
|
144
150
|
}
|
|
145
151
|
/**
|
|
146
152
|
* Save the new chat config in the chat service and the user preferences
|
|
147
153
|
*/
|
|
148
154
|
save() {
|
|
149
155
|
this.chatService.updateChatConfig(this.config);
|
|
150
|
-
this._update.emit();
|
|
156
|
+
this._update.emit(this.config);
|
|
151
157
|
}
|
|
152
158
|
/**
|
|
153
159
|
* Cancel the current changes
|
|
154
160
|
*/
|
|
155
161
|
cancel() {
|
|
156
|
-
this._cancel.emit();
|
|
162
|
+
this._cancel.emit(this.chatService.chatConfig$.value);
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
ChatSettingsV3Component.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
160
|
-
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\">\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
|
|
166
|
+
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"] }] });
|
|
161
167
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatSettingsV3Component, decorators: [{
|
|
162
168
|
type: Component,
|
|
163
|
-
args: [{ selector: 'sq-chat-settings-v3', standalone: true, imports: [CommonModule, FormsModule], template: "<div class=\"sq-chat-settings\">\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
|
|
169
|
+
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"] }]
|
|
164
170
|
}], propDecorators: { instanceId: [{
|
|
165
171
|
type: Input
|
|
166
172
|
}], _update: [{
|
|
@@ -171,8 +177,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
171
177
|
args: ["cancel"]
|
|
172
178
|
}] } });
|
|
173
179
|
|
|
174
|
-
// Define the Zod representation for the
|
|
175
|
-
const
|
|
180
|
+
// Define the Zod representation for the connectionSettings object
|
|
181
|
+
const connectionSettingsSchema = z.object({
|
|
176
182
|
restEndpoint: z.string().optional(),
|
|
177
183
|
websocketEndpoint: z.string().optional(),
|
|
178
184
|
signalRTransport: z.enum(["WebSockets", "ServerSentEvents", "LongPolling", "None"]),
|
|
@@ -186,50 +192,10 @@ const serviceSettingsSchema = z.object({
|
|
|
186
192
|
model_id: z.string(),
|
|
187
193
|
temperature: z.number(),
|
|
188
194
|
top_p: z.number(),
|
|
189
|
-
|
|
190
|
-
results_per_prompt: z.number(),
|
|
191
|
-
presence_penalty: z.number(),
|
|
192
|
-
frequency_penalty: z.number(),
|
|
193
|
-
});
|
|
194
|
-
// Define the Zod representation for the TextChunksOptions interface
|
|
195
|
-
const textChunksOptionsSchema = z.object({
|
|
196
|
-
extendMode: z.enum(['None', 'Sentence', 'Chars']).optional(),
|
|
197
|
-
extendScope: z.number().optional(),
|
|
198
|
-
});
|
|
199
|
-
// Define the Zod representation for the contextOptions object
|
|
200
|
-
const contextOptionsSchema = z.object({
|
|
201
|
-
docColumns: z.array(z.string()),
|
|
202
|
-
textChunkFillGaps: z.number(),
|
|
203
|
-
html: z.boolean(),
|
|
204
|
-
topPassagesOptions: z.object({
|
|
205
|
-
topPassages: z.number(),
|
|
206
|
-
topPassagesMinScore: z.number(),
|
|
207
|
-
textChunkOptions: textChunksOptionsSchema,
|
|
208
|
-
}),
|
|
209
|
-
matchingPassagesOptions: z.object({
|
|
210
|
-
matchingPassagesPerDoc: z.number(),
|
|
211
|
-
fromTopDocuments: z.number(),
|
|
212
|
-
matchingPassagesMinScore: z.number(),
|
|
213
|
-
textChunkOptions: textChunksOptionsSchema,
|
|
214
|
-
}),
|
|
215
|
-
relevantExtractsOptions: z.object({
|
|
216
|
-
topRelevantExtractsPerDoc: z.number(),
|
|
217
|
-
fromTopDocuments: z.number(),
|
|
218
|
-
textChunkOptions: textChunksOptionsSchema,
|
|
219
|
-
}),
|
|
220
|
-
htmlOptions: z.object({
|
|
221
|
-
images: z.boolean(),
|
|
222
|
-
links: z.boolean(),
|
|
223
|
-
tables: z.boolean(),
|
|
224
|
-
extendTables: z.boolean(),
|
|
225
|
-
}),
|
|
226
|
-
});
|
|
227
|
-
// Define the Zod representation for the contextSettings object
|
|
228
|
-
const contextSettingsSchema = z.object({
|
|
229
|
-
app: z.string().optional(),
|
|
230
|
-
query: z.object({}).optional(),
|
|
231
|
-
contextOptions: contextOptionsSchema,
|
|
195
|
+
max_tokens: z.number()
|
|
232
196
|
});
|
|
197
|
+
// Define the Zod representation for the additionalServiceSettings object
|
|
198
|
+
const additionalServiceSettingsSchema = z.object({});
|
|
233
199
|
// Define the Zod representation for the uiSettings object
|
|
234
200
|
const uiSettingsSchema = z.object({
|
|
235
201
|
display: z.boolean(),
|
|
@@ -237,22 +203,58 @@ const uiSettingsSchema = z.object({
|
|
|
237
203
|
functions: z.boolean(),
|
|
238
204
|
temperature: z.boolean(),
|
|
239
205
|
top_p: z.boolean(),
|
|
240
|
-
|
|
206
|
+
max_tokens: z.boolean(),
|
|
241
207
|
debug: z.boolean(),
|
|
242
208
|
displaySystemPrompt: z.boolean(),
|
|
209
|
+
displayUserPrompt: z.boolean()
|
|
210
|
+
});
|
|
211
|
+
// Define the Zod representation for the defaultValues object
|
|
212
|
+
const defaultValuesSchema = z.object({
|
|
213
|
+
service_id: z.string(),
|
|
214
|
+
model_id: z.string(),
|
|
215
|
+
functions: z.array(z.object({
|
|
216
|
+
name: z.string(),
|
|
217
|
+
enabled: z.boolean()
|
|
218
|
+
})),
|
|
219
|
+
temperature: z.number(),
|
|
220
|
+
top_p: z.number(),
|
|
221
|
+
max_tokens: z.number(),
|
|
222
|
+
debug: z.boolean(),
|
|
243
223
|
systemPrompt: z.string(),
|
|
224
|
+
userPrompt: z.string()
|
|
225
|
+
});
|
|
226
|
+
// Define the Zod representation for the modeSettings object
|
|
227
|
+
const initializationSchema = z.object({
|
|
228
|
+
event: z.enum(['Query', 'Prompt']),
|
|
229
|
+
forcedWorkflow: z.string().optional(),
|
|
230
|
+
displayUserQuery: z.boolean().optional(), // Optional for event 'Prompt'
|
|
231
|
+
}).refine(data => ((data.event === "Query") ? (!!data.forcedWorkflow && data.displayUserQuery !== undefined && data.displayUserQuery !== null) : true), {
|
|
232
|
+
message: "The 'forcedWorkflow' and 'displayUserQuery' properties must be provided when the initialization's event is 'Query'.",
|
|
233
|
+
});
|
|
234
|
+
const modeSettingsSchema = z.object({
|
|
235
|
+
enabledUserInput: z.boolean(),
|
|
244
236
|
displayUserPrompt: z.boolean(),
|
|
245
|
-
|
|
237
|
+
sendUserPrompt: z.boolean(),
|
|
238
|
+
initialization: initializationSchema
|
|
239
|
+
});
|
|
240
|
+
// Define the Zod representation for the savedChatSettings object
|
|
241
|
+
const savedChatSettingsSchema = z.object({
|
|
242
|
+
enabled: z.boolean(),
|
|
243
|
+
display: z.boolean()
|
|
244
|
+
});
|
|
245
|
+
// Define the Zod representation for the globalSettings object
|
|
246
|
+
const globalSettingsSchema = z.object({
|
|
247
|
+
disclaimer: z.string().optional(),
|
|
246
248
|
});
|
|
247
249
|
// Define the Zod representation for the entire ChatConfig object
|
|
248
250
|
const chatConfigSchema = z.object({
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
251
|
+
connectionSettings: connectionSettingsSchema,
|
|
252
|
+
defaultValues: defaultValuesSchema,
|
|
253
|
+
modeSettings: modeSettingsSchema,
|
|
252
254
|
uiSettings: uiSettingsSchema,
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
255
|
+
additionalServiceSettings: additionalServiceSettingsSchema,
|
|
256
|
+
savedChatSettings: savedChatSettingsSchema,
|
|
257
|
+
globalSettings: globalSettingsSchema
|
|
256
258
|
});
|
|
257
259
|
|
|
258
260
|
class ChatService {
|
|
@@ -269,7 +271,6 @@ class ChatService {
|
|
|
269
271
|
this.savedChats$ = new BehaviorSubject([]);
|
|
270
272
|
/** Emit the saved chat to load */
|
|
271
273
|
this.loadSavedChat$ = new BehaviorSubject(undefined);
|
|
272
|
-
this.searchService = inject(SearchService);
|
|
273
274
|
this.userSettingsService = inject(UserSettingsWebService);
|
|
274
275
|
this.notificationsService = inject(NotificationsService);
|
|
275
276
|
this.auditService = inject(AuditWebService);
|
|
@@ -277,6 +278,7 @@ class ChatService {
|
|
|
277
278
|
this.loginService = inject(LoginService);
|
|
278
279
|
this.appService = inject(AppService);
|
|
279
280
|
this.intlService = inject(IntlService);
|
|
281
|
+
this.modalService = inject(ModalService);
|
|
280
282
|
}
|
|
281
283
|
get assistants() {
|
|
282
284
|
if (!this.userSettingsService.userSettings)
|
|
@@ -314,24 +316,68 @@ class ChatService {
|
|
|
314
316
|
this._savedChatId = savedChatId;
|
|
315
317
|
}
|
|
316
318
|
/**
|
|
317
|
-
* Initialize the chat config by
|
|
318
|
-
*
|
|
319
|
+
* Initialize the chat config by managing ONLY sub-object **defaultValues** configs of the standard app config (defined in the customization json tab ) and the user preferences.
|
|
320
|
+
* To do so, a tracking mechanism is implemented to notify the user about the available updates in the defaultValues object of the standard app config.
|
|
321
|
+
* The rest of the config object coming from "standard app config" is used as it is without any override.
|
|
322
|
+
* Thus, the user preferences are used only for the defaultValues object.
|
|
323
|
+
* This provide a centralized way to manage the rest of the config object by admins and ensure a unique common behavior for all users.
|
|
319
324
|
*/
|
|
320
325
|
initChatConfig() {
|
|
321
326
|
const key = this.chatInstanceId;
|
|
322
327
|
const userSettingsConfig = this.assistants[key] || {};
|
|
323
|
-
const
|
|
324
|
-
// Validate the object against the schema
|
|
328
|
+
const standardChatConfig = this.appService.app?.data?.assistants?.[key];
|
|
325
329
|
try {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
...
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
330
|
+
// Validate the whole config object against the schema
|
|
331
|
+
chatConfigSchema.parse(standardChatConfig);
|
|
332
|
+
// If the user preferences do not contain a config's defaultValues object, keep using the standard app config and nothing to store in the user preferences
|
|
333
|
+
if (!userSettingsConfig.defaultValues) {
|
|
334
|
+
this.chatConfig$.next({ ...standardChatConfig });
|
|
335
|
+
this.initConfig$.next(true);
|
|
336
|
+
}
|
|
337
|
+
else { // If the user has its own defaultValues in its userSettings, then we need to check for potential updates made by admins in the meantime and how he wants to manage them
|
|
338
|
+
// Retrieve already stored hashes in the user settings if exists
|
|
339
|
+
const appliedDefaultValuesHash = userSettingsConfig.hashes?.["applied-defaultValues-hash"];
|
|
340
|
+
const skippedDefaultValuesHash = userSettingsConfig.hashes?.["skipped-defaultValues-hash"];
|
|
341
|
+
// Create a hash of the current defaultValues of the standardChatConfig
|
|
342
|
+
const currentDefaultValuesHash = Utils.sha512(JSON.stringify(standardChatConfig.defaultValues));
|
|
343
|
+
// Implement the tracking mechanism to notify the user about the available updates in the defaultValues object of the standard app config
|
|
344
|
+
const condition = (currentDefaultValuesHash !== appliedDefaultValuesHash) && (currentDefaultValuesHash !== skippedDefaultValuesHash);
|
|
345
|
+
if (condition) {
|
|
346
|
+
this.modalService
|
|
347
|
+
.confirm({
|
|
348
|
+
title: "Available updates !",
|
|
349
|
+
message: "Changes have been made to the default configuration. Do you want to update your own version ?",
|
|
350
|
+
buttons: [
|
|
351
|
+
new ModalButton({ result: -4 /* ModalResult.No */, text: "See no more" }),
|
|
352
|
+
new ModalButton({ result: -7 /* ModalResult.Ignore */, text: "Remind me later" }),
|
|
353
|
+
new ModalButton({ result: -1 /* ModalResult.OK */, text: "Update", primary: true })
|
|
354
|
+
],
|
|
355
|
+
confirmType: 2 /* ConfirmType.Warning */
|
|
356
|
+
}).then(res => {
|
|
357
|
+
if (res === -1 /* ModalResult.OK */) {
|
|
358
|
+
const hashes = { "applied-defaultValues-hash": currentDefaultValuesHash, "skipped-defaultValues-hash": undefined };
|
|
359
|
+
// Update the chat config and store its defaultValues in the user preferences
|
|
360
|
+
this.updateChatConfig({ ...standardChatConfig }, hashes, true);
|
|
361
|
+
this.initConfig$.next(true);
|
|
362
|
+
}
|
|
363
|
+
else if (res === -4 /* ModalResult.No */) {
|
|
364
|
+
// Do not notify the user about changes while this skipped version is not updated
|
|
365
|
+
const hashes = { ...userSettingsConfig.hashes, "skipped-defaultValues-hash": currentDefaultValuesHash };
|
|
366
|
+
this.updateChatConfig({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues }, hashes, false);
|
|
367
|
+
this.initConfig$.next(true);
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
// Just pick the version in the user settings, nothing to be updated
|
|
371
|
+
this.chatConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
|
|
372
|
+
this.initConfig$.next(true);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
else { // No available updates Or updates has been already skipped, then just pick the version in the user settings
|
|
377
|
+
this.chatConfig$.next({ ...standardChatConfig, defaultValues: userSettingsConfig.defaultValues });
|
|
378
|
+
this.initConfig$.next(true);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
335
381
|
}
|
|
336
382
|
catch (error) {
|
|
337
383
|
this.notificationsService.error(`Missing valid configuration for the assistant instance '${key}'`);
|
|
@@ -339,25 +385,25 @@ class ChatService {
|
|
|
339
385
|
}
|
|
340
386
|
}
|
|
341
387
|
/**
|
|
342
|
-
* Update the chat config and store
|
|
388
|
+
* Update the chat config and store its defaultValues in the user preferences
|
|
343
389
|
* @param config The updated chat config
|
|
344
390
|
* @param notify Whether to notify the user about the update
|
|
345
391
|
* @param successCallback The callback to execute if the update is successful
|
|
346
392
|
* @param errorCallback The callback to execute if the update fails
|
|
347
393
|
*/
|
|
348
|
-
updateChatConfig(config, notify = true, successCallback, errorCallback) {
|
|
394
|
+
updateChatConfig(config, hashes, notify = true, successCallback, errorCallback) {
|
|
349
395
|
this.chatConfig$.next(config);
|
|
350
396
|
const assistants = Object.assign({}, this.assistants);
|
|
351
|
-
assistants[this.chatInstanceId] = config;
|
|
352
|
-
this.userSettingsService.patch({ assistants }).subscribe(next => {
|
|
353
|
-
if (notify) {
|
|
354
|
-
successCallback ? successCallback() : this.notificationsService.success(`The configuration of the assistant instance '${this.chatInstanceId}' has been successfully updated`);
|
|
355
|
-
}
|
|
356
|
-
}, error => {
|
|
397
|
+
assistants[this.chatInstanceId] = { ...assistants[this.chatInstanceId], defaultValues: config.defaultValues, hashes };
|
|
398
|
+
this.userSettingsService.patch({ assistants }).subscribe(next => { }, error => {
|
|
357
399
|
if (notify) {
|
|
358
400
|
errorCallback ? errorCallback() : this.notificationsService.error(`The update of the assistant instance '${this.chatInstanceId}' configuration failed`);
|
|
359
401
|
}
|
|
360
402
|
console.error("Could not patch assistants!", error);
|
|
403
|
+
}, () => {
|
|
404
|
+
if (notify) {
|
|
405
|
+
successCallback ? successCallback() : this.notificationsService.success(`The assistant instance '${this.chatInstanceId}' configuration has been successfully updated`);
|
|
406
|
+
}
|
|
361
407
|
});
|
|
362
408
|
}
|
|
363
409
|
/**
|
|
@@ -432,10 +478,11 @@ class WebSocketChatService extends ChatService {
|
|
|
432
478
|
super();
|
|
433
479
|
this.connectionBuilt$ = new Subject(); // Emit when the connection is built
|
|
434
480
|
this.connectionStarted$ = new Subject(); // Emit when the connection is started
|
|
435
|
-
this.
|
|
436
|
-
this.
|
|
437
|
-
this.
|
|
438
|
-
this.
|
|
481
|
+
this._messageHandlers = new Map();
|
|
482
|
+
this._actionMap = new Map();
|
|
483
|
+
this._progress = undefined;
|
|
484
|
+
this._content = "";
|
|
485
|
+
this._attachments = [];
|
|
439
486
|
this.signalRService = inject(SignalRWebService);
|
|
440
487
|
this.authenticationService = inject(AuthenticationService);
|
|
441
488
|
}
|
|
@@ -480,8 +527,8 @@ class WebSocketChatService extends ChatService {
|
|
|
480
527
|
* It can be overridden by the app config
|
|
481
528
|
*/
|
|
482
529
|
getRequestsUrl() {
|
|
483
|
-
if (this.chatConfig$.value.
|
|
484
|
-
this.REQUEST_URL = this.chatConfig$.value.
|
|
530
|
+
if (this.chatConfig$.value.connectionSettings.websocketEndpoint) {
|
|
531
|
+
this.REQUEST_URL = this.chatConfig$.value.connectionSettings.websocketEndpoint;
|
|
485
532
|
}
|
|
486
533
|
else {
|
|
487
534
|
throw new Error(`The property 'websocketEndpoint' must be provided when attempting to use 'WebSocket' in assistant instance`);
|
|
@@ -495,7 +542,7 @@ class WebSocketChatService extends ChatService {
|
|
|
495
542
|
modelsSubject.complete();
|
|
496
543
|
});
|
|
497
544
|
// Send the request to get the list of models
|
|
498
|
-
this.connection.invoke('ListModels', { debug: this.chatConfig$.value.debug })
|
|
545
|
+
this.connection.invoke('ListModels', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
499
546
|
.catch(error => {
|
|
500
547
|
console.error('Error invoking ListModels:', error);
|
|
501
548
|
modelsSubject.complete();
|
|
@@ -506,12 +553,12 @@ class WebSocketChatService extends ChatService {
|
|
|
506
553
|
listFunctions() {
|
|
507
554
|
const functionsSubject = new Subject();
|
|
508
555
|
this.connection.on('ListFunctions', (res) => {
|
|
509
|
-
this.functions = res.functions;
|
|
556
|
+
this.functions = res.functions?.filter(func => func.enabled);
|
|
510
557
|
functionsSubject.next(this.functions);
|
|
511
558
|
functionsSubject.complete();
|
|
512
559
|
});
|
|
513
560
|
// Send the request to get the list of functions
|
|
514
|
-
this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.debug })
|
|
561
|
+
this.connection.invoke('ListFunctions', { debug: this.chatConfig$.value.defaultValues.debug })
|
|
515
562
|
.catch(error => {
|
|
516
563
|
console.error('Error invoking ListFunctions:', error);
|
|
517
564
|
functionsSubject.complete();
|
|
@@ -519,31 +566,37 @@ class WebSocketChatService extends ChatService {
|
|
|
519
566
|
});
|
|
520
567
|
return functionsSubject.asObservable();
|
|
521
568
|
}
|
|
522
|
-
fetch(messages, query
|
|
569
|
+
fetch(messages, query) {
|
|
523
570
|
// Start streaming by invoking the Chat method
|
|
524
571
|
this.streaming$.next(true);
|
|
525
572
|
// Prepare the payload to send to the Chat method
|
|
526
573
|
const data = {
|
|
527
574
|
history: messages,
|
|
528
|
-
functions: this.chatConfig$.value.functions,
|
|
529
|
-
debug: this.chatConfig$.value.debug,
|
|
530
|
-
serviceSettings:
|
|
531
|
-
|
|
532
|
-
|
|
575
|
+
functions: this.chatConfig$.value.defaultValues.functions?.filter(func => func.enabled).map(func => func.name),
|
|
576
|
+
debug: this.chatConfig$.value.defaultValues.debug,
|
|
577
|
+
serviceSettings: {
|
|
578
|
+
service_id: this.chatConfig$.value.defaultValues.service_id,
|
|
579
|
+
model_id: this.chatConfig$.value.defaultValues.model_id,
|
|
580
|
+
top_p: this.chatConfig$.value.defaultValues.top_p,
|
|
581
|
+
temperature: this.chatConfig$.value.defaultValues.temperature,
|
|
582
|
+
max_tokens: this.chatConfig$.value.defaultValues.max_tokens,
|
|
583
|
+
...this.chatConfig$.value.additionalServiceSettings
|
|
584
|
+
},
|
|
585
|
+
appQuery: {
|
|
533
586
|
app: this.appService.appName,
|
|
534
587
|
query
|
|
535
588
|
}
|
|
536
589
|
};
|
|
537
|
-
if (this.chatConfig$.value.
|
|
590
|
+
if (this.chatConfig$.value.savedChatSettings.enabled) {
|
|
538
591
|
data.instanceId = this.chatInstanceId;
|
|
539
592
|
data.savedChatId = this.savedChatId;
|
|
540
593
|
}
|
|
541
594
|
let response = { role: "assistant", content: "", additionalProperties: { display: true } }; // here display: true is needed in order to be able to show the progress
|
|
542
595
|
// Create a Subject to signal completion
|
|
543
596
|
const completion$ = new Subject();
|
|
544
|
-
// Create observables for each non-global handler in the
|
|
597
|
+
// Create observables for each non-global handler in the _messageHandlers map (default and eventual custom ones) once it is triggered by the hub connection
|
|
545
598
|
const observables = Array
|
|
546
|
-
.from(this.
|
|
599
|
+
.from(this._messageHandlers.entries())
|
|
547
600
|
.filter(([eventName, eventHandler]) => !eventHandler.isGlobalHandler)
|
|
548
601
|
.map(([eventName, eventHandler]) => {
|
|
549
602
|
return fromEvent(this.connection, eventName).pipe(map((event) => eventHandler.handler(event)) // Execute the corresponding handler
|
|
@@ -554,25 +607,26 @@ class WebSocketChatService extends ChatService {
|
|
|
554
607
|
);
|
|
555
608
|
// Invoke the Chat method
|
|
556
609
|
this.connection.invoke('Chat', data)
|
|
557
|
-
.then(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.
|
|
610
|
+
.then(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.defaultValues.service_id)) // When the server indicates it has successfully finished invoking the method, notify the audit service with the recent chat history
|
|
558
611
|
.catch(error => {
|
|
559
612
|
console.error('Error invoking Chat:', error);
|
|
560
613
|
return Promise.resolve(); // Return a resolved promise to handle the error and prevent unhandled promise rejection
|
|
561
614
|
})
|
|
562
615
|
.finally(() => {
|
|
563
616
|
this.streaming$.next(false); // Complete streaming regardless of success or error
|
|
564
|
-
this.
|
|
565
|
-
this.
|
|
566
|
-
this.
|
|
567
|
-
this.
|
|
617
|
+
this._actionMap.clear(); // Clear the _actionMap
|
|
618
|
+
this._content = ""; // Clear the _content
|
|
619
|
+
this._progress = undefined; // Clear the _progress
|
|
620
|
+
this._attachments = []; // Clear the _attachments
|
|
621
|
+
this._executionTime = ""; // Clear the _executionTime
|
|
568
622
|
completion$.next(); // Emit a signal to complete the observables
|
|
569
623
|
completion$.complete(); // Complete the subject
|
|
570
624
|
});
|
|
571
625
|
// Return the merged observables
|
|
572
626
|
return combined$.pipe(map(() => {
|
|
573
|
-
// Define $progress from the
|
|
574
|
-
const actions = Array.from(this.
|
|
575
|
-
|
|
627
|
+
// Define $progress from the _actionMap
|
|
628
|
+
const actions = Array.from(this._actionMap.values());
|
|
629
|
+
this._progress = actions.length > 0
|
|
576
630
|
? actions.map((a) => ({
|
|
577
631
|
title: a.displayName ?? "",
|
|
578
632
|
content: a.displayValue ?? "",
|
|
@@ -580,20 +634,18 @@ class WebSocketChatService extends ChatService {
|
|
|
580
634
|
time: a.executionTime,
|
|
581
635
|
}))
|
|
582
636
|
: undefined;
|
|
583
|
-
//
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
if (!!this.content || $progress || $attachment.length > 0) {
|
|
587
|
-
response = { ...response, content: this.content, additionalProperties: { ...response.additionalProperties, $progress, $attachment } };
|
|
637
|
+
// As soon as the first _content or $progress is defined, the assistant is considered as streaming
|
|
638
|
+
if (!!this._content || this._progress || this._attachments.length > 0) {
|
|
639
|
+
response = { ...response, content: this._content, additionalProperties: { ...response.additionalProperties, $progress: this._progress, $attachment: this._attachments } };
|
|
588
640
|
}
|
|
589
641
|
// Return the result
|
|
590
|
-
return { history: [...messages, response], executionTime: this.
|
|
642
|
+
return { history: [...messages, response], executionTime: this._executionTime };
|
|
591
643
|
}));
|
|
592
644
|
}
|
|
593
645
|
listSavedChat() {
|
|
594
646
|
const data = {
|
|
595
647
|
instanceId: this.chatInstanceId,
|
|
596
|
-
debug: this.chatConfig$.value.debug
|
|
648
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
597
649
|
};
|
|
598
650
|
this.connection.on('SavedChatList', (res) => {
|
|
599
651
|
this.savedChats$.next(res.savedChats); // emits the result to the savedChats$ subject
|
|
@@ -610,7 +662,7 @@ class WebSocketChatService extends ChatService {
|
|
|
610
662
|
const data = {
|
|
611
663
|
instanceId: this.chatInstanceId,
|
|
612
664
|
savedChatId: id,
|
|
613
|
-
debug: this.chatConfig$.value.debug
|
|
665
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
614
666
|
};
|
|
615
667
|
this.connection.on('SavedChatGet', (res) => {
|
|
616
668
|
savedChatSubject.next(res.savedChat);
|
|
@@ -625,12 +677,58 @@ class WebSocketChatService extends ChatService {
|
|
|
625
677
|
});
|
|
626
678
|
return savedChatSubject.asObservable();
|
|
627
679
|
}
|
|
680
|
+
addSavedChat(messages) {
|
|
681
|
+
const addSavedChatSubject = new Subject();
|
|
682
|
+
const data = {
|
|
683
|
+
instanceId: this.chatInstanceId,
|
|
684
|
+
savedChatId: ChatService.generateGUID(),
|
|
685
|
+
history: messages,
|
|
686
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
687
|
+
};
|
|
688
|
+
this.connection.on('SavedChatAdd', (res) => {
|
|
689
|
+
this.setSavedChatId(res.savedChat.id); // Persist the savedChatId
|
|
690
|
+
addSavedChatSubject.next(res.savedChat);
|
|
691
|
+
addSavedChatSubject.complete();
|
|
692
|
+
});
|
|
693
|
+
// Invoke the method SavedChatAdd
|
|
694
|
+
this.connection.invoke('SavedChatAdd', data)
|
|
695
|
+
.catch(error => {
|
|
696
|
+
console.error('Error invoking SavedChatAdd:', error);
|
|
697
|
+
addSavedChatSubject.complete();
|
|
698
|
+
return Promise.resolve();
|
|
699
|
+
});
|
|
700
|
+
return addSavedChatSubject.asObservable();
|
|
701
|
+
}
|
|
702
|
+
updateSavedChat(id, name, messages) {
|
|
703
|
+
const updateSavedChatSubject = new Subject();
|
|
704
|
+
const data = {
|
|
705
|
+
instanceId: this.chatInstanceId,
|
|
706
|
+
savedChatId: id,
|
|
707
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
708
|
+
};
|
|
709
|
+
if (name)
|
|
710
|
+
data["title"] = name;
|
|
711
|
+
if (messages)
|
|
712
|
+
data["history"] = messages;
|
|
713
|
+
this.connection.on('SavedChatUpdate', (res) => {
|
|
714
|
+
updateSavedChatSubject.next(res.savedChat);
|
|
715
|
+
updateSavedChatSubject.complete();
|
|
716
|
+
});
|
|
717
|
+
// Invoke the method SavedChatUpdate
|
|
718
|
+
this.connection.invoke('SavedChatUpdate', data)
|
|
719
|
+
.catch(error => {
|
|
720
|
+
console.error('Error invoking SavedChatUpdate:', error);
|
|
721
|
+
updateSavedChatSubject.complete();
|
|
722
|
+
return Promise.resolve();
|
|
723
|
+
});
|
|
724
|
+
return updateSavedChatSubject.asObservable();
|
|
725
|
+
}
|
|
628
726
|
deleteSavedChat(ids) {
|
|
629
727
|
const deleteSavedChatSubject = new Subject();
|
|
630
728
|
const data = {
|
|
631
729
|
instanceId: this.chatInstanceId,
|
|
632
730
|
SavedChatIds: ids,
|
|
633
|
-
debug: this.chatConfig$.value.debug
|
|
731
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
634
732
|
};
|
|
635
733
|
this.connection.on('SavedChatDelete', (res) => {
|
|
636
734
|
deleteSavedChatSubject.next(res.deleteCount);
|
|
@@ -652,28 +750,36 @@ class WebSocketChatService extends ChatService {
|
|
|
652
750
|
initMessageHandlers() {
|
|
653
751
|
this.addMessageHandler("Debug", { handler: (debug) => console.log(debug),
|
|
654
752
|
isGlobalHandler: true });
|
|
655
|
-
this.addMessageHandler("ActionStart", { handler: (action) => this.
|
|
753
|
+
this.addMessageHandler("ActionStart", { handler: (action) => this._actionMap.set(action.guid, action),
|
|
656
754
|
isGlobalHandler: false });
|
|
657
755
|
this.addMessageHandler("ActionResult", {
|
|
658
|
-
handler: (action) => this.
|
|
756
|
+
handler: (action) => this._actionMap.set(action.guid, { ...this._actionMap.get(action.guid), ...action }),
|
|
659
757
|
isGlobalHandler: false
|
|
660
758
|
});
|
|
661
759
|
this.addMessageHandler("ActionStop", {
|
|
662
|
-
handler: (action) => this.
|
|
760
|
+
handler: (action) => this._actionMap.set(action.guid, { ...this._actionMap.get(action.guid), ...action }),
|
|
663
761
|
isGlobalHandler: false
|
|
664
762
|
});
|
|
665
763
|
this.addMessageHandler("ContextMessage", {
|
|
666
|
-
handler: (message) => this.
|
|
764
|
+
handler: (message) => this._attachments.push(message.metadata),
|
|
667
765
|
isGlobalHandler: false
|
|
668
766
|
});
|
|
669
767
|
this.addMessageHandler("Message", {
|
|
670
|
-
handler: (message) => this.
|
|
768
|
+
handler: (message) => this._content += message ?? "",
|
|
671
769
|
isGlobalHandler: false
|
|
672
770
|
});
|
|
673
771
|
this.addMessageHandler("History", {
|
|
674
772
|
handler: (history) => {
|
|
675
773
|
this.chatHistory = history.history;
|
|
676
|
-
|
|
774
|
+
// Re-attach the $progress and $attachment of the last response to the last assistant's response in the chat history
|
|
775
|
+
this.chatHistory.at(-1).additionalProperties.$progress = this._progress;
|
|
776
|
+
this.chatHistory.at(-1).additionalProperties.$attachment = this._attachments;
|
|
777
|
+
// Save/update the chat if savedChat enabled
|
|
778
|
+
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
779
|
+
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
780
|
+
action.pipe(take(1)).subscribe();
|
|
781
|
+
}
|
|
782
|
+
this._executionTime = history.executionTime;
|
|
677
783
|
},
|
|
678
784
|
isGlobalHandler: false
|
|
679
785
|
});
|
|
@@ -696,20 +802,20 @@ class WebSocketChatService extends ChatService {
|
|
|
696
802
|
});
|
|
697
803
|
}
|
|
698
804
|
/**
|
|
699
|
-
* Override and register the entire
|
|
700
|
-
* @param
|
|
805
|
+
* Override and register the entire _messageHandlers map by merging the provided map with the default one
|
|
806
|
+
* @param _messageHandlers
|
|
701
807
|
*/
|
|
702
|
-
overrideMessageHandlers(
|
|
808
|
+
overrideMessageHandlers(_messageHandlers) {
|
|
703
809
|
// Clear the already registered global chat handlers before merging the new ones
|
|
704
|
-
this.
|
|
810
|
+
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
705
811
|
if (eventHandler.isGlobalHandler) {
|
|
706
812
|
this.unsubscribeMessageHandler(eventName);
|
|
707
813
|
}
|
|
708
814
|
});
|
|
709
815
|
// Merge the new event handlers with the existing ones
|
|
710
|
-
this.
|
|
816
|
+
this._messageHandlers = new Map([...this._messageHandlers, ..._messageHandlers]);
|
|
711
817
|
// Register the global chat handlers among the merged map
|
|
712
|
-
this.
|
|
818
|
+
this._messageHandlers.forEach((eventHandler, eventName) => {
|
|
713
819
|
if (eventHandler.isGlobalHandler) {
|
|
714
820
|
this.registerMessageHandler(eventName, eventHandler);
|
|
715
821
|
}
|
|
@@ -723,7 +829,7 @@ class WebSocketChatService extends ChatService {
|
|
|
723
829
|
* @param eventHandler The handler to be called when the event is received
|
|
724
830
|
*/
|
|
725
831
|
addMessageHandler(eventName, eventHandler) {
|
|
726
|
-
this.
|
|
832
|
+
this._messageHandlers.set(eventName, eventHandler);
|
|
727
833
|
if (eventHandler.isGlobalHandler) {
|
|
728
834
|
this.registerMessageHandler(eventName, eventHandler);
|
|
729
835
|
}
|
|
@@ -744,17 +850,17 @@ class WebSocketChatService extends ChatService {
|
|
|
744
850
|
});
|
|
745
851
|
}
|
|
746
852
|
/**
|
|
747
|
-
* Remove a listener for a specific event from the
|
|
853
|
+
* Remove a listener for a specific event from the _messageHandlers map and unsubscribe from receiving messages for this event from the SignalR hub.
|
|
748
854
|
* @param eventName Name of the event to remove the listener for
|
|
749
855
|
*/
|
|
750
856
|
removeMessageHandler(eventName) {
|
|
751
|
-
this.
|
|
857
|
+
this._messageHandlers.delete(eventName);
|
|
752
858
|
this.unsubscribeMessageHandler(eventName);
|
|
753
859
|
}
|
|
754
860
|
/**
|
|
755
861
|
* Unsubscribe from receiving messages for a specific event from the SignalR hub.
|
|
756
862
|
* ALL its related listeners will be removed from hub connection
|
|
757
|
-
* This is needed to prevent accumulating old listeners when overriding the entire
|
|
863
|
+
* This is needed to prevent accumulating old listeners when overriding the entire _messageHandlers map
|
|
758
864
|
* @param eventName Name of the event
|
|
759
865
|
*/
|
|
760
866
|
unsubscribeMessageHandler(eventName) {
|
|
@@ -773,7 +879,7 @@ class WebSocketChatService extends ChatService {
|
|
|
773
879
|
return;
|
|
774
880
|
}
|
|
775
881
|
const logLevel = this.getLogLevel();
|
|
776
|
-
this.connection = this.signalRService.buildConnection(this.REQUEST_URL, { ...this.defaultOptions, ...options }, logLevel);
|
|
882
|
+
this.connection = this.signalRService.buildConnection(this.REQUEST_URL, { ...this.defaultOptions, ...options }, logLevel, true);
|
|
777
883
|
resolve();
|
|
778
884
|
});
|
|
779
885
|
}
|
|
@@ -792,7 +898,7 @@ class WebSocketChatService extends ChatService {
|
|
|
792
898
|
return this.signalRService.stopConnection(this.connection);
|
|
793
899
|
}
|
|
794
900
|
getTransports() {
|
|
795
|
-
switch (this.chatConfig$.value?.
|
|
901
|
+
switch (this.chatConfig$.value?.connectionSettings.signalRTransport) {
|
|
796
902
|
case "WebSockets":
|
|
797
903
|
return HttpTransportType.WebSockets;
|
|
798
904
|
case "ServerSentEvents":
|
|
@@ -804,7 +910,7 @@ class WebSocketChatService extends ChatService {
|
|
|
804
910
|
}
|
|
805
911
|
}
|
|
806
912
|
getLogLevel() {
|
|
807
|
-
switch (this.chatConfig$.value?.
|
|
913
|
+
switch (this.chatConfig$.value?.connectionSettings.signalRLogLevel) {
|
|
808
914
|
case "Critical":
|
|
809
915
|
return LogLevel.Critical; // Log level for diagnostic messages that indicate a failure that will terminate the entire application.
|
|
810
916
|
case "Debug":
|
|
@@ -1078,10 +1184,10 @@ class ChatReferenceComponent {
|
|
|
1078
1184
|
}
|
|
1079
1185
|
}
|
|
1080
1186
|
ChatReferenceComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1081
|
-
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}: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
|
|
1187
|
+
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"] }] });
|
|
1082
1188
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatReferenceComponent, decorators: [{
|
|
1083
1189
|
type: Component,
|
|
1084
|
-
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}: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
|
|
1190
|
+
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"] }]
|
|
1085
1191
|
}], propDecorators: { reference: [{
|
|
1086
1192
|
type: Input
|
|
1087
1193
|
}], attachment: [{
|
|
@@ -1211,6 +1317,26 @@ class ChatMessageComponent {
|
|
|
1211
1317
|
}
|
|
1212
1318
|
this.referenceClicked.emit(record);
|
|
1213
1319
|
}
|
|
1320
|
+
getLinkText(node) {
|
|
1321
|
+
if (node.text) {
|
|
1322
|
+
return node.text; // Return directly if text is provided in node.text ([Example link](https://example.com))
|
|
1323
|
+
}
|
|
1324
|
+
else if (node.children && node.children.length > 0) {
|
|
1325
|
+
// Recursively search for text content in child nodes
|
|
1326
|
+
for (const child of node.children) {
|
|
1327
|
+
if (child.type === 'text' && child.value) {
|
|
1328
|
+
return child.value; // Return the value of the first text node found ([**Emphasized Link Text**](https://example.com))
|
|
1329
|
+
}
|
|
1330
|
+
else if (child.children && child.children.length > 0) {
|
|
1331
|
+
const textContent = this.getLinkText(child); // Recursively search child nodes ([](https://example.com))
|
|
1332
|
+
if (textContent) {
|
|
1333
|
+
return textContent; // Return text content if found
|
|
1334
|
+
}
|
|
1335
|
+
}
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return 'link'; // Return empty string if no text content is found
|
|
1339
|
+
}
|
|
1214
1340
|
/**
|
|
1215
1341
|
* Reformat [ids: 12.2, 42.5] to [12.2][42.5]
|
|
1216
1342
|
*/
|
|
@@ -1228,11 +1354,11 @@ class ChatMessageComponent {
|
|
|
1228
1354
|
}
|
|
1229
1355
|
}
|
|
1230
1356
|
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 });
|
|
1231
|
-
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\" [title]=\"step.time ?? ''\">\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 </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}: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 #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:#f8f8f8;border:1px solid #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-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))}.sq-chat-message-action{position:absolute;right:calc(0rem - var(--ast-size-2, .5rem));top:var(--ast-size-2, .5rem);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 });
|
|
1357
|
+
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 });
|
|
1232
1358
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatMessageComponent, decorators: [{
|
|
1233
1359
|
type: Component,
|
|
1234
1360
|
args: [{ selector: "sq-chat-message", changeDetection: ChangeDetectionStrategy.OnPush, standalone: true, imports: [CommonModule, UtilsModule, CollapseModule, RemarkModule,
|
|
1235
|
-
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\"
|
|
1361
|
+
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"] }]
|
|
1236
1362
|
}], ctorParameters: function () { return [{ type: i1$1.SearchService }, { type: i2$1.UIService }, { type: i3.PrincipalWebService }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }]; }, propDecorators: { message: [{
|
|
1237
1363
|
type: Input
|
|
1238
1364
|
}], conversation: [{
|
|
@@ -1275,7 +1401,10 @@ class RestChatService extends ChatService {
|
|
|
1275
1401
|
this.listFunctions()
|
|
1276
1402
|
])),
|
|
1277
1403
|
// Map the results of parallel requests to a boolean indicating success
|
|
1278
|
-
map(([models, functions]) =>
|
|
1404
|
+
map(([models, functions]) => {
|
|
1405
|
+
this.initProcess$.next(true);
|
|
1406
|
+
return !!models && !!functions;
|
|
1407
|
+
}),
|
|
1279
1408
|
// Any errors during the process are caught, logged, and re-thrown to propagate the error further
|
|
1280
1409
|
catchError((error) => {
|
|
1281
1410
|
console.error('Error occurred:', error);
|
|
@@ -1289,8 +1418,8 @@ class RestChatService extends ChatService {
|
|
|
1289
1418
|
* It can be overridden by the app config
|
|
1290
1419
|
*/
|
|
1291
1420
|
getRequestsUrl() {
|
|
1292
|
-
if (this.chatConfig$.value.
|
|
1293
|
-
this.REQUEST_URL = this.chatConfig$.value.
|
|
1421
|
+
if (this.chatConfig$.value.connectionSettings.restEndpoint) {
|
|
1422
|
+
this.REQUEST_URL = this.chatConfig$.value.connectionSettings.restEndpoint;
|
|
1294
1423
|
}
|
|
1295
1424
|
else {
|
|
1296
1425
|
throw new Error(`The property 'restEndpoint' must be provided when attempting to use 'REST' in assistant instance`);
|
|
@@ -1299,7 +1428,7 @@ class RestChatService extends ChatService {
|
|
|
1299
1428
|
listModels() {
|
|
1300
1429
|
const data = {
|
|
1301
1430
|
action: "listmodels",
|
|
1302
|
-
debug: this.chatConfig$.value.debug
|
|
1431
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1303
1432
|
};
|
|
1304
1433
|
return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.models), tap(models => this.models = models?.filter(model => !!model.enable)), catchError((error) => {
|
|
1305
1434
|
console.error('Error invoking listmodels:', error);
|
|
@@ -1309,30 +1438,36 @@ class RestChatService extends ChatService {
|
|
|
1309
1438
|
listFunctions() {
|
|
1310
1439
|
const data = {
|
|
1311
1440
|
action: "listfunctions",
|
|
1312
|
-
debug: this.chatConfig$.value.debug
|
|
1441
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1313
1442
|
};
|
|
1314
|
-
return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.functions), tap(functions => this.functions = functions), catchError((error) => {
|
|
1443
|
+
return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.functions), tap((functions) => this.functions = functions?.filter(func => func.enabled && !!this.chatConfig$.value.defaultValues.functions.find(fn => fn.name === func.functionName))), catchError((error) => {
|
|
1315
1444
|
console.error('Error invoking listfunctions:', error);
|
|
1316
1445
|
return throwError(() => error);
|
|
1317
1446
|
}));
|
|
1318
1447
|
}
|
|
1319
|
-
fetch(messages, query
|
|
1448
|
+
fetch(messages, query) {
|
|
1320
1449
|
// Start streaming by invoking the Chat method
|
|
1321
1450
|
this.streaming$.next(true);
|
|
1322
1451
|
// Prepare the payload to send to the Chat method
|
|
1323
1452
|
const data = {
|
|
1324
1453
|
action: "chat",
|
|
1325
1454
|
history: messages,
|
|
1326
|
-
functions: this.chatConfig$.value.functions,
|
|
1327
|
-
debug: this.chatConfig$.value.debug,
|
|
1328
|
-
serviceSettings:
|
|
1329
|
-
|
|
1330
|
-
|
|
1455
|
+
functions: this.chatConfig$.value.defaultValues.functions?.filter(func => func.enabled).map(func => func.name),
|
|
1456
|
+
debug: this.chatConfig$.value.defaultValues.debug,
|
|
1457
|
+
serviceSettings: {
|
|
1458
|
+
service_id: this.chatConfig$.value.defaultValues.service_id,
|
|
1459
|
+
model_id: this.chatConfig$.value.defaultValues.model_id,
|
|
1460
|
+
top_p: this.chatConfig$.value.defaultValues.top_p,
|
|
1461
|
+
temperature: this.chatConfig$.value.defaultValues.temperature,
|
|
1462
|
+
max_tokens: this.chatConfig$.value.defaultValues.max_tokens,
|
|
1463
|
+
...this.chatConfig$.value.additionalServiceSettings
|
|
1464
|
+
},
|
|
1465
|
+
appQuery: {
|
|
1331
1466
|
app: this.appService.appName,
|
|
1332
1467
|
query
|
|
1333
1468
|
}
|
|
1334
1469
|
};
|
|
1335
|
-
if (this.chatConfig$.value.
|
|
1470
|
+
if (this.chatConfig$.value.savedChatSettings.enabled) {
|
|
1336
1471
|
data.instanceId = this.chatInstanceId;
|
|
1337
1472
|
data.savedChatId = this.savedChatId;
|
|
1338
1473
|
}
|
|
@@ -1366,33 +1501,71 @@ class RestChatService extends ChatService {
|
|
|
1366
1501
|
if (res.context) {
|
|
1367
1502
|
response.additionalProperties.$attachment = res.context.map((ctx) => ctx.additionalProperties);
|
|
1368
1503
|
}
|
|
1369
|
-
// Update the chat history with the history property of the res
|
|
1504
|
+
// Update the chat history with the incoming history property of the res AND the processed response message
|
|
1370
1505
|
this.chatHistory = res.history;
|
|
1506
|
+
this.chatHistory[this.chatHistory.length - 1] = response;
|
|
1507
|
+
// Save/update the chat if savedChat enabled
|
|
1508
|
+
if (this.chatConfig$.value.savedChatSettings.enabled && this.chatHistory.some((msg) => msg.additionalProperties?.isUserInput === true)) {
|
|
1509
|
+
const action = !this.savedChatId ? this.addSavedChat(this.chatHistory) : this.updateSavedChat(this.savedChatId, undefined, this.chatHistory);
|
|
1510
|
+
action.pipe(take(1)).subscribe();
|
|
1511
|
+
}
|
|
1371
1512
|
// Return the result
|
|
1372
1513
|
return { history: [...messages, response], executionTime: res.executionTime };
|
|
1373
|
-
}), tap(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.
|
|
1514
|
+
}), tap(() => this.notifyAudit(this.chatHistory, this.chatConfig$.value.defaultValues.service_id)), finalize(() => this.streaming$.next(false)));
|
|
1374
1515
|
}
|
|
1375
1516
|
listSavedChat() {
|
|
1376
1517
|
const data = {
|
|
1377
1518
|
action: "SavedChatList",
|
|
1378
1519
|
instanceId: this.chatInstanceId,
|
|
1379
|
-
debug: this.chatConfig$.value.debug
|
|
1520
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1380
1521
|
};
|
|
1381
1522
|
this.jsonMethodWebService.get(this.REQUEST_URL, data).subscribe(res => this.savedChats$.next(res.savedChats), error => {
|
|
1382
|
-
console.error('Error occurred while calling the SavedChatList API:', error);
|
|
1383
|
-
this.notificationsService.error('Error occurred while calling the SavedChatList API');
|
|
1523
|
+
console.error('Error occurred while calling the SavedChatList API:', error.error.errorMessage);
|
|
1524
|
+
this.notificationsService.error('Error occurred while calling the SavedChatList API:', error.error.errorMessage);
|
|
1384
1525
|
});
|
|
1385
1526
|
}
|
|
1527
|
+
addSavedChat(messages) {
|
|
1528
|
+
const data = {
|
|
1529
|
+
action: "SavedChatAdd",
|
|
1530
|
+
instanceId: this.chatInstanceId,
|
|
1531
|
+
savedChatId: ChatService.generateGUID(),
|
|
1532
|
+
history: messages,
|
|
1533
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1534
|
+
};
|
|
1535
|
+
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.savedChat), tap((savedChat) => this.setSavedChatId(savedChat.id)), // Persist the savedChatId
|
|
1536
|
+
catchError((error) => {
|
|
1537
|
+
console.error('Error occurred while calling the SavedChatAdd API:', error.error.errorMessage);
|
|
1538
|
+
this.notificationsService.error('Error occurred while calling the SavedChatAdd API:', error.error.errorMessage);
|
|
1539
|
+
return throwError(() => error);
|
|
1540
|
+
}));
|
|
1541
|
+
}
|
|
1386
1542
|
getSavedChat(id) {
|
|
1387
1543
|
const data = {
|
|
1388
1544
|
action: "SavedChatGet",
|
|
1389
1545
|
instanceId: this.chatInstanceId,
|
|
1390
1546
|
savedChatId: id,
|
|
1391
|
-
debug: this.chatConfig$.value.debug
|
|
1547
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1392
1548
|
};
|
|
1393
1549
|
return this.jsonMethodWebService.get(this.REQUEST_URL, data).pipe(map(res => res.savedChat), catchError((error) => {
|
|
1394
|
-
console.error('Error occurred while calling the SavedChatGet API:', error);
|
|
1395
|
-
this.notificationsService.error('Error occurred while calling the SavedChatGet API');
|
|
1550
|
+
console.error('Error occurred while calling the SavedChatGet API:', error.error.errorMessage);
|
|
1551
|
+
this.notificationsService.error('Error occurred while calling the SavedChatGet API:', error.error.errorMessage);
|
|
1552
|
+
return throwError(() => error);
|
|
1553
|
+
}));
|
|
1554
|
+
}
|
|
1555
|
+
updateSavedChat(id, name, messages) {
|
|
1556
|
+
const data = {
|
|
1557
|
+
action: "SavedChatUpdate",
|
|
1558
|
+
instanceId: this.chatInstanceId,
|
|
1559
|
+
savedChatId: id,
|
|
1560
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1561
|
+
};
|
|
1562
|
+
if (name)
|
|
1563
|
+
data["title"] = name;
|
|
1564
|
+
if (messages)
|
|
1565
|
+
data["history"] = messages;
|
|
1566
|
+
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.savedChat), catchError((error) => {
|
|
1567
|
+
console.error('Error occurred while calling the SavedChatUpdate API:', error.error.errorMessage);
|
|
1568
|
+
this.notificationsService.error('Error occurred while calling the SavedChatUpdate API:', error.error.errorMessage);
|
|
1396
1569
|
return throwError(() => error);
|
|
1397
1570
|
}));
|
|
1398
1571
|
}
|
|
@@ -1401,11 +1574,11 @@ class RestChatService extends ChatService {
|
|
|
1401
1574
|
action: "SavedChatDelete",
|
|
1402
1575
|
instanceId: this.chatInstanceId,
|
|
1403
1576
|
savedChatIds: ids,
|
|
1404
|
-
debug: this.chatConfig$.value.debug
|
|
1577
|
+
debug: this.chatConfig$.value.defaultValues.debug
|
|
1405
1578
|
};
|
|
1406
1579
|
return this.jsonMethodWebService.post(this.REQUEST_URL, data).pipe(map(res => res.deletedCount), catchError((error) => {
|
|
1407
|
-
console.error('Error occurred while calling the SavedChatDelete API:', error);
|
|
1408
|
-
this.notificationsService.error('Error occurred while calling the SavedChatDelete API
|
|
1580
|
+
console.error('Error occurred while calling the SavedChatDelete API:', error.error.errorMessage);
|
|
1581
|
+
this.notificationsService.error('Error occurred while calling the SavedChatDelete API:', error.error.errorMessage);
|
|
1409
1582
|
return throwError(() => error);
|
|
1410
1583
|
}));
|
|
1411
1584
|
}
|
|
@@ -1419,14 +1592,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1419
1592
|
class ChatComponent extends AbstractFacet {
|
|
1420
1593
|
constructor() {
|
|
1421
1594
|
super();
|
|
1595
|
+
this.loginService = inject(LoginService);
|
|
1596
|
+
this.websocketService = inject(WebSocketChatService);
|
|
1597
|
+
this.restService = inject(RestChatService);
|
|
1598
|
+
this.instanceManagerService = inject(InstanceManagerService);
|
|
1599
|
+
this.searchService = inject(SearchService);
|
|
1600
|
+
this.principalService = inject(PrincipalWebService);
|
|
1601
|
+
this.cdr = inject(ChangeDetectorRef);
|
|
1602
|
+
/** Define the query to use to fetch answers */
|
|
1603
|
+
this.query = this.searchService.query;
|
|
1422
1604
|
/** Define the protocol to be used for this chat instance*/
|
|
1423
1605
|
this.protocol = "WEBSOCKET";
|
|
1424
1606
|
/** Map of listeners overriding default registered ones*/
|
|
1425
1607
|
this.messageHandlers = new Map();
|
|
1426
1608
|
/** When the assistant answer a user question, automatically scroll down to the bottom of the discussion */
|
|
1427
1609
|
this.automaticScrollToLastResponse = false;
|
|
1428
|
-
this.enableChat = true;
|
|
1429
|
-
this.showCredits = true;
|
|
1430
1610
|
this.customAssistantIcon = '';
|
|
1431
1611
|
this.data = new EventEmitter();
|
|
1432
1612
|
this.referenceClicked = new EventEmitter();
|
|
@@ -1439,16 +1619,10 @@ class ChatComponent extends AbstractFacet {
|
|
|
1439
1619
|
this._actions = [];
|
|
1440
1620
|
this.sub = new Subscription();
|
|
1441
1621
|
this.changes$ = new BehaviorSubject(undefined);
|
|
1442
|
-
this.
|
|
1622
|
+
this.firstChangesHandled = false;
|
|
1443
1623
|
this.isAtBottom = true;
|
|
1444
1624
|
this.initializationError = false;
|
|
1445
|
-
this.
|
|
1446
|
-
this.websocketService = inject(WebSocketChatService);
|
|
1447
|
-
this.restService = inject(RestChatService);
|
|
1448
|
-
this.instanceManagerService = inject(InstanceManagerService);
|
|
1449
|
-
this.searchService = inject(SearchService);
|
|
1450
|
-
this.principalService = inject(PrincipalWebService);
|
|
1451
|
-
this.cdr = inject(ChangeDetectorRef);
|
|
1625
|
+
this.enabledUserInput = false;
|
|
1452
1626
|
this._actions.push(new Action({
|
|
1453
1627
|
icon: 'fas fa-sync',
|
|
1454
1628
|
title: 'Reset chat',
|
|
@@ -1458,13 +1632,14 @@ class ChatComponent extends AbstractFacet {
|
|
|
1458
1632
|
ngOnInit() {
|
|
1459
1633
|
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 => {
|
|
1460
1634
|
this.config = config;
|
|
1635
|
+
this.enabledUserInput = this.config.modeSettings.enabledUserInput;
|
|
1461
1636
|
this._config.emit(config);
|
|
1462
1637
|
try {
|
|
1463
1638
|
this.updateModelDescription();
|
|
1464
|
-
if (!this.
|
|
1639
|
+
if (!this.firstChangesHandled) {
|
|
1465
1640
|
this.handleChanges();
|
|
1466
1641
|
this.addScrollListener();
|
|
1467
|
-
this.
|
|
1642
|
+
this.firstChangesHandled = true;
|
|
1468
1643
|
}
|
|
1469
1644
|
}
|
|
1470
1645
|
catch (error) {
|
|
@@ -1500,12 +1675,50 @@ class ChatComponent extends AbstractFacet {
|
|
|
1500
1675
|
get actions() { return this._actions; }
|
|
1501
1676
|
handleChanges() {
|
|
1502
1677
|
const changes = this.changes$.value;
|
|
1678
|
+
// If the chat service is a WebSocketChatService, handle the override of the message handlers if exists
|
|
1503
1679
|
if (changes?.messageHandlers && this.messageHandlers && this.chatService instanceof WebSocketChatService) {
|
|
1504
1680
|
this.chatService.overrideMessageHandlers(this.messageHandlers);
|
|
1505
1681
|
}
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1682
|
+
/**
|
|
1683
|
+
* Initialize the chat with the provided chat messages if exists, otherwise load the default chat
|
|
1684
|
+
* Once the chat is initialized (firstChangesHandled is true), allow opening the chat with the new provided messages (if exists)
|
|
1685
|
+
*/
|
|
1686
|
+
if (!this.firstChangesHandled || changes?.chat) {
|
|
1687
|
+
const openChat = () => {
|
|
1688
|
+
if (this.messages$.value && this.config.savedChatSettings.enabled) {
|
|
1689
|
+
this.chatService.listSavedChat(); // Refresh the list of saved chats
|
|
1690
|
+
}
|
|
1691
|
+
this.openChat(this.chat.messages);
|
|
1692
|
+
};
|
|
1693
|
+
this.chat ? openChat() : this.loadDefaultChat();
|
|
1694
|
+
}
|
|
1695
|
+
/**
|
|
1696
|
+
* If the chat is initialized, the initialization event is "Query", the query changes and the queryChangeShouldTriggerReload function is provided,
|
|
1697
|
+
* then the chat should be reloaded if the function returns true
|
|
1698
|
+
* Otherwise, the chat should be reloaded by default
|
|
1699
|
+
*/
|
|
1700
|
+
if (this.firstChangesHandled && changes?.query && this.config.modeSettings.initialization.event === 'Query') {
|
|
1701
|
+
const previousQuery = changes.query.previousValue;
|
|
1702
|
+
const currentQuery = changes.query.currentValue;
|
|
1703
|
+
if (this.queryChangeShouldTriggerReload ? this.queryChangeShouldTriggerReload(previousQuery, currentQuery) : true) {
|
|
1704
|
+
this.triggerReloadAfterQueryChange(currentQuery);
|
|
1705
|
+
}
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
triggerReloadAfterQueryChange(query) {
|
|
1709
|
+
const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
|
|
1710
|
+
const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
|
|
1711
|
+
/**
|
|
1712
|
+
* If the provided query text is not empty, then add the user query message to the chat history and invoke the assistant
|
|
1713
|
+
* Otherwise, just start a new chat with a warning message inviting the user to perform a full text search to retrieve some results
|
|
1714
|
+
*/
|
|
1715
|
+
if (!!this.query.text) {
|
|
1716
|
+
const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
|
|
1717
|
+
this.openChat(this.config.modeSettings.sendUserPrompt ? [systemMsg, userMsg, userQueryMsg] : [systemMsg, userQueryMsg]);
|
|
1718
|
+
}
|
|
1719
|
+
else {
|
|
1720
|
+
const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
|
|
1721
|
+
this.openChat([warningMsg]);
|
|
1509
1722
|
}
|
|
1510
1723
|
}
|
|
1511
1724
|
addScrollListener() {
|
|
@@ -1515,7 +1728,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1515
1728
|
}));
|
|
1516
1729
|
}
|
|
1517
1730
|
updateModelDescription() {
|
|
1518
|
-
this.modelDescription = this.chatService.getModel(this.config.
|
|
1731
|
+
this.modelDescription = this.chatService.getModel(this.config.defaultValues.service_id, this.config.defaultValues.model_id);
|
|
1519
1732
|
this.assistantIcon = !!this.customAssistantIcon ? this.customAssistantIcon : 'sq-sinequa';
|
|
1520
1733
|
switch (this.modelDescription?.provider) {
|
|
1521
1734
|
case 'Google':
|
|
@@ -1542,17 +1755,15 @@ class ChatComponent extends AbstractFacet {
|
|
|
1542
1755
|
this.chatService.chatHistory = this.chatService.chatHistory.slice(0, this.messageToEdit);
|
|
1543
1756
|
this.messageToEdit = undefined;
|
|
1544
1757
|
}
|
|
1545
|
-
// Re-attach the $progress and $attachment of the last response to the last assistant's response in the chat history
|
|
1546
|
-
this.chatService.chatHistory.at(-1).additionalProperties.$progress = this.messages$.value.at(-1).additionalProperties.$progress;
|
|
1547
|
-
this.chatService.chatHistory.at(-1).additionalProperties.$attachment = this.messages$.value.at(-1).additionalProperties.$attachment;
|
|
1548
1758
|
// Fetch the answer
|
|
1549
1759
|
this.fetchAnswer(this.question.trim(), this.chatService.chatHistory);
|
|
1550
1760
|
// Clear the input value in the UI
|
|
1551
1761
|
this.questionInput.nativeElement.value = '';
|
|
1762
|
+
this.questionInput.nativeElement.style.height = `auto`;
|
|
1552
1763
|
}
|
|
1553
1764
|
}
|
|
1554
1765
|
fetchAnswer(question, conversation) {
|
|
1555
|
-
const userMsg = { role: 'user', content: question, additionalProperties: { display: true } };
|
|
1766
|
+
const userMsg = { role: 'user', content: question, additionalProperties: { display: true, isUserInput: true } };
|
|
1556
1767
|
const messages = [...conversation, userMsg];
|
|
1557
1768
|
this.messages$.next(messages);
|
|
1558
1769
|
this.fetch(messages);
|
|
@@ -1609,22 +1820,56 @@ class ChatComponent extends AbstractFacet {
|
|
|
1609
1820
|
}
|
|
1610
1821
|
}, 10);
|
|
1611
1822
|
}
|
|
1823
|
+
/**
|
|
1824
|
+
* Start a new chat with the defaultValues settings
|
|
1825
|
+
* The savedChatId in the chat service will be reset, so that the upcoming saved chat operations will be performed on the fresh new chat
|
|
1826
|
+
* If the savedChat feature is enabled, the list of saved chats will be refreshed
|
|
1827
|
+
*/
|
|
1612
1828
|
newChat() {
|
|
1613
|
-
this.chatService.
|
|
1829
|
+
this.chatService.setSavedChatId(undefined); // Reset the savedChatId
|
|
1830
|
+
if (this.config.savedChatSettings.enabled) {
|
|
1831
|
+
this.chatService.listSavedChat(); // Refresh the list of saved chats
|
|
1832
|
+
}
|
|
1614
1833
|
this.loadDefaultChat(); // Start a new chat
|
|
1615
1834
|
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Start the default chat with the defaultValues settings
|
|
1837
|
+
* If the chat is meant to be initialized with event === "Query", the corresponding user query message will be added to the chat history
|
|
1838
|
+
*/
|
|
1616
1839
|
loadDefaultChat() {
|
|
1617
|
-
this.
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1840
|
+
const systemMsg = { role: 'system', content: this.config.defaultValues.systemPrompt, additionalProperties: { display: false } };
|
|
1841
|
+
const userMsg = { role: 'user', content: ChatService.formatPrompt(this.config.defaultValues.userPrompt, { principal: this.principalService.principal }), additionalProperties: { display: this.config.modeSettings.displayUserPrompt } };
|
|
1842
|
+
if (this.config.modeSettings.initialization.event === 'Query') {
|
|
1843
|
+
// If the provided query text is not empty, then add the user query message to the chat history and invoke the assistant
|
|
1844
|
+
// Otherwise, just start a new chat with a warning message inviting the user to perform a full text search to retrieve some results
|
|
1845
|
+
if (!!this.query.text) {
|
|
1846
|
+
const userQueryMsg = { role: 'user', content: this.query.text, additionalProperties: { display: this.config.modeSettings.initialization.displayUserQuery, query: this.query, forcedWorkflow: this.config.modeSettings.initialization.forcedWorkflow, isUserInput: true } };
|
|
1847
|
+
this.openChat(this.config.modeSettings.sendUserPrompt ? [systemMsg, userMsg, userQueryMsg] : [systemMsg, userQueryMsg]);
|
|
1848
|
+
}
|
|
1849
|
+
else {
|
|
1850
|
+
const warningMsg = { role: 'assistant', content: "You must perform a full text search to retrieve some results", additionalProperties: { display: true } };
|
|
1851
|
+
this.openChat([warningMsg]);
|
|
1852
|
+
}
|
|
1853
|
+
}
|
|
1854
|
+
else {
|
|
1855
|
+
this.openChat([systemMsg, userMsg]);
|
|
1856
|
+
}
|
|
1621
1857
|
}
|
|
1858
|
+
/**
|
|
1859
|
+
* Start/open a new chat with the provided messages and chatId
|
|
1860
|
+
* If the last message is from the user, a request to the assistant is made to get an answer
|
|
1861
|
+
* If the last message is from the assistant, the conversation is loaded right away
|
|
1862
|
+
* @param messages The list of messages of the chat
|
|
1863
|
+
* @param chatId The id of the chat. If provided (ie. an existing discussion in the saved chat index), update the savedChatId in the chat service for the upcoming saved chat operations
|
|
1864
|
+
*/
|
|
1622
1865
|
openChat(messages, chatId) {
|
|
1623
1866
|
if (!messages || !Array.isArray(messages)) {
|
|
1624
1867
|
console.error('Error occurs while trying to load the chat discussion. Invalid messages received :', messages);
|
|
1625
1868
|
return;
|
|
1626
1869
|
}
|
|
1627
|
-
|
|
1870
|
+
if (chatId) {
|
|
1871
|
+
this.chatService.setSavedChatId(chatId);
|
|
1872
|
+
}
|
|
1628
1873
|
this.resetChat();
|
|
1629
1874
|
this.messages$.next(messages);
|
|
1630
1875
|
this.chatService.chatHistory = messages;
|
|
@@ -1637,6 +1882,11 @@ class ChatComponent extends AbstractFacet {
|
|
|
1637
1882
|
this.terminateFetch();
|
|
1638
1883
|
}
|
|
1639
1884
|
}
|
|
1885
|
+
/**
|
|
1886
|
+
* Reset the chat by clearing the messages and the chat history
|
|
1887
|
+
* The question input will be focused after the chat is reset
|
|
1888
|
+
* The fetch subscription will be terminated
|
|
1889
|
+
*/
|
|
1640
1890
|
resetChat() {
|
|
1641
1891
|
if (this.messages$.value) {
|
|
1642
1892
|
this.messages$.next(undefined); // Reset chat
|
|
@@ -1648,8 +1898,7 @@ class ChatComponent extends AbstractFacet {
|
|
|
1648
1898
|
onLoadChat() {
|
|
1649
1899
|
this.loading$.next(true);
|
|
1650
1900
|
this.sub.add(this.chatService.loadSavedChat$
|
|
1651
|
-
.pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.
|
|
1652
|
-
).subscribe());
|
|
1901
|
+
.pipe(filter(savedChat => !!savedChat), switchMap(savedChat => this.chatService.getSavedChat(savedChat.id)), filter(savedChatHistory => !!savedChatHistory), tap(savedChatHistory => this.openChat(savedChatHistory.history, savedChatHistory.id))).subscribe());
|
|
1653
1902
|
}
|
|
1654
1903
|
terminateFetch() {
|
|
1655
1904
|
this.dataSubscription?.unsubscribe();
|
|
@@ -1675,60 +1924,44 @@ class ChatComponent extends AbstractFacet {
|
|
|
1675
1924
|
}
|
|
1676
1925
|
onKeyUp(event) {
|
|
1677
1926
|
switch (event.key) {
|
|
1678
|
-
case '
|
|
1679
|
-
this.
|
|
1680
|
-
break;
|
|
1681
|
-
case 'ArrowDown':
|
|
1682
|
-
this.navigateMessage(1);
|
|
1927
|
+
case 'Backspace':
|
|
1928
|
+
this.calculateHeight();
|
|
1683
1929
|
break;
|
|
1684
1930
|
case 'Enter':
|
|
1685
|
-
|
|
1931
|
+
if (!event.shiftKey)
|
|
1932
|
+
this.submitQuestion();
|
|
1933
|
+
this.calculateHeight();
|
|
1686
1934
|
break;
|
|
1687
1935
|
default:
|
|
1688
1936
|
break;
|
|
1689
1937
|
}
|
|
1690
|
-
// Handle Shift + Enter
|
|
1691
|
-
if (event.shiftKey && event.key === 'Enter') {
|
|
1692
|
-
this.submitQuestion();
|
|
1693
|
-
}
|
|
1694
1938
|
}
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
}
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
}
|
|
1703
|
-
this.currentMessageIndex = (this.currentMessageIndex ?? userMessages.length) + direction;
|
|
1704
|
-
if (this.currentMessageIndex < 0) {
|
|
1705
|
-
// If the user presses up arrow on the first message, stay at the first message
|
|
1706
|
-
this.currentMessageIndex = 0;
|
|
1707
|
-
}
|
|
1708
|
-
else if (this.currentMessageIndex >= userMessages.length) {
|
|
1709
|
-
// If the user presses down arrow on the last previous message, clear the input
|
|
1710
|
-
this.currentMessageIndex = undefined;
|
|
1711
|
-
this.question = '';
|
|
1712
|
-
return;
|
|
1713
|
-
}
|
|
1714
|
-
this.question = userMessages[this.currentMessageIndex].content;
|
|
1939
|
+
calculateHeight() {
|
|
1940
|
+
const maxHeight = 170;
|
|
1941
|
+
const el = this.questionInput.nativeElement;
|
|
1942
|
+
el.style.maxHeight = `${maxHeight}px`;
|
|
1943
|
+
el.style.height = 'auto';
|
|
1944
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
1945
|
+
el.style.overflowY = el.scrollHeight >= maxHeight ? 'scroll' : 'hidden';
|
|
1715
1946
|
}
|
|
1716
1947
|
}
|
|
1717
1948
|
ChatComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1718
|
-
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", protocol: "protocol", messageHandlers: "messageHandlers", automaticScrollToLastResponse: "automaticScrollToLastResponse", chat: "chat",
|
|
1949
|
+
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", customAssistantIcon: "customAssistantIcon" }, outputs: { data: "data", referenceClicked: "referenceClicked", openPreview: "openPreview", loading$: "loading", error: "error", _config: "config" }, providers: [
|
|
1719
1950
|
RestChatService,
|
|
1720
1951
|
WebSocketChatService
|
|
1721
|
-
], 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 pb-
|
|
1952
|
+
], 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 !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\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)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.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)}\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", "assistantIcon", "streaming", "canEdit", "canRegenerate", "canCopy"], outputs: ["referenceClicked", "edit", "regenerate", "openPreview"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1722
1953
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatComponent, decorators: [{
|
|
1723
1954
|
type: Component,
|
|
1724
1955
|
args: [{ selector: 'sq-chat-v3', providers: [
|
|
1725
1956
|
RestChatService,
|
|
1726
1957
|
WebSocketChatService
|
|
1727
|
-
], 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 pb-
|
|
1958
|
+
], 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 !== 'assistant'\"\n [message]=\"message\"\n [conversation]=\"messages\"\n [assistantIcon]=\"customAssistantIcon || assistantIcon\"\n [streaming]=\"last && (chatService.streaming$ | async)\"\n [canEdit]=\"(loading$ | async) === false && (chatService.streaming$ | async) === false && messageToEdit === undefined && message.role !== 'assistant'\"\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)\" (regenerate)=\"regenerateMessage(index)\"\n (referenceClicked)=\"referenceClicked.emit($event)\"\n (openPreview)=\"openPreview.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)}\n"] }]
|
|
1728
1959
|
}], ctorParameters: function () { return []; }, propDecorators: { instanceId: [{
|
|
1729
1960
|
type: Input
|
|
1730
1961
|
}], query: [{
|
|
1731
1962
|
type: Input
|
|
1963
|
+
}], queryChangeShouldTriggerReload: [{
|
|
1964
|
+
type: Input
|
|
1732
1965
|
}], protocol: [{
|
|
1733
1966
|
type: Input
|
|
1734
1967
|
}], messageHandlers: [{
|
|
@@ -1737,10 +1970,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImpor
|
|
|
1737
1970
|
type: Input
|
|
1738
1971
|
}], chat: [{
|
|
1739
1972
|
type: Input
|
|
1740
|
-
}], enableChat: [{
|
|
1741
|
-
type: Input
|
|
1742
|
-
}], showCredits: [{
|
|
1743
|
-
type: Input
|
|
1744
1973
|
}], customAssistantIcon: [{
|
|
1745
1974
|
type: Input
|
|
1746
1975
|
}], data: [{
|
|
@@ -1793,12 +2022,41 @@ class SavedChatsComponent {
|
|
|
1793
2022
|
this.chatService = this.instanceManagerService.getInstance(this.instanceId);
|
|
1794
2023
|
}
|
|
1795
2024
|
onListSavedChat() {
|
|
1796
|
-
this.subscription.add(this.chatService.savedChats$.subscribe((savedChats) =>
|
|
2025
|
+
this.subscription.add(this.chatService.savedChats$.subscribe((savedChats) => {
|
|
2026
|
+
this.groupedSavedChats$.next(this._groupSavedChatsByDate(savedChats));
|
|
2027
|
+
}));
|
|
1797
2028
|
}
|
|
1798
2029
|
onLoad(savedChat) {
|
|
2030
|
+
this.chatService.setSavedChatId(savedChat.id);
|
|
1799
2031
|
this.chatService.loadSavedChat$.next(savedChat);
|
|
2032
|
+
this.chatService.listSavedChat();
|
|
1800
2033
|
this.load.emit(savedChat);
|
|
1801
2034
|
}
|
|
2035
|
+
onRename(savedChat) {
|
|
2036
|
+
const model = {
|
|
2037
|
+
title: 'Rename saved discussion',
|
|
2038
|
+
message: `Please enter a new name for the discussion "${savedChat.title}".`,
|
|
2039
|
+
buttons: [
|
|
2040
|
+
new ModalButton({ result: -2 /* ModalResult.Cancel */ }),
|
|
2041
|
+
new ModalButton({ result: -1 /* ModalResult.OK */, text: "Rename", primary: true })
|
|
2042
|
+
],
|
|
2043
|
+
output: savedChat.title,
|
|
2044
|
+
validators: [Validators.required]
|
|
2045
|
+
};
|
|
2046
|
+
this.modalService.prompt(model).then(res => {
|
|
2047
|
+
if (res === -1 /* ModalResult.OK */) {
|
|
2048
|
+
this.subscription.add(this.chatService.updateSavedChat(savedChat.id, model.output)
|
|
2049
|
+
.pipe(tap(() => {
|
|
2050
|
+
this.notificationsService.success(`The saved discussion "${savedChat.title}" has been successfully renamed to "${model.output}".`);
|
|
2051
|
+
this.chatService.listSavedChat();
|
|
2052
|
+
}), catchError((error) => {
|
|
2053
|
+
console.error('Error occurred while updating the saved chat:', error);
|
|
2054
|
+
this.notificationsService.error(`Error occurred while updating the saved discussion "${savedChat.title}"`);
|
|
2055
|
+
return throwError(() => error);
|
|
2056
|
+
})).subscribe());
|
|
2057
|
+
}
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
1802
2060
|
onDelete(savedChat) {
|
|
1803
2061
|
this.modalService
|
|
1804
2062
|
.confirm({
|
|
@@ -1875,10 +2133,10 @@ class SavedChatsComponent {
|
|
|
1875
2133
|
}
|
|
1876
2134
|
}
|
|
1877
2135
|
SavedChatsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1878
|
-
SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\"
|
|
2136
|
+
SavedChatsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: SavedChatsComponent, isStandalone: true, selector: "sq-saved-chats-v3", inputs: { instanceId: "instanceId" }, outputs: { load: "load", delete: "delete" }, ngImport: i0, template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\" [class.active]=\"chatService.savedChatId === savedChat.id\"\n (click)=\"onLoad(savedChat)\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"$event.stopPropagation(); onRename(savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"$event.stopPropagation(); onDelete(savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-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}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "ngmodule", type: ModalModule }, { kind: "ngmodule", type: UtilsModule }, { kind: "directive", type: i2$1.TooltipDirective, selector: "[sqTooltip]", inputs: ["sqTooltip", "sqTooltipData", "sqTooltipTemplate", "placement", "fallbackPlacements", "delay", "hoverableTooltip", "tooltipClass"] }] });
|
|
1879
2137
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: SavedChatsComponent, decorators: [{
|
|
1880
2138
|
type: Component,
|
|
1881
|
-
args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\"
|
|
2139
|
+
args: [{ selector: 'sq-saved-chats-v3', standalone: true, imports: [CommonModule, ModalModule, UtilsModule], template: "<ng-container *ngIf=\"(chatService.chatConfig$ | async)?.savedChatSettings.display\">\n <div *ngFor=\"let group of (groupedSavedChats$ | async)\" class=\"saved-chats\">\n <div class=\"saved-chat-date\">{{group.key}}</div>\n <div *ngFor=\"let savedChat of group.value\" class=\"saved-chat p-2\" [class.active]=\"chatService.savedChatId === savedChat.id\"\n (click)=\"onLoad(savedChat)\">\n <span class=\"title me-1\">{{savedChat.title}}</span>\n <i class=\"saved-chat-actions fas fa-pen mx-1\" [sqTooltip]=\"'Rename'\"\n (click)=\"$event.stopPropagation(); onRename(savedChat)\"></i>\n <i class=\"saved-chat-actions fas fa-trash ms-1\" [sqTooltip]=\"'Delete'\"\n (click)=\"$event.stopPropagation(); onDelete(savedChat)\"></i>\n </div>\n </div>\n</ng-container>\n", styles: [".ast-primary{color:var(--ast-primary-color, #005DA7);background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover{background-color:var(--ast-primary-bg, #f2f8fe)}.ast-primary-hover:hover{color:var(--ast-primary-color, #005DA7)}.ast-secondary{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-secondary-bg, #FFF8F1)}.ast-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}.saved-chats .saved-chat-date{font-weight:500;color:#a9a9a9;margin-top:.5rem}.saved-chats .saved-chat{display:flex;align-items:center;cursor:pointer;margin-left:.25rem}.saved-chats .saved-chat span{flex-grow:1;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.saved-chats .saved-chat .saved-chat-actions{display:none}.saved-chats .saved-chat:hover,.saved-chats .saved-chat.active{color:var(--ast-secondary-color, #FF732E);background-color:var(--ast-saved-chat-hover-background, #FFF8F1)}.saved-chats .saved-chat:hover .saved-chat-actions{display:block}.saved-chats .title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n"] }]
|
|
1882
2140
|
}], propDecorators: { instanceId: [{
|
|
1883
2141
|
type: Input
|
|
1884
2142
|
}], load: [{
|
|
@@ -1903,9 +2161,81 @@ const enAssistant = Utils.merge({}, _enAssistant);
|
|
|
1903
2161
|
const frAssistant = Utils.merge({}, _frAssistant);
|
|
1904
2162
|
const deAssistant = Utils.merge({}, _deAssistant);
|
|
1905
2163
|
|
|
2164
|
+
class ChatPrompt {
|
|
2165
|
+
constructor(model, modalRef, formBuilder) {
|
|
2166
|
+
this.model = model;
|
|
2167
|
+
this.modalRef = modalRef;
|
|
2168
|
+
this.formBuilder = formBuilder;
|
|
2169
|
+
this.defaultButtons = [
|
|
2170
|
+
new ModalButton({
|
|
2171
|
+
result: -1 /* ModalResult.OK */,
|
|
2172
|
+
primary: true,
|
|
2173
|
+
validation: this.form
|
|
2174
|
+
}),
|
|
2175
|
+
new ModalButton({
|
|
2176
|
+
result: -2 /* ModalResult.Cancel */
|
|
2177
|
+
})
|
|
2178
|
+
];
|
|
2179
|
+
}
|
|
2180
|
+
ngOnInit() {
|
|
2181
|
+
this.inputControl = new UntypedFormControl(this.model.output, this.model.validators || Validators.required);
|
|
2182
|
+
this.form = this.formBuilder.group({
|
|
2183
|
+
input: this.inputControl
|
|
2184
|
+
});
|
|
2185
|
+
this.formChanges = Utils.subscribe(this.form.valueChanges, (value) => {
|
|
2186
|
+
this.model.output = this.inputControl.value;
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
ngOnDestroy() {
|
|
2190
|
+
this.formChanges.unsubscribe();
|
|
2191
|
+
}
|
|
2192
|
+
get title() {
|
|
2193
|
+
return this.model.title ? this.model.title : "msg#modal.prompt.title";
|
|
2194
|
+
}
|
|
2195
|
+
get buttons() {
|
|
2196
|
+
return (this.model.buttons && this.model.buttons.length > 0) ? this.model.buttons : this.defaultButtons;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
ChatPrompt.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatPrompt, deps: [{ token: MODAL_MODEL }, { token: i1$2.ModalRef }, { token: i2.UntypedFormBuilder }], target: i0.ɵɵFactoryTarget.Component });
|
|
2200
|
+
ChatPrompt.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.0.6", type: ChatPrompt, isStandalone: true, selector: "sq-chat-prompt", ngImport: i0, template: `
|
|
2201
|
+
<form name="prompt" novalidate [formGroup]="form">
|
|
2202
|
+
<sq-modal [title]="title" [buttons]="buttons">
|
|
2203
|
+
<div class="mb-3 sq-form-group">
|
|
2204
|
+
<label class="form-label" for="input">{{model.message | sqMessage:model.messageParams}}</label>
|
|
2205
|
+
<input [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="off" sqAutofocus *ngIf="!model.rowCount">
|
|
2206
|
+
<textarea [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="on" rows="{{model.rowCount}}" sqAutofocus *ngIf="!!model.rowCount">
|
|
2207
|
+
</textarea>
|
|
2208
|
+
</div>
|
|
2209
|
+
</sq-modal>
|
|
2210
|
+
</form>
|
|
2211
|
+
`, isInline: true, dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: BsModalModule }, { kind: "component", type: i4.BsModal, selector: "sq-modal", inputs: ["title", "buttons", "showHeader", "showFooter", "isProcessingState"] }, { kind: "ngmodule", type: ValidationModule }, { kind: "directive", type: i5$1.ValidationDirective, selector: "[sqValidation]", inputs: ["sqValidation"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: IntlModule }, { kind: "pipe", type: i6$1.MessagePipe, name: "sqMessage" }] });
|
|
2212
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.0.6", ngImport: i0, type: ChatPrompt, decorators: [{
|
|
2213
|
+
type: Component,
|
|
2214
|
+
args: [{
|
|
2215
|
+
selector: "sq-chat-prompt",
|
|
2216
|
+
template: `
|
|
2217
|
+
<form name="prompt" novalidate [formGroup]="form">
|
|
2218
|
+
<sq-modal [title]="title" [buttons]="buttons">
|
|
2219
|
+
<div class="mb-3 sq-form-group">
|
|
2220
|
+
<label class="form-label" for="input">{{model.message | sqMessage:model.messageParams}}</label>
|
|
2221
|
+
<input [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="off" sqAutofocus *ngIf="!model.rowCount">
|
|
2222
|
+
<textarea [sqValidation]="form" type="text" class="form-control" id="input" formControlName="input" spellcheck="on" rows="{{model.rowCount}}" sqAutofocus *ngIf="!!model.rowCount">
|
|
2223
|
+
</textarea>
|
|
2224
|
+
</div>
|
|
2225
|
+
</sq-modal>
|
|
2226
|
+
</form>
|
|
2227
|
+
`,
|
|
2228
|
+
standalone: true,
|
|
2229
|
+
imports: [CommonModule, BsModalModule, ValidationModule, ReactiveFormsModule, IntlModule],
|
|
2230
|
+
}]
|
|
2231
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
2232
|
+
type: Inject,
|
|
2233
|
+
args: [MODAL_MODEL]
|
|
2234
|
+
}] }, { type: i1$2.ModalRef }, { type: i2.UntypedFormBuilder }]; } });
|
|
2235
|
+
|
|
1906
2236
|
/**
|
|
1907
2237
|
* Generated bundle index. Do not edit.
|
|
1908
2238
|
*/
|
|
1909
2239
|
|
|
1910
|
-
export { ChatComponent, ChatService, ChatSettingsV3Component, FormatIconComponent, InitialsAvatarComponent, InstanceManagerService, RestChatService, SavedChatsComponent, WebSocketChatService, chatConfigSchema, deAssistant, enAssistant, frAssistant
|
|
2240
|
+
export { ChatComponent, ChatPrompt, ChatService, ChatSettingsV3Component, FormatIconComponent, InitialsAvatarComponent, InstanceManagerService, RestChatService, SavedChatsComponent, WebSocketChatService, chatConfigSchema, connectionSettingsSchema, deAssistant, enAssistant, frAssistant };
|
|
1911
2241
|
//# sourceMappingURL=sinequa-assistant-chat.mjs.map
|