ciyidogan commited on
Commit
16b8b39
·
verified ·
1 Parent(s): 08ca155

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

Browse files
flare-ui/src/app/components/environment/environment.component.ts CHANGED
@@ -29,7 +29,10 @@ import { EnvironmentService } from '../../services/environment.service';
29
  MatIconModule,
30
  MatProgressSpinnerModule,
31
  MatSnackBarModule,
32
- MatExpansionModule
 
 
 
33
  ],
34
  template: `
35
  <div class="environment-container">
@@ -158,14 +161,17 @@ import { EnvironmentService } from '../../services/environment.service';
158
  [disabled]="loading"
159
  >
160
  <mat-option value="no_stt">No STT</mat-option>
161
- <mat-option value="elevenlabs">ElevenLabs</mat-option>
 
 
 
162
  <mat-option value="flicker">Flicker (Coming Soon)</mat-option>
163
  </mat-select>
164
  <mat-icon matPrefix>mic</mat-icon>
165
  </mat-form-field>
166
 
167
  <mat-form-field appearance="outline" class="api-key-field">
168
- <mat-label>STT API Key</mat-label>
169
  <input
170
  matInput
171
  type="password"
@@ -173,12 +179,140 @@ import { EnvironmentService } from '../../services/environment.service';
173
  [(ngModel)]="environment.stt_engine_api_key"
174
  [disabled]="loading || environment.stt_engine === 'no_stt'"
175
  [required]="environment.stt_engine !== 'no_stt'"
176
- placeholder="Enter STT API key"
177
  >
178
  <mat-icon matPrefix>key</mat-icon>
 
 
 
 
 
 
 
 
 
 
179
  </mat-form-field>
180
  </div>
181
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
182
  <mat-expansion-panel class="prompt-panel">
183
  <mat-expansion-panel-header>
184
  <mat-panel-title>
@@ -336,6 +470,64 @@ import { EnvironmentService } from '../../services/environment.service';
336
  }
337
  }
338
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
339
  ::ng-deep {
340
  .mat-mdc-form-field-icon-prefix {
341
  padding-right: 12px;
@@ -364,21 +556,45 @@ export class EnvironmentComponent implements OnInit {
364
  tts_engine: 'no_tts',
365
  tts_engine_api_key: '',
366
  stt_engine: 'no_stt',
367
- stt_engine_api_key: ''
 
 
 
 
 
 
 
 
 
 
368
  };
369
 
 
370
  loading = true;
371
  saving = false;
372
 
373
  ngOnInit() {
374
  this.loadEnvironment();
375
  }
376
-
377
  loadEnvironment() {
378
  this.loading = true;
379
  this.apiService.getEnvironment().subscribe({
380
  next: (env) => {
381
  this.environment = env;
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  this.loading = false;
383
  },
384
  error: (err) => {
@@ -432,13 +648,59 @@ export class EnvironmentComponent implements OnInit {
432
  this.environment.tts_engine_api_key = '';
433
  }
434
  }
435
-
436
  onSTTEngineChange() {
437
  if (this.environment.stt_engine === 'no_stt') {
438
  this.environment.stt_engine_api_key = '';
 
 
 
439
  }
440
  }
441
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
442
  save() {
443
  this.saving = true;
444
 
 
29
  MatIconModule,
30
  MatProgressSpinnerModule,
31
  MatSnackBarModule,
32
+ MatExpansionModule,
33
+ MatSliderModule,
34
+ MatTooltipModule,
35
+ MatCheckboxModule
36
  ],
37
  template: `
38
  <div class="environment-container">
 
161
  [disabled]="loading"
162
  >
163
  <mat-option value="no_stt">No STT</mat-option>
164
+ <mat-option value="google">Google Cloud Speech-to-Text</mat-option>
165
+ <mat-option value="azure">Azure Speech Services (Coming Soon)</mat-option>
166
+ <mat-option value="amazon">Amazon Transcribe (Coming Soon)</mat-option>
167
+ <mat-option value="gpt4o_realtime">GPT-4o Realtime (Coming Soon)</mat-option>
168
  <mat-option value="flicker">Flicker (Coming Soon)</mat-option>
169
  </mat-select>
170
  <mat-icon matPrefix>mic</mat-icon>
171
  </mat-form-field>
172
 
173
  <mat-form-field appearance="outline" class="api-key-field">
174
+ <mat-label>STT API Key / Credentials</mat-label>
175
  <input
176
  matInput
177
  type="password"
 
179
  [(ngModel)]="environment.stt_engine_api_key"
180
  [disabled]="loading || environment.stt_engine === 'no_stt'"
181
  [required]="environment.stt_engine !== 'no_stt'"
182
+ [placeholder]="getSTTKeyPlaceholder()"
183
  >
184
  <mat-icon matPrefix>key</mat-icon>
185
+ <button mat-icon-button matSuffix
186
+ *ngIf="environment.stt_engine === 'google'"
187
+ (click)="fileInput.click()"
188
+ [disabled]="loading"
189
+ matTooltip="Upload Google credentials JSON">
190
+ <mat-icon>upload_file</mat-icon>
191
+ </button>
192
+ <input #fileInput type="file" accept=".json"
193
+ style="display: none"
194
+ (change)="onSTTCredentialsFileSelected($event)">
195
  </mat-form-field>
196
  </div>
197
 
198
+ <!-- STT Settings Panel -->
199
+ <mat-expansion-panel class="stt-settings-panel"
200
+ *ngIf="environment.stt_engine !== 'no_stt'"
201
+ [expanded]="sttSettingsExpanded">
202
+ <mat-expansion-panel-header>
203
+ <mat-panel-title>
204
+ <mat-icon>settings_voice</mat-icon>
205
+ STT Advanced Settings
206
+ </mat-panel-title>
207
+ <mat-panel-description>
208
+ Configure speech recognition parameters
209
+ </mat-panel-description>
210
+ </mat-expansion-panel-header>
211
+
212
+ <div class="stt-settings-grid">
213
+ <mat-form-field appearance="outline">
214
+ <mat-label>Speech Timeout (ms)</mat-label>
215
+ <input matInput type="number"
216
+ name="speechTimeout"
217
+ [(ngModel)]="environment.stt_settings!.speech_timeout_ms"
218
+ min="500" max="5000" step="100"
219
+ [disabled]="loading">
220
+ <mat-icon matPrefix>timer</mat-icon>
221
+ <mat-hint>Silence duration to end speech (500-5000ms)</mat-hint>
222
+ </mat-form-field>
223
+
224
+ <mat-form-field appearance="outline">
225
+ <mat-label>Noise Reduction Level</mat-label>
226
+ <mat-select name="noiseReduction"
227
+ [(ngModel)]="environment.stt_settings!.noise_reduction_level"
228
+ [disabled]="loading">
229
+ <mat-option [value]="0">Off</mat-option>
230
+ <mat-option [value]="1">Low</mat-option>
231
+ <mat-option [value]="2">Medium</mat-option>
232
+ <mat-option [value]="3">High</mat-option>
233
+ </mat-select>
234
+ <mat-icon matPrefix>noise_aware</mat-icon>
235
+ </mat-form-field>
236
+
237
+ <mat-form-field appearance="outline" class="full-width">
238
+ <mat-label>VAD Sensitivity</mat-label>
239
+ <mat-slider min="0" max="1" step="0.1"
240
+ [discrete]="true"
241
+ [displayWith]="formatVAD">
242
+ <input matSliderThumb
243
+ name="vadSensitivity"
244
+ [(ngModel)]="environment.stt_settings!.vad_sensitivity"
245
+ [disabled]="loading">
246
+ </mat-slider>
247
+ <mat-icon matPrefix>graphic_eq</mat-icon>
248
+ <mat-hint>Voice activity detection sensitivity (0=low, 1=high)</mat-hint>
249
+ </mat-form-field>
250
+
251
+ <mat-form-field appearance="outline">
252
+ <mat-label>Language</mat-label>
253
+ <mat-select name="sttLanguage"
254
+ [(ngModel)]="environment.stt_settings!.language"
255
+ [disabled]="loading">
256
+ <mat-option value="tr-TR">Turkish (tr-TR)</mat-option>
257
+ <mat-option value="en-US">English (en-US)</mat-option>
258
+ <mat-option value="de-DE">German (de-DE)</mat-option>
259
+ <mat-option value="fr-FR">French (fr-FR)</mat-option>
260
+ <mat-option value="es-ES">Spanish (es-ES)</mat-option>
261
+ </mat-select>
262
+ <mat-icon matPrefix>language</mat-icon>
263
+ </mat-form-field>
264
+
265
+ <mat-form-field appearance="outline"
266
+ *ngIf="environment.stt_engine === 'google'">
267
+ <mat-label>Model</mat-label>
268
+ <mat-select name="sttModel"
269
+ [(ngModel)]="environment.stt_settings!.model"
270
+ [disabled]="loading">
271
+ <mat-option value="latest_long">Latest Long (Best for conversations)</mat-option>
272
+ <mat-option value="command_and_search">Command & Search (Short queries)</mat-option>
273
+ <mat-option value="phone_call">Phone Call (Telephony)</mat-option>
274
+ <mat-option value="video">Video (Multiple speakers)</mat-option>
275
+ </mat-select>
276
+ <mat-icon matPrefix>model_training</mat-icon>
277
+ </mat-form-field>
278
+
279
+ <div class="checkbox-group">
280
+ <mat-checkbox name="useEnhanced"
281
+ [(ngModel)]="environment.stt_settings!.use_enhanced"
282
+ [disabled]="loading || environment.stt_engine !== 'google'">
283
+ Use Enhanced Model
284
+ <mat-icon matTooltip="Better accuracy but higher cost" class="info-icon">info</mat-icon>
285
+ </mat-checkbox>
286
+
287
+ <mat-checkbox name="enablePunctuation"
288
+ [(ngModel)]="environment.stt_settings!.enable_punctuation"
289
+ [disabled]="loading">
290
+ Automatic Punctuation
291
+ </mat-checkbox>
292
+
293
+ <mat-checkbox name="interimResults"
294
+ [(ngModel)]="environment.stt_settings!.interim_results"
295
+ [disabled]="loading">
296
+ Show Interim Results
297
+ </mat-checkbox>
298
+ </div>
299
+ </div>
300
+
301
+ <div class="stt-info-card" *ngIf="environment.stt_engine === 'google'">
302
+ <mat-icon>info</mat-icon>
303
+ <div>
304
+ <strong>Google Cloud Setup Required:</strong>
305
+ <ol>
306
+ <li>Create a Google Cloud project</li>
307
+ <li>Enable Speech-to-Text API</li>
308
+ <li>Create service account & download JSON key</li>
309
+ <li>Upload JSON key file as STT API Key</li>
310
+ </ol>
311
+ <p class="cost-info">Cost: ~$0.024/minute (standard), ~$0.036/minute (enhanced)</p>
312
+ </div>
313
+ </div>
314
+ </mat-expansion-panel>
315
+
316
  <mat-expansion-panel class="prompt-panel">
317
  <mat-expansion-panel-header>
318
  <mat-panel-title>
 
470
  }
471
  }
472
 
473
+ .stt-settings-panel {
474
+ margin-bottom: 20px;
475
+
476
+ .stt-settings-grid {
477
+ display: grid;
478
+ grid-template-columns: 1fr 1fr;
479
+ gap: 16px;
480
+
481
+ .full-width {
482
+ grid-column: 1 / -1;
483
+ }
484
+
485
+ .checkbox-group {
486
+ grid-column: 1 / -1;
487
+ display: flex;
488
+ flex-direction: column;
489
+ gap: 12px;
490
+
491
+ mat-checkbox {
492
+ display: flex;
493
+ align-items: center;
494
+
495
+ .info-icon {
496
+ font-size: 18px;
497
+ margin-left: 8px;
498
+ color: #666;
499
+ cursor: help;
500
+ }
501
+ }
502
+ }
503
+ }
504
+
505
+ .stt-info-card {
506
+ margin-top: 16px;
507
+ padding: 16px;
508
+ background-color: #e3f2fd;
509
+ border-radius: 4px;
510
+ display: flex;
511
+ gap: 16px;
512
+
513
+ mat-icon {
514
+ color: #1976d2;
515
+ flex-shrink: 0;
516
+ }
517
+
518
+ ol {
519
+ margin: 8px 0;
520
+ padding-left: 20px;
521
+ }
522
+
523
+ .cost-info {
524
+ margin-top: 8px;
525
+ font-size: 14px;
526
+ color: #666;
527
+ }
528
+ }
529
+ }
530
+
531
  ::ng-deep {
532
  .mat-mdc-form-field-icon-prefix {
533
  padding-right: 12px;
 
556
  tts_engine: 'no_tts',
557
  tts_engine_api_key: '',
558
  stt_engine: 'no_stt',
559
+ stt_engine_api_key: '',
560
+ stt_settings: {
561
+ speech_timeout_ms: 2000,
562
+ noise_reduction_level: 2,
563
+ vad_sensitivity: 0.5,
564
+ language: 'tr-TR',
565
+ model: 'latest_long',
566
+ use_enhanced: true,
567
+ enable_punctuation: true,
568
+ interim_results: true
569
+ }
570
  };
571
 
572
+ sttSettingsExpanded = false;
573
  loading = true;
574
  saving = false;
575
 
576
  ngOnInit() {
577
  this.loadEnvironment();
578
  }
579
+
580
  loadEnvironment() {
581
  this.loading = true;
582
  this.apiService.getEnvironment().subscribe({
583
  next: (env) => {
584
  this.environment = env;
585
+ // Ensure STT settings exist
586
+ if (!this.environment.stt_settings) {
587
+ this.environment.stt_settings = {
588
+ speech_timeout_ms: 2000,
589
+ noise_reduction_level: 2,
590
+ vad_sensitivity: 0.5,
591
+ language: 'tr-TR',
592
+ model: 'latest_long',
593
+ use_enhanced: true,
594
+ enable_punctuation: true,
595
+ interim_results: true
596
+ };
597
+ }
598
  this.loading = false;
599
  },
600
  error: (err) => {
 
648
  this.environment.tts_engine_api_key = '';
649
  }
650
  }
651
+
652
  onSTTEngineChange() {
653
  if (this.environment.stt_engine === 'no_stt') {
654
  this.environment.stt_engine_api_key = '';
655
+ this.sttSettingsExpanded = false;
656
+ } else {
657
+ this.sttSettingsExpanded = true;
658
  }
659
  }
660
 
661
+ formatVAD(value: number): string {
662
+ return value.toFixed(1);
663
+ }
664
+
665
+ getSTTKeyPlaceholder(): string {
666
+ switch(this.environment.stt_engine) {
667
+ case 'google':
668
+ return 'Google service account JSON content';
669
+ case 'azure':
670
+ return 'Azure subscription key';
671
+ case 'amazon':
672
+ return 'AWS access key';
673
+ case 'gpt4o_realtime':
674
+ return 'OpenAI API key';
675
+ default:
676
+ return 'Enter API key';
677
+ }
678
+ }
679
+
680
+ onSTTCredentialsFileSelected(event: any) {
681
+ const file = event.target.files[0];
682
+ if (file && file.type === 'application/json') {
683
+ const reader = new FileReader();
684
+ reader.onload = (e: any) => {
685
+ try {
686
+ // Validate it's a valid JSON
687
+ const jsonContent = JSON.parse(e.target.result);
688
+ // Store the entire JSON content as the API key
689
+ this.environment.stt_engine_api_key = e.target.result;
690
+ this.snackBar.open('Google credentials loaded successfully', 'Close', {
691
+ duration: 3000
692
+ });
693
+ } catch (error) {
694
+ this.snackBar.open('Invalid JSON file', 'Close', {
695
+ duration: 3000,
696
+ panelClass: 'error-snackbar'
697
+ });
698
+ }
699
+ };
700
+ reader.readAsText(file);
701
+ }
702
+ }
703
+
704
  save() {
705
  this.saving = true;
706