ciyidogan commited on
Commit
0d34e18
·
verified ·
1 Parent(s): 10dafff

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

Browse files
flare-ui/src/app/components/environment/environment.component.html CHANGED
@@ -1,275 +1,296 @@
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>
 
 
 
 
 
 
 
 
 
1
+ <mat-card>
2
+ <mat-card-header>
3
+ <mat-card-title>
4
+ <mat-icon>settings</mat-icon>
5
+ Environment Configuration
6
+ </mat-card-title>
7
+ </mat-card-header>
8
+
9
+ <mat-card-content>
10
+ @if (loading) {
11
+ <div class="loading-container">
12
+ <mat-spinner></mat-spinner>
13
+ <p>Loading configuration...</p>
14
+ </div>
15
+ } @else {
16
+ <form [formGroup]="form">
17
  <!-- LLM Provider Section -->
18
+ <div class="provider-section">
19
+ <h3>
20
+ <mat-icon>smart_toy</mat-icon>
21
  LLM Provider
22
  </h3>
23
 
24
  <mat-form-field appearance="outline" class="full-width">
25
+ <mat-label>Provider</mat-label>
26
+ <mat-icon matPrefix>{{ getLLMProviderIcon(currentLLMProvider || {}) }}</mat-icon>
27
+ <mat-select formControlName="llm_provider_name"
28
+ (selectionChange)="onLLMProviderChange($event.value)">
29
+ @for (provider of llmProviders; track provider.name) {
30
+ <mat-option [value]="provider.name">
31
+ <mat-icon>{{ getLLMProviderIcon(provider) }}</mat-icon>
32
+ {{ provider.display_name }}
33
+ </mat-option>
34
+ }
35
  </mat-select>
36
+ @if (currentLLMProvider?.description) {
37
+ <mat-hint>{{ currentLLMProvider.description }}</mat-hint>
38
+ }
39
  </mat-form-field>
40
 
41
+ @if (currentLLMProvider?.requires_api_key) {
42
+ <mat-form-field appearance="outline" class="full-width">
43
+ <mat-label>{{ getApiKeyLabel('llm') }}</mat-label>
44
+ <mat-icon matPrefix>key</mat-icon>
45
+ <input matInput
46
+ type="password"
47
+ formControlName="llm_provider_api_key"
48
+ [placeholder]="getApiKeyPlaceholder('llm')">
49
+ <mat-error *ngIf="form.get('llm_provider_api_key')?.hasError('required')">
50
+ API key is required for {{ currentLLMProvider?.display_name }}
51
+ </mat-error>
52
+ </mat-form-field>
53
+ }
54
 
55
+ @if (currentLLMProvider?.requires_endpoint) {
56
+ <mat-form-field appearance="outline" class="full-width">
57
  <mat-label>Endpoint URL</mat-label>
 
58
  <mat-icon matPrefix>link</mat-icon>
59
+ <input matInput
60
+ formControlName="llm_provider_endpoint"
61
+ [placeholder]="getEndpointPlaceholder('llm')">
62
+ <button mat-icon-button matSuffix
63
+ (click)="testConnection()"
64
+ type="button"
65
+ matTooltip="Test connection">
66
+ <mat-icon>wifi_tethering</mat-icon>
67
+ </button>
68
+ <mat-error *ngIf="form.get('llm_provider_endpoint')?.hasError('required')">
69
+ Endpoint is required for {{ currentLLMProvider?.display_name }}
70
  </mat-error>
71
  </mat-form-field>
72
+ }
 
 
 
 
 
 
 
73
 
74
+ <!-- LLM Settings (Internal Prompt & Parameter Collection) -->
75
+ @if (currentLLMProvider) {
76
+ <mat-expansion-panel class="settings-panel">
77
+ <mat-expansion-panel-header>
78
+ <mat-panel-title>
79
+ <mat-icon>psychology</mat-icon>
80
+ Internal System Prompt
81
+ </mat-panel-title>
82
+ <mat-panel-description>
83
+ Configure the internal prompt for intent detection
84
+ </mat-panel-description>
85
+ </mat-expansion-panel-header>
86
+
87
+ <div class="panel-content">
88
+ <p class="hint-text">
89
+ This prompt is prepended to all intent detection requests.
90
+ Use placeholders: &lt;intent names&gt;, &lt;intent captions&gt;, &lt;project language&gt;
91
+ </p>
92
+ <mat-form-field appearance="outline" class="full-width">
93
+ <mat-label>Internal Prompt</mat-label>
94
+ <textarea matInput
95
+ [(ngModel)]="internalPrompt"
96
+ [ngModelOptions]="{standalone: true}"
97
+ rows="6"
98
+ placeholder="Enter internal system prompt..."></textarea>
99
+ </mat-form-field>
100
+ </div>
101
+ </mat-expansion-panel>
102
+
103
+ <mat-expansion-panel class="settings-panel">
104
+ <mat-expansion-panel-header>
105
+ <mat-panel-title>
106
+ <mat-icon>quiz</mat-icon>
107
+ Parameter Collection Configuration
108
+ </mat-panel-title>
109
+ <mat-panel-description>
110
+ Configure smart parameter collection behavior
111
+ </mat-panel-description>
112
+ </mat-expansion-panel-header>
113
+
114
+ <div class="panel-content">
115
+ <mat-slide-toggle [(ngModel)]="parameterCollectionConfig.enabled"
116
+ [ngModelOptions]="{standalone: true}">
117
+ Enable Smart Parameter Collection
118
+ </mat-slide-toggle>
119
+
120
+ <div class="config-grid" *ngIf="parameterCollectionConfig.enabled">
121
+ <div class="config-item">
122
+ <label>Max Parameters per Question</label>
123
+ <mat-slider min="1" max="5" step="1" discrete>
124
+ <input matSliderThumb [(ngModel)]="parameterCollectionConfig.max_params_per_question"
125
+ [ngModelOptions]="{standalone: true}">
126
+ </mat-slider>
127
+ <span class="slider-value">{{ parameterCollectionConfig.max_params_per_question }}</span>
128
+ </div>
129
+
130
+ <mat-slide-toggle [(ngModel)]="parameterCollectionConfig.show_all_required"
131
+ [ngModelOptions]="{standalone: true}">
132
+ Show All Required Parameters
133
+ </mat-slide-toggle>
134
+
135
+ <mat-slide-toggle [(ngModel)]="parameterCollectionConfig.ask_optional_params"
136
+ [ngModelOptions]="{standalone: true}">
137
+ Ask for Optional Parameters
138
+ </mat-slide-toggle>
139
 
140
+ <mat-slide-toggle [(ngModel)]="parameterCollectionConfig.group_related_params"
141
+ [ngModelOptions]="{standalone: true}">
142
+ Group Related Parameters
143
+ </mat-slide-toggle>
 
 
 
 
 
 
 
 
 
 
 
144
 
145
+ <div class="config-item">
146
+ <label>Minimum Confidence Score</label>
147
+ <mat-slider min="0" max="1" step="0.1" discrete>
148
+ <input matSliderThumb [(ngModel)]="parameterCollectionConfig.min_confidence_score"
149
+ [ngModelOptions]="{standalone: true}">
150
+ </mat-slider>
151
+ <span class="slider-value">{{ parameterCollectionConfig.min_confidence_score }}</span>
152
+ </div>
153
 
154
+ <mat-form-field appearance="outline" class="full-width">
155
+ <mat-label>Collection Prompt Template</mat-label>
156
+ <textarea matInput
157
+ [(ngModel)]="parameterCollectionConfig.collection_prompt"
158
+ [ngModelOptions]="{standalone: true}"
159
+ rows="8"></textarea>
160
+ <button mat-icon-button matSuffix
161
+ (click)="resetCollectionPrompt()"
162
+ type="button"
163
+ matTooltip="Reset to default">
164
+ <mat-icon>refresh</mat-icon>
165
+ </button>
166
+ </mat-form-field>
167
+ </div>
168
+ </div>
169
+ </mat-expansion-panel>
170
+ }
171
  </div>
172
 
173
  <mat-divider></mat-divider>
174
 
175
  <!-- TTS Provider Section -->
176
+ <div class="provider-section">
177
+ <h3>
178
+ <mat-icon>record_voice_over</mat-icon>
179
  TTS Provider
180
  </h3>
181
 
182
  <mat-form-field appearance="outline" class="full-width">
183
+ <mat-label>Provider</mat-label>
184
+ <mat-icon matPrefix>{{ getTTSProviderIcon(currentTTSProvider || {}) }}</mat-icon>
185
+ <mat-select formControlName="tts_provider_name"
186
+ (selectionChange)="onTTSProviderChange($event.value)">
187
+ @for (provider of ttsProviders; track provider.name) {
188
+ <mat-option [value]="provider.name">
189
+ <mat-icon>{{ getTTSProviderIcon(provider) }}</mat-icon>
190
+ {{ provider.display_name }}
191
+ </mat-option>
192
+ }
193
  </mat-select>
194
+ @if (currentTTSProvider?.description) {
195
+ <mat-hint>{{ currentTTSProvider.description }}</mat-hint>
196
+ }
197
  </mat-form-field>
198
 
199
+ @if (currentTTSProvider?.requires_api_key) {
200
+ <mat-form-field appearance="outline" class="full-width">
201
+ <mat-label>{{ getApiKeyLabel('tts') }}</mat-label>
202
+ <mat-icon matPrefix>key</mat-icon>
203
+ <input matInput
204
+ type="password"
205
+ formControlName="tts_provider_api_key"
206
+ [placeholder]="getApiKeyPlaceholder('tts')">
207
+ <mat-error *ngIf="form.get('tts_provider_api_key')?.hasError('required')">
208
+ API key is required for {{ currentTTSProvider?.display_name }}
209
  </mat-error>
210
  </mat-form-field>
211
+ }
212
 
213
+ @if (currentTTSProvider?.requires_endpoint) {
214
+ <mat-form-field appearance="outline" class="full-width">
215
+ <mat-label>Endpoint URL</mat-label>
 
216
  <mat-icon matPrefix>link</mat-icon>
217
+ <input matInput
218
+ formControlName="tts_provider_endpoint"
219
+ [placeholder]="getEndpointPlaceholder('tts')">
220
+ <mat-error *ngIf="form.get('tts_provider_endpoint')?.hasError('required')">
221
+ Endpoint is required for {{ currentTTSProvider?.display_name }}
222
+ </mat-error>
223
  </mat-form-field>
224
+ }
 
 
 
 
225
  </div>
226
 
227
  <mat-divider></mat-divider>
228
 
229
  <!-- STT Provider Section -->
230
+ <div class="provider-section">
231
+ <h3>
232
  <mat-icon>mic</mat-icon>
233
  STT Provider
234
  </h3>
235
 
236
  <mat-form-field appearance="outline" class="full-width">
237
+ <mat-label>Provider</mat-label>
238
+ <mat-icon matPrefix>{{ getSTTProviderIcon(currentSTTProvider || {}) }}</mat-icon>
239
+ <mat-select formControlName="stt_provider_name"
240
+ (selectionChange)="onSTTProviderChange($event.value)">
241
+ @for (provider of sttProviders; track provider.name) {
242
+ <mat-option [value]="provider.name">
243
+ <mat-icon>{{ getSTTProviderIcon(provider) }}</mat-icon>
244
+ {{ provider.display_name }}
245
+ </mat-option>
246
+ }
247
  </mat-select>
248
+ @if (currentSTTProvider?.description) {
249
+ <mat-hint>{{ currentSTTProvider.description }}</mat-hint>
250
+ }
251
  </mat-form-field>
252
 
253
+ @if (currentSTTProvider?.requires_api_key) {
254
+ <mat-form-field appearance="outline" class="full-width">
255
+ <mat-label>{{ getApiKeyLabel('stt') }}</mat-label>
256
+ <mat-icon matPrefix>key</mat-icon>
257
+ <input matInput
258
+ [type]="currentSTTProvider.name === 'google' ? 'text' : 'password'"
259
+ formControlName="stt_provider_api_key"
260
+ [placeholder]="getApiKeyPlaceholder('stt')">
261
+ <mat-error *ngIf="form.get('stt_provider_api_key')?.hasError('required')">
262
+ {{ currentSTTProvider.name === 'google' ? 'Credentials path' : 'API key' }} is required for {{ currentSTTProvider?.display_name }}
263
  </mat-error>
264
  </mat-form-field>
265
+ }
266
 
267
+ @if (currentSTTProvider?.requires_endpoint) {
268
+ <mat-form-field appearance="outline" class="full-width">
269
+ <mat-label>Endpoint URL</mat-label>
 
270
  <mat-icon matPrefix>link</mat-icon>
271
+ <input matInput
272
+ formControlName="stt_provider_endpoint"
273
+ [placeholder]="getEndpointPlaceholder('stt')">
274
+ <mat-error *ngIf="form.get('stt_provider_endpoint')?.hasError('required')">
275
+ Endpoint is required for {{ currentSTTProvider?.display_name }}
276
+ </mat-error>
277
  </mat-form-field>
278
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
279
  </div>
280
  </form>
281
+ }
282
+ </mat-card-content>
283
+
284
+ <mat-card-actions align="end">
285
+ <button mat-button (click)="loadEnvironment()" [disabled]="loading || saving">
286
+ <mat-icon>refresh</mat-icon>
287
+ Reload
288
+ </button>
289
+ <button mat-raised-button color="primary"
290
+ (click)="save()"
291
+ [disabled]="form.invalid || loading || saving">
292
+ <mat-icon>save</mat-icon>
293
+ {{ saving ? 'Saving...' : 'Save Configuration' }}
294
+ </button>
295
+ </mat-card-actions>
296
+ </mat-card>