Spaces:
Running
Running
Update flare-ui/src/app/dialogs/version-edit-dialog/version-edit-dialog.component.ts
Browse files
flare-ui/src/app/dialogs/version-edit-dialog/version-edit-dialog.component.ts
CHANGED
@@ -16,7 +16,9 @@ import { MatExpansionModule } from '@angular/material/expansion';
|
|
16 |
import { MatDividerModule } from '@angular/material/divider';
|
17 |
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
18 |
import { MatListModule } from '@angular/material/list';
|
|
|
19 |
import { ApiService, Project, Version } from '../../services/api.service';
|
|
|
20 |
import ConfirmDialogComponent from '../confirm-dialog/confirm-dialog.component';
|
21 |
|
22 |
// Interfaces for multi-language support
|
@@ -25,6 +27,16 @@ interface LocalizedExample {
|
|
25 |
example: string;
|
26 |
}
|
27 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
28 |
@Component({
|
29 |
selector: 'app-version-edit-dialog',
|
30 |
standalone: true,
|
@@ -46,7 +58,8 @@ interface LocalizedExample {
|
|
46 |
MatExpansionModule,
|
47 |
MatDividerModule,
|
48 |
MatProgressBarModule,
|
49 |
-
MatListModule
|
|
|
50 |
],
|
51 |
templateUrl: './version-edit-dialog.component.html',
|
52 |
styleUrls: ['./version-edit-dialog.component.scss']
|
@@ -56,183 +69,186 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
56 |
versions: Version[] = [];
|
57 |
selectedVersion: Version | null = null;
|
58 |
versionForm!: FormGroup;
|
59 |
-
|
60 |
loading = false;
|
61 |
saving = false;
|
62 |
publishing = false;
|
63 |
-
creating = false;
|
64 |
-
isDirty = false;
|
65 |
-
|
66 |
-
selectedTabIndex = 0;
|
67 |
-
testUserMessage = '';
|
68 |
-
testResult: any = null;
|
69 |
testing = false;
|
|
|
|
|
|
|
70 |
|
71 |
-
//
|
72 |
selectedExampleLocale: string = 'tr';
|
|
|
73 |
|
74 |
constructor(
|
75 |
private fb: FormBuilder,
|
76 |
-
private
|
|
|
77 |
private snackBar: MatSnackBar,
|
78 |
private dialog: MatDialog,
|
79 |
public dialogRef: MatDialogRef<VersionEditDialogComponent>,
|
80 |
-
@Inject(MAT_DIALOG_DATA) public data:
|
81 |
) {
|
82 |
this.project = data.project;
|
83 |
-
this.versions = [...this.project.versions].sort((a, b) => b.no - a.no);
|
84 |
this.selectedExampleLocale = this.project.default_locale || 'tr';
|
85 |
}
|
86 |
|
87 |
ngOnInit() {
|
88 |
this.initializeForm();
|
89 |
-
|
90 |
-
|
91 |
-
const unpublished = this.versions.find(v => !v.published);
|
92 |
-
this.selectedVersion = unpublished || this.versions[0] || null;
|
93 |
-
|
94 |
-
if (this.selectedVersion) {
|
95 |
-
this.loadVersion(this.selectedVersion);
|
96 |
-
}
|
97 |
-
|
98 |
-
this.versionForm.valueChanges.subscribe(() => {
|
99 |
-
this.isDirty = true;
|
100 |
-
});
|
101 |
}
|
102 |
|
103 |
initializeForm() {
|
104 |
this.versionForm = this.fb.group({
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
}),
|
120 |
-
intents: this.fb.array([])
|
121 |
-
last_update_date: ['']
|
122 |
});
|
123 |
|
124 |
-
//
|
125 |
-
this.versionForm.
|
126 |
-
|
127 |
-
if (useFineTune) {
|
128 |
-
fineTuneControl?.setValidators([Validators.required]);
|
129 |
-
} else {
|
130 |
-
fineTuneControl?.clearValidators();
|
131 |
-
fineTuneControl?.setValue('');
|
132 |
-
}
|
133 |
-
fineTuneControl?.updateValueAndValidity();
|
134 |
});
|
135 |
}
|
136 |
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
repo_id: version.llm.repo_id || '',
|
154 |
-
generation_config: version.llm.generation_config || {
|
155 |
-
max_new_tokens: 512,
|
156 |
-
temperature: 0.7,
|
157 |
-
top_p: 0.95,
|
158 |
-
repetition_penalty: 1.1
|
159 |
-
},
|
160 |
-
use_fine_tune: version.llm.use_fine_tune || false,
|
161 |
-
fine_tune_zip: version.llm.fine_tune_zip || ''
|
162 |
-
}
|
163 |
-
});
|
164 |
}
|
165 |
-
|
166 |
-
// Clear and rebuild intents
|
167 |
-
this.intents.clear();
|
168 |
-
(version.intents || []).forEach(intent => {
|
169 |
-
this.intents.push(this.createIntentFormGroup(intent));
|
170 |
-
});
|
171 |
|
172 |
-
|
|
|
173 |
}
|
174 |
-
|
175 |
-
|
|
|
|
|
|
|
|
|
|
|
176 |
this.loading = true;
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
this.
|
181 |
-
this.versions = [...project.versions].sort((a, b) => b.no - a.no);
|
182 |
|
183 |
-
//
|
184 |
-
if (
|
185 |
-
|
186 |
-
if (currentVersion) {
|
187 |
-
this.loadVersion(currentVersion);
|
188 |
-
} else if (this.versions.length > 0) {
|
189 |
-
this.loadVersion(this.versions[0]);
|
190 |
-
}
|
191 |
-
} else if (this.versions.length > 0) {
|
192 |
-
this.loadVersion(this.versions[0]);
|
193 |
}
|
|
|
|
|
|
|
|
|
|
|
194 |
}
|
195 |
-
}
|
196 |
-
this.snackBar.open('Failed to reload versions', 'Close', { duration: 3000 });
|
197 |
-
} finally {
|
198 |
-
this.loading = false;
|
199 |
-
}
|
200 |
}
|
201 |
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
212 |
});
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
219 |
});
|
220 |
}
|
221 |
-
|
222 |
-
|
223 |
}
|
224 |
|
225 |
-
|
226 |
return this.fb.group({
|
227 |
-
name: [
|
228 |
-
caption: [
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
236 |
});
|
237 |
}
|
238 |
|
@@ -261,6 +277,23 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
261 |
return [];
|
262 |
}
|
263 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
264 |
addLocalizedExample(intentIndex: number, example: string) {
|
265 |
if (!example.trim()) return;
|
266 |
|
@@ -294,6 +327,18 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
294 |
this.isDirty = true;
|
295 |
}
|
296 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
297 |
// Check if version can be edited
|
298 |
get canEdit(): boolean {
|
299 |
return !this.selectedVersion?.published;
|
@@ -301,6 +346,7 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
301 |
|
302 |
addIntent() {
|
303 |
this.intents.push(this.createIntentFormGroup());
|
|
|
304 |
}
|
305 |
|
306 |
removeIntent(index: number) {
|
@@ -318,6 +364,7 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
318 |
dialogRef.afterClosed().subscribe(confirmed => {
|
319 |
if (confirmed) {
|
320 |
this.intents.removeAt(index);
|
|
|
321 |
}
|
322 |
});
|
323 |
}
|
@@ -368,14 +415,8 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
368 |
});
|
369 |
}
|
370 |
|
371 |
-
|
372 |
-
|
373 |
-
parameters.push(this.createParameterFormGroup());
|
374 |
-
}
|
375 |
-
|
376 |
-
removeParameter(intentIndex: number, paramIndex: number) {
|
377 |
-
const parameters = this.getIntentParameters(intentIndex);
|
378 |
-
parameters.removeAt(paramIndex);
|
379 |
}
|
380 |
|
381 |
async createVersion() {
|
@@ -407,45 +448,42 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
407 |
// Copy from selected version
|
408 |
const sourceVersion = this.versions.find(v => v.no === result.selectedValue);
|
409 |
if (sourceVersion) {
|
|
|
410 |
newVersionData = {
|
411 |
-
...
|
412 |
no: undefined,
|
413 |
published: false,
|
414 |
last_update_date: undefined,
|
415 |
-
caption: `Copy of version ${sourceVersion.no}
|
416 |
-
description: sourceVersion.caption ? `Copy of ${sourceVersion.caption}` : `Copy of version ${sourceVersion.no}`
|
417 |
};
|
418 |
}
|
419 |
} else {
|
420 |
// Create blank version
|
421 |
newVersionData = {
|
422 |
-
caption:
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
top_p: 0.95,
|
432 |
-
top_k: 50,
|
433 |
-
repetition_penalty: 1.1
|
434 |
-
},
|
435 |
-
use_fine_tune: false,
|
436 |
-
fine_tune_zip: ''
|
437 |
},
|
438 |
-
intents: []
|
439 |
-
parameters: []
|
440 |
};
|
441 |
}
|
442 |
-
|
443 |
-
|
444 |
-
|
445 |
-
|
446 |
-
|
447 |
-
|
|
|
|
|
|
|
448 |
} catch (error) {
|
|
|
449 |
this.snackBar.open('Failed to create version', 'Close', { duration: 3000 });
|
450 |
} finally {
|
451 |
this.loading = false;
|
@@ -454,355 +492,209 @@ export default class VersionEditDialogComponent implements OnInit {
|
|
454 |
});
|
455 |
}
|
456 |
|
457 |
-
async
|
458 |
-
if (!this.selectedVersion || !this.canEdit) {
|
459 |
-
this.snackBar.open('Cannot save published version', 'Close', { duration: 3000 });
|
460 |
-
return;
|
461 |
-
}
|
462 |
-
|
463 |
-
if (this.versionForm.invalid) {
|
464 |
-
const invalidFields: string[] = [];
|
465 |
-
Object.keys(this.versionForm.controls).forEach(key => {
|
466 |
-
const control = this.versionForm.get(key);
|
467 |
-
if (control && control.invalid) {
|
468 |
-
invalidFields.push(key);
|
469 |
-
}
|
470 |
-
});
|
471 |
-
|
472 |
-
this.intents.controls.forEach((intent, index) => {
|
473 |
-
if (intent.invalid) {
|
474 |
-
invalidFields.push(`Intent ${index + 1}`);
|
475 |
-
}
|
476 |
-
});
|
477 |
-
|
478 |
-
this.snackBar.open(`Please fix validation errors in: ${invalidFields.join(', ')}`, 'Close', {
|
479 |
-
duration: 5000
|
480 |
-
});
|
481 |
-
return;
|
482 |
-
}
|
483 |
-
|
484 |
-
const currentVersion = this.selectedVersion!;
|
485 |
-
|
486 |
-
this.saving = true;
|
487 |
-
|
488 |
-
try {
|
489 |
-
const formValue = this.versionForm.getRawValue();
|
490 |
-
|
491 |
-
// updateData'yı backend'in beklediği formatta hazırla
|
492 |
-
const updateData = {
|
493 |
-
caption: formValue.caption,
|
494 |
-
general_prompt: formValue.general_prompt || '',
|
495 |
-
llm: formValue.llm,
|
496 |
-
intents: formValue.intents.map((intent: any) => ({
|
497 |
-
name: intent.name,
|
498 |
-
caption: intent.caption,
|
499 |
-
detection_prompt: intent.detection_prompt,
|
500 |
-
examples: Array.isArray(intent.examples) ? intent.examples : [],
|
501 |
-
parameters: Array.isArray(intent.parameters) ? intent.parameters.map((param: any) => ({
|
502 |
-
name: param.name,
|
503 |
-
caption: param.caption,
|
504 |
-
type: param.type,
|
505 |
-
required: param.required,
|
506 |
-
variable_name: param.variable_name,
|
507 |
-
extraction_prompt: param.extraction_prompt,
|
508 |
-
validation_regex: param.validation_regex,
|
509 |
-
invalid_prompt: param.invalid_prompt,
|
510 |
-
type_error_prompt: param.type_error_prompt
|
511 |
-
})) : [],
|
512 |
-
action: intent.action,
|
513 |
-
fallback_timeout_prompt: intent.fallback_timeout_prompt,
|
514 |
-
fallback_error_prompt: intent.fallback_error_prompt
|
515 |
-
})),
|
516 |
-
last_update_date: currentVersion.last_update_date || ''
|
517 |
-
};
|
518 |
-
|
519 |
-
console.log('Saving version data:', JSON.stringify(updateData, null, 2));
|
520 |
-
|
521 |
-
const result = await this.apiService.updateVersion(
|
522 |
-
this.project.id,
|
523 |
-
currentVersion.no,
|
524 |
-
updateData
|
525 |
-
).toPromise();
|
526 |
-
|
527 |
-
this.snackBar.open('Version saved successfully', 'Close', { duration: 3000 });
|
528 |
-
|
529 |
-
this.isDirty = false;
|
530 |
-
|
531 |
-
if (result) {
|
532 |
-
this.selectedVersion = result;
|
533 |
-
this.versionForm.patchValue({
|
534 |
-
last_update_date: result.last_update_date
|
535 |
-
});
|
536 |
-
}
|
537 |
-
|
538 |
-
await this.loadVersions();
|
539 |
-
|
540 |
-
} catch (error: any) {
|
541 |
-
console.error('Save error:', error);
|
542 |
-
|
543 |
-
if (error.status === 409) {
|
544 |
-
// Race condition handling
|
545 |
-
await this.handleRaceCondition(currentVersion);
|
546 |
-
} else if (error.status === 400 && error.error?.detail?.includes('Published versions')) {
|
547 |
-
this.snackBar.open('Published versions cannot be modified. Create a new version instead.', 'Close', {
|
548 |
-
duration: 5000,
|
549 |
-
panelClass: 'error-snackbar'
|
550 |
-
});
|
551 |
-
} else {
|
552 |
-
const errorMessage = error.error?.detail || error.message || 'Failed to save version';
|
553 |
-
this.snackBar.open(errorMessage, 'Close', {
|
554 |
-
duration: 5000,
|
555 |
-
panelClass: 'error-snackbar'
|
556 |
-
});
|
557 |
-
}
|
558 |
-
} finally {
|
559 |
-
this.saving = false;
|
560 |
-
}
|
561 |
-
}
|
562 |
-
|
563 |
-
// Race condition handling
|
564 |
-
private async handleRaceCondition(currentVersion: Version) {
|
565 |
-
const formValue = this.versionForm.getRawValue();
|
566 |
-
|
567 |
-
const retryUpdateData = {
|
568 |
-
caption: formValue.caption,
|
569 |
-
general_prompt: formValue.general_prompt || '',
|
570 |
-
llm: formValue.llm,
|
571 |
-
intents: formValue.intents.map((intent: any) => ({
|
572 |
-
name: intent.name,
|
573 |
-
caption: intent.caption,
|
574 |
-
detection_prompt: intent.detection_prompt,
|
575 |
-
examples: Array.isArray(intent.examples) ? intent.examples : [],
|
576 |
-
parameters: Array.isArray(intent.parameters) ? intent.parameters : [],
|
577 |
-
action: intent.action,
|
578 |
-
fallback_timeout_prompt: intent.fallback_timeout_prompt,
|
579 |
-
fallback_error_prompt: intent.fallback_error_prompt
|
580 |
-
})),
|
581 |
-
last_update_date: currentVersion.last_update_date || ''
|
582 |
-
};
|
583 |
-
|
584 |
-
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
585 |
-
width: '500px',
|
586 |
-
data: {
|
587 |
-
title: 'Version Modified',
|
588 |
-
message: 'This version was modified by another user. Do you want to reload and lose your changes, or force save?',
|
589 |
-
confirmText: 'Force Save',
|
590 |
-
cancelText: 'Reload',
|
591 |
-
confirmColor: 'warn'
|
592 |
-
}
|
593 |
-
});
|
594 |
-
|
595 |
-
dialogRef.afterClosed().subscribe(async (forceSave) => {
|
596 |
-
if (forceSave) {
|
597 |
-
try {
|
598 |
-
await this.apiService.updateVersion(
|
599 |
-
this.project.id,
|
600 |
-
currentVersion.no,
|
601 |
-
retryUpdateData,
|
602 |
-
true
|
603 |
-
).toPromise();
|
604 |
-
this.snackBar.open('Version force saved', 'Close', { duration: 3000 });
|
605 |
-
await this.loadVersions();
|
606 |
-
} catch (err: any) {
|
607 |
-
this.snackBar.open(err.error?.detail || 'Force save failed', 'Close', {
|
608 |
-
duration: 5000,
|
609 |
-
panelClass: 'error-snackbar'
|
610 |
-
});
|
611 |
-
}
|
612 |
-
} else {
|
613 |
-
await this.loadVersions();
|
614 |
-
}
|
615 |
-
});
|
616 |
-
}
|
617 |
-
|
618 |
-
async publishVersion() {
|
619 |
if (!this.selectedVersion) return;
|
620 |
-
|
621 |
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
622 |
-
width: '
|
623 |
data: {
|
624 |
-
title: '
|
625 |
-
message: `
|
626 |
-
confirmText: '
|
627 |
-
|
628 |
}
|
629 |
});
|
630 |
|
631 |
dialogRef.afterClosed().subscribe(async (confirmed) => {
|
632 |
-
if (confirmed
|
633 |
-
this.
|
634 |
try {
|
635 |
-
await this.
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
|
|
|
|
641 |
|
642 |
-
|
643 |
-
|
|
|
|
|
644 |
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
});
|
650 |
} finally {
|
651 |
-
this.
|
652 |
}
|
653 |
}
|
654 |
});
|
655 |
}
|
656 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
657 |
async deleteVersion() {
|
658 |
if (!this.selectedVersion || this.selectedVersion.published) return;
|
659 |
-
|
660 |
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
661 |
width: '400px',
|
662 |
data: {
|
663 |
title: 'Delete Version',
|
664 |
-
message: `Are you sure you want to delete version
|
665 |
confirmText: 'Delete',
|
666 |
confirmColor: 'warn'
|
667 |
}
|
668 |
});
|
669 |
|
670 |
dialogRef.afterClosed().subscribe(async (confirmed) => {
|
671 |
-
if (confirmed
|
|
|
672 |
try {
|
673 |
-
await this.
|
674 |
-
this.project.id,
|
675 |
-
this.selectedVersion.no
|
676 |
-
).toPromise();
|
677 |
-
|
678 |
-
this.snackBar.open('Version deleted successfully', 'Close', { duration: 3000 });
|
679 |
|
680 |
-
|
681 |
-
await this.
|
682 |
-
|
683 |
-
if (this.versions.length > 0) {
|
684 |
-
this.loadVersion(this.versions[0]);
|
685 |
-
} else {
|
686 |
-
this.selectedVersion = null;
|
687 |
-
}
|
688 |
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
|
|
694 |
}
|
695 |
}
|
696 |
});
|
697 |
}
|
698 |
|
699 |
-
|
700 |
-
if (!this.
|
701 |
-
|
702 |
-
|
703 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
704 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
705 |
this.testing = true;
|
706 |
this.testResult = null;
|
707 |
-
|
708 |
// Simulate intent detection test
|
709 |
setTimeout(() => {
|
710 |
-
|
711 |
-
const intents = this.versionForm.get('intents')?.value || [];
|
712 |
|
713 |
-
// Simple
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
// Random detection for demo
|
732 |
-
if (!detectedIntent && intents.length > 0) {
|
733 |
-
const randomIntent = intents[Math.floor(Math.random() * intents.length)];
|
734 |
-
detectedIntent = randomIntent.name;
|
735 |
-
confidence = 0.65;
|
736 |
}
|
737 |
-
|
738 |
-
this.testResult = {
|
739 |
-
success: true,
|
740 |
-
intent: detectedIntent,
|
741 |
-
confidence: confidence,
|
742 |
-
parameters: detectedIntent ? this.extractTestParameters(detectedIntent) : []
|
743 |
-
};
|
744 |
-
|
745 |
this.testing = false;
|
746 |
}, 1500);
|
747 |
}
|
748 |
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
try {
|
763 |
-
return await this.apiService.getAPIs().toPromise() || [];
|
764 |
-
} catch {
|
765 |
-
return [];
|
766 |
-
}
|
767 |
-
}
|
768 |
-
|
769 |
-
private async reloadProject() {
|
770 |
-
this.loading = true;
|
771 |
-
try {
|
772 |
-
const projects = await this.apiService.getProjects().toPromise() || [];
|
773 |
-
const updatedProject = projects.find(p => p.id === this.project.id);
|
774 |
-
|
775 |
-
if (updatedProject) {
|
776 |
-
this.project = updatedProject;
|
777 |
-
this.versions = [...updatedProject.versions].sort((a, b) => b.no - a.no);
|
778 |
-
}
|
779 |
-
} catch (error) {
|
780 |
-
console.error('Failed to reload project:', error);
|
781 |
-
} finally {
|
782 |
-
this.loading = false;
|
783 |
-
}
|
784 |
-
}
|
785 |
|
786 |
-
|
787 |
-
|
788 |
-
|
789 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
790 |
}
|
791 |
-
|
792 |
-
const { default: VersionCompareDialogComponent } = await import('../version-compare-dialog/version-compare-dialog.component');
|
793 |
-
|
794 |
-
this.dialog.open(VersionCompareDialogComponent, {
|
795 |
-
width: '90vw',
|
796 |
-
maxWidth: '1000px',
|
797 |
-
maxHeight: '80vh',
|
798 |
-
data: {
|
799 |
-
versions: this.versions,
|
800 |
-
selectedVersion: this.selectedVersion
|
801 |
-
}
|
802 |
-
});
|
803 |
-
}
|
804 |
-
|
805 |
-
close() {
|
806 |
-
this.dialogRef.close(true);
|
807 |
}
|
808 |
}
|
|
|
16 |
import { MatDividerModule } from '@angular/material/divider';
|
17 |
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
18 |
import { MatListModule } from '@angular/material/list';
|
19 |
+
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
20 |
import { ApiService, Project, Version } from '../../services/api.service';
|
21 |
+
import { LocaleManagerService } from '../../services/locale-manager.service';
|
22 |
import ConfirmDialogComponent from '../confirm-dialog/confirm-dialog.component';
|
23 |
|
24 |
// Interfaces for multi-language support
|
|
|
27 |
example: string;
|
28 |
}
|
29 |
|
30 |
+
interface LocalizedCaption {
|
31 |
+
locale_code: string;
|
32 |
+
caption: string;
|
33 |
+
}
|
34 |
+
|
35 |
+
interface Locale {
|
36 |
+
code: string;
|
37 |
+
name: string;
|
38 |
+
}
|
39 |
+
|
40 |
@Component({
|
41 |
selector: 'app-version-edit-dialog',
|
42 |
standalone: true,
|
|
|
58 |
MatExpansionModule,
|
59 |
MatDividerModule,
|
60 |
MatProgressBarModule,
|
61 |
+
MatListModule,
|
62 |
+
MatProgressSpinnerModule
|
63 |
],
|
64 |
templateUrl: './version-edit-dialog.component.html',
|
65 |
styleUrls: ['./version-edit-dialog.component.scss']
|
|
|
69 |
versions: Version[] = [];
|
70 |
selectedVersion: Version | null = null;
|
71 |
versionForm!: FormGroup;
|
|
|
72 |
loading = false;
|
73 |
saving = false;
|
74 |
publishing = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
testing = false;
|
76 |
+
testInput = '';
|
77 |
+
testResult: any = null;
|
78 |
+
isDirty = false;
|
79 |
|
80 |
+
// Multi-language support
|
81 |
selectedExampleLocale: string = 'tr';
|
82 |
+
availableLocales: Locale[] = [];
|
83 |
|
84 |
constructor(
|
85 |
private fb: FormBuilder,
|
86 |
+
private api: ApiService,
|
87 |
+
private localeService: LocaleManagerService,
|
88 |
private snackBar: MatSnackBar,
|
89 |
private dialog: MatDialog,
|
90 |
public dialogRef: MatDialogRef<VersionEditDialogComponent>,
|
91 |
+
@Inject(MAT_DIALOG_DATA) public data: { project: Project }
|
92 |
) {
|
93 |
this.project = data.project;
|
|
|
94 |
this.selectedExampleLocale = this.project.default_locale || 'tr';
|
95 |
}
|
96 |
|
97 |
ngOnInit() {
|
98 |
this.initializeForm();
|
99 |
+
this.loadVersions();
|
100 |
+
this.loadAvailableLocales();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
101 |
}
|
102 |
|
103 |
initializeForm() {
|
104 |
this.versionForm = this.fb.group({
|
105 |
+
caption: [''],
|
106 |
+
prompt: ['', Validators.required],
|
107 |
+
welcome_prompt: [''],
|
108 |
+
model: ['gpt-3.5-turbo'],
|
109 |
+
generation_config: this.fb.group({
|
110 |
+
max_new_tokens: [512],
|
111 |
+
temperature: [0.7],
|
112 |
+
top_p: [0.9],
|
113 |
+
top_k: [null],
|
114 |
+
do_sample: [true]
|
115 |
+
}),
|
116 |
+
fine_tune: this.fb.group({
|
117 |
+
enabled: [false],
|
118 |
+
adapter_path: ['']
|
119 |
}),
|
120 |
+
intents: this.fb.array([])
|
|
|
121 |
});
|
122 |
|
123 |
+
// Mark form as dirty on any change
|
124 |
+
this.versionForm.valueChanges.subscribe(() => {
|
125 |
+
this.isDirty = true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
});
|
127 |
}
|
128 |
|
129 |
+
async loadAvailableLocales() {
|
130 |
+
// Get supported locales from project
|
131 |
+
const supportedCodes = [
|
132 |
+
this.project.default_locale,
|
133 |
+
...(this.project.supported_languages || [])
|
134 |
+
].filter(Boolean);
|
135 |
+
|
136 |
+
// Get locale details
|
137 |
+
for (const code of supportedCodes) {
|
138 |
+
const localeInfo = await this.localeService.getLocaleDetails(code).toPromise();
|
139 |
+
if (localeInfo) {
|
140 |
+
this.availableLocales.push({
|
141 |
+
code: localeInfo.code,
|
142 |
+
name: localeInfo.name
|
143 |
+
});
|
144 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
145 |
}
|
146 |
+
}
|
|
|
|
|
|
|
|
|
|
|
147 |
|
148 |
+
getAvailableLocales(): Locale[] {
|
149 |
+
return this.availableLocales;
|
150 |
}
|
151 |
+
|
152 |
+
getLocaleName(localeCode: string): string {
|
153 |
+
const locale = this.availableLocales.find(l => l.code === localeCode);
|
154 |
+
return locale?.name || localeCode;
|
155 |
+
}
|
156 |
+
|
157 |
+
loadVersions() {
|
158 |
this.loading = true;
|
159 |
+
this.api.getProjectVersions(this.project.id).subscribe({
|
160 |
+
next: (versions) => {
|
161 |
+
this.versions = versions;
|
162 |
+
this.loading = false;
|
|
|
163 |
|
164 |
+
// Auto-select if only one version
|
165 |
+
if (versions.length === 1) {
|
166 |
+
this.onVersionChange(versions[0]);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
167 |
}
|
168 |
+
},
|
169 |
+
error: (error) => {
|
170 |
+
console.error('Error loading versions:', error);
|
171 |
+
this.snackBar.open('Failed to load versions', 'Close', { duration: 3000 });
|
172 |
+
this.loading = false;
|
173 |
}
|
174 |
+
});
|
|
|
|
|
|
|
|
|
175 |
}
|
176 |
|
177 |
+
onVersionChange(version: Version | null) {
|
178 |
+
if (!version) return;
|
179 |
+
|
180 |
+
this.selectedVersion = version;
|
181 |
+
this.loading = true;
|
182 |
+
this.isDirty = false;
|
183 |
+
|
184 |
+
this.api.getVersionDetails(this.project.id, version.no).subscribe({
|
185 |
+
next: (details) => {
|
186 |
+
this.populateForm(details);
|
187 |
+
this.loading = false;
|
188 |
+
},
|
189 |
+
error: (error) => {
|
190 |
+
console.error('Error loading version details:', error);
|
191 |
+
this.snackBar.open('Failed to load version details', 'Close', { duration: 3000 });
|
192 |
+
this.loading = false;
|
193 |
+
}
|
194 |
});
|
195 |
+
}
|
196 |
+
|
197 |
+
populateForm(version: any) {
|
198 |
+
// Clear existing intents
|
199 |
+
const intentsArray = this.versionForm.get('intents') as FormArray;
|
200 |
+
while (intentsArray.length > 0) {
|
201 |
+
intentsArray.removeAt(0);
|
202 |
+
}
|
203 |
+
|
204 |
+
// Populate basic fields
|
205 |
+
this.versionForm.patchValue({
|
206 |
+
caption: version.caption || '',
|
207 |
+
prompt: version.prompt || '',
|
208 |
+
welcome_prompt: version.welcome_prompt || '',
|
209 |
+
model: version.model || 'gpt-3.5-turbo',
|
210 |
+
generation_config: version.generation_config || {},
|
211 |
+
fine_tune: version.fine_tune || { enabled: false }
|
212 |
+
});
|
213 |
+
|
214 |
+
// Add intents
|
215 |
+
if (version.intents && Array.isArray(version.intents)) {
|
216 |
+
version.intents.forEach((intent: any) => {
|
217 |
+
intentsArray.push(this.createIntentFormGroup(intent));
|
218 |
});
|
219 |
}
|
220 |
+
|
221 |
+
this.isDirty = false;
|
222 |
}
|
223 |
|
224 |
+
createIntentFormGroup(intent?: any): FormGroup {
|
225 |
return this.fb.group({
|
226 |
+
name: [intent?.name || '', Validators.required],
|
227 |
+
caption: [intent?.caption || ''],
|
228 |
+
requiresApproval: [intent?.requiresApproval || false],
|
229 |
+
dependencies: [intent?.dependencies || []],
|
230 |
+
examples: [intent?.examples || []],
|
231 |
+
detection_prompt: [intent?.detection_prompt || '', Validators.required],
|
232 |
+
parameters: this.fb.array(
|
233 |
+
(intent?.parameters || []).map((p: any) => this.createParameterFormGroup(p))
|
234 |
+
),
|
235 |
+
action: [intent?.action || ''],
|
236 |
+
fallback_timeout_prompt: [intent?.fallback_timeout_prompt || ''],
|
237 |
+
fallback_error_prompt: [intent?.fallback_error_prompt || '']
|
238 |
+
});
|
239 |
+
}
|
240 |
+
|
241 |
+
createParameterFormGroup(param?: any): FormGroup {
|
242 |
+
return this.fb.group({
|
243 |
+
name: [param?.name || '', Validators.required],
|
244 |
+
caption: [param?.caption || []],
|
245 |
+
type: [param?.type || 'str', Validators.required],
|
246 |
+
required: [param?.required !== false],
|
247 |
+
variable_name: [param?.variable_name || '', Validators.required],
|
248 |
+
extraction_prompt: [param?.extraction_prompt || ''],
|
249 |
+
validation_regex: [param?.validation_regex || ''],
|
250 |
+
invalid_prompt: [param?.invalid_prompt || ''],
|
251 |
+
type_error_prompt: [param?.type_error_prompt || '']
|
252 |
});
|
253 |
}
|
254 |
|
|
|
277 |
return [];
|
278 |
}
|
279 |
|
280 |
+
getParameterCaptionDisplay(captions: LocalizedCaption[]): string {
|
281 |
+
if (!captions || !Array.isArray(captions) || captions.length === 0) {
|
282 |
+
return '(No caption)';
|
283 |
+
}
|
284 |
+
|
285 |
+
// Try to find caption for selected locale
|
286 |
+
const selectedCaption = captions.find(c => c.locale_code === this.selectedExampleLocale);
|
287 |
+
if (selectedCaption) return selectedCaption.caption;
|
288 |
+
|
289 |
+
// Try default locale
|
290 |
+
const defaultCaption = captions.find(c => c.locale_code === this.project.default_locale);
|
291 |
+
if (defaultCaption) return defaultCaption.caption;
|
292 |
+
|
293 |
+
// Return first available caption
|
294 |
+
return captions[0].caption;
|
295 |
+
}
|
296 |
+
|
297 |
addLocalizedExample(intentIndex: number, example: string) {
|
298 |
if (!example.trim()) return;
|
299 |
|
|
|
327 |
this.isDirty = true;
|
328 |
}
|
329 |
|
330 |
+
addParameter(intentIndex: number) {
|
331 |
+
const parameters = this.getIntentParameters(intentIndex);
|
332 |
+
parameters.push(this.createParameterFormGroup());
|
333 |
+
this.isDirty = true;
|
334 |
+
}
|
335 |
+
|
336 |
+
removeParameter(intentIndex: number, paramIndex: number) {
|
337 |
+
const parameters = this.getIntentParameters(intentIndex);
|
338 |
+
parameters.removeAt(paramIndex);
|
339 |
+
this.isDirty = true;
|
340 |
+
}
|
341 |
+
|
342 |
// Check if version can be edited
|
343 |
get canEdit(): boolean {
|
344 |
return !this.selectedVersion?.published;
|
|
|
346 |
|
347 |
addIntent() {
|
348 |
this.intents.push(this.createIntentFormGroup());
|
349 |
+
this.isDirty = true;
|
350 |
}
|
351 |
|
352 |
removeIntent(index: number) {
|
|
|
364 |
dialogRef.afterClosed().subscribe(confirmed => {
|
365 |
if (confirmed) {
|
366 |
this.intents.removeAt(index);
|
367 |
+
this.isDirty = true;
|
368 |
}
|
369 |
});
|
370 |
}
|
|
|
415 |
});
|
416 |
}
|
417 |
|
418 |
+
async getAvailableAPIs() {
|
419 |
+
return this.api.getAPIs().toPromise();
|
|
|
|
|
|
|
|
|
|
|
|
|
420 |
}
|
421 |
|
422 |
async createVersion() {
|
|
|
448 |
// Copy from selected version
|
449 |
const sourceVersion = this.versions.find(v => v.no === result.selectedValue);
|
450 |
if (sourceVersion) {
|
451 |
+
const details = await this.api.getVersionDetails(this.project.id, sourceVersion.no).toPromise();
|
452 |
newVersionData = {
|
453 |
+
...details,
|
454 |
no: undefined,
|
455 |
published: false,
|
456 |
last_update_date: undefined,
|
457 |
+
caption: `Copy of version ${sourceVersion.no}`
|
|
|
458 |
};
|
459 |
}
|
460 |
} else {
|
461 |
// Create blank version
|
462 |
newVersionData = {
|
463 |
+
caption: 'New Version',
|
464 |
+
prompt: '',
|
465 |
+
welcome_prompt: '',
|
466 |
+
model: 'gpt-3.5-turbo',
|
467 |
+
generation_config: {
|
468 |
+
max_new_tokens: 512,
|
469 |
+
temperature: 0.7,
|
470 |
+
top_p: 0.9,
|
471 |
+
do_sample: true
|
|
|
|
|
|
|
|
|
|
|
|
|
472 |
},
|
473 |
+
intents: []
|
|
|
474 |
};
|
475 |
}
|
476 |
+
|
477 |
+
// Create new version
|
478 |
+
const newVersion = await this.api.createVersion(this.project.id, newVersionData).toPromise();
|
479 |
+
|
480 |
+
// Reload versions and select the new one
|
481 |
+
await this.loadVersions();
|
482 |
+
this.onVersionChange(newVersion);
|
483 |
+
|
484 |
+
this.snackBar.open('Version created successfully', 'Close', { duration: 3000 });
|
485 |
} catch (error) {
|
486 |
+
console.error('Error creating version:', error);
|
487 |
this.snackBar.open('Failed to create version', 'Close', { duration: 3000 });
|
488 |
} finally {
|
489 |
this.loading = false;
|
|
|
492 |
});
|
493 |
}
|
494 |
|
495 |
+
async copyVersion() {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
496 |
if (!this.selectedVersion) return;
|
497 |
+
|
498 |
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
499 |
+
width: '400px',
|
500 |
data: {
|
501 |
+
title: 'Copy Version',
|
502 |
+
message: `Create a copy of version ${this.selectedVersion.no}?`,
|
503 |
+
confirmText: 'Copy',
|
504 |
+
cancelText: 'Cancel'
|
505 |
}
|
506 |
});
|
507 |
|
508 |
dialogRef.afterClosed().subscribe(async (confirmed) => {
|
509 |
+
if (confirmed) {
|
510 |
+
this.loading = true;
|
511 |
try {
|
512 |
+
const details = await this.api.getVersionDetails(this.project.id, this.selectedVersion!.no).toPromise();
|
513 |
+
const copyData = {
|
514 |
+
...details,
|
515 |
+
no: undefined,
|
516 |
+
published: false,
|
517 |
+
last_update_date: undefined,
|
518 |
+
caption: `Copy of version ${this.selectedVersion!.no}`
|
519 |
+
};
|
520 |
|
521 |
+
const newVersion = await this.api.createVersion(this.project.id, copyData).toPromise();
|
522 |
+
|
523 |
+
await this.loadVersions();
|
524 |
+
this.onVersionChange(newVersion);
|
525 |
|
526 |
+
this.snackBar.open('Version copied successfully', 'Close', { duration: 3000 });
|
527 |
+
} catch (error) {
|
528 |
+
console.error('Error copying version:', error);
|
529 |
+
this.snackBar.open('Failed to copy version', 'Close', { duration: 3000 });
|
|
|
530 |
} finally {
|
531 |
+
this.loading = false;
|
532 |
}
|
533 |
}
|
534 |
});
|
535 |
}
|
536 |
|
537 |
+
async compareVersions() {
|
538 |
+
const { default: VersionCompareDialogComponent } = await import('../version-compare-dialog/version-compare-dialog.component');
|
539 |
+
|
540 |
+
this.dialog.open(VersionCompareDialogComponent, {
|
541 |
+
width: '90vw',
|
542 |
+
maxWidth: '1200px',
|
543 |
+
data: {
|
544 |
+
versions: this.versions,
|
545 |
+
selectedVersion: this.selectedVersion
|
546 |
+
}
|
547 |
+
});
|
548 |
+
}
|
549 |
+
|
550 |
async deleteVersion() {
|
551 |
if (!this.selectedVersion || this.selectedVersion.published) return;
|
552 |
+
|
553 |
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
554 |
width: '400px',
|
555 |
data: {
|
556 |
title: 'Delete Version',
|
557 |
+
message: `Are you sure you want to delete version ${this.selectedVersion.no}? This action cannot be undone.`,
|
558 |
confirmText: 'Delete',
|
559 |
confirmColor: 'warn'
|
560 |
}
|
561 |
});
|
562 |
|
563 |
dialogRef.afterClosed().subscribe(async (confirmed) => {
|
564 |
+
if (confirmed) {
|
565 |
+
this.loading = true;
|
566 |
try {
|
567 |
+
await this.api.deleteVersion(this.project.id, this.selectedVersion!.no).toPromise();
|
|
|
|
|
|
|
|
|
|
|
568 |
|
569 |
+
this.selectedVersion = null;
|
570 |
+
await this.loadVersions();
|
|
|
|
|
|
|
|
|
|
|
|
|
571 |
|
572 |
+
this.snackBar.open('Version deleted successfully', 'Close', { duration: 3000 });
|
573 |
+
} catch (error) {
|
574 |
+
console.error('Error deleting version:', error);
|
575 |
+
this.snackBar.open('Failed to delete version', 'Close', { duration: 3000 });
|
576 |
+
} finally {
|
577 |
+
this.loading = false;
|
578 |
}
|
579 |
}
|
580 |
});
|
581 |
}
|
582 |
|
583 |
+
saveVersion() {
|
584 |
+
if (!this.selectedVersion || !this.canEdit || this.versionForm.invalid) return;
|
585 |
+
|
586 |
+
this.saving = true;
|
587 |
+
const formValue = this.versionForm.value;
|
588 |
+
|
589 |
+
this.api.updateVersion(this.project.id, this.selectedVersion.no, formValue).subscribe({
|
590 |
+
next: () => {
|
591 |
+
this.snackBar.open('Version saved successfully', 'Close', { duration: 3000 });
|
592 |
+
this.isDirty = false;
|
593 |
+
this.saving = false;
|
594 |
+
},
|
595 |
+
error: (error) => {
|
596 |
+
console.error('Error saving version:', error);
|
597 |
+
this.snackBar.open('Failed to save version', 'Close', { duration: 3000 });
|
598 |
+
this.saving = false;
|
599 |
+
}
|
600 |
+
});
|
601 |
+
}
|
602 |
|
603 |
+
publishVersion() {
|
604 |
+
if (!this.selectedVersion || this.selectedVersion.published || this.isDirty) return;
|
605 |
+
|
606 |
+
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
607 |
+
width: '500px',
|
608 |
+
data: {
|
609 |
+
title: 'Publish Version',
|
610 |
+
message: `Publishing version ${this.selectedVersion.no} will make it the active version for all users. Published versions cannot be edited. Continue?`,
|
611 |
+
confirmText: 'Publish',
|
612 |
+
confirmColor: 'accent'
|
613 |
+
}
|
614 |
+
});
|
615 |
+
|
616 |
+
dialogRef.afterClosed().subscribe((confirmed) => {
|
617 |
+
if (confirmed) {
|
618 |
+
this.publishing = true;
|
619 |
+
|
620 |
+
this.api.publishVersion(this.project.id, this.selectedVersion!.no).subscribe({
|
621 |
+
next: () => {
|
622 |
+
this.snackBar.open('Version published successfully', 'Close', { duration: 3000 });
|
623 |
+
this.publishing = false;
|
624 |
+
|
625 |
+
// Reload to update status
|
626 |
+
this.loadVersions();
|
627 |
+
this.onVersionChange(this.selectedVersion);
|
628 |
+
},
|
629 |
+
error: (error) => {
|
630 |
+
console.error('Error publishing version:', error);
|
631 |
+
this.snackBar.open('Failed to publish version', 'Close', { duration: 3000 });
|
632 |
+
this.publishing = false;
|
633 |
+
}
|
634 |
+
});
|
635 |
+
}
|
636 |
+
});
|
637 |
+
}
|
638 |
+
|
639 |
+
testIntentDetection() {
|
640 |
+
if (!this.testInput || !this.selectedVersion) return;
|
641 |
+
|
642 |
this.testing = true;
|
643 |
this.testResult = null;
|
644 |
+
|
645 |
// Simulate intent detection test
|
646 |
setTimeout(() => {
|
647 |
+
const intents = this.intents.value;
|
|
|
648 |
|
649 |
+
// Simple simulation - in real app, this would call the backend
|
650 |
+
const randomIntent = intents[Math.floor(Math.random() * intents.length)];
|
651 |
+
|
652 |
+
if (randomIntent && Math.random() > 0.3) {
|
653 |
+
this.testResult = {
|
654 |
+
intent: randomIntent.name,
|
655 |
+
confidence: 0.75 + Math.random() * 0.20,
|
656 |
+
parameters: randomIntent.parameters.map((p: any) => ({
|
657 |
+
name: p.name,
|
658 |
+
extracted: Math.random() > 0.5,
|
659 |
+
value: Math.random() > 0.5 ? 'Sample Value' : null
|
660 |
+
}))
|
661 |
+
};
|
662 |
+
} else {
|
663 |
+
this.testResult = {
|
664 |
+
intent: null,
|
665 |
+
confidence: 0
|
666 |
+
};
|
|
|
|
|
|
|
|
|
|
|
667 |
}
|
668 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
669 |
this.testing = false;
|
670 |
}, 1500);
|
671 |
}
|
672 |
|
673 |
+
close() {
|
674 |
+
if (this.isDirty) {
|
675 |
+
const dialogRef = this.dialog.open(ConfirmDialogComponent, {
|
676 |
+
width: '400px',
|
677 |
+
data: {
|
678 |
+
title: 'Unsaved Changes',
|
679 |
+
message: 'You have unsaved changes. Do you want to save before closing?',
|
680 |
+
confirmText: 'Save & Close',
|
681 |
+
cancelText: 'Discard Changes',
|
682 |
+
showThirdOption: true,
|
683 |
+
thirdOptionText: 'Cancel'
|
684 |
+
}
|
685 |
+
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
686 |
|
687 |
+
dialogRef.afterClosed().subscribe(result => {
|
688 |
+
if (result === 'confirm') {
|
689 |
+
this.saveVersion();
|
690 |
+
this.dialogRef.close();
|
691 |
+
} else if (result === 'cancel') {
|
692 |
+
this.dialogRef.close();
|
693 |
+
}
|
694 |
+
// If result is null or 'third', don't close
|
695 |
+
});
|
696 |
+
} else {
|
697 |
+
this.dialogRef.close();
|
698 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
699 |
}
|
700 |
}
|