RED-9582 finish copilot

This commit is contained in:
Dan Percic 2024-12-09 14:37:02 +02:00
parent a3526d338f
commit 4933c7a678
10 changed files with 122 additions and 108 deletions

View File

@ -1,4 +1,4 @@
import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core';
import { inject, provideEnvironmentInitializer } from '@angular/core';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
import { templateExistsWhenEnteringAdmin } from '@guards/dossier-template-exists.guard';
import { DossierTemplatesGuard } from '@guards/dossier-templates.guard';
@ -82,15 +82,9 @@ const dossierTemplateIdRoutes: IqserRoutes = [
},
providers: [
RulesService,
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory: () => {
const service = inject(CopilotService);
console.log('Prepare copilot');
return () => service.connectAsync('/api/llm/llm-websocket');
},
},
provideEnvironmentInitializer(() => {
return inject(CopilotService).connectAsync('/api/llm/llm-websocket');
}),
],
},
{

View File

@ -7,13 +7,17 @@
<div [class.collapsed]="collapsed()" class="right-container flex-column">
<div class="collapsed-wrapper">
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: ('copilot' | translate) }"></ng-container>
<div class="all-caps-label" translate="dossier-details.title"></div>
<ng-container
*ngTemplateOutlet="collapsible; context: { action: 'expand', tooltip: ('copilot.label' | translate) }"
></ng-container>
<div class="all-caps-label" translate="copilot.label"></div>
</div>
<div class="header-wrapper flex mt-8">
<div class="heading-xl flex-1">Copilot</div>
<ng-container *ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: ('copilot' | translate) }"></ng-container>
<div class="heading-xl flex-1">{{ 'copilot.label' | translate | titlecase }}</div>
<ng-container
*ngTemplateOutlet="collapsible; context: { action: 'collapse', tooltip: ('copilot.label' | translate) }"
></ng-container>
</div>
<div class="mt-24">
@ -42,7 +46,7 @@
<ng-template #collapsible let-action="action" let-tooltip="tooltip">
<iqser-circle-button
(action)="collapsed.set(!collapsed())"
(action)="toggleCollapse()"
[icon]="'iqser:' + action"
[tooltipPosition]="IqserTooltipPositions.before"
[tooltip]="tooltip"

View File

@ -1,5 +1,16 @@
import { NgIf, NgTemplateOutlet } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, computed, inject, input, OnInit, signal, viewChild } from '@angular/core';
import { NgIf, NgTemplateOutlet, TitleCasePipe } from '@angular/common';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
computed,
DestroyRef,
inject,
input,
OnInit,
signal,
viewChild,
} from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { FormsModule } from '@angular/forms';
import { MatIcon } from '@angular/material/icon';
@ -71,6 +82,7 @@ const RULE_VALIDATION_TIMEOUT = 2000;
MatTooltip,
NgTemplateOutlet,
DatePipe,
TitleCasePipe,
],
})
export default class RulesScreenComponent implements OnInit, ComponentCanDeactivate {
@ -114,6 +126,7 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
) {
const username = this.#currentUser.id;
const tenant = inject(TenantsService).activeTenantId;
inject(DestroyRef).onDestroy(() => this.#copilotService.deactivate());
this.#copilotService
.listen<{ token?: string }>('/user/' + username + '/queue/' + tenant + '/rules-copilot')
.pipe(
@ -121,9 +134,7 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
map(res => res?.token),
)
.subscribe(token => {
console.log('WS token: ' + token);
if (token === null) {
console.log(this.#conversation());
this.#conversation.update(responses => [...responses, { ...endingSentence }]);
return;
}
@ -132,13 +143,11 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
return [...responses, { ...last, text: (last.text ?? '') + token }];
});
});
this.#copilotService.send('manageradmin');
}
set isLeavingPage(isLeaving: boolean) {
this.isLeaving = isLeaving;
this._changeDetectorRef.detectChanges();
this._changeDetectorRef.markForCheck();
}
get changed(): boolean {
@ -156,6 +165,13 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
this.#closeProblemsView();
}
toggleCollapse() {
this.collapsed.update(collapsed => !collapsed);
if (this.#conversation().length === 1) {
this.#copilotService.send('Hello!');
}
}
add(question: string) {
this.#conversation.update(responses => {
const last = responses.pop();
@ -164,7 +180,6 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
last.date = new Date().toISOString();
return [...responses, last, { ...endingSentence }];
});
console.log(this.#conversation());
this.inputWithAction().reset();
this.#copilotService.send(question);
}
@ -194,7 +209,7 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
}
(window as any).monaco.editor.setTheme(this._editorThemeService.getTheme(true));
await this.#configureSyntaxHighlighting();
this._changeDetectorRef.detectChanges();
this._changeDetectorRef.markForCheck();
}
@Debounce()
@ -218,7 +233,7 @@ export default class RulesScreenComponent implements OnInit, ComponentCanDeactiv
this.currentLines = this.initialLines;
this.#decorations = this.#codeEditor?.deltaDecorations(this.#decorations, []) || [];
this.#removeErrorMarkers();
this._changeDetectorRef.detectChanges();
this._changeDetectorRef.markForCheck();
this._loadingService.stop();
}

View File

@ -163,12 +163,6 @@ export class FilePreviewScreenComponent extends AutoUnsubscribe implements OnIni
private readonly _componentLogService: ComponentLogService,
) {
super();
effect(() => {
const file = this.state.file();
console.log('FILE CHANGED');
// this._fileDataService.loadAnnotations(file).then();
});
effect(() => {
const file = this.state.file();
if (file.analysisRequired && !file.excludedFromAutomaticAnalysis) {

View File

@ -1,4 +1,4 @@
import { ENVIRONMENT_INITIALIZER, inject } from '@angular/core';
import { inject, provideEnvironmentInitializer } from '@angular/core';
import { PendingChangesGuard } from '@guards/can-deactivate.guard';
import { IqserRoutes } from '@iqser/common-ui';
import { WebSocketService } from '@services/web-socket.service';
@ -21,14 +21,9 @@ export default [
DocumentUnloadedGuard,
TablesService,
FileAssignService,
{
provide: ENVIRONMENT_INITIALIZER,
multi: true,
useFactory: () => {
const service = inject(WebSocketService);
return () => service.connectAsync('/redaction-gateway-v1/websocket');
},
},
provideEnvironmentInitializer(async () => {
return inject(WebSocketService).connectAsync('/redaction-gateway-v1/websocket');
}),
],
},
] satisfies IqserRoutes;

View File

@ -59,7 +59,7 @@ export abstract class StompService extends RxStomp {
connect(url: string) {
this.configure({
debug: (msg: string) => this.#logger.debug(msg),
debug: (msg: string) => this.#logger.debug('[WS] ' + msg),
brokerURL: this.#config.API_URL + url,
reconnectDelay: 0,
});

View File

@ -275,9 +275,6 @@
"watermarks": "Wasserzeichen"
},
"analysis-disabled": "",
"annotation": {
"pending": "(Analyse steht aus)"
},
"annotation-actions": {
"accept-recommendation": {
"label": "Empfehlung annehmen"
@ -333,14 +330,14 @@
"error": "Rekategorisierung des Bilds fehlgeschlagen: {error}",
"success": "Bild wurde einer neuen Kategorie zugeordnet."
},
"remove": {
"error": "Entfernen der Schwärzung fehlgeschlagen: {error}",
"success": "Schwärzung wurde entfernt"
},
"remove-hint": {
"error": "Entfernen des Hinweises fehlgeschlagen: {error}",
"success": "Hinweis wurde entfernt"
},
"remove": {
"error": "Entfernen der Schwärzung fehlgeschlagen: {error}",
"success": "Schwärzung wurde entfernt"
},
"undo": {
"error": "Die Aktion konnte nicht rückgängig gemacht werden. Fehler: {error}",
"success": "Rücksetzung erfolgreich"
@ -353,15 +350,15 @@
"remove-highlights": {
"label": "Ausgewählte Markierungen entfernen"
},
"resize": {
"label": "Größe ändern"
},
"resize-accept": {
"label": "Neue Größe speichern"
},
"resize-cancel": {
"label": "Größenänderung abbrechen"
},
"resize": {
"label": "Größe ändern"
},
"see-references": {
"label": "Referenzen anzeigen"
},
@ -396,6 +393,9 @@
"skipped": "Ignorierte Schwärzung",
"text-highlight": "Markierung"
},
"annotation": {
"pending": "(Analyse steht aus)"
},
"annotations": "Annotationen",
"archived-dossiers-listing": {
"no-data": {
@ -702,6 +702,9 @@
}
},
"content": "Grund",
"copilot": {
"label": ""
},
"dashboard": {
"empty-template": {
"description": "Diese Vorlage enthält keine Dossiers. Erstellen Sie ein Dossier, um nach diesen Regeln zu schwärzen.",
@ -1023,13 +1026,13 @@
"recent": "Neu ({hours} h)",
"unassigned": "Keinem Bearbeiter zugewiesen"
},
"reanalyse": {
"action": "Datei analysieren"
},
"reanalyse-dossier": {
"error": "Einplanung der Dateien für die Reanalyse fehlgeschlagen. Bitte versuchen Sie es noch einmal.",
"success": "Dateien für Reanalyse vorgesehen."
},
"reanalyse": {
"action": "Datei analysieren"
},
"report-download": "",
"start-auto-analysis": "Auto-Analyse aktivieren",
"stop-auto-analysis": "Auto-Analyse anhalten",
@ -1105,14 +1108,6 @@
"total-documents": "Dokumente",
"total-people": "<strong>{count}</strong> {count, plural, one{Benutzer} other {Benutzer}}"
},
"dossier-templates": {
"label": "Dossier-Vorlagen",
"status": {
"active": "Aktiv",
"inactive": "Inaktiv",
"incomplete": "Unvollständig"
}
},
"dossier-templates-listing": {
"action": {
"clone": "Vorlage klonen",
@ -1147,6 +1142,14 @@
"title": "{length} {length, plural, one{Dossier-Vorlage} other{Dossier-Vorlagen}}"
}
},
"dossier-templates": {
"label": "Dossier-Vorlagen",
"status": {
"active": "Aktiv",
"inactive": "Inaktiv",
"incomplete": "Unvollständig"
}
},
"dossier-watermark-selector": {
"heading": "Wasserzeichen auf Dokumenten",
"no-watermark": "Kein Wasserzeichen in der Dossier-Vorlage verfügbar:<br>Bitten Sie Ihren Admin, eines zu konfigurieren.",
@ -1357,15 +1360,6 @@
"title": "{length} {length, plural, one{Wörterbuch} other{Wörterbücher}}"
}
},
"entity": {
"info": {
"actions": {
"revert": "Zurücksetzen",
"save": "Änderungen speichern"
},
"heading": "Entität bearbeiten"
}
},
"entity-rules-screen": {
"error": {
"generic": "Fehler: Aktualisierung der Entitätsregeln fehlgeschlagen."
@ -1379,19 +1373,28 @@
"title": "Entitätsregeln-Editor",
"warnings-found": "{warnings, plural, one{A warning} other{{warnings} warnings}} in Regeln gefunden"
},
"entity": {
"info": {
"actions": {
"revert": "Zurücksetzen",
"save": "Änderungen speichern"
},
"heading": "Entität bearbeiten"
}
},
"error": {
"deleted-entity": {
"dossier": {
"action": "Zurück zur Übersicht",
"label": "Dieses Dossier wurde gelöscht!"
},
"file": {
"action": "Zurück zum Dossier",
"label": "Diese Datei wurde gelöscht!"
},
"file-dossier": {
"action": "Zurück zur Übersicht",
"label": "Das Dossier dieser Datei wurde gelöscht!"
},
"file": {
"action": "Zurück zum Dossier",
"label": "Diese Datei wurde gelöscht!"
}
},
"file-preview": {
@ -1409,12 +1412,6 @@
},
"exact-date": "{day}. {month} {year} um {hour}:{minute} Uhr",
"file": "Datei",
"file-attribute": {
"update": {
"error": "Aktualisierung des Werts für das Datei-Attribut fehlgeschlagen. Bitte versuchen Sie es noch einmal.",
"success": "Der Wert für das Dateiattribut wurde erfolgreich aktualisiert."
}
},
"file-attribute-encoding-types": {
"ascii": "ASCII",
"iso": "ISO-8859-1",
@ -1425,6 +1422,12 @@
"number": "Nummer",
"text": "Freier Text"
},
"file-attribute": {
"update": {
"error": "Aktualisierung des Werts für das Datei-Attribut fehlgeschlagen. Bitte versuchen Sie es noch einmal.",
"success": "Der Wert für das Dateiattribut wurde erfolgreich aktualisiert."
}
},
"file-attributes-configurations": {
"cancel": "Abbrechen",
"form": {
@ -1642,15 +1645,6 @@
"zip": "Die Zip-Datei wurde erfolgreich hochgeladen!"
}
},
"filter": {
"analysis": "Analyse erforderlich",
"comment": "Kommentare",
"hint": "Nur Hinweise",
"image": "Bilder",
"none": "Keine Annotationen",
"redaction": "Schwärzung",
"updated": "Aktualisiert"
},
"filter-menu": {
"filter-options": "Filteroptionen",
"filter-types": "Filter",
@ -1660,6 +1654,15 @@
"unseen-pages": "Nur Annotationen auf ungesehenen Seiten",
"with-comments": "Nur Annotationen mit Kommentaren"
},
"filter": {
"analysis": "Analyse erforderlich",
"comment": "Kommentare",
"hint": "Nur Hinweise",
"image": "Bilder",
"none": "Keine Annotationen",
"redaction": "Schwärzung",
"updated": "Aktualisiert"
},
"filters": {
"assigned-people": "Bearbeiter",
"documents-status": "Dokumentenstatus",
@ -1949,13 +1952,6 @@
"user-promoted-to-approver": "Sie wurden zum Genehmiger in einem Dossier ernannt: <b>{dossierHref, select, null{{dossierName}} other{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b>",
"user-removed-as-dossier-member": "Sie wurden als Dossier-Mitglied entfernt: \n<b>{dossierHref, select, null{{dossierName}} other\n{<a href=\"{dossierHref}\" target=\"_blank\">{dossierName}</a>}}</b>\n"
},
"notifications": {
"button-text": "Benachrichtigungen",
"deleted-dossier": "Gelöschtes Dossier",
"label": "Benachrichtigungen",
"mark-all-as-read": "Alle als gelesen markieren",
"mark-as": "Als {type, select, read{gelesen} unread{ungelesen} other{}} markieren"
},
"notifications-screen": {
"category": {
"email-notifications": "E-Mail-Benachrichtigungen",
@ -1969,6 +1965,7 @@
"dossier": "Benachrichtigungen zu Dossiers",
"other": "Andere Benachrichtigungen"
},
"options-title": "Wählen Sie aus, bei welchen Aktivitäten Sie benachrichtigt werden möchten",
"options": {
"ASSIGN_APPROVER": "Wenn ich einem Dokument als Genehmiger zugewiesen werde",
"ASSIGN_REVIEWER": "Wenn ich einem Dokument als Prüfer zugewiesen werde",
@ -1986,7 +1983,6 @@
"USER_PROMOTED_TO_APPROVER": "Wenn ich Genehmiger in einem Dossier werde",
"USER_REMOVED_AS_DOSSIER_MEMBER": "Wenn ich die Dossier-Mitgliedschaft verliere"
},
"options-title": "Wählen Sie aus, bei welchen Aktivitäten Sie benachrichtigt werden möchten",
"schedule": {
"daily": "Tägliche Zusammenfassung",
"instant": "Sofort",
@ -1994,6 +1990,13 @@
},
"title": "Benachrichtigungseinstellungen"
},
"notifications": {
"button-text": "Benachrichtigungen",
"deleted-dossier": "Gelöschtes Dossier",
"label": "Benachrichtigungen",
"mark-all-as-read": "Alle als gelesen markieren",
"mark-as": "Als {type, select, read{gelesen} unread{ungelesen} other{}} markieren"
},
"ocr": {
"confirmation-dialog": {
"cancel": "Abbrechen",
@ -2105,10 +2108,6 @@
"warnings-label": "Dialoge und Meldungen",
"warnings-subtitle": "„Nicht mehr anzeigen“-Optionen"
},
"processing": {
"basic": "Verarbeitung läuft",
"ocr": "OCR"
},
"processing-status": {
"ocr": "OCR",
"pending": "Ausstehend",
@ -2116,6 +2115,10 @@
"processed": "Verarbeitet",
"processing": "Verarbeitung läuft"
},
"processing": {
"basic": "Verarbeitung läuft",
"ocr": "OCR"
},
"readonly": "Lesemodus",
"readonly-archived": "Lesemodus (archiviert)",
"redact-text": {
@ -2385,12 +2388,6 @@
"red-user-admin": "{count, plural, one{Benutzeradmin} other{Benutzeradmins}}",
"regular": "{count, plural, one{regulärer Benutzer} other{reguläre Benutzer}}"
},
"search": {
"active-dossiers": "Dokumente in aktiven Dossiers",
"all-dossiers": "Alle Dokumente",
"placeholder": "Dokumente durchsuchen...",
"this-dossier": "In diesem Dossier"
},
"search-screen": {
"cols": {
"assignee": "Bearbeiter",
@ -2414,6 +2411,12 @@
"no-match": "Der Suchbegriff wurde in keinem der Dokumente gefunden.",
"table-header": "{length} {length, plural, one{Suchergebnis} other{Suchergebnisse}}"
},
"search": {
"active-dossiers": "Dokumente in aktiven Dossiers",
"all-dossiers": "Alle Dokumente",
"placeholder": "Dokumente durchsuchen...",
"this-dossier": "In diesem Dossier"
},
"seconds": "Sekunden",
"size": "Größe",
"smtp-auth-config": {

View File

@ -702,6 +702,9 @@
}
},
"content": "Reason",
"copilot": {
"label": "Copilot"
},
"dashboard": {
"empty-template": {
"description": "This template does not contain any dossiers. Create a dossier that applies this ruleset.",

View File

@ -702,6 +702,9 @@
}
},
"content": "Grund",
"copilot": {
"label": ""
},
"dashboard": {
"empty-template": {
"description": "Diese Vorlage enthält keine Dossiers. Erstellen Sie ein Dossier, um nach diesen Regeln zu schwärzen.",

View File

@ -702,6 +702,9 @@
}
},
"content": "Reason",
"copilot": {
"label": "Copilot"
},
"dashboard": {
"empty-template": {
"description": "This template does not contain any dossiers. Create a dossier that applies this ruleset.",