Spaces:
Paused
Paused
| import { Component, Inject, OnInit } from '@angular/core'; | |
| import { CommonModule } from '@angular/common'; | |
| import { FormBuilder, FormGroup, Validators, ReactiveFormsModule, FormArray, FormsModule } from '@angular/forms'; | |
| import { MatDialogRef, MAT_DIALOG_DATA, MatDialogModule, MatDialog } from '@angular/material/dialog'; | |
| import { MatTabsModule } from '@angular/material/tabs'; | |
| import { MatFormFieldModule } from '@angular/material/form-field'; | |
| import { MatInputModule } from '@angular/material/input'; | |
| import { MatSelectModule } from '@angular/material/select'; | |
| import { MatCheckboxModule } from '@angular/material/checkbox'; | |
| import { MatButtonModule } from '@angular/material/button'; | |
| import { MatIconModule } from '@angular/material/icon'; | |
| import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; | |
| import { MatTableModule } from '@angular/material/table'; | |
| import { MatChipsModule } from '@angular/material/chips'; | |
| import { MatExpansionModule } from '@angular/material/expansion'; | |
| import { MatDividerModule } from '@angular/material/divider'; | |
| import { MatProgressBarModule } from '@angular/material/progress-bar'; | |
| import { MatListModule } from '@angular/material/list'; | |
| import { ApiService, Project, Version } from '../../services/api.service'; | |
| import ConfirmDialogComponent from '../confirm-dialog/confirm-dialog.component'; | |
| ({ | |
| selector: 'app-version-edit-dialog', | |
| standalone: true, | |
| imports: [ | |
| CommonModule, | |
| ReactiveFormsModule, | |
| FormsModule, | |
| MatDialogModule, | |
| MatTabsModule, | |
| MatFormFieldModule, | |
| MatInputModule, | |
| MatSelectModule, | |
| MatCheckboxModule, | |
| MatButtonModule, | |
| MatIconModule, | |
| MatSnackBarModule, | |
| MatTableModule, | |
| MatChipsModule, | |
| MatExpansionModule, | |
| MatDividerModule, | |
| MatProgressBarModule, | |
| MatListModule | |
| ], | |
| templateUrl: './version-edit-dialog.component.html', | |
| styleUrls: ['./version-edit-dialog.component.scss'] | |
| }) | |
| export default class VersionEditDialogComponent implements OnInit { | |
| project: Project; | |
| versions: Version[] = []; | |
| selectedVersion: Version | null = null; | |
| versionForm!: FormGroup; | |
| loading = false; | |
| saving = false; | |
| publishing = false; | |
| creating = false; | |
| isDirty = false; | |
| selectedTabIndex = 0; | |
| testUserMessage = ''; | |
| testResult: any = null; | |
| testing = false; | |
| constructor( | |
| private fb: FormBuilder, | |
| private apiService: ApiService, | |
| private snackBar: MatSnackBar, | |
| private dialog: MatDialog, | |
| public dialogRef: MatDialogRef<VersionEditDialogComponent>, | |
| (MAT_DIALOG_DATA) public data: any | |
| ) { | |
| this.project = data.project; | |
| this.versions = [...this.project.versions].sort((a, b) => b.id - a.id); | |
| } | |
| ngOnInit() { | |
| this.initializeForm(); | |
| // Select the latest unpublished version or the latest version | |
| const unpublished = this.versions.find(v => !v.published); | |
| this.selectedVersion = unpublished || this.versions[0] || null; | |
| if (this.selectedVersion) { | |
| this.loadVersion(this.selectedVersion); | |
| } | |
| this.versionForm.valueChanges.subscribe(() => { | |
| this.isDirty = true; | |
| }); | |
| } | |
| initializeForm() { | |
| this.versionForm = this.fb.group({ | |
| id: [{value: '', disabled: true}], | |
| caption: ['', Validators.required], | |
| published: [{value: false, disabled: true}], | |
| general_prompt: ['', Validators.required], | |
| llm: this.fb.group({ | |
| repo_id: ['', Validators.required], | |
| generation_config: this.fb.group({ | |
| max_new_tokens: [256, [Validators.required, Validators.min(1), Validators.max(2048)]], | |
| temperature: [0.2, [Validators.required, Validators.min(0), Validators.max(2)]], | |
| top_p: [0.8, [Validators.required, Validators.min(0), Validators.max(1)]], | |
| repetition_penalty: [1.1, [Validators.required, Validators.min(1), Validators.max(2)]] | |
| }), | |
| use_fine_tune: [false], | |
| fine_tune_zip: [''] | |
| }), | |
| intents: this.fb.array([]), | |
| last_update_date: [''] | |
| }); | |
| // Watch for fine-tune toggle | |
| this.versionForm.get('llm.use_fine_tune')?.valueChanges.subscribe(useFineTune => { | |
| const fineTuneControl = this.versionForm.get('llm.fine_tune_zip'); | |
| if (useFineTune) { | |
| fineTuneControl?.setValidators([Validators.required]); | |
| } else { | |
| fineTuneControl?.clearValidators(); | |
| fineTuneControl?.setValue(''); | |
| } | |
| fineTuneControl?.updateValueAndValidity(); | |
| }); | |
| } | |
| loadVersion(version: Version) { | |
| this.selectedVersion = version; | |
| // Form değerlerini set et | |
| this.versionForm.patchValue({ | |
| id: version.id, | |
| caption: version.caption || '', | |
| published: version.published || false, | |
| general_prompt: (version as any).general_prompt || '', // Backend'den gelen general_prompt | |
| last_update_date: version.last_update_date || '' | |
| }); | |
| // LLM config'i ayrı set et | |
| if (version.llm) { | |
| this.versionForm.patchValue({ | |
| llm: { | |
| repo_id: version.llm.repo_id || '', | |
| generation_config: version.llm.generation_config || { | |
| max_new_tokens: 512, | |
| temperature: 0.7, | |
| top_p: 0.95, | |
| repetition_penalty: 1.1 | |
| }, | |
| use_fine_tune: version.llm.use_fine_tune || false, | |
| fine_tune_zip: version.llm.fine_tune_zip || '' | |
| } | |
| }); | |
| } | |
| // Clear and rebuild intents | |
| this.intents.clear(); | |
| (version.intents || []).forEach(intent => { | |
| this.intents.push(this.createIntentFormGroup(intent)); | |
| }); | |
| this.isDirty = false; | |
| } | |
| async loadVersions() { | |
| this.loading = true; | |
| try { | |
| const project = await this.apiService.getProject(this.project.id).toPromise(); | |
| if (project) { | |
| this.project = project; | |
| this.versions = [...project.versions].sort((a, b) => b.id - a.id); | |
| // Re-select current version if it still exists | |
| if (this.selectedVersion) { | |
| const currentVersion = this.versions.find(v => v.id === this.selectedVersion!.id); | |
| if (currentVersion) { | |
| this.loadVersion(currentVersion); | |
| } else if (this.versions.length > 0) { | |
| this.loadVersion(this.versions[0]); | |
| } | |
| } else if (this.versions.length > 0) { | |
| this.loadVersion(this.versions[0]); | |
| } | |
| } | |
| } catch (error) { | |
| this.snackBar.open('Failed to reload versions', 'Close', { duration: 3000 }); | |
| } finally { | |
| this.loading = false; | |
| } | |
| } | |
| createIntentFormGroup(intent: any = {}): FormGroup { | |
| const group = this.fb.group({ | |
| name: [intent.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9-]+$/)]], | |
| caption: [intent.caption || ''], | |
| locale: [intent.locale || 'tr-TR'], | |
| detection_prompt: [intent.detection_prompt || '', Validators.required], | |
| examples: this.fb.array([]), | |
| parameters: this.fb.array([]), | |
| action: [intent.action || '', Validators.required], | |
| fallback_timeout_prompt: [intent.fallback_timeout_prompt || ''], | |
| fallback_error_prompt: [intent.fallback_error_prompt || ''] | |
| }); | |
| // Examples ve parameters'ı ayrı olarak ekle | |
| if (intent.examples && Array.isArray(intent.examples)) { | |
| const examplesArray = group.get('examples') as FormArray; | |
| intent.examples.forEach((example: string) => { | |
| examplesArray.push(this.fb.control(example)); | |
| }); | |
| } | |
| if (intent.parameters && Array.isArray(intent.parameters)) { | |
| const parametersArray = group.get('parameters') as FormArray; | |
| intent.parameters.forEach((param: any) => { | |
| parametersArray.push(this.createParameterFormGroup(param)); | |
| }); | |
| } | |
| return group; | |
| } | |
| private populateIntentParameters(intentFormGroup: FormGroup, parameters: any[]) { | |
| const parametersArray = intentFormGroup.get('parameters') as FormArray; | |
| parameters.forEach(param => { | |
| parametersArray.push(this.createParameterFormGroup(param)); | |
| }); | |
| } | |
| createParameterFormGroup(param: any = {}): FormGroup { | |
| return this.fb.group({ | |
| name: [param.name || '', [Validators.required, Validators.pattern(/^[a-zA-Z0-9_]+$/)]], | |
| caption: [param.caption || ''], | |
| type: [param.type || 'str', Validators.required], | |
| required: [param.required !== false], | |
| variable_name: [param.variable_name || '', Validators.required], | |
| extraction_prompt: [param.extraction_prompt || ''], | |
| validation_regex: [param.validation_regex || ''], | |
| invalid_prompt: [param.invalid_prompt || ''], | |
| type_error_prompt: [param.type_error_prompt || ''] | |
| }); | |
| } | |
| get intents() { | |
| return this.versionForm.get('intents') as FormArray; | |
| } | |
| getIntentParameters(intentIndex: number): FormArray { | |
| return this.intents.at(intentIndex).get('parameters') as FormArray; | |
| } | |
| getIntentExamples(intentIndex: number): FormArray { | |
| return this.intents.at(intentIndex).get('examples') as FormArray; | |
| } | |
| addIntent() { | |
| this.intents.push(this.createIntentFormGroup()); | |
| } | |
| removeIntent(index: number) { | |
| const intent = this.intents.at(index).value; | |
| const dialogRef = this.dialog.open(ConfirmDialogComponent, { | |
| width: '400px', | |
| data: { | |
| title: 'Delete Intent', | |
| message: `Are you sure you want to delete intent "${intent.name}"?`, | |
| confirmText: 'Delete', | |
| confirmColor: 'warn' | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(confirmed => { | |
| if (confirmed) { | |
| this.intents.removeAt(index); | |
| } | |
| }); | |
| } | |
| async editIntent(intentIndex: number) { | |
| const { default: IntentEditDialogComponent } = await import('../intent-edit-dialog/intent-edit-dialog.component'); | |
| const intent = this.intents.at(intentIndex); | |
| const currentValue = intent.value; | |
| // Intent verilerini dialog'a gönder | |
| const dialogRef = this.dialog.open(IntentEditDialogComponent, { | |
| width: '90vw', | |
| maxWidth: '1000px', | |
| data: { | |
| intent: { | |
| ...currentValue, | |
| examples: currentValue.examples || [], | |
| parameters: currentValue.parameters || [] | |
| }, | |
| project: this.project, | |
| apis: await this.getAvailableAPIs() | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(result => { | |
| if (result) { | |
| // FormArray'leri yeniden oluştur | |
| intent.patchValue({ | |
| name: result.name, | |
| caption: result.caption, | |
| locale: result.locale, | |
| detection_prompt: result.detection_prompt, | |
| action: result.action, | |
| fallback_timeout_prompt: result.fallback_timeout_prompt, | |
| fallback_error_prompt: result.fallback_error_prompt | |
| }); | |
| // Examples'ı güncelle | |
| const examplesArray = intent.get('examples') as FormArray; | |
| examplesArray.clear(); | |
| (result.examples || []).forEach((example: string) => { | |
| examplesArray.push(this.fb.control(example)); | |
| }); | |
| // Parameters'ı güncelle | |
| const parametersArray = intent.get('parameters') as FormArray; | |
| parametersArray.clear(); | |
| (result.parameters || []).forEach((param: any) => { | |
| parametersArray.push(this.createParameterFormGroup(param)); | |
| }); | |
| } | |
| }); | |
| } | |
| addParameter(intentIndex: number) { | |
| const parameters = this.getIntentParameters(intentIndex); | |
| parameters.push(this.createParameterFormGroup()); | |
| } | |
| removeParameter(intentIndex: number, paramIndex: number) { | |
| const parameters = this.getIntentParameters(intentIndex); | |
| parameters.removeAt(paramIndex); | |
| } | |
| addExample(intentIndex: number, example: string) { | |
| if (example.trim()) { | |
| const examples = this.getIntentExamples(intentIndex); | |
| examples.push(this.fb.control(example)); | |
| } | |
| } | |
| removeExample(intentIndex: number, exampleIndex: number) { | |
| const examples = this.getIntentExamples(intentIndex); | |
| examples.removeAt(exampleIndex); | |
| } | |
| async createVersion() { | |
| const publishedVersions = this.versions.filter(v => v.published); | |
| const dialogRef = this.dialog.open(ConfirmDialogComponent, { | |
| width: '500px', | |
| data: { | |
| title: 'Create New Version', | |
| message: 'Which published version would you like to use as a base for the new version?', | |
| showDropdown: true, | |
| dropdownOptions: publishedVersions.map(v => ({ // ✅ publishedVersions kullan | |
| value: v.id, | |
| label: `Version ${v.id} - ${v.caption || 'No description'}` | |
| })), | |
| dropdownPlaceholder: 'Select published version (or leave empty for blank)', | |
| confirmText: 'Create', | |
| cancelText: 'Cancel' | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(async (result) => { | |
| if (result?.confirmed) { | |
| this.loading = true; | |
| try { | |
| let newVersionData; | |
| if (result.selectedValue) { | |
| // Copy from selected version | |
| const sourceVersion = this.versions.find(v => v.id === result.selectedValue); | |
| if (sourceVersion) { | |
| newVersionData = { | |
| ...sourceVersion, | |
| id: undefined, | |
| published: false, | |
| last_update_date: undefined, | |
| caption: `Copy of version ${sourceVersion.id}`, | |
| description: sourceVersion.caption ? `Copy of ${sourceVersion.caption}` : `Copy of version ${sourceVersion.id}` | |
| }; | |
| } | |
| } else { | |
| // Create blank version | |
| newVersionData = { | |
| caption: `Version ${this.versions.length + 1}`, | |
| description: 'New version', | |
| default_api: '', | |
| published: false, | |
| llm: { | |
| repo_id: '', | |
| generation_config: { | |
| max_new_tokens: 512, | |
| temperature: 0.7, | |
| top_p: 0.95, | |
| top_k: 50, | |
| repetition_penalty: 1.1 | |
| }, | |
| use_fine_tune: false, | |
| fine_tune_zip: '' | |
| }, | |
| intents: [], | |
| parameters: [] | |
| }; | |
| } | |
| if (newVersionData) { | |
| await this.apiService.createVersion(this.project.id, newVersionData).toPromise(); | |
| await this.loadVersions(); | |
| this.snackBar.open('Version created successfully!', 'Close', { duration: 3000 }); | |
| } | |
| } catch (error) { | |
| this.snackBar.open('Failed to create version', 'Close', { duration: 3000 }); | |
| } finally { | |
| this.loading = false; | |
| } | |
| } | |
| }); | |
| } | |
| async saveVersion() { | |
| if (!this.selectedVersion) { | |
| this.snackBar.open('No version selected', 'Close', { duration: 3000 }); | |
| return; | |
| } | |
| if (this.versionForm.invalid) { | |
| const invalidFields: string[] = []; | |
| Object.keys(this.versionForm.controls).forEach(key => { | |
| const control = this.versionForm.get(key); | |
| if (control && control.invalid) { | |
| invalidFields.push(key); | |
| } | |
| }); | |
| this.intents.controls.forEach((intent, index) => { | |
| if (intent.invalid) { | |
| invalidFields.push(`Intent ${index + 1}`); | |
| } | |
| }); | |
| this.snackBar.open(`Please fix validation errors in: ${invalidFields.join(', ')}`, 'Close', { | |
| duration: 5000 | |
| }); | |
| return; | |
| } | |
| const currentVersion = this.selectedVersion!; | |
| this.saving = true; | |
| try { | |
| const formValue = this.versionForm.getRawValue(); | |
| // updateData'yı backend'in beklediği formatta hazırla | |
| const updateData = { | |
| caption: formValue.caption, | |
| general_prompt: formValue.general_prompt || '', // Bu alan eksikti | |
| llm: formValue.llm, | |
| intents: formValue.intents.map((intent: any) => ({ | |
| name: intent.name, | |
| caption: intent.caption, | |
| locale: intent.locale, | |
| detection_prompt: intent.detection_prompt, | |
| examples: Array.isArray(intent.examples) ? intent.examples.filter((ex: any) => ex) : [], | |
| parameters: Array.isArray(intent.parameters) ? intent.parameters.map((param: any) => ({ | |
| name: param.name, | |
| caption: param.caption, | |
| type: param.type, | |
| required: param.required, | |
| variable_name: param.variable_name, | |
| extraction_prompt: param.extraction_prompt, | |
| validation_regex: param.validation_regex, | |
| invalid_prompt: param.invalid_prompt, | |
| type_error_prompt: param.type_error_prompt | |
| })) : [], | |
| action: intent.action, | |
| fallback_timeout_prompt: intent.fallback_timeout_prompt, | |
| fallback_error_prompt: intent.fallback_error_prompt | |
| })), | |
| last_update_date: currentVersion.last_update_date || '' | |
| }; | |
| console.log('Saving version data:', JSON.stringify(updateData, null, 2)); | |
| const result = await this.apiService.updateVersion( | |
| this.project.id, | |
| currentVersion.id, | |
| updateData | |
| ).toPromise(); | |
| this.snackBar.open('Version saved successfully', 'Close', { duration: 3000 }); | |
| this.isDirty = false; | |
| if (result) { | |
| this.selectedVersion = result; | |
| this.versionForm.patchValue({ | |
| last_update_date: result.last_update_date | |
| }); | |
| } | |
| await this.loadVersions(); | |
| } catch (error: any) { | |
| console.error('Save error:', error); | |
| if (error.status === 409) { | |
| // Race condition handling için ayrı metod çağır | |
| await this.handleRaceCondition(currentVersion); | |
| } else { | |
| const errorMessage = error.error?.detail || error.message || 'Failed to save version'; | |
| this.snackBar.open(errorMessage, 'Close', { | |
| duration: 5000, | |
| panelClass: 'error-snackbar' | |
| }); | |
| } | |
| } finally { | |
| this.saving = false; | |
| } | |
| } | |
| // Race condition handling için ayrı metod | |
| private async handleRaceCondition(currentVersion: Version) { | |
| const formValue = this.versionForm.getRawValue(); | |
| const retryUpdateData = { | |
| caption: formValue.caption, | |
| general_prompt: formValue.general_prompt || '', | |
| llm: formValue.llm, | |
| intents: formValue.intents.map((intent: any) => ({ | |
| name: intent.name, | |
| caption: intent.caption, | |
| locale: intent.locale, | |
| detection_prompt: intent.detection_prompt, | |
| examples: Array.isArray(intent.examples) ? intent.examples.filter((ex: any) => ex) : [], | |
| parameters: Array.isArray(intent.parameters) ? intent.parameters : [], | |
| action: intent.action, | |
| fallback_timeout_prompt: intent.fallback_timeout_prompt, | |
| fallback_error_prompt: intent.fallback_error_prompt | |
| })), | |
| last_update_date: currentVersion.last_update_date || '' | |
| }; | |
| const dialogRef = this.dialog.open(ConfirmDialogComponent, { | |
| width: '500px', | |
| data: { | |
| title: 'Version Modified', | |
| message: 'This version was modified by another user. Do you want to reload and lose your changes, or force save?', | |
| confirmText: 'Force Save', | |
| cancelText: 'Reload', | |
| confirmColor: 'warn' | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(async (forceSave) => { | |
| if (forceSave) { | |
| try { | |
| await this.apiService.updateVersion( | |
| this.project.id, | |
| currentVersion.id, | |
| retryUpdateData, | |
| true | |
| ).toPromise(); | |
| this.snackBar.open('Version force saved', 'Close', { duration: 3000 }); | |
| await this.loadVersions(); | |
| } catch (err: any) { | |
| this.snackBar.open(err.error?.detail || 'Force save failed', 'Close', { | |
| duration: 5000, | |
| panelClass: 'error-snackbar' | |
| }); | |
| } | |
| } else { | |
| await this.loadVersions(); | |
| } | |
| }); | |
| } | |
| async publishVersion() { | |
| if (!this.selectedVersion) return; | |
| const dialogRef = this.dialog.open(ConfirmDialogComponent, { | |
| width: '500px', | |
| data: { | |
| title: 'Publish Version', | |
| message: `Are you sure you want to publish version "${this.selectedVersion.caption}"? This will unpublish all other versions.`, | |
| confirmText: 'Publish', | |
| confirmColor: 'primary' | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(async (confirmed) => { | |
| if (confirmed && this.selectedVersion) { | |
| this.publishing = true; | |
| try { | |
| await this.apiService.publishVersion( | |
| this.project.id, | |
| this.selectedVersion.id | |
| ).toPromise(); | |
| this.snackBar.open('Version published successfully', 'Close', { duration: 3000 }); | |
| // Reload to get updated data | |
| await this.reloadProject(); | |
| } catch (error: any) { | |
| this.snackBar.open(error.error?.detail || 'Failed to publish version', 'Close', { | |
| duration: 5000, | |
| panelClass: 'error-snackbar' | |
| }); | |
| } finally { | |
| this.publishing = false; | |
| } | |
| } | |
| }); | |
| } | |
| async deleteVersion() { | |
| if (!this.selectedVersion || this.selectedVersion.published) return; | |
| const dialogRef = this.dialog.open(ConfirmDialogComponent, { | |
| width: '400px', | |
| data: { | |
| title: 'Delete Version', | |
| message: `Are you sure you want to delete version "${this.selectedVersion.caption}"?`, | |
| confirmText: 'Delete', | |
| confirmColor: 'warn' | |
| } | |
| }); | |
| dialogRef.afterClosed().subscribe(async (confirmed) => { | |
| if (confirmed && this.selectedVersion) { | |
| try { | |
| await this.apiService.deleteVersion( | |
| this.project.id, | |
| this.selectedVersion.id | |
| ).toPromise(); | |
| this.snackBar.open('Version deleted successfully', 'Close', { duration: 3000 }); | |
| // Reload and select another version | |
| await this.reloadProject(); | |
| if (this.versions.length > 0) { | |
| this.loadVersion(this.versions[0]); | |
| } else { | |
| this.selectedVersion = null; | |
| } | |
| } catch (error: any) { | |
| this.snackBar.open(error.error?.detail || 'Failed to delete version', 'Close', { | |
| duration: 5000, | |
| panelClass: 'error-snackbar' | |
| }); | |
| } | |
| } | |
| }); | |
| } | |
| async testIntentDetection() { | |
| if (!this.testUserMessage.trim()) { | |
| this.snackBar.open('Please enter a test message', 'Close', { duration: 3000 }); | |
| return; | |
| } | |
| this.testing = true; | |
| this.testResult = null; | |
| // Simulate intent detection test | |
| setTimeout(() => { | |
| // This is a mock - in real implementation, this would call the Spark service | |
| const intents = this.versionForm.get('intents')?.value || []; | |
| // Simple matching for demo | |
| let detectedIntent = null; | |
| let confidence = 0; | |
| for (const intent of intents) { | |
| for (const example of intent.examples || []) { | |
| if (this.testUserMessage.toLowerCase().includes(example.toLowerCase())) { | |
| detectedIntent = intent.name; | |
| confidence = 0.95; | |
| break; | |
| } | |
| } | |
| if (detectedIntent) break; | |
| } | |
| // Random detection for demo | |
| if (!detectedIntent && intents.length > 0) { | |
| const randomIntent = intents[Math.floor(Math.random() * intents.length)]; | |
| detectedIntent = randomIntent.name; | |
| confidence = 0.65; | |
| } | |
| this.testResult = { | |
| success: true, | |
| intent: detectedIntent, | |
| confidence: confidence, | |
| parameters: detectedIntent ? this.extractTestParameters(detectedIntent) : [] | |
| }; | |
| this.testing = false; | |
| }, 1500); | |
| } | |
| private extractTestParameters(intentName: string): any[] { | |
| // Mock parameter extraction | |
| const intent = this.intents.value.find((i: any) => i.name === intentName); | |
| if (!intent) return []; | |
| return intent.parameters.map((param: any) => ({ | |
| name: param.name, | |
| value: param.type === 'date' ? '2025-06-15' : 'test_value', | |
| extracted: Math.random() > 0.3 | |
| })); | |
| } | |
| async getAvailableAPIs(): Promise<any[]> { | |
| try { | |
| return await this.apiService.getAPIs().toPromise() || []; | |
| } catch { | |
| return []; | |
| } | |
| } | |
| private async reloadProject() { | |
| this.loading = true; | |
| try { | |
| const projects = await this.apiService.getProjects().toPromise() || []; | |
| const updatedProject = projects.find(p => p.id === this.project.id); | |
| if (updatedProject) { | |
| this.project = updatedProject; | |
| this.versions = [...updatedProject.versions].sort((a, b) => b.id - a.id); | |
| } | |
| } catch (error) { | |
| console.error('Failed to reload project:', error); | |
| } finally { | |
| this.loading = false; | |
| } | |
| } | |
| async compareVersions() { | |
| if (this.versions.length < 2) { | |
| this.snackBar.open('Need at least 2 versions to compare', 'Close', { duration: 3000 }); | |
| return; | |
| } | |
| const { default: VersionCompareDialogComponent } = await import('../version-compare-dialog/version-compare-dialog.component'); | |
| this.dialog.open(VersionCompareDialogComponent, { | |
| width: '90vw', | |
| maxWidth: '1000px', | |
| maxHeight: '80vh', | |
| data: { | |
| versions: this.versions, | |
| selectedVersion: this.selectedVersion | |
| } | |
| }); | |
| } | |
| close() { | |
| this.dialogRef.close(true); | |
| } | |
| } |