ciyidogan commited on
Commit
0dd2a6a
·
verified ·
1 Parent(s): 78be6d7

Update flare-ui/src/app/components/environment/environment.component.ts

Browse files
flare-ui/src/app/components/environment/environment.component.ts CHANGED
@@ -1,339 +1,401 @@
1
- import { Component, inject, OnInit } from '@angular/core';
2
- import { CommonModule } from '@angular/common';
3
- import { FormsModule } from '@angular/forms';
4
- import { MatCardModule } from '@angular/material/card';
5
- import { MatFormFieldModule } from '@angular/material/form-field';
6
- import { MatInputModule } from '@angular/material/input';
7
- import { MatSelectModule } from '@angular/material/select';
8
- import { MatButtonModule } from '@angular/material/button';
9
- import { MatIconModule } from '@angular/material/icon';
10
- import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
11
- import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
12
- import { MatExpansionModule } from '@angular/material/expansion';
13
- import { MatSliderModule } from '@angular/material/slider';
14
- import { MatCheckboxModule } from '@angular/material/checkbox';
15
- import { MatListModule } from '@angular/material/list';
16
- import { ApiService, Environment, STTSettings, TTSSettings, ParameterCollectionConfig } from '../../services/api.service';
17
- import { EnvironmentService } from '../../services/environment.service';
 
 
 
 
 
18
 
19
  @Component({
20
  selector: 'app-environment',
21
- standalone: true,
22
- imports: [
23
- CommonModule,
24
- FormsModule,
25
- MatCardModule,
26
- MatFormFieldModule,
27
- MatInputModule,
28
- MatSelectModule,
29
- MatButtonModule,
30
- MatIconModule,
31
- MatProgressSpinnerModule,
32
- MatSnackBarModule,
33
- MatExpansionModule,
34
- MatSliderModule,
35
- MatCheckboxModule,
36
- MatListModule
37
- ],
38
  templateUrl: './environment.component.html',
39
  styleUrls: ['./environment.component.scss']
40
  })
41
  export class EnvironmentComponent implements OnInit {
42
- private apiService = inject(ApiService);
43
- private snackBar = inject(MatSnackBar);
44
- private environmentService = inject(EnvironmentService);
45
-
46
- environment: Environment = {
47
- work_mode: 'hfcloud',
48
- cloud_token: '',
49
- spark_endpoint: '',
50
- internal_prompt: '',
51
- tts_engine: 'no_tts',
52
- tts_engine_api_key: '',
53
- stt_engine: 'no_stt',
54
- stt_engine_api_key: ''
55
- };
56
-
57
- ttsSettings: TTSSettings = {
58
- use_ssml: false
59
- };
60
-
61
- // Separate STT settings object with defaults
62
- sttSettings: STTSettings = {
63
- speech_timeout_ms: 2000,
64
- noise_reduction_level: 2,
65
- vad_sensitivity: 0.5,
66
- language: 'tr-TR',
67
- model: 'latest_long',
68
- use_enhanced: true,
69
- enable_punctuation: true,
70
- interim_results: true
71
- };
72
-
73
- // Parameter Collection Configuration
74
- parameterCollectionConfig: ParameterCollectionConfig = {
75
- max_params_per_question: 2,
76
- smart_grouping: true,
77
- retry_unanswered: true,
78
- collection_prompt: ''
79
- };
80
-
81
- loading = true;
82
  saving = false;
83
-
84
- conversation_history: string = '{{conversation_history}}';
85
- intent_name: string = '{{intent_name}}';
86
- intent_caption: string = '{{intent_caption}}';
87
- collected_params: string = '{{collected_params}}';
88
- missing_params: string = '{{missing_params}}';
89
- unanswered_params: string = '{{unanswered_params}}';
90
- max_params: string = '{{max_params}}';
91
- project_language: string = '{{project_language}}';
92
 
93
- ngOnInit() {
 
 
 
 
 
 
 
 
 
 
 
 
94
  this.loadEnvironment();
95
  }
96
 
97
- loadEnvironment() {
98
- this.loading = true;
99
- this.apiService.getEnvironment().subscribe({
100
- next: (env) => {
101
- this.environment = env;
102
-
103
- // Load TTS settings or use defaults
104
- if (env.tts_settings) {
105
- this.ttsSettings = { ...this.ttsSettings, ...env.tts_settings };
106
- }
107
-
108
- // Load STT settings or use defaults
109
- if (env.stt_settings) {
110
- this.sttSettings = { ...this.sttSettings, ...env.stt_settings };
111
- }
112
-
113
- // Load Parameter Collection Configuration
114
- if (env.parameter_collection_config) {
115
- this.parameterCollectionConfig = { ...this.parameterCollectionConfig, ...env.parameter_collection_config };
116
- }
117
-
118
- this.loading = false;
119
- },
120
- error: (err) => {
121
- this.snackBar.open('Failed to load environment configuration', 'Close', {
122
- duration: 5000,
123
- panelClass: 'error-snackbar'
124
- });
125
- this.loading = false;
126
- }
 
127
  });
128
- }
129
-
130
- formatSliderLabel(value: number): string {
131
- return `${value}`;
132
- }
133
-
134
- getTokenLabel(): string {
135
- switch(this.environment.work_mode) {
136
- case 'gpt4o':
137
- case 'gpt4o-mini':
138
- return 'OpenAI API Key';
139
- case 'hfcloud':
140
- case 'cloud':
141
- return 'Cloud Token';
142
- default:
143
- return 'Cloud Token';
144
- }
145
- }
146
 
147
- getTokenPlaceholder(): string {
148
- switch(this.environment.work_mode) {
149
- case 'gpt4o':
150
- case 'gpt4o-mini':
151
- return 'sk-...';
152
- case 'hfcloud':
153
- case 'cloud':
154
- return 'Enter cloud token';
155
- default:
156
- return 'Enter token';
157
- }
158
- }
159
-
160
- isGPTMode(): boolean {
161
- return this.environment.work_mode === 'gpt4o' || this.environment.work_mode === 'gpt4o-mini';
162
  }
163
 
164
- onTTSEngineChange() {
165
- if (this.environment.tts_engine === 'no_tts') {
166
- this.environment.tts_engine_api_key = '';
167
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  }
169
 
170
- onSTTEngineChange() {
171
- if (this.environment.stt_engine === 'no_stt') {
172
- this.environment.stt_engine_api_key = '';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
  }
174
  }
175
 
176
- isTTSProviderSSMLCapable(): boolean {
177
- return this.environment.tts_engine === 'elevenlabs';
178
- }
179
-
180
- // STT Key methods
181
- getSTTKeyLabel(): string {
182
- switch(this.environment.stt_engine) {
183
- case 'google':
184
- return 'Service Account JSON Path';
185
- case 'azure':
186
- return 'Azure Subscription Key';
187
- case 'amazon':
188
- return 'AWS Access Key';
189
- case 'flicker':
190
- return 'Flicker API Key';
191
- default:
192
- return 'STT API Key';
 
 
 
 
193
  }
194
  }
195
 
196
- getSTTKeyPlaceholder(): string {
197
- switch(this.environment.stt_engine) {
198
- case 'google':
199
- return '/credentials/google-service-account.json';
200
- case 'azure':
201
- return 'Enter Azure subscription key';
202
- case 'amazon':
203
- return 'Enter AWS access key';
204
- case 'flicker':
205
- return 'Enter Flicker API key';
206
- default:
207
- return 'Enter STT API key';
 
 
 
 
 
 
 
 
 
208
  }
209
  }
210
 
211
- getSTTKeyHint(): string {
212
- switch(this.environment.stt_engine) {
213
- case 'google':
214
- return 'Path to service account JSON file for Google Cloud';
215
- case 'azure':
216
- return 'Subscription key from Azure portal';
217
- case 'amazon':
218
- return 'AWS IAM access key with Transcribe permissions';
219
- case 'flicker':
220
- return 'API key from Flicker dashboard';
221
- default:
222
- return '';
223
  }
224
- }
225
-
226
- formatMilliseconds(value: number): string {
227
- return `${value}ms`;
228
- }
229
 
230
- save() {
231
  this.saving = true;
 
232
 
233
- // Include all settings in the save
234
- const saveData = {
235
- ...this.environment,
236
- stt_settings: this.sttSettings,
237
- tts_settings: this.ttsSettings,
238
- parameter_collection_config: this.parameterCollectionConfig
239
- };
240
-
241
- this.apiService.updateEnvironment(saveData).subscribe({
242
- next: () => {
243
- // Environment service'i güncelle
244
- this.environmentService.updateEnvironment(saveData);
245
-
246
- this.snackBar.open('Environment configuration saved successfully', 'Close', {
247
- duration: 3000
248
- });
249
- this.saving = false;
 
 
 
 
 
250
  },
251
- error: (err) => {
252
- this.snackBar.open(
253
- err.error?.detail || 'Failed to save configuration',
254
- 'Close',
255
- { duration: 5000, panelClass: 'error-snackbar' }
256
- );
257
- this.saving = false;
 
 
 
 
 
 
 
258
  }
259
- });
260
- }
261
 
262
- testConnection() {
263
- this.snackBar.open('Testing connection to Spark endpoint...', undefined, {
264
- duration: 2000
265
- });
266
-
267
- // TODO: Implement actual connection test
268
- setTimeout(() => {
269
- this.snackBar.open('Connection successful!', 'Close', {
270
- duration: 3000
 
 
 
 
 
 
 
 
 
 
271
  });
272
- }, 2000);
273
  }
274
 
275
- reloadFromSpark() {
276
- if (this.isGPTMode()) {
 
 
 
 
 
 
 
 
277
  return;
278
  }
279
 
280
- this.snackBar.open('Reloading configuration from Spark...', undefined, {
281
- duration: 2000
282
- });
283
-
284
- setTimeout(() => {
285
- this.loadEnvironment();
286
- this.snackBar.open('Configuration reloaded', 'Close', {
287
- duration: 3000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
288
  });
289
- }, 1000);
290
  }
291
 
292
- showSnackBar(message: string) {
293
- this.snackBar.open(message, 'Close', {
294
- duration: 3000
295
- });
296
  }
297
 
298
- get envForm() {
299
- return {
300
- valid: true // Form validation için basit bir getter
301
- };
302
  }
303
 
304
- onWorkModeChange() {
305
- this.environmentService.updateEnvironment(this.environment);
306
  }
307
 
308
- resetCollectionPrompt() {
309
- this.parameterCollectionConfig.collection_prompt = this.getDefaultCollectionPrompt()
310
  }
311
-
312
- getDefaultCollectionPrompt(): string {
313
- return `You are a helpful assistant collecting information from the user.
314
-
315
- Conversation context:
316
- {{conversation_history}}
317
 
318
- Intent: {{intent_name}} - {{intent_caption}}
319
-
320
- Already collected:
321
- {{collected_params}}
322
 
323
- Still needed:
324
- {{missing_params}}
 
325
 
326
- Previously asked but not answered:
327
- {{unanswered_params}}
 
328
 
329
- Rules:
330
- 1. Ask for maximum {{max_params}} parameters in one question
331
- 2. Group parameters that naturally go together (like from/to cities, dates)
332
- 3. If some parameters were asked before but not answered, include them again
333
- 4. Be natural and conversational in {{project_language}}
334
- 5. Don't repeat information already collected
335
- 6. Ask in a friendly, human way
336
 
337
- Generate a natural question to collect the missing parameters.`;
338
- }
 
339
  }
 
1
+ import { Component, OnInit } from '@angular/core';
2
+ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
3
+ import { MatSnackBar } from '@angular/material/snack-bar';
4
+ import { ApiService } from '../services/api.service';
5
+ import { finalize } from 'rxjs/operators';
6
+
7
+ interface ProviderConfig {
8
+ type: string;
9
+ name: string;
10
+ display_name: string;
11
+ requires_endpoint: boolean;
12
+ requires_api_key: boolean;
13
+ requires_repo_info: boolean;
14
+ description?: string;
15
+ }
16
+
17
+ interface ProviderSettings {
18
+ name: string;
19
+ api_key?: string;
20
+ endpoint?: string;
21
+ settings: any;
22
+ }
23
 
24
  @Component({
25
  selector: 'app-environment',
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  templateUrl: './environment.component.html',
27
  styleUrls: ['./environment.component.scss']
28
  })
29
  export class EnvironmentComponent implements OnInit {
30
+ environmentForm!: FormGroup;
31
+ loading = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
  saving = false;
33
+ showInternalPrompt = false;
34
+ showParameterCollection = false;
35
+
36
+ // Provider lists
37
+ allProviders: ProviderConfig[] = [];
38
+ llmProviders: ProviderConfig[] = [];
39
+ ttsProviders: ProviderConfig[] = [];
40
+ sttProviders: ProviderConfig[] = [];
 
41
 
42
+ // Current provider configs
43
+ currentLLMProvider?: ProviderConfig;
44
+ currentTTSProvider?: ProviderConfig;
45
+ currentSTTProvider?: ProviderConfig;
46
+
47
+ constructor(
48
+ private fb: FormBuilder,
49
+ private apiService: ApiService,
50
+ private snackBar: MatSnackBar
51
+ ) {}
52
+
53
+ ngOnInit(): void {
54
+ this.initializeForm();
55
  this.loadEnvironment();
56
  }
57
 
58
+ initializeForm(): void {
59
+ this.environmentForm = this.fb.group({
60
+ // LLM Provider
61
+ llm_provider_name: ['', Validators.required],
62
+ llm_provider_api_key: [''],
63
+ llm_provider_endpoint: [''],
64
+ internal_prompt: [''],
65
+
66
+ // Parameter Collection Config
67
+ max_params_per_question: [2, [Validators.min(1), Validators.max(5)]],
68
+ retry_unanswered: [true],
69
+ collection_prompt: [''],
70
+
71
+ // TTS Provider
72
+ tts_provider_name: ['no_tts'],
73
+ tts_provider_api_key: [''],
74
+ tts_provider_endpoint: [''],
75
+ tts_use_ssml: [false],
76
+
77
+ // STT Provider
78
+ stt_provider_name: ['no_stt'],
79
+ stt_provider_api_key: [''],
80
+ stt_provider_endpoint: [''],
81
+ stt_speech_timeout_ms: [2000],
82
+ stt_noise_reduction_level: [2],
83
+ stt_vad_sensitivity: [0.5],
84
+ stt_language: ['tr-TR'],
85
+ stt_model: ['latest_long'],
86
+ stt_use_enhanced: [true],
87
+ stt_enable_punctuation: [true],
88
+ stt_interim_results: [true]
89
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ // Subscribe to provider changes
92
+ this.environmentForm.get('llm_provider_name')?.valueChanges.subscribe(name => {
93
+ this.onLLMProviderChange(name);
94
+ });
95
+
96
+ this.environmentForm.get('tts_provider_name')?.valueChanges.subscribe(name => {
97
+ this.onTTSProviderChange(name);
98
+ });
99
+
100
+ this.environmentForm.get('stt_provider_name')?.valueChanges.subscribe(name => {
101
+ this.onSTTProviderChange(name);
102
+ });
 
 
 
103
  }
104
 
105
+ loadEnvironment(): void {
106
+ this.loading = true;
107
+ this.apiService.getEnvironment()
108
+ .pipe(finalize(() => this.loading = false))
109
+ .subscribe({
110
+ next: (data) => {
111
+ // Store providers
112
+ this.allProviders = data.providers || [];
113
+ this.llmProviders = this.allProviders.filter(p => p.type === 'llm');
114
+ this.ttsProviders = [{
115
+ type: 'tts',
116
+ name: 'no_tts',
117
+ display_name: 'No TTS',
118
+ requires_endpoint: false,
119
+ requires_api_key: false,
120
+ requires_repo_info: false
121
+ }, ...this.allProviders.filter(p => p.type === 'tts')];
122
+ this.sttProviders = [{
123
+ type: 'stt',
124
+ name: 'no_stt',
125
+ display_name: 'No STT',
126
+ requires_endpoint: false,
127
+ requires_api_key: false,
128
+ requires_repo_info: false
129
+ }, ...this.allProviders.filter(p => p.type === 'stt')];
130
+
131
+ // Set form values
132
+ this.environmentForm.patchValue({
133
+ // LLM Provider
134
+ llm_provider_name: data.llm_provider?.name || '',
135
+ llm_provider_api_key: data.llm_provider?.api_key || '',
136
+ llm_provider_endpoint: data.llm_provider?.endpoint || '',
137
+ internal_prompt: data.llm_provider?.settings?.internal_prompt || '',
138
+
139
+ // Parameter Collection
140
+ max_params_per_question: data.llm_provider?.settings?.parameter_collection_config?.max_params_per_question || 2,
141
+ retry_unanswered: data.llm_provider?.settings?.parameter_collection_config?.retry_unanswered ?? true,
142
+ collection_prompt: data.llm_provider?.settings?.parameter_collection_config?.collection_prompt || '',
143
+
144
+ // TTS Provider
145
+ tts_provider_name: data.tts_provider?.name || 'no_tts',
146
+ tts_provider_api_key: data.tts_provider?.api_key || '',
147
+ tts_provider_endpoint: data.tts_provider?.endpoint || '',
148
+ tts_use_ssml: data.tts_provider?.settings?.use_ssml || false,
149
+
150
+ // STT Provider
151
+ stt_provider_name: data.stt_provider?.name || 'no_stt',
152
+ stt_provider_api_key: data.stt_provider?.api_key || '',
153
+ stt_provider_endpoint: data.stt_provider?.endpoint || '',
154
+ stt_speech_timeout_ms: data.stt_provider?.settings?.speech_timeout_ms || 2000,
155
+ stt_noise_reduction_level: data.stt_provider?.settings?.noise_reduction_level || 2,
156
+ stt_vad_sensitivity: data.stt_provider?.settings?.vad_sensitivity || 0.5,
157
+ stt_language: data.stt_provider?.settings?.language || 'tr-TR',
158
+ stt_model: data.stt_provider?.settings?.model || 'latest_long',
159
+ stt_use_enhanced: data.stt_provider?.settings?.use_enhanced ?? true,
160
+ stt_enable_punctuation: data.stt_provider?.settings?.enable_punctuation ?? true,
161
+ stt_interim_results: data.stt_provider?.settings?.interim_results ?? true
162
+ });
163
+
164
+ // Trigger provider change handlers
165
+ this.onLLMProviderChange(data.llm_provider?.name || '');
166
+ this.onTTSProviderChange(data.tts_provider?.name || 'no_tts');
167
+ this.onSTTProviderChange(data.stt_provider?.name || 'no_stt');
168
+ },
169
+ error: (error) => {
170
+ this.snackBar.open('Failed to load environment configuration', 'Close', {
171
+ duration: 3000,
172
+ panelClass: ['error-snackbar']
173
+ });
174
+ }
175
+ });
176
  }
177
 
178
+ onLLMProviderChange(name: string): void {
179
+ this.currentLLMProvider = this.llmProviders.find(p => p.name === name);
180
+
181
+ if (this.currentLLMProvider) {
182
+ // Update validators
183
+ const apiKeyControl = this.environmentForm.get('llm_provider_api_key');
184
+ const endpointControl = this.environmentForm.get('llm_provider_endpoint');
185
+
186
+ if (this.currentLLMProvider.requires_api_key) {
187
+ apiKeyControl?.setValidators([Validators.required]);
188
+ } else {
189
+ apiKeyControl?.clearValidators();
190
+ }
191
+
192
+ if (this.currentLLMProvider.requires_endpoint) {
193
+ endpointControl?.setValidators([Validators.required, Validators.pattern('https?://.+')]);
194
+ } else {
195
+ endpointControl?.clearValidators();
196
+ }
197
+
198
+ apiKeyControl?.updateValueAndValidity();
199
+ endpointControl?.updateValueAndValidity();
200
  }
201
  }
202
 
203
+ onTTSProviderChange(name: string): void {
204
+ this.currentTTSProvider = this.ttsProviders.find(p => p.name === name);
205
+
206
+ if (this.currentTTSProvider) {
207
+ const apiKeyControl = this.environmentForm.get('tts_provider_api_key');
208
+ const endpointControl = this.environmentForm.get('tts_provider_endpoint');
209
+
210
+ if (this.currentTTSProvider.requires_api_key && name !== 'no_tts') {
211
+ apiKeyControl?.setValidators([Validators.required]);
212
+ } else {
213
+ apiKeyControl?.clearValidators();
214
+ }
215
+
216
+ if (this.currentTTSProvider.requires_endpoint && name !== 'no_tts') {
217
+ endpointControl?.setValidators([Validators.required, Validators.pattern('https?://.+')]);
218
+ } else {
219
+ endpointControl?.clearValidators();
220
+ }
221
+
222
+ apiKeyControl?.updateValueAndValidity();
223
+ endpointControl?.updateValueAndValidity();
224
  }
225
  }
226
 
227
+ onSTTProviderChange(name: string): void {
228
+ this.currentSTTProvider = this.sttProviders.find(p => p.name === name);
229
+
230
+ if (this.currentSTTProvider) {
231
+ const apiKeyControl = this.environmentForm.get('stt_provider_api_key');
232
+ const endpointControl = this.environmentForm.get('stt_provider_endpoint');
233
+
234
+ if (this.currentSTTProvider.requires_api_key && name !== 'no_stt') {
235
+ apiKeyControl?.setValidators([Validators.required]);
236
+ } else {
237
+ apiKeyControl?.clearValidators();
238
+ }
239
+
240
+ if (this.currentSTTProvider.requires_endpoint && name !== 'no_stt') {
241
+ endpointControl?.setValidators([Validators.required, Validators.pattern('https?://.+')]);
242
+ } else {
243
+ endpointControl?.clearValidators();
244
+ }
245
+
246
+ apiKeyControl?.updateValueAndValidity();
247
+ endpointControl?.updateValueAndValidity();
248
  }
249
  }
250
 
251
+ save(): void {
252
+ if (this.environmentForm.invalid) {
253
+ Object.keys(this.environmentForm.controls).forEach(key => {
254
+ const control = this.environmentForm.get(key);
255
+ if (control && control.invalid) {
256
+ control.markAsTouched();
257
+ }
258
+ });
259
+ return;
 
 
 
260
  }
 
 
 
 
 
261
 
 
262
  this.saving = true;
263
+ const formValue = this.environmentForm.value;
264
 
265
+ // Build environment update payload
266
+ const payload = {
267
+ llm_provider: {
268
+ name: formValue.llm_provider_name,
269
+ api_key: formValue.llm_provider_api_key || null,
270
+ endpoint: formValue.llm_provider_endpoint || null,
271
+ settings: {
272
+ internal_prompt: formValue.internal_prompt || null,
273
+ parameter_collection_config: {
274
+ max_params_per_question: formValue.max_params_per_question,
275
+ retry_unanswered: formValue.retry_unanswered,
276
+ collection_prompt: formValue.collection_prompt || null
277
+ }
278
+ }
279
+ },
280
+ tts_provider: {
281
+ name: formValue.tts_provider_name,
282
+ api_key: formValue.tts_provider_api_key || null,
283
+ endpoint: formValue.tts_provider_endpoint || null,
284
+ settings: {
285
+ use_ssml: formValue.tts_use_ssml
286
+ }
287
  },
288
+ stt_provider: {
289
+ name: formValue.stt_provider_name,
290
+ api_key: formValue.stt_provider_api_key || null,
291
+ endpoint: formValue.stt_provider_endpoint || null,
292
+ settings: {
293
+ speech_timeout_ms: formValue.stt_speech_timeout_ms,
294
+ noise_reduction_level: formValue.stt_noise_reduction_level,
295
+ vad_sensitivity: formValue.stt_vad_sensitivity,
296
+ language: formValue.stt_language,
297
+ model: formValue.stt_model,
298
+ use_enhanced: formValue.stt_use_enhanced,
299
+ enable_punctuation: formValue.stt_enable_punctuation,
300
+ interim_results: formValue.stt_interim_results
301
+ }
302
  }
303
+ };
 
304
 
305
+ this.apiService.updateEnvironment(payload)
306
+ .pipe(finalize(() => this.saving = false))
307
+ .subscribe({
308
+ next: () => {
309
+ this.snackBar.open('Environment configuration saved successfully', 'Close', {
310
+ duration: 3000,
311
+ panelClass: ['success-snackbar']
312
+ });
313
+ },
314
+ error: (error) => {
315
+ this.snackBar.open(
316
+ error.error?.detail || 'Failed to save environment configuration',
317
+ 'Close',
318
+ {
319
+ duration: 5000,
320
+ panelClass: ['error-snackbar']
321
+ }
322
+ );
323
+ }
324
  });
 
325
  }
326
 
327
+ testConnection(): void {
328
+ const endpoint = this.environmentForm.get('llm_provider_endpoint')?.value;
329
+ const apiKey = this.environmentForm.get('llm_provider_api_key')?.value;
330
+ const provider = this.environmentForm.get('llm_provider_name')?.value;
331
+
332
+ if (!endpoint) {
333
+ this.snackBar.open('Please enter an endpoint URL', 'Close', {
334
+ duration: 3000,
335
+ panelClass: ['error-snackbar']
336
+ });
337
  return;
338
  }
339
 
340
+ this.loading = true;
341
+ this.apiService.testConnection({ endpoint, api_key: apiKey, provider })
342
+ .pipe(finalize(() => this.loading = false))
343
+ .subscribe({
344
+ next: (result) => {
345
+ if (result.success) {
346
+ this.snackBar.open('Connection successful!', 'Close', {
347
+ duration: 3000,
348
+ panelClass: ['success-snackbar']
349
+ });
350
+ } else {
351
+ this.snackBar.open(result.message || 'Connection failed', 'Close', {
352
+ duration: 5000,
353
+ panelClass: ['error-snackbar']
354
+ });
355
+ }
356
+ },
357
+ error: (error) => {
358
+ this.snackBar.open('Connection test failed', 'Close', {
359
+ duration: 3000,
360
+ panelClass: ['error-snackbar']
361
+ });
362
+ }
363
  });
 
364
  }
365
 
366
+ toggleInternalPrompt(): void {
367
+ this.showInternalPrompt = !this.showInternalPrompt;
 
 
368
  }
369
 
370
+ toggleParameterCollection(): void {
371
+ this.showParameterCollection = !this.showParameterCollection;
 
 
372
  }
373
 
374
+ isLLMEndpointRequired(): boolean {
375
+ return this.currentLLMProvider?.requires_endpoint || false;
376
  }
377
 
378
+ isLLMApiKeyRequired(): boolean {
379
+ return this.currentLLMProvider?.requires_api_key || false;
380
  }
 
 
 
 
 
 
381
 
382
+ isTTSEnabled(): boolean {
383
+ return this.environmentForm.get('tts_provider_name')?.value !== 'no_tts';
384
+ }
 
385
 
386
+ isSTTEnabled(): boolean {
387
+ return this.environmentForm.get('stt_provider_name')?.value !== 'no_stt';
388
+ }
389
 
390
+ getLLMProviderDescription(): string {
391
+ return this.currentLLMProvider?.description || '';
392
+ }
393
 
394
+ getTTSProviderDescription(): string {
395
+ return this.currentTTSProvider?.description || '';
396
+ }
 
 
 
 
397
 
398
+ getSTTProviderDescription(): string {
399
+ return this.currentSTTProvider?.description || '';
400
+ }
401
  }