ciyidogan commited on
Commit
8ad9f22
·
verified ·
1 Parent(s): 0dd2a6a

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

Browse files
flare-ui/src/app/components/environment/environment.component.html CHANGED
@@ -1,456 +1,275 @@
1
- <div class="environment-container">
2
- <mat-card>
3
- <mat-card-header>
4
- <mat-card-title>
5
- <mat-icon>settings</mat-icon>
6
- Environment Configuration
7
- </mat-card-title>
8
- </mat-card-header>
 
 
 
9
 
10
- <mat-card-content>
11
- @if (isGPTMode()) {
12
- <mat-card class="info-card">
13
- <mat-card-content>
14
- <mat-icon>info</mat-icon>
15
- <div>
16
- <strong>{{ environment.work_mode === 'gpt4o' ? 'GPT-4o' : 'GPT-4o Mini' }} Mode</strong>
17
- <p>This mode uses OpenAI's API which has usage-based pricing.</p>
18
- <p>Approximate cost: {{ environment.work_mode === 'gpt4o' ? '$0.01-0.03' : '$0.001-0.003' }} per conversation turn.</p>
19
- </div>
20
- </mat-card-content>
21
- </mat-card>
22
- }
 
 
 
23
 
24
- <form (ngSubmit)="save()" #envForm="ngForm">
25
- <mat-form-field appearance="outline" class="full-width">
26
- <mat-label>Work Mode</mat-label>
27
- <mat-select
28
- name="workMode"
29
- [(ngModel)]="environment.work_mode"
30
- (selectionChange)="onWorkModeChange()"
31
- required
32
- [disabled]="loading"
33
- >
34
- <mat-option value="hfcloud">HF Cloud</mat-option>
35
- <mat-option value="cloud">Cloud</mat-option>
36
- <mat-option value="on-premise">On-Premise</mat-option>
37
- <mat-option value="gpt4o">GPT-4o</mat-option>
38
- <mat-option value="gpt4o-mini">GPT-4o Mini</mat-option>
39
- </mat-select>
40
- <mat-icon matPrefix>cloud</mat-icon>
 
 
 
41
  </mat-form-field>
 
 
 
 
 
 
 
 
42
 
 
 
 
 
 
 
 
 
 
43
  <mat-form-field appearance="outline" class="full-width">
44
- <mat-label>{{ getTokenLabel() }}</mat-label>
45
- <input
46
- matInput
47
- type="password"
48
- name="cloudToken"
49
- [(ngModel)]="environment.cloud_token"
50
- [disabled]="loading || environment.work_mode === 'on-premise'"
51
- [placeholder]="getTokenPlaceholder()"
52
- >
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  <mat-icon matPrefix>vpn_key</mat-icon>
54
- <mat-hint>{{ isGPTMode() ? 'Required for OpenAI API access' : 'Required for HF Cloud and Cloud modes' }}</mat-hint>
 
 
55
  </mat-form-field>
56
 
57
- <mat-form-field appearance="outline" class="full-width">
58
- <mat-label>Spark Endpoint</mat-label>
59
- <input
60
- matInput
61
- type="url"
62
- name="sparkEndpoint"
63
- [(ngModel)]="environment.spark_endpoint"
64
- [required]="!isGPTMode()"
65
- [disabled]="loading || isGPTMode()"
66
- placeholder="https://spark-service.example.com"
67
- >
68
  <mat-icon matPrefix>link</mat-icon>
69
- <button
70
- mat-icon-button
71
- matSuffix
72
- type="button"
73
- (click)="testConnection()"
74
- [disabled]="loading || !environment.spark_endpoint || isGPTMode()"
75
- matTooltip="Test Connection"
76
- >
77
- <mat-icon>wifi_tethering</mat-icon>
78
- </button>
79
- @if (isGPTMode()) {
80
- <mat-hint>Not required for GPT mode</mat-hint>
81
- }
82
  </mat-form-field>
83
 
84
- <!-- TTS Configuration -->
85
- <div class="engine-row">
86
- <mat-form-field appearance="outline" class="engine-field">
87
- <mat-label>TTS Engine</mat-label>
88
- <mat-select
89
- name="ttsEngine"
90
- [(ngModel)]="environment.tts_engine"
91
- (selectionChange)="onTTSEngineChange()"
92
- [disabled]="loading"
93
- >
94
- <mat-option value="no_tts">No TTS</mat-option>
95
- <mat-option value="elevenlabs">ElevenLabs</mat-option>
96
- <mat-option value="blaze">Blaze (Coming Soon)</mat-option>
97
- </mat-select>
98
- <mat-icon matPrefix>record_voice_over</mat-icon>
99
- </mat-form-field>
100
 
101
- <mat-form-field appearance="outline" class="api-key-field">
102
- <mat-label>TTS API Key</mat-label>
103
- <input
104
- matInput
105
- type="password"
106
- name="ttsApiKey"
107
- [(ngModel)]="environment.tts_engine_api_key"
108
- [disabled]="loading || environment.tts_engine === 'no_tts'"
109
- [required]="environment.tts_engine !== 'no_tts'"
110
- placeholder="Enter TTS API key"
111
- >
112
- <mat-icon matPrefix>key</mat-icon>
113
- </mat-form-field>
114
 
115
- <mat-checkbox
116
- name="ttsUseSSML"
117
- [(ngModel)]="ttsSettings.use_ssml"
118
- [disabled]="loading || !isTTSProviderSSMLCapable()"
119
- *ngIf="environment.tts_engine !== 'no_tts'">
120
- Use SSML
121
- </mat-checkbox>
 
 
 
 
 
 
 
 
 
122
 
123
- </div>
 
 
 
 
 
 
 
 
 
 
124
 
125
- <!-- STT Configuration -->
126
- <div class="engine-row">
127
- <mat-form-field appearance="outline" class="engine-field">
128
- <mat-label>STT Engine</mat-label>
129
- <mat-select
130
- name="sttEngine"
131
- [(ngModel)]="environment.stt_engine"
132
- (selectionChange)="onSTTEngineChange()"
133
- [disabled]="loading"
134
- >
135
- <mat-option value="no_stt">No STT</mat-option>
136
- <mat-option value="google">Google Cloud Speech</mat-option>
137
- <mat-option value="azure">Azure Speech (Coming Soon)</mat-option>
138
- <mat-option value="amazon">Amazon Transcribe (Coming Soon)</mat-option>
139
- <mat-option value="flicker">Flicker (Coming Soon)</mat-option>
140
- </mat-select>
141
- <mat-icon matPrefix>mic</mat-icon>
142
- </mat-form-field>
143
 
144
- <mat-form-field appearance="outline" class="api-key-field">
145
- <mat-label>{{ getSTTKeyLabel() }}</mat-label>
146
- <input
147
- matInput
148
- [type]="environment.stt_engine === 'google' ? 'text' : 'password'"
149
- name="sttApiKey"
150
- [(ngModel)]="environment.stt_engine_api_key"
151
- [disabled]="loading || environment.stt_engine === 'no_stt'"
152
- [required]="environment.stt_engine !== 'no_stt'"
153
- [placeholder]="getSTTKeyPlaceholder()"
154
- >
155
- <mat-icon matPrefix>key</mat-icon>
156
- <mat-hint>{{ getSTTKeyHint() }}</mat-hint>
157
- </mat-form-field>
158
- </div>
159
 
160
- <div>
161
- <!-- STT Settings Panel -->
162
- <mat-expansion-panel class="settings-panel" *ngIf="environment.stt_engine !== 'no_stt'">
163
- <mat-expansion-panel-header>
164
- <mat-panel-title>
165
- <mat-icon>settings_voice</mat-icon>
166
- STT Settings
167
- </mat-panel-title>
168
- <mat-panel-description>
169
- Advanced speech recognition settings
170
- </mat-panel-description>
171
- </mat-expansion-panel-header>
172
-
173
- <div class="stt-settings-content">
174
- <!-- Language -->
175
- <mat-form-field appearance="outline" class="full-width">
176
- <mat-label>Language</mat-label>
177
- <mat-select
178
- name="sttLanguage"
179
- [(ngModel)]="sttSettings.language"
180
- [disabled]="loading"
181
- >
182
- <mat-option value="tr-TR">Turkish (tr-TR)</mat-option>
183
- <mat-option value="en-US">English US (en-US)</mat-option>
184
- <mat-option value="en-GB">English UK (en-GB)</mat-option>
185
- <mat-option value="de-DE">German (de-DE)</mat-option>
186
- <mat-option value="fr-FR">French (fr-FR)</mat-option>
187
- <mat-option value="es-ES">Spanish (es-ES)</mat-option>
188
  </mat-select>
189
- <mat-icon matPrefix>language</mat-icon>
190
  </mat-form-field>
191
-
192
- <!-- Model -->
193
- <mat-form-field appearance="outline" class="full-width" *ngIf="environment.stt_engine === 'google'">
194
- <mat-label>Recognition Model</mat-label>
195
- <mat-select
196
- name="sttModel"
197
- [(ngModel)]="sttSettings.model"
198
- [disabled]="loading"
199
- >
200
- <mat-option value="latest_long">Latest Long (Best for long audio)</mat-option>
201
- <mat-option value="latest_short">Latest Short (Best for short audio)</mat-option>
202
- <mat-option value="command_and_search">Command and Search</mat-option>
203
- <mat-option value="phone_call">Phone Call</mat-option>
204
- <mat-option value="video">Video</mat-option>
205
- </mat-select>
206
- <mat-icon matPrefix>model_training</mat-icon>
207
  </mat-form-field>
208
-
209
- <!-- Speech Timeout -->
210
- <div class="slider-field">
211
- <label>Speech Timeout: {{ sttSettings.speech_timeout_ms }}ms</label>
212
- <mat-slider
213
- [min]="500"
214
- [max]="5000"
215
- [step]="100"
216
- [discrete]="true"
217
- [displayWith]="formatMilliseconds"
218
- >
219
- <input matSliderThumb
220
- name="sttSpeechTimeout"
221
- [(ngModel)]="sttSettings.speech_timeout_ms">
222
- </mat-slider>
223
- <mat-hint>Silence duration to end speech detection</mat-hint>
224
- </div>
225
-
226
- <!-- VAD Sensitivity -->
227
- <div class="slider-field">
228
- <label>Voice Activity Detection Sensitivity: {{ sttSettings.vad_sensitivity }}</label>
229
- <mat-slider
230
- [min]="0"
231
- [max]="1"
232
- [step]="0.1"
233
- [discrete]="true"
234
- >
235
- <input matSliderThumb
236
- name="sttVadSensitivity"
237
- [(ngModel)]="sttSettings.vad_sensitivity">
238
- </mat-slider>
239
- <mat-hint>Higher values = more sensitive</mat-hint>
240
- </div>
241
-
242
- <!-- Noise Reduction Level -->
243
- <div class="slider-field">
244
- <label>Noise Reduction Level: {{ sttSettings.noise_reduction_level }}</label>
245
- <mat-slider
246
- [min]="0"
247
- [max]="3"
248
- [step]="1"
249
- [discrete]="true"
250
- >
251
- <input matSliderThumb
252
- name="sttNoiseReduction"
253
- [(ngModel)]="sttSettings.noise_reduction_level">
254
- </mat-slider>
255
- <mat-hint>0 = Off, 3 = Maximum</mat-hint>
256
- </div>
257
-
258
- <!-- Checkboxes -->
259
- <div class="checkbox-group">
260
- <mat-checkbox
261
- name="sttUseEnhanced"
262
- [(ngModel)]="sttSettings.use_enhanced"
263
- [disabled]="loading"
264
- *ngIf="environment.stt_engine === 'google'">
265
- Use Enhanced Model
266
- </mat-checkbox>
267
-
268
- <mat-checkbox
269
- name="sttEnablePunctuation"
270
- [(ngModel)]="sttSettings.enable_punctuation"
271
- [disabled]="loading">
272
- Enable Automatic Punctuation
273
- </mat-checkbox>
274
-
275
- <mat-checkbox
276
- name="sttInterimResults"
277
- [(ngModel)]="sttSettings.interim_results"
278
- [disabled]="loading">
279
- Show Interim Results
280
- </mat-checkbox>
281
- </div>
282
  </div>
283
- </mat-expansion-panel>
284
- </div>
285
 
286
- <mat-expansion-panel class="prompt-panel settings-panel">
287
- <mat-expansion-panel-header>
288
- <mat-panel-title>
289
- <mat-icon>psychology</mat-icon>
290
- Internal System Prompt
291
- </mat-panel-title>
292
- <mat-panel-description>
293
- Advanced configuration for LLM
294
- </mat-panel-description>
295
- </mat-expansion-panel-header>
296
-
297
- <mat-form-field appearance="outline" class="full-width">
298
- <mat-label>Internal Prompt</mat-label>
299
- <textarea
300
- matInput
301
- name="internalPrompt"
302
- [(ngModel)]="environment.internal_prompt"
303
- [disabled]="loading"
304
- rows="10"
305
- placeholder="Enter internal system prompt..."
306
- class="code-textarea"
307
- ></textarea>
308
- <mat-hint>This prompt will be prepended to all project prompts</mat-hint>
309
- </mat-form-field>
310
- </mat-expansion-panel>
311
 
312
- <!-- Parameter Collection Configuration -->
313
- <mat-expansion-panel class="prompt-panel settings-panel">
314
- <mat-expansion-panel-header>
315
- <mat-panel-title>
316
- <mat-icon>psychology</mat-icon>
317
- Parameter Collection Configuration
318
- </mat-panel-title>
319
- <mat-panel-description>
320
- Configure smart parameter collection behavior
321
- </mat-panel-description>
322
- </mat-expansion-panel-header>
323
-
324
- <div class="param-collection-content">
325
- <div class="config-grid">
326
- <!-- Max Parameters Per Question -->
327
- <div class="slider-field">
328
- <label>Max Parameters Per Question: {{ parameterCollectionConfig.max_params_per_question }}</label>
329
- <mat-slider
330
- [min]="1"
331
- [max]="5"
332
- [step]="1"
333
- [discrete]="true"
334
- >
335
- <input matSliderThumb
336
- name="maxParamsPerQuestion"
337
- [(ngModel)]="parameterCollectionConfig.max_params_per_question">
338
- </mat-slider>
339
- <mat-hint>Maximum number of parameters to ask in one question</mat-hint>
340
- </div>
341
-
342
- <!-- Retry Unanswered -->
343
- <mat-checkbox
344
- name="retryUnanswered"
345
- [(ngModel)]="parameterCollectionConfig.retry_unanswered"
346
- [disabled]="loading"
347
- class="collection-checkbox">
348
- Re-ask parameters that the user didn't answer
349
  </mat-checkbox>
350
  </div>
351
-
352
- <!-- Collection Prompt Template -->
353
- <mat-form-field appearance="outline" class="full-width">
354
- <mat-label>Collection Prompt Template</mat-label>
355
- <textarea
356
- matInput
357
- name="collectionPrompt"
358
- [(ngModel)]="parameterCollectionConfig.collection_prompt"
359
- [disabled]="loading"
360
- rows="12"
361
- placeholder="Enter the prompt template for generating parameter questions..."
362
- class="code-textarea"
363
- ></textarea>
364
- </mat-form-field>
365
-
366
- <!-- Template Variables Help -->
367
- <mat-expansion-panel class="help-panel">
368
- <mat-expansion-panel-header>
369
- <mat-panel-title>
370
- <mat-icon>help_outline</mat-icon>
371
- Template Variables Reference
372
- </mat-panel-title>
373
- </mat-expansion-panel-header>
374
-
375
- <mat-list>
376
- <mat-list-item>
377
- <mat-icon matListItemIcon>code</mat-icon>
378
- <div matListItemTitle><code>{{conversation_history}}</code></div>
379
- <div matListItemLine>Recent conversation between user and assistant</div>
380
- </mat-list-item>
381
- <mat-list-item>
382
- <mat-icon matListItemIcon>code</mat-icon>
383
- <div matListItemTitle><code>{{intent_name}}</code></div>
384
- <div matListItemLine>Technical name of the detected intent</div>
385
- </mat-list-item>
386
- <mat-list-item>
387
- <mat-icon matListItemIcon>code</mat-icon>
388
- <div matListItemTitle><code>{{intent_caption}}</code></div>
389
- <div matListItemLine>Human-readable caption of the intent</div>
390
- </mat-list-item>
391
- <mat-list-item>
392
- <mat-icon matListItemIcon>code</mat-icon>
393
- <div matListItemTitle><code>{{collected_params}}</code></div>
394
- <div matListItemLine>Parameters already collected with their values</div>
395
- </mat-list-item>
396
- <mat-list-item>
397
- <mat-icon matListItemIcon>code</mat-icon>
398
- <div matListItemTitle><code>{{missing_params}}</code></div>
399
- <div matListItemLine>Parameters still needed to complete the request</div>
400
- </mat-list-item>
401
- <mat-list-item>
402
- <mat-icon matListItemIcon>code</mat-icon>
403
- <div matListItemTitle><code>{{unanswered_params}}</code></div>
404
- <div matListItemLine>Parameters asked before but not answered by user</div>
405
- </mat-list-item>
406
- <mat-list-item>
407
- <mat-icon matListItemIcon>code</mat-icon>
408
- <div matListItemTitle><code>{{max_params}}</code></div>
409
- <div matListItemLine>Maximum number of parameters to ask in one question</div>
410
- </mat-list-item>
411
- <mat-list-item>
412
- <mat-icon matListItemIcon>code</mat-icon>
413
- <div matListItemTitle><code>{{project_language}}</code></div>
414
- <div matListItemLine>Language setting of the current project</div>
415
- </mat-list-item>
416
- </mat-list>
417
- </mat-expansion-panel>
418
-
419
- <!-- Reset to Default Button -->
420
- <button mat-stroked-button type="button" (click)="resetCollectionPrompt()" [disabled]="loading">
421
- <mat-icon>restore</mat-icon>
422
- Reset to Default Template
423
- </button>
424
  </div>
425
  </mat-expansion-panel>
426
-
427
- <div class="form-actions">
428
- <button
429
- mat-raised-button
430
- color="primary"
431
- type="submit"
432
- [disabled]="loading || !envForm.valid || saving"
433
- >
434
- @if (saving) {
435
- <mat-spinner diameter="20"></mat-spinner>
436
- Saving...
437
- } @else {
438
- <mat-icon>save</mat-icon>
439
- Save
440
- }
441
- </button>
442
-
443
- <button
444
- mat-raised-button
445
- type="button"
446
- (click)="reloadFromSpark()"
447
- [disabled]="loading || isGPTMode()"
448
- >
449
- <mat-icon>refresh</mat-icon>
450
- Reload from Spark
451
- </button>
452
- </div>
453
- </form>
454
- </mat-card-content>
455
- </mat-card>
456
- </div>
 
1
+ <div class="environment-container">
2
+ <mat-card class="main-card">
3
+ <mat-card-header>
4
+ <mat-card-title>
5
+ <mat-icon>settings</mat-icon>
6
+ Environment Configuration
7
+ </mat-card-title>
8
+ </mat-card-header>
9
+
10
+ <mat-card-content>
11
+ <form [formGroup]="environmentForm" (ngSubmit)="save()">
12
 
13
+ <!-- LLM Provider Section -->
14
+ <div class="section">
15
+ <h3 class="section-title">
16
+ <mat-icon>psychology</mat-icon>
17
+ LLM Provider
18
+ </h3>
19
+
20
+ <mat-form-field appearance="outline" class="full-width">
21
+ <mat-label>LLM Provider</mat-label>
22
+ <mat-select formControlName="llm_provider_name" [disabled]="loading">
23
+ <mat-option *ngFor="let provider of llmProviders" [value]="provider.name">
24
+ {{ provider.display_name }}
25
+ </mat-option>
26
+ </mat-select>
27
+ <mat-hint *ngIf="getLLMProviderDescription()">{{ getLLMProviderDescription() }}</mat-hint>
28
+ </mat-form-field>
29
 
30
+ <mat-form-field appearance="outline" class="full-width" *ngIf="isLLMApiKeyRequired()">
31
+ <mat-label>API Key</mat-label>
32
+ <input matInput type="password" formControlName="llm_provider_api_key" [disabled]="loading">
33
+ <mat-icon matPrefix>vpn_key</mat-icon>
34
+ <mat-error *ngIf="environmentForm.get('llm_provider_api_key')?.hasError('required')">
35
+ API key is required
36
+ </mat-error>
37
+ </mat-form-field>
38
+
39
+ <div class="endpoint-row" *ngIf="isLLMEndpointRequired()">
40
+ <mat-form-field appearance="outline" class="endpoint-field">
41
+ <mat-label>Endpoint URL</mat-label>
42
+ <input matInput formControlName="llm_provider_endpoint" [disabled]="loading">
43
+ <mat-icon matPrefix>link</mat-icon>
44
+ <mat-error *ngIf="environmentForm.get('llm_provider_endpoint')?.hasError('required')">
45
+ Endpoint is required
46
+ </mat-error>
47
+ <mat-error *ngIf="environmentForm.get('llm_provider_endpoint')?.hasError('pattern')">
48
+ Invalid URL format
49
+ </mat-error>
50
  </mat-form-field>
51
+
52
+ <button mat-stroked-button type="button" (click)="testConnection()"
53
+ [disabled]="loading || !environmentForm.get('llm_provider_endpoint')?.value"
54
+ class="test-button">
55
+ <mat-icon>speed</mat-icon>
56
+ Test Connection
57
+ </button>
58
+ </div>
59
 
60
+ <!-- Internal Prompt -->
61
+ <mat-expansion-panel class="settings-panel">
62
+ <mat-expansion-panel-header>
63
+ <mat-panel-title>
64
+ <mat-icon>chat</mat-icon>
65
+ Internal System Prompt
66
+ </mat-panel-title>
67
+ </mat-expansion-panel-header>
68
+
69
  <mat-form-field appearance="outline" class="full-width">
70
+ <mat-label>Internal Prompt</mat-label>
71
+ <textarea matInput formControlName="internal_prompt" rows="10" [disabled]="loading"></textarea>
72
+ <mat-hint>
73
+ Available placeholders: &lt;intent names&gt;, &lt;intent captions&gt;, &lt;project language&gt;
74
+ </mat-hint>
75
+ </mat-form-field>
76
+ </mat-expansion-panel>
77
+
78
+ <!-- Parameter Collection Config -->
79
+ <mat-expansion-panel class="settings-panel">
80
+ <mat-expansion-panel-header>
81
+ <mat-panel-title>
82
+ <mat-icon>input</mat-icon>
83
+ Parameter Collection Configuration
84
+ </mat-panel-title>
85
+ </mat-expansion-panel-header>
86
+
87
+ <div class="parameter-config">
88
+ <mat-form-field appearance="outline" class="small-field">
89
+ <mat-label>Max Parameters per Question</mat-label>
90
+ <input matInput type="number" formControlName="max_params_per_question"
91
+ min="1" max="5" [disabled]="loading">
92
+ </mat-form-field>
93
+
94
+ <mat-checkbox formControlName="retry_unanswered" [disabled]="loading">
95
+ Retry Unanswered Parameters
96
+ </mat-checkbox>
97
+
98
+ <mat-form-field appearance="outline" class="full-width">
99
+ <mat-label>Collection Prompt Template</mat-label>
100
+ <textarea matInput formControlName="collection_prompt" rows="8" [disabled]="loading"></textarea>
101
+ <mat-hint>
102
+ Available placeholders: {{conversation_history}}, {{intent_name}}, {{missing_params}}, etc.
103
+ </mat-hint>
104
+ </mat-form-field>
105
+ </div>
106
+ </mat-expansion-panel>
107
+ </div>
108
+
109
+ <mat-divider></mat-divider>
110
+
111
+ <!-- TTS Provider Section -->
112
+ <div class="section">
113
+ <h3 class="section-title">
114
+ <mat-icon>volume_up</mat-icon>
115
+ TTS Provider
116
+ </h3>
117
+
118
+ <mat-form-field appearance="outline" class="full-width">
119
+ <mat-label>TTS Provider</mat-label>
120
+ <mat-select formControlName="tts_provider_name" [disabled]="loading">
121
+ <mat-option *ngFor="let provider of ttsProviders" [value]="provider.name">
122
+ {{ provider.display_name }}
123
+ </mat-option>
124
+ </mat-select>
125
+ <mat-hint *ngIf="getTTSProviderDescription()">{{ getTTSProviderDescription() }}</mat-hint>
126
+ </mat-form-field>
127
+
128
+ <div *ngIf="isTTSEnabled()">
129
+ <mat-form-field appearance="outline" class="full-width"
130
+ *ngIf="currentTTSProvider?.requires_api_key">
131
+ <mat-label>TTS API Key</mat-label>
132
+ <input matInput type="password" formControlName="tts_provider_api_key" [disabled]="loading">
133
  <mat-icon matPrefix>vpn_key</mat-icon>
134
+ <mat-error *ngIf="environmentForm.get('tts_provider_api_key')?.hasError('required')">
135
+ API key is required
136
+ </mat-error>
137
  </mat-form-field>
138
 
139
+ <mat-form-field appearance="outline" class="full-width"
140
+ *ngIf="currentTTSProvider?.requires_endpoint">
141
+ <mat-label>TTS Endpoint URL</mat-label>
142
+ <input matInput formControlName="tts_provider_endpoint" [disabled]="loading">
 
 
 
 
 
 
 
143
  <mat-icon matPrefix>link</mat-icon>
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  </mat-form-field>
145
 
146
+ <mat-checkbox formControlName="tts_use_ssml" [disabled]="loading">
147
+ Enable SSML Support
148
+ </mat-checkbox>
149
+ </div>
150
+ </div>
 
 
 
 
 
 
 
 
 
 
 
151
 
152
+ <mat-divider></mat-divider>
 
 
 
 
 
 
 
 
 
 
 
 
153
 
154
+ <!-- STT Provider Section -->
155
+ <div class="section">
156
+ <h3 class="section-title">
157
+ <mat-icon>mic</mat-icon>
158
+ STT Provider
159
+ </h3>
160
+
161
+ <mat-form-field appearance="outline" class="full-width">
162
+ <mat-label>STT Provider</mat-label>
163
+ <mat-select formControlName="stt_provider_name" [disabled]="loading">
164
+ <mat-option *ngFor="let provider of sttProviders" [value]="provider.name">
165
+ {{ provider.display_name }}
166
+ </mat-option>
167
+ </mat-select>
168
+ <mat-hint *ngIf="getSTTProviderDescription()">{{ getSTTProviderDescription() }}</mat-hint>
169
+ </mat-form-field>
170
 
171
+ <div *ngIf="isSTTEnabled()">
172
+ <mat-form-field appearance="outline" class="full-width"
173
+ *ngIf="currentSTTProvider?.requires_api_key">
174
+ <mat-label>STT API Key / Credentials Path</mat-label>
175
+ <input matInput formControlName="stt_provider_api_key" [disabled]="loading">
176
+ <mat-icon matPrefix>vpn_key</mat-icon>
177
+ <mat-hint>For Google STT, provide the path to service account JSON file</mat-hint>
178
+ <mat-error *ngIf="environmentForm.get('stt_provider_api_key')?.hasError('required')">
179
+ API key or credentials path is required
180
+ </mat-error>
181
+ </mat-form-field>
182
 
183
+ <mat-form-field appearance="outline" class="full-width"
184
+ *ngIf="currentSTTProvider?.requires_endpoint">
185
+ <mat-label>STT Endpoint URL</mat-label>
186
+ <input matInput formControlName="stt_provider_endpoint" [disabled]="loading">
187
+ <mat-icon matPrefix>link</mat-icon>
188
+ </mat-form-field>
189
+
190
+ <!-- STT Settings -->
191
+ <mat-expansion-panel class="settings-panel">
192
+ <mat-expansion-panel-header>
193
+ <mat-panel-title>
194
+ <mat-icon>tune</mat-icon>
195
+ STT Settings
196
+ </mat-panel-title>
197
+ </mat-expansion-panel-header>
 
 
 
198
 
199
+ <div class="stt-settings">
200
+ <div class="settings-row">
201
+ <mat-form-field appearance="outline" class="small-field">
202
+ <mat-label>Speech Timeout (ms)</mat-label>
203
+ <input matInput type="number" formControlName="stt_speech_timeout_ms" [disabled]="loading">
204
+ </mat-form-field>
 
 
 
 
 
 
 
 
 
205
 
206
+ <mat-form-field appearance="outline" class="small-field">
207
+ <mat-label>Noise Reduction Level</mat-label>
208
+ <mat-select formControlName="stt_noise_reduction_level" [disabled]="loading">
209
+ <mat-option [value]="0">Off</mat-option>
210
+ <mat-option [value]="1">Low</mat-option>
211
+ <mat-option [value]="2">Medium</mat-option>
212
+ <mat-option [value]="3">High</mat-option>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
213
  </mat-select>
 
214
  </mat-form-field>
215
+
216
+ <mat-form-field appearance="outline" class="small-field">
217
+ <mat-label>VAD Sensitivity</mat-label>
218
+ <input matInput type="number" formControlName="stt_vad_sensitivity"
219
+ min="0" max="1" step="0.1" [disabled]="loading">
 
 
 
 
 
 
 
 
 
 
 
220
  </mat-form-field>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  </div>
 
 
222
 
223
+ <div class="settings-row">
224
+ <mat-form-field appearance="outline" class="small-field">
225
+ <mat-label>Language</mat-label>
226
+ <input matInput formControlName="stt_language" [disabled]="loading">
227
+ <mat-hint>Use {{current_language_code}} for dynamic language</mat-hint>
228
+ </mat-form-field>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
 
230
+ <mat-form-field appearance="outline" class="small-field">
231
+ <mat-label>Model</mat-label>
232
+ <input matInput formControlName="stt_model" [disabled]="loading">
233
+ </mat-form-field>
234
+ </div>
235
+
236
+ <div class="settings-row">
237
+ <mat-checkbox formControlName="stt_use_enhanced" [disabled]="loading">
238
+ Use Enhanced Model
239
+ </mat-checkbox>
240
+
241
+ <mat-checkbox formControlName="stt_enable_punctuation" [disabled]="loading">
242
+ Enable Punctuation
243
+ </mat-checkbox>
244
+
245
+ <mat-checkbox formControlName="stt_interim_results" [disabled]="loading">
246
+ Enable Interim Results
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  </mat-checkbox>
248
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  </div>
250
  </mat-expansion-panel>
251
+ </div>
252
+ </div>
253
+
254
+ <!-- Action Buttons -->
255
+ <div class="actions">
256
+ <button mat-raised-button color="primary" type="submit"
257
+ [disabled]="loading || saving || environmentForm.invalid">
258
+ <mat-icon>save</mat-icon>
259
+ Save Configuration
260
+ </button>
261
+
262
+ <button mat-button type="button" (click)="loadEnvironment()" [disabled]="loading || saving">
263
+ <mat-icon>refresh</mat-icon>
264
+ Reload
265
+ </button>
266
+ </div>
267
+ </form>
268
+ </mat-card-content>
269
+ </mat-card>
270
+ </div>
271
+
272
+ <!-- Loading Overlay -->
273
+ <div class="loading-overlay" *ngIf="loading || saving">
274
+ <mat-spinner></mat-spinner>
275
+ </div>