ciyidogan commited on
Commit
9a94981
·
verified ·
1 Parent(s): c78df6c

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
@@ -19,6 +19,12 @@ 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
  @Component({
23
  selector: 'app-version-edit-dialog',
24
  standalone: true,
@@ -61,6 +67,9 @@ export default class VersionEditDialogComponent implements OnInit {
61
  testUserMessage = '';
62
  testResult: any = null;
63
  testing = false;
 
 
 
64
 
65
  constructor(
66
  private fb: FormBuilder,
@@ -72,6 +81,7 @@ export default class VersionEditDialogComponent implements OnInit {
72
  ) {
73
  this.project = data.project;
74
  this.versions = [...this.project.versions].sort((a, b) => b.no - a.no);
 
75
  }
76
 
77
  ngOnInit() {
@@ -88,7 +98,6 @@ export default class VersionEditDialogComponent implements OnInit {
88
  this.versionForm.valueChanges.subscribe(() => {
89
  this.isDirty = true;
90
  });
91
-
92
  }
93
 
94
  initializeForm() {
@@ -133,7 +142,7 @@ export default class VersionEditDialogComponent implements OnInit {
133
  no: version.no,
134
  caption: version.caption || '',
135
  published: version.published || false,
136
- general_prompt: (version as any).general_prompt || '', // Backend'den gelen general_prompt
137
  last_update_date: version.last_update_date || ''
138
  });
139
 
@@ -194,23 +203,15 @@ export default class VersionEditDialogComponent implements OnInit {
194
  const group = this.fb.group({
195
  name: [intent.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9-]+$/)]],
196
  caption: [intent.caption || ''],
197
- locale: [intent.locale || 'tr-TR'],
198
  detection_prompt: [intent.detection_prompt || '', Validators.required],
199
- examples: this.fb.array([]),
200
  parameters: this.fb.array([]),
201
  action: [intent.action || '', Validators.required],
202
  fallback_timeout_prompt: [intent.fallback_timeout_prompt || ''],
203
  fallback_error_prompt: [intent.fallback_error_prompt || '']
204
  });
205
 
206
- // Examples ve parameters'ı ayrı olarak ekle
207
- if (intent.examples && Array.isArray(intent.examples)) {
208
- const examplesArray = group.get('examples') as FormArray;
209
- intent.examples.forEach((example: any) => {
210
- examplesArray.push(this.fb.control(example));
211
- });
212
- }
213
-
214
  if (intent.parameters && Array.isArray(intent.parameters)) {
215
  const parametersArray = group.get('parameters') as FormArray;
216
  intent.parameters.forEach((param: any) => {
@@ -221,13 +222,6 @@ export default class VersionEditDialogComponent implements OnInit {
221
  return group;
222
  }
223
 
224
- private populateIntentParameters(intentFormGroup: FormGroup, parameters: any[]) {
225
- const parametersArray = intentFormGroup.get('parameters') as FormArray;
226
- parameters.forEach(param => {
227
- parametersArray.push(this.createParameterFormGroup(param));
228
- });
229
- }
230
-
231
  createParameterFormGroup(param: any = {}): FormGroup {
232
  return this.fb.group({
233
  name: [param.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_]+$/)]],
@@ -250,8 +244,59 @@ export default class VersionEditDialogComponent implements OnInit {
250
  return this.intents.at(intentIndex).get('parameters') as FormArray;
251
  }
252
 
253
- getIntentExamples(intentIndex: number): FormArray {
254
- return this.intents.at(intentIndex).get('examples') as FormArray;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  }
256
 
257
  addIntent() {
@@ -300,30 +345,25 @@ export default class VersionEditDialogComponent implements OnInit {
300
 
301
  dialogRef.afterClosed().subscribe(result => {
302
  if (result) {
303
- // FormArray'leri yeniden oluştur
304
  intent.patchValue({
305
  name: result.name,
306
  caption: result.caption,
307
- locale: result.locale,
308
  detection_prompt: result.detection_prompt,
 
309
  action: result.action,
310
  fallback_timeout_prompt: result.fallback_timeout_prompt,
311
  fallback_error_prompt: result.fallback_error_prompt
312
  });
313
 
314
- // Examples'ı güncelle
315
- const examplesArray = intent.get('examples') as FormArray;
316
- examplesArray.clear();
317
- (result.examples || []).forEach((example: string) => {
318
- examplesArray.push(this.fb.control(example));
319
- });
320
-
321
- // Parameters'ı güncelle
322
  const parametersArray = intent.get('parameters') as FormArray;
323
  parametersArray.clear();
324
  (result.parameters || []).forEach((param: any) => {
325
  parametersArray.push(this.createParameterFormGroup(param));
326
  });
 
 
327
  }
328
  });
329
  }
@@ -338,18 +378,6 @@ export default class VersionEditDialogComponent implements OnInit {
338
  parameters.removeAt(paramIndex);
339
  }
340
 
341
- addExample(intentIndex: number, example: string) {
342
- if (example.trim()) {
343
- const examples = this.getIntentExamples(intentIndex);
344
- examples.push(this.fb.control(example));
345
- }
346
- }
347
-
348
- removeExample(intentIndex: number, exampleIndex: number) {
349
- const examples = this.getIntentExamples(intentIndex);
350
- examples.removeAt(exampleIndex);
351
- }
352
-
353
  async createVersion() {
354
  const publishedVersions = this.versions.filter(v => v.published);
355
 
@@ -359,7 +387,7 @@ export default class VersionEditDialogComponent implements OnInit {
359
  title: 'Create New Version',
360
  message: 'Which published version would you like to use as a base for the new version?',
361
  showDropdown: true,
362
- dropdownOptions: publishedVersions.map(v => ({ // ✅ publishedVersions kullan
363
  value: v.no,
364
  label: `Version ${v.no} - ${v.caption || 'No description'}`
365
  })),
@@ -427,8 +455,8 @@ export default class VersionEditDialogComponent implements OnInit {
427
  }
428
 
429
  async saveVersion() {
430
- if (!this.selectedVersion) {
431
- this.snackBar.open('No version selected', 'Close', { duration: 3000 });
432
  return;
433
  }
434
 
@@ -463,7 +491,7 @@ export default class VersionEditDialogComponent implements OnInit {
463
  // updateData'yı backend'in beklediği formatta hazırla
464
  const updateData = {
465
  caption: formValue.caption,
466
- general_prompt: formValue.general_prompt || '', // Bu alan eksikti
467
  llm: formValue.llm,
468
  intents: formValue.intents.map((intent: any) => ({
469
  name: intent.name,
@@ -513,8 +541,13 @@ export default class VersionEditDialogComponent implements OnInit {
513
  console.error('Save error:', error);
514
 
515
  if (error.status === 409) {
516
- // Race condition handling için ayrı metod çağır
517
  await this.handleRaceCondition(currentVersion);
 
 
 
 
 
518
  } else {
519
  const errorMessage = error.error?.detail || error.message || 'Failed to save version';
520
  this.snackBar.open(errorMessage, 'Close', {
@@ -527,7 +560,7 @@ export default class VersionEditDialogComponent implements OnInit {
527
  }
528
  }
529
 
530
- // Race condition handling için ayrı metod
531
  private async handleRaceCondition(currentVersion: Version) {
532
  const formValue = this.versionForm.getRawValue();
533
 
@@ -682,8 +715,11 @@ export default class VersionEditDialogComponent implements OnInit {
682
  let confidence = 0;
683
 
684
  for (const intent of intents) {
685
- for (const example of intent.examples || []) {
686
- if (this.testUserMessage.toLowerCase().includes(example.toLowerCase())) {
 
 
 
687
  detectedIntent = intent.name;
688
  confidence = 0.95;
689
  break;
 
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
23
+ interface LocalizedExample {
24
+ locale_code: string;
25
+ example: string;
26
+ }
27
+
28
  @Component({
29
  selector: 'app-version-edit-dialog',
30
  standalone: true,
 
67
  testUserMessage = '';
68
  testResult: any = null;
69
  testing = false;
70
+
71
+ // Locale for examples
72
+ selectedExampleLocale: string = 'tr';
73
 
74
  constructor(
75
  private fb: FormBuilder,
 
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() {
 
98
  this.versionForm.valueChanges.subscribe(() => {
99
  this.isDirty = true;
100
  });
 
101
  }
102
 
103
  initializeForm() {
 
142
  no: version.no,
143
  caption: version.caption || '',
144
  published: version.published || false,
145
+ general_prompt: (version as any).general_prompt || '',
146
  last_update_date: version.last_update_date || ''
147
  });
148
 
 
203
  const group = this.fb.group({
204
  name: [intent.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9-]+$/)]],
205
  caption: [intent.caption || ''],
 
206
  detection_prompt: [intent.detection_prompt || '', Validators.required],
207
+ examples: [intent.examples || []], // Store as array, not FormArray
208
  parameters: this.fb.array([]),
209
  action: [intent.action || '', Validators.required],
210
  fallback_timeout_prompt: [intent.fallback_timeout_prompt || ''],
211
  fallback_error_prompt: [intent.fallback_error_prompt || '']
212
  });
213
 
214
+ // Parameters'ı ayrı olarak ekle
 
 
 
 
 
 
 
215
  if (intent.parameters && Array.isArray(intent.parameters)) {
216
  const parametersArray = group.get('parameters') as FormArray;
217
  intent.parameters.forEach((param: any) => {
 
222
  return group;
223
  }
224
 
 
 
 
 
 
 
 
225
  createParameterFormGroup(param: any = {}): FormGroup {
226
  return this.fb.group({
227
  name: [param.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_]+$/)]],
 
244
  return this.intents.at(intentIndex).get('parameters') as FormArray;
245
  }
246
 
247
+ // LocalizedExample support methods
248
+ getLocalizedExamples(examples: any[], locale: string): LocalizedExample[] {
249
+ if (!examples || !Array.isArray(examples)) return [];
250
+
251
+ // Check if examples are in new format
252
+ if (examples.length > 0 && typeof examples[0] === 'object' && 'locale_code' in examples[0]) {
253
+ return examples.filter(ex => ex.locale_code === locale);
254
+ }
255
+
256
+ // Old format - convert to new
257
+ if (typeof examples[0] === 'string') {
258
+ return examples.map(ex => ({ locale_code: locale, example: ex }));
259
+ }
260
+
261
+ return [];
262
+ }
263
+
264
+ addLocalizedExample(intentIndex: number, example: string) {
265
+ if (!example.trim()) return;
266
+
267
+ const intent = this.intents.at(intentIndex);
268
+ const currentExamples = intent.get('examples')?.value || [];
269
+
270
+ // Check if already exists
271
+ const exists = currentExamples.some((ex: any) =>
272
+ ex.locale_code === this.selectedExampleLocale && ex.example === example.trim()
273
+ );
274
+
275
+ if (!exists) {
276
+ const newExamples = [...currentExamples, {
277
+ locale_code: this.selectedExampleLocale,
278
+ example: example.trim()
279
+ }];
280
+ intent.patchValue({ examples: newExamples });
281
+ this.isDirty = true;
282
+ }
283
+ }
284
+
285
+ removeLocalizedExample(intentIndex: number, exampleToRemove: LocalizedExample) {
286
+ const intent = this.intents.at(intentIndex);
287
+ const currentExamples = intent.get('examples')?.value || [];
288
+
289
+ const newExamples = currentExamples.filter((ex: any) =>
290
+ !(ex.locale_code === exampleToRemove.locale_code && ex.example === exampleToRemove.example)
291
+ );
292
+
293
+ intent.patchValue({ examples: newExamples });
294
+ this.isDirty = true;
295
+ }
296
+
297
+ // Check if version can be edited
298
+ get canEdit(): boolean {
299
+ return !this.selectedVersion?.published;
300
  }
301
 
302
  addIntent() {
 
345
 
346
  dialogRef.afterClosed().subscribe(result => {
347
  if (result) {
348
+ // Update intent with result
349
  intent.patchValue({
350
  name: result.name,
351
  caption: result.caption,
 
352
  detection_prompt: result.detection_prompt,
353
+ examples: result.examples || [],
354
  action: result.action,
355
  fallback_timeout_prompt: result.fallback_timeout_prompt,
356
  fallback_error_prompt: result.fallback_error_prompt
357
  });
358
 
359
+ // Update parameters
 
 
 
 
 
 
 
360
  const parametersArray = intent.get('parameters') as FormArray;
361
  parametersArray.clear();
362
  (result.parameters || []).forEach((param: any) => {
363
  parametersArray.push(this.createParameterFormGroup(param));
364
  });
365
+
366
+ this.isDirty = true;
367
  }
368
  });
369
  }
 
378
  parameters.removeAt(paramIndex);
379
  }
380
 
 
 
 
 
 
 
 
 
 
 
 
 
381
  async createVersion() {
382
  const publishedVersions = this.versions.filter(v => v.published);
383
 
 
387
  title: 'Create New Version',
388
  message: 'Which published version would you like to use as a base for the new version?',
389
  showDropdown: true,
390
+ dropdownOptions: publishedVersions.map(v => ({
391
  value: v.no,
392
  label: `Version ${v.no} - ${v.caption || 'No description'}`
393
  })),
 
455
  }
456
 
457
  async saveVersion() {
458
+ if (!this.selectedVersion || !this.canEdit) {
459
+ this.snackBar.open('Cannot save published version', 'Close', { duration: 3000 });
460
  return;
461
  }
462
 
 
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,
 
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', {
 
560
  }
561
  }
562
 
563
+ // Race condition handling
564
  private async handleRaceCondition(currentVersion: Version) {
565
  const formValue = this.versionForm.getRawValue();
566
 
 
715
  let confidence = 0;
716
 
717
  for (const intent of intents) {
718
+ // Check examples in all locales
719
+ const allExamples = intent.examples || [];
720
+ for (const example of allExamples) {
721
+ const exampleText = typeof example === 'string' ? example : example.example;
722
+ if (this.testUserMessage.toLowerCase().includes(exampleText.toLowerCase())) {
723
  detectedIntent = intent.name;
724
  confidence = 0.95;
725
  break;