ciyidogan commited on
Commit
a1d47a0
·
verified ·
1 Parent(s): 2911ce4

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

Browse files
flare-ui/src/app/components/environment/environment.component.ts CHANGED
@@ -1,6 +1,7 @@
1
  import { Component, OnInit } from '@angular/core';
2
  import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
3
- import { MatSnackBar } from '@angular/material/snack-bar';
 
4
  import { ApiService } from '../../services/api.service';
5
  import { EnvironmentService } from '../../services/environment.service';
6
  import { CommonModule } from '@angular/common';
@@ -15,6 +16,8 @@ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
15
  import { MatExpansionModule } from '@angular/material/expansion';
16
  import { MatDividerModule } from '@angular/material/divider';
17
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
 
 
18
 
19
  // Provider interfaces
20
  interface ProviderConfig {
@@ -39,7 +42,6 @@ interface EnvironmentConfig {
39
  tts_provider: ProviderSettings;
40
  stt_provider: ProviderSettings;
41
  providers: ProviderConfig[];
42
- parameter_collection_config: any;
43
  }
44
 
45
  @Component({
@@ -48,6 +50,7 @@ interface EnvironmentConfig {
48
  imports: [
49
  CommonModule,
50
  ReactiveFormsModule,
 
51
  MatCardModule,
52
  MatFormFieldModule,
53
  MatInputModule,
@@ -58,7 +61,10 @@ interface EnvironmentConfig {
58
  MatSlideToggleModule,
59
  MatExpansionModule,
60
  MatDividerModule,
61
- MatProgressSpinnerModule
 
 
 
62
  ],
63
  templateUrl: './environment.component.html',
64
  styleUrls: ['./environment.component.scss']
@@ -67,6 +73,7 @@ export class EnvironmentComponent implements OnInit {
67
  form: FormGroup;
68
  loading = false;
69
  saving = false;
 
70
 
71
  // Provider lists
72
  llmProviders: ProviderConfig[] = [];
@@ -78,9 +85,17 @@ export class EnvironmentComponent implements OnInit {
78
  currentTTSProvider?: ProviderConfig;
79
  currentSTTProvider?: ProviderConfig;
80
 
81
- // Settings
82
- parameterCollectionConfig: any = {};
83
- internalPrompt = '';
 
 
 
 
 
 
 
 
84
 
85
  constructor(
86
  private fb: FormBuilder,
@@ -110,196 +125,280 @@ export class EnvironmentComponent implements OnInit {
110
  this.loadEnvironment();
111
  }
112
 
113
- loadEnvironment() {
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  this.loading = true;
 
 
115
  this.apiService.getEnvironment().subscribe({
116
- next: (data: EnvironmentConfig) => {
117
- // Separate providers by type
118
- this.llmProviders = data.providers.filter(p => p.type === 'llm');
119
- this.ttsProviders = data.providers.filter(p => p.type === 'tts');
120
- this.sttProviders = data.providers.filter(p => p.type === 'stt');
121
-
122
- // Load current settings
123
  if (data.llm_provider) {
124
- this.form.patchValue({
125
- llm_provider_name: data.llm_provider.name,
126
- llm_provider_api_key: data.llm_provider.api_key || '',
127
- llm_provider_endpoint: data.llm_provider.endpoint || ''
128
- });
129
-
130
- // Extract settings
131
- this.internalPrompt = data.llm_provider.settings?.internal_prompt || '';
132
- this.parameterCollectionConfig = data.llm_provider.settings?.parameter_collection_config || this.getDefaultParameterCollectionConfig();
133
-
134
- this.onLLMProviderChange(data.llm_provider.name);
135
  }
136
-
137
- if (data.tts_provider) {
138
- this.form.patchValue({
139
- tts_provider_name: data.tts_provider.name,
140
- tts_provider_api_key: data.tts_provider.api_key || '',
141
- tts_provider_endpoint: data.tts_provider.endpoint || ''
142
- });
143
- this.onTTSProviderChange(data.tts_provider.name);
144
- }
145
-
146
- if (data.stt_provider) {
147
- this.form.patchValue({
148
- stt_provider_name: data.stt_provider.name,
149
- stt_provider_api_key: data.stt_provider.api_key || '',
150
- stt_provider_endpoint: data.stt_provider.endpoint || ''
151
- });
152
- this.onSTTProviderChange(data.stt_provider.name);
153
- }
154
-
155
  this.loading = false;
 
156
  },
157
  error: (err) => {
158
- this.snackBar.open('Failed to load environment configuration', 'Close', {
159
- duration: 5000,
160
- panelClass: 'error-snackbar'
161
- });
162
  this.loading = false;
 
163
  }
164
  });
165
  }
166
 
167
- onLLMProviderChange(providerName: string) {
168
- this.currentLLMProvider = this.llmProviders.find(p => p.name === providerName);
169
-
170
- // Enable/disable fields based on provider requirements
171
- const apiKeyControl = this.form.get('llm_provider_api_key');
172
- const endpointControl = this.form.get('llm_provider_endpoint');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
- if (this.currentLLMProvider) {
175
- // API Key field
176
- if (this.currentLLMProvider.requires_api_key) {
177
- apiKeyControl?.enable();
178
- apiKeyControl?.setValidators([Validators.required]);
179
- } else {
180
- apiKeyControl?.disable();
181
- apiKeyControl?.clearValidators();
182
- }
183
-
184
- // Endpoint field
185
- if (this.currentLLMProvider.requires_endpoint) {
186
- endpointControl?.enable();
187
- endpointControl?.setValidators([Validators.required]);
188
- } else {
189
- endpointControl?.disable();
190
- endpointControl?.clearValidators();
191
- }
192
-
193
- apiKeyControl?.updateValueAndValidity();
194
- endpointControl?.updateValueAndValidity();
195
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
 
197
- // Update environment service
198
- this.updateEnvironmentService();
 
 
199
  }
200
 
201
- onTTSProviderChange(providerName: string) {
202
- this.currentTTSProvider = this.ttsProviders.find(p => p.name === providerName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
- const apiKeyControl = this.form.get('tts_provider_api_key');
205
- const endpointControl = this.form.get('tts_provider_endpoint');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
 
207
- if (this.currentTTSProvider) {
208
- // API Key field
209
- if (this.currentTTSProvider.requires_api_key) {
210
- apiKeyControl?.enable();
211
- apiKeyControl?.setValidators([Validators.required]);
212
- } else {
213
- apiKeyControl?.disable();
214
- apiKeyControl?.clearValidators();
215
- apiKeyControl?.setValue('');
216
- }
217
-
218
- // Endpoint field
219
- if (this.currentTTSProvider.requires_endpoint) {
220
- endpointControl?.enable();
221
- endpointControl?.setValidators([Validators.required]);
222
- } else {
223
- endpointControl?.disable();
224
- endpointControl?.clearValidators();
225
- endpointControl?.setValue('');
226
- }
227
-
228
- apiKeyControl?.updateValueAndValidity();
229
- endpointControl?.updateValueAndValidity();
230
  }
 
 
 
 
 
 
231
  }
232
 
233
- onSTTProviderChange(providerName: string) {
234
- this.currentSTTProvider = this.sttProviders.find(p => p.name === providerName);
 
235
 
236
- const apiKeyControl = this.form.get('stt_provider_api_key');
237
- const endpointControl = this.form.get('stt_provider_endpoint');
 
 
 
 
 
 
 
 
 
 
238
 
239
- if (this.currentSTTProvider) {
240
- // API Key field
241
- if (this.currentSTTProvider.requires_api_key) {
242
- apiKeyControl?.enable();
243
- apiKeyControl?.setValidators([Validators.required]);
244
- } else {
245
- apiKeyControl?.disable();
246
- apiKeyControl?.clearValidators();
247
- apiKeyControl?.setValue('');
248
- }
249
-
250
- // Endpoint field
251
- if (this.currentSTTProvider.requires_endpoint) {
252
- endpointControl?.enable();
253
- endpointControl?.setValidators([Validators.required]);
254
- } else {
255
- endpointControl?.disable();
256
- endpointControl?.clearValidators();
257
- endpointControl?.setValue('');
258
- }
259
-
260
- apiKeyControl?.updateValueAndValidity();
261
- endpointControl?.updateValueAndValidity();
262
  }
 
 
 
263
  }
264
 
265
- getDefaultParameterCollectionConfig() {
266
- return {
267
- enabled: true,
268
- max_params_per_question: 2,
269
- show_all_required: true,
270
- ask_optional_params: false,
271
- group_related_params: true,
272
- min_confidence_score: 0.7,
273
- collection_prompt: `You are a smart parameter collection assistant.
274
- Based on the conversation and the parameters needed, generate a natural question to collect missing parameters.
275
-
276
- Rules:
277
- 1. Ask for maximum {{max_params}} parameters in one question
278
- 2. Group parameters that naturally go together (like from/to cities, dates)
279
- 3. If some parameters were asked before but not answered, include them again
280
- 4. Be natural and conversational in {{project_language}}
281
- 5. Use context from the conversation to make the question flow naturally
282
-
283
- Generate ONLY the question, nothing else.`
284
- };
285
  }
286
 
287
- save() {
288
  if (this.form.invalid) {
289
- this.form.markAllAsTouched();
290
  return;
291
  }
292
 
293
  this.saving = true;
294
-
295
  const formValue = this.form.value;
296
-
297
- // Build provider settings
298
  const saveData = {
299
  llm_provider: {
300
  name: formValue.llm_provider_name,
301
- api_key: formValue.llm_provider_api_key || null,
302
- endpoint: formValue.llm_provider_endpoint || null,
303
  settings: {
304
  internal_prompt: this.internalPrompt,
305
  parameter_collection_config: this.parameterCollectionConfig
@@ -307,159 +406,141 @@ Generate ONLY the question, nothing else.`
307
  },
308
  tts_provider: {
309
  name: formValue.tts_provider_name,
310
- api_key: formValue.tts_provider_api_key || null,
311
- endpoint: formValue.tts_provider_endpoint || null,
312
  settings: {}
313
  },
314
  stt_provider: {
315
  name: formValue.stt_provider_name,
316
- api_key: formValue.stt_provider_api_key || null,
317
- endpoint: formValue.stt_provider_endpoint || null,
318
  settings: {}
319
- },
320
- parameter_collection_config: this.parameterCollectionConfig
321
  };
322
-
323
- this.apiService.updateEnvironment(saveData).subscribe({
324
  next: () => {
325
- // Update environment service
326
- this.updateEnvironmentService();
327
-
328
- this.snackBar.open('Environment configuration saved successfully', 'Close', {
329
- duration: 3000
330
- });
331
  this.saving = false;
332
  },
333
  error: (err) => {
334
- this.snackBar.open(
335
- err.error?.detail || 'Failed to save configuration',
336
- 'Close',
337
- { duration: 5000, panelClass: 'error-snackbar' }
338
- );
339
  this.saving = false;
340
  }
341
  });
342
  }
343
 
344
- private updateEnvironmentService() {
345
- // Update environment service with current form values
346
- const formValue = this.form.value;
347
- this.environmentService.setLLMProvider(formValue.llm_provider_name);
348
- }
349
-
350
- getLLMProviderIcon(provider: ProviderConfig): string {
351
- const iconMap: { [key: string]: string } = {
352
- 'spark': 'flash_on',
353
- 'gpt4o': 'psychology',
354
- 'gpt4o-mini': 'psychology_alt'
355
- };
356
- return iconMap[provider.name] || 'smart_toy';
357
- }
358
-
359
- getTTSProviderIcon(provider: ProviderConfig): string {
360
- const iconMap: { [key: string]: string } = {
361
- 'no_tts': 'volume_off',
362
- 'elevenlabs': 'record_voice_over',
363
- 'blaze': 'campaign'
364
- };
365
- return iconMap[provider.name] || 'volume_up';
366
- }
367
-
368
- getSTTProviderIcon(provider: ProviderConfig): string {
369
- const iconMap: { [key: string]: string } = {
370
- 'no_stt': 'mic_off',
371
- 'google': 'g_translate',
372
- 'azure': 'cloud',
373
- 'flicker': 'light_mode'
374
- };
375
- return iconMap[provider.name] || 'mic';
376
  }
377
 
378
- getApiKeyLabel(providerType: string): string {
379
- const provider = providerType === 'llm' ? this.currentLLMProvider :
380
- providerType === 'tts' ? this.currentTTSProvider :
381
- this.currentSTTProvider;
382
-
383
- if (!provider) return 'API Key';
384
 
385
- // Special cases
386
- if (provider.name === 'google' && providerType === 'stt') {
387
- return 'Service Account JSON Path';
 
 
 
 
388
  }
389
-
390
- return 'API Key';
391
  }
392
 
393
- getApiKeyPlaceholder(providerType: string): string {
394
- const provider = providerType === 'llm' ? this.currentLLMProvider :
395
- providerType === 'tts' ? this.currentTTSProvider :
396
- this.currentSTTProvider;
397
 
398
- if (!provider) return 'Enter API key';
399
-
400
- // Provider-specific placeholders
401
- const placeholders: { [key: string]: string } = {
402
- 'spark': 'Enter Spark token',
403
- 'gpt4o': 'sk-...',
404
- 'gpt4o-mini': 'sk-...',
405
- 'google': '/path/to/credentials.json',
406
- 'azure': 'Enter Azure subscription key',
407
- 'elevenlabs': 'Enter ElevenLabs API key'
408
- };
409
-
410
- return placeholders[provider.name] || 'Enter API key';
411
  }
412
 
413
- getEndpointPlaceholder(providerType: string): string {
414
- const provider = providerType === 'llm' ? this.currentLLMProvider :
415
- providerType === 'tts' ? this.currentTTSProvider :
416
- this.currentSTTProvider;
417
-
418
- if (!provider) return 'https://...';
419
-
420
- // Provider-specific placeholders
421
- const placeholders: { [key: string]: string } = {
422
- 'spark': 'http://localhost:7861',
423
- 'blaze': 'https://blaze-tts.example.com',
424
- 'flicker': 'https://flicker-stt.example.com'
425
- };
426
-
427
- return placeholders[provider.name] || 'https://...';
428
  }
429
 
430
- formatSliderLabel(value: number): string {
431
- return `${value}`;
 
 
 
 
 
 
 
 
 
 
432
  }
433
 
434
- resetCollectionPrompt() {
435
- this.parameterCollectionConfig.collection_prompt = this.getDefaultParameterCollectionConfig().collection_prompt;
 
 
 
 
 
 
 
 
 
 
 
436
  }
437
 
438
- testConnection() {
439
- if (!this.currentLLMProvider?.requires_endpoint) {
440
- this.snackBar.open('This provider does not require endpoint testing', 'Close', {
441
- duration: 3000
442
- });
443
- return;
 
 
 
 
444
  }
 
 
 
 
 
445
 
 
446
  const endpoint = this.form.get('llm_provider_endpoint')?.value;
447
  if (!endpoint) {
448
- this.snackBar.open('Please enter an endpoint URL', 'Close', {
449
- duration: 3000
450
- });
451
  return;
452
  }
453
-
454
- this.snackBar.open('Testing connection...', undefined, {
455
- duration: 2000
456
- });
457
 
 
458
  // TODO: Implement actual connection test
459
- setTimeout(() => {
460
- this.snackBar.open('Connection successful!', 'Close', {
461
- duration: 3000
462
- });
463
- }, 2000);
464
  }
465
  }
 
1
  import { Component, OnInit } from '@angular/core';
2
  import { FormBuilder, FormGroup, Validators, ReactiveFormsModule } from '@angular/forms';
3
+ import { FormsModule } from '@angular/forms';
4
+ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
5
  import { ApiService } from '../../services/api.service';
6
  import { EnvironmentService } from '../../services/environment.service';
7
  import { CommonModule } from '@angular/common';
 
16
  import { MatExpansionModule } from '@angular/material/expansion';
17
  import { MatDividerModule } from '@angular/material/divider';
18
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
19
+ import { MatTooltipModule } from '@angular/material/tooltip';
20
+ import { MatDialogModule } from '@angular/material/dialog';
21
 
22
  // Provider interfaces
23
  interface ProviderConfig {
 
42
  tts_provider: ProviderSettings;
43
  stt_provider: ProviderSettings;
44
  providers: ProviderConfig[];
 
45
  }
46
 
47
  @Component({
 
50
  imports: [
51
  CommonModule,
52
  ReactiveFormsModule,
53
+ FormsModule,
54
  MatCardModule,
55
  MatFormFieldModule,
56
  MatInputModule,
 
61
  MatSlideToggleModule,
62
  MatExpansionModule,
63
  MatDividerModule,
64
+ MatProgressSpinnerModule,
65
+ MatSnackBarModule,
66
+ MatTooltipModule,
67
+ MatDialogModule
68
  ],
69
  templateUrl: './environment.component.html',
70
  styleUrls: ['./environment.component.scss']
 
73
  form: FormGroup;
74
  loading = false;
75
  saving = false;
76
+ isLoading = false;
77
 
78
  // Provider lists
79
  llmProviders: ProviderConfig[] = [];
 
85
  currentTTSProvider?: ProviderConfig;
86
  currentSTTProvider?: ProviderConfig;
87
 
88
+ // Settings for LLM
89
+ internalPrompt: string = '';
90
+ parameterCollectionConfig: any = {
91
+ enabled: false,
92
+ max_params_per_question: 1,
93
+ show_all_required: false,
94
+ ask_optional_params: false,
95
+ group_related_params: false,
96
+ min_confidence_score: 0.7,
97
+ collection_prompt: 'Please provide the following information:'
98
+ };
99
 
100
  constructor(
101
  private fb: FormBuilder,
 
125
  this.loadEnvironment();
126
  }
127
 
128
+ // Safe getters for template
129
+ get currentLLMProviderSafe(): ProviderConfig | null {
130
+ return this.currentLLMProvider || null;
131
+ }
132
+
133
+ get currentTTSProviderSafe(): ProviderConfig | null {
134
+ return this.currentTTSProvider || null;
135
+ }
136
+
137
+ get currentSTTProviderSafe(): ProviderConfig | null {
138
+ return this.currentSTTProvider || null;
139
+ }
140
+
141
+ loadEnvironment(): void {
142
  this.loading = true;
143
+ this.isLoading = true;
144
+
145
  this.apiService.getEnvironment().subscribe({
146
+ next: (data: any) => {
147
+ // Check if it's new format or legacy
 
 
 
 
 
148
  if (data.llm_provider) {
149
+ this.handleNewFormat(data);
150
+ } else {
151
+ this.handleLegacyFormat(data);
 
 
 
 
 
 
 
 
152
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  this.loading = false;
154
+ this.isLoading = false;
155
  },
156
  error: (err) => {
157
+ console.error('Failed to load environment:', err);
158
+ this.snackBar.open('Failed to load environment configuration', 'Close', { duration: 3000 });
 
 
159
  this.loading = false;
160
+ this.isLoading = false;
161
  }
162
  });
163
  }
164
 
165
+ handleNewFormat(data: EnvironmentConfig): void {
166
+ // Update provider lists
167
+ if (data.providers) {
168
+ this.llmProviders = data.providers.filter(p => p.type === 'llm');
169
+ this.ttsProviders = data.providers.filter(p => p.type === 'tts');
170
+ this.sttProviders = data.providers.filter(p => p.type === 'stt');
171
+ }
172
+
173
+ // Set form values
174
+ this.form.patchValue({
175
+ llm_provider_name: data.llm_provider?.name || '',
176
+ llm_provider_api_key: data.llm_provider?.api_key || '',
177
+ llm_provider_endpoint: data.llm_provider?.endpoint || '',
178
+ tts_provider_name: data.tts_provider?.name || 'no_tts',
179
+ tts_provider_api_key: data.tts_provider?.api_key || '',
180
+ tts_provider_endpoint: data.tts_provider?.endpoint || '',
181
+ stt_provider_name: data.stt_provider?.name || 'no_stt',
182
+ stt_provider_api_key: data.stt_provider?.api_key || '',
183
+ stt_provider_endpoint: data.stt_provider?.endpoint || ''
184
+ });
185
+
186
+ // Set internal prompt and parameter collection config
187
+ this.internalPrompt = data.llm_provider?.settings?.internal_prompt || '';
188
+ this.parameterCollectionConfig = data.llm_provider?.settings?.parameter_collection_config || this.parameterCollectionConfig;
189
+
190
+ // Update current providers
191
+ this.updateCurrentProviders();
192
 
193
+ // Notify environment service
194
+ if (data.tts_provider?.name !== 'no_tts') {
195
+ this.environmentService.setTTSEnabled(true);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
196
  }
197
+ if (data.stt_provider?.name !== 'no_stt') {
198
+ this.environmentService.setSTTEnabled(true);
199
+ }
200
+ }
201
+
202
+ handleLegacyFormat(data: any): void {
203
+ console.warn('Legacy environment format detected, using defaults');
204
+
205
+ // Set default providers if not present
206
+ this.llmProviders = this.getDefaultProviders('llm');
207
+ this.ttsProviders = this.getDefaultProviders('tts');
208
+ this.sttProviders = this.getDefaultProviders('stt');
209
+
210
+ // Map legacy fields
211
+ this.form.patchValue({
212
+ llm_provider_name: data.work_mode || 'spark',
213
+ llm_provider_api_key: data.cloud_token || '',
214
+ llm_provider_endpoint: data.spark_endpoint || '',
215
+ tts_provider_name: data.tts_engine || 'no_tts',
216
+ tts_provider_api_key: data.tts_engine_api_key || '',
217
+ stt_provider_name: data.stt_engine || 'no_stt',
218
+ stt_provider_api_key: data.stt_engine_api_key || ''
219
+ });
220
 
221
+ this.internalPrompt = data.internal_prompt || '';
222
+ this.parameterCollectionConfig = data.parameter_collection_config || this.parameterCollectionConfig;
223
+
224
+ this.updateCurrentProviders();
225
  }
226
 
227
+ getDefaultProviders(type: string): ProviderConfig[] {
228
+ const defaults: { [key: string]: ProviderConfig[] } = {
229
+ llm: [
230
+ {
231
+ type: 'llm',
232
+ name: 'spark',
233
+ display_name: 'Spark (YTU Cosmos)',
234
+ requires_endpoint: true,
235
+ requires_api_key: true,
236
+ requires_repo_info: true,
237
+ description: 'YTU Cosmos Spark LLM Service'
238
+ },
239
+ {
240
+ type: 'llm',
241
+ name: 'gpt4o',
242
+ display_name: 'GPT-4o',
243
+ requires_endpoint: false,
244
+ requires_api_key: true,
245
+ requires_repo_info: false,
246
+ description: 'OpenAI GPT-4o model'
247
+ },
248
+ {
249
+ type: 'llm',
250
+ name: 'gpt4o-mini',
251
+ display_name: 'GPT-4o Mini',
252
+ requires_endpoint: false,
253
+ requires_api_key: true,
254
+ requires_repo_info: false,
255
+ description: 'OpenAI GPT-4o Mini model'
256
+ }
257
+ ],
258
+ tts: [
259
+ {
260
+ type: 'tts',
261
+ name: 'no_tts',
262
+ display_name: 'No TTS',
263
+ requires_endpoint: false,
264
+ requires_api_key: false,
265
+ requires_repo_info: false,
266
+ description: 'Disable text-to-speech'
267
+ },
268
+ {
269
+ type: 'tts',
270
+ name: 'elevenlabs',
271
+ display_name: 'ElevenLabs',
272
+ requires_endpoint: false,
273
+ requires_api_key: true,
274
+ requires_repo_info: false,
275
+ description: 'ElevenLabs TTS service'
276
+ }
277
+ ],
278
+ stt: [
279
+ {
280
+ type: 'stt',
281
+ name: 'no_stt',
282
+ display_name: 'No STT',
283
+ requires_endpoint: false,
284
+ requires_api_key: false,
285
+ requires_repo_info: false,
286
+ description: 'Disable speech-to-text'
287
+ },
288
+ {
289
+ type: 'stt',
290
+ name: 'google',
291
+ display_name: 'Google Cloud STT',
292
+ requires_endpoint: false,
293
+ requires_api_key: true,
294
+ requires_repo_info: false,
295
+ description: 'Google Cloud Speech-to-Text'
296
+ }
297
+ ]
298
+ };
299
 
300
+ return defaults[type] || [];
301
+ }
302
+
303
+ updateCurrentProviders(): void {
304
+ const llmName = this.form.get('llm_provider_name')?.value;
305
+ const ttsName = this.form.get('tts_provider_name')?.value;
306
+ const sttName = this.form.get('stt_provider_name')?.value;
307
+
308
+ this.currentLLMProvider = this.llmProviders.find(p => p.name === llmName);
309
+ this.currentTTSProvider = this.ttsProviders.find(p => p.name === ttsName);
310
+ this.currentSTTProvider = this.sttProviders.find(p => p.name === sttName);
311
+
312
+ // Update form validators based on requirements
313
+ this.updateFormValidators();
314
+ }
315
+
316
+ updateFormValidators(): void {
317
+ // LLM validators
318
+ if (this.currentLLMProvider?.requires_api_key) {
319
+ this.form.get('llm_provider_api_key')?.setValidators(Validators.required);
320
+ } else {
321
+ this.form.get('llm_provider_api_key')?.clearValidators();
322
+ }
323
 
324
+ if (this.currentLLMProvider?.requires_endpoint) {
325
+ this.form.get('llm_provider_endpoint')?.setValidators(Validators.required);
326
+ } else {
327
+ this.form.get('llm_provider_endpoint')?.clearValidators();
328
+ }
329
+
330
+ // TTS validators
331
+ if (this.currentTTSProvider?.requires_api_key) {
332
+ this.form.get('tts_provider_api_key')?.setValidators(Validators.required);
333
+ } else {
334
+ this.form.get('tts_provider_api_key')?.clearValidators();
335
+ }
336
+
337
+ // STT validators
338
+ if (this.currentSTTProvider?.requires_api_key) {
339
+ this.form.get('stt_provider_api_key')?.setValidators(Validators.required);
340
+ } else {
341
+ this.form.get('stt_provider_api_key')?.clearValidators();
 
 
 
 
 
342
  }
343
+
344
+ // Update validity
345
+ this.form.get('llm_provider_api_key')?.updateValueAndValidity();
346
+ this.form.get('llm_provider_endpoint')?.updateValueAndValidity();
347
+ this.form.get('tts_provider_api_key')?.updateValueAndValidity();
348
+ this.form.get('stt_provider_api_key')?.updateValueAndValidity();
349
  }
350
 
351
+ onLLMProviderChange(value: string): void {
352
+ this.currentLLMProvider = this.llmProviders.find(p => p.name === value);
353
+ this.updateFormValidators();
354
 
355
+ // Reset fields if provider doesn't require them
356
+ if (!this.currentLLMProvider?.requires_api_key) {
357
+ this.form.get('llm_provider_api_key')?.setValue('');
358
+ }
359
+ if (!this.currentLLMProvider?.requires_endpoint) {
360
+ this.form.get('llm_provider_endpoint')?.setValue('');
361
+ }
362
+ }
363
+
364
+ onTTSProviderChange(value: string): void {
365
+ this.currentTTSProvider = this.ttsProviders.find(p => p.name === value);
366
+ this.updateFormValidators();
367
 
368
+ if (!this.currentTTSProvider?.requires_api_key) {
369
+ this.form.get('tts_provider_api_key')?.setValue('');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
370
  }
371
+
372
+ // Notify environment service
373
+ this.environmentService.setTTSEnabled(value !== 'no_tts');
374
  }
375
 
376
+ onSTTProviderChange(value: string): void {
377
+ this.currentSTTProvider = this.sttProviders.find(p => p.name === value);
378
+ this.updateFormValidators();
379
+
380
+ if (!this.currentSTTProvider?.requires_api_key) {
381
+ this.form.get('stt_provider_api_key')?.setValue('');
382
+ }
383
+
384
+ // Notify environment service
385
+ this.environmentService.setSTTEnabled(value !== 'no_stt');
 
 
 
 
 
 
 
 
 
 
386
  }
387
 
388
+ saveEnvironment(): void {
389
  if (this.form.invalid) {
390
+ this.snackBar.open('Please fix validation errors', 'Close', { duration: 3000 });
391
  return;
392
  }
393
 
394
  this.saving = true;
 
395
  const formValue = this.form.value;
396
+
 
397
  const saveData = {
398
  llm_provider: {
399
  name: formValue.llm_provider_name,
400
+ api_key: formValue.llm_provider_api_key,
401
+ endpoint: formValue.llm_provider_endpoint,
402
  settings: {
403
  internal_prompt: this.internalPrompt,
404
  parameter_collection_config: this.parameterCollectionConfig
 
406
  },
407
  tts_provider: {
408
  name: formValue.tts_provider_name,
409
+ api_key: formValue.tts_provider_api_key,
410
+ endpoint: formValue.tts_provider_endpoint,
411
  settings: {}
412
  },
413
  stt_provider: {
414
  name: formValue.stt_provider_name,
415
+ api_key: formValue.stt_provider_api_key,
416
+ endpoint: formValue.stt_provider_endpoint,
417
  settings: {}
418
+ }
 
419
  };
420
+
421
+ this.apiService.updateEnvironment(saveData as any).subscribe({
422
  next: () => {
423
+ this.snackBar.open('Environment configuration saved successfully', 'Close', { duration: 3000 });
 
 
 
 
 
424
  this.saving = false;
425
  },
426
  error: (err) => {
427
+ console.error('Failed to save environment:', err);
428
+ this.snackBar.open('Failed to save environment configuration', 'Close', { duration: 3000 });
 
 
 
429
  this.saving = false;
430
  }
431
  });
432
  }
433
 
434
+ // Icon helpers
435
+ getLLMProviderIcon(provider: ProviderConfig | null): string {
436
+ if (!provider || !provider.name) return 'smart_toy';
437
+
438
+ switch(provider.name) {
439
+ case 'gpt4o':
440
+ case 'gpt4o-mini':
441
+ return 'psychology';
442
+ case 'spark':
443
+ return 'auto_awesome';
444
+ default:
445
+ return 'smart_toy';
446
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
  }
448
 
449
+ getTTSProviderIcon(provider: ProviderConfig | null): string {
450
+ if (!provider || !provider.name) return 'record_voice_over';
 
 
 
 
451
 
452
+ switch(provider.name) {
453
+ case 'elevenlabs':
454
+ return 'graphic_eq';
455
+ case 'blaze':
456
+ return 'volume_up';
457
+ default:
458
+ return 'record_voice_over';
459
  }
 
 
460
  }
461
 
462
+ getSTTProviderIcon(provider: ProviderConfig | null): string {
463
+ if (!provider || !provider.name) return 'mic';
 
 
464
 
465
+ switch(provider.name) {
466
+ case 'google':
467
+ return 'g_translate';
468
+ case 'azure':
469
+ return 'cloud';
470
+ case 'flicker':
471
+ return 'mic_none';
472
+ default:
473
+ return 'mic';
474
+ }
 
 
 
475
  }
476
 
477
+ getProviderIcon(provider: ProviderConfig): string {
478
+ switch(provider.type) {
479
+ case 'llm':
480
+ return this.getLLMProviderIcon(provider);
481
+ case 'tts':
482
+ return this.getTTSProviderIcon(provider);
483
+ case 'stt':
484
+ return this.getSTTProviderIcon(provider);
485
+ default:
486
+ return 'settings';
487
+ }
 
 
 
 
488
  }
489
 
490
+ // Helper methods
491
+ getApiKeyLabel(type: string): string {
492
+ switch(type) {
493
+ case 'llm':
494
+ return this.currentLLMProvider?.name === 'spark' ? 'API Token' : 'API Key';
495
+ case 'tts':
496
+ return 'API Key';
497
+ case 'stt':
498
+ return this.currentSTTProvider?.name === 'google' ? 'Credentials JSON Path' : 'API Key';
499
+ default:
500
+ return 'API Key';
501
+ }
502
  }
503
 
504
+ getApiKeyPlaceholder(type: string): string {
505
+ switch(type) {
506
+ case 'llm':
507
+ if (this.currentLLMProvider?.name === 'spark') return 'Enter Spark token';
508
+ if (this.currentLLMProvider?.name?.includes('gpt')) return 'sk-...';
509
+ return 'Enter API key';
510
+ case 'tts':
511
+ return 'Enter TTS API key';
512
+ case 'stt':
513
+ return this.currentSTTProvider?.name === 'google' ? '/path/to/credentials.json' : 'Enter STT API key';
514
+ default:
515
+ return 'Enter API key';
516
+ }
517
  }
518
 
519
+ getEndpointPlaceholder(type: string): string {
520
+ switch(type) {
521
+ case 'llm':
522
+ return 'https://spark-api.example.com';
523
+ case 'tts':
524
+ return 'https://tts-api.example.com';
525
+ case 'stt':
526
+ return 'https://stt-api.example.com';
527
+ default:
528
+ return 'https://api.example.com';
529
  }
530
+ }
531
+
532
+ resetCollectionPrompt(): void {
533
+ this.parameterCollectionConfig.collection_prompt = 'Please provide the following information:';
534
+ }
535
 
536
+ testConnection(): void {
537
  const endpoint = this.form.get('llm_provider_endpoint')?.value;
538
  if (!endpoint) {
539
+ this.snackBar.open('Please enter an endpoint URL', 'Close', { duration: 2000 });
 
 
540
  return;
541
  }
 
 
 
 
542
 
543
+ this.snackBar.open('Testing connection...', 'Close', { duration: 2000 });
544
  // TODO: Implement actual connection test
 
 
 
 
 
545
  }
546
  }