import { Component, inject, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { MatCardModule } from '@angular/material/card'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatSliderModule } from '@angular/material/slider'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { MatListModule } from '@angular/material/list'; import { ApiService, Environment, STTSettings, TTSSettings, ParameterCollectionConfig } from '../../services/api.service'; import { EnvironmentService } from '../../services/environment.service'; @Component({ selector: 'app-environment', standalone: true, imports: [ CommonModule, FormsModule, MatCardModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule, MatSnackBarModule, MatExpansionModule, MatSliderModule, MatCheckboxModule, MatListModule ], templateUrl: './environment.component.html', styleUrls: ['./environment.component.scss'] }) export class EnvironmentComponent implements OnInit { private apiService = inject(ApiService); private snackBar = inject(MatSnackBar); private environmentService = inject(EnvironmentService); environment: Environment = { work_mode: 'hfcloud', cloud_token: '', spark_endpoint: '', internal_prompt: '', tts_engine: 'no_tts', tts_engine_api_key: '', stt_engine: 'no_stt', stt_engine_api_key: '' }; ttsSettings: TTSSettings = { use_ssml: false }; // Separate STT settings object with defaults sttSettings: STTSettings = { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true }; // Parameter Collection Configuration parameterCollectionConfig: ParameterCollectionConfig = { max_params_per_question: 2, smart_grouping: true, retry_unanswered: true, collection_prompt: '' }; loading = true; saving = false; conversation_history: string = '{{conversation_history}}'; intent_name: string = '{{intent_name}}'; intent_caption: string = '{{intent_caption}}'; collected_params: string = '{{collected_params}}'; missing_params: string = '{{missing_params}}'; unanswered_params: string = '{{unanswered_params}}'; max_params: string = '{{max_params}}'; project_language: string = '{{project_language}}'; ngOnInit() { this.loadEnvironment(); } loadEnvironment() { this.loading = true; this.apiService.getEnvironment().subscribe({ next: (env) => { this.environment = env; // Load TTS settings or use defaults if (env.tts_settings) { this.ttsSettings = { ...this.ttsSettings, ...env.tts_settings }; } // Load STT settings or use defaults if (env.stt_settings) { this.sttSettings = { ...this.sttSettings, ...env.stt_settings }; } // Load Parameter Collection Configuration if (env.parameter_collection_config) { this.parameterCollectionConfig = { ...this.parameterCollectionConfig, ...env.parameter_collection_config }; } this.loading = false; }, error: (err) => { this.snackBar.open('Failed to load environment configuration', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); this.loading = false; } }); } formatSliderLabel(value: number): string { return `${value}`; } getTokenLabel(): string { switch(this.environment.work_mode) { case 'gpt4o': case 'gpt4o-mini': return 'OpenAI API Key'; case 'hfcloud': case 'cloud': return 'Cloud Token'; default: return 'Cloud Token'; } } getTokenPlaceholder(): string { switch(this.environment.work_mode) { case 'gpt4o': case 'gpt4o-mini': return 'sk-...'; case 'hfcloud': case 'cloud': return 'Enter cloud token'; default: return 'Enter token'; } } isGPTMode(): boolean { return this.environment.work_mode === 'gpt4o' || this.environment.work_mode === 'gpt4o-mini'; } onTTSEngineChange() { if (this.environment.tts_engine === 'no_tts') { this.environment.tts_engine_api_key = ''; } } onSTTEngineChange() { if (this.environment.stt_engine === 'no_stt') { this.environment.stt_engine_api_key = ''; } } isTTSProviderSSMLCapable(): boolean { return this.environment.tts_engine === 'elevenlabs'; } // STT Key methods getSTTKeyLabel(): string { switch(this.environment.stt_engine) { case 'google': return 'Service Account JSON Path'; case 'azure': return 'Azure Subscription Key'; case 'amazon': return 'AWS Access Key'; case 'flicker': return 'Flicker API Key'; default: return 'STT API Key'; } } getSTTKeyPlaceholder(): string { switch(this.environment.stt_engine) { case 'google': return '/credentials/google-service-account.json'; case 'azure': return 'Enter Azure subscription key'; case 'amazon': return 'Enter AWS access key'; case 'flicker': return 'Enter Flicker API key'; default: return 'Enter STT API key'; } } getSTTKeyHint(): string { switch(this.environment.stt_engine) { case 'google': return 'Path to service account JSON file for Google Cloud'; case 'azure': return 'Subscription key from Azure portal'; case 'amazon': return 'AWS IAM access key with Transcribe permissions'; case 'flicker': return 'API key from Flicker dashboard'; default: return ''; } } formatMilliseconds(value: number): string { return `${value}ms`; } save() { this.saving = true; // Include all settings in the save const saveData = { ...this.environment, stt_settings: this.sttSettings, tts_settings: this.ttsSettings, parameter_collection_config: this.parameterCollectionConfig }; this.apiService.updateEnvironment(saveData).subscribe({ next: () => { // Environment service'i güncelle this.environmentService.updateEnvironment(saveData); this.snackBar.open('Environment configuration saved successfully', 'Close', { duration: 3000 }); this.saving = false; }, error: (err) => { this.snackBar.open( err.error?.detail || 'Failed to save configuration', 'Close', { duration: 5000, panelClass: 'error-snackbar' } ); this.saving = false; } }); } testConnection() { this.snackBar.open('Testing connection to Spark endpoint...', undefined, { duration: 2000 }); // TODO: Implement actual connection test setTimeout(() => { this.snackBar.open('Connection successful!', 'Close', { duration: 3000 }); }, 2000); } reloadFromSpark() { if (this.isGPTMode()) { return; } this.snackBar.open('Reloading configuration from Spark...', undefined, { duration: 2000 }); setTimeout(() => { this.loadEnvironment(); this.snackBar.open('Configuration reloaded', 'Close', { duration: 3000 }); }, 1000); } showSnackBar(message: string) { this.snackBar.open(message, 'Close', { duration: 3000 }); } get envForm() { return { valid: true // Form validation için basit bir getter }; } onWorkModeChange() { this.environmentService.updateEnvironment(this.environment); } resetCollectionPrompt() { this.parameterCollectionConfig.collection_prompt = this.getDefaultCollectionPrompt() } getDefaultCollectionPrompt(): string { return `You are a helpful assistant collecting information from the user. Conversation context: {{conversation_history}} Intent: {{intent_name}} - {{intent_caption}} Already collected: {{collected_params}} Still needed: {{missing_params}} Previously asked but not answered: {{unanswered_params}} Rules: 1. Ask for maximum {{max_params}} parameters in one question 2. Group parameters that naturally go together (like from/to cities, dates) 3. If some parameters were asked before but not answered, include them again 4. Be natural and conversational in {{project_language}} 5. Don't repeat information already collected 6. Ask in a friendly, human way Generate a natural question to collect the missing parameters.`; } }