import { Component, inject, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; import { MatCardModule } from '@angular/material/card'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { MatSelectModule } from '@angular/material/select'; import { MatButtonModule } from '@angular/material/button'; import { MatIconModule } from '@angular/material/icon'; import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar'; import { MatExpansionModule } from '@angular/material/expansion'; import { MatSliderModule } from '@angular/material/slider'; import { MatTooltipModule } from '@angular/material/tooltip'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { ApiService, Environment, STTSettings } from '../../services/api.service'; import { EnvironmentService } from '../../services/environment.service'; @Component({ selector: 'app-environment', standalone: true, imports: [ CommonModule, FormsModule, MatCardModule, MatFormFieldModule, MatInputModule, MatSelectModule, MatButtonModule, MatIconModule, MatProgressSpinnerModule, MatSnackBarModule, MatExpansionModule, MatSliderModule, MatTooltipModule, MatCheckboxModule ], template: `
settings Environment Configuration @if (isGPTMode()) { info
{{ environment.work_mode === 'gpt4o' ? 'GPT-4o' : 'GPT-4o Mini' }} Mode

This mode uses OpenAI's API which has usage-based pricing.

Approximate cost: {{ environment.work_mode === 'gpt4o' ? '$0.01-0.03' : '$0.001-0.003' }} per conversation turn.

}
Work Mode HF Cloud Cloud On-Premise GPT-4o GPT-4o Mini cloud {{ getTokenLabel() }} vpn_key {{ isGPTMode() ? 'Required for OpenAI API access' : 'Required for HF Cloud and Cloud modes' }} Spark Endpoint link @if (isGPTMode()) { Not required for GPT mode }
TTS Engine No TTS ElevenLabs Blaze (Coming Soon) record_voice_over TTS API Key key
STT Engine No STT Google Cloud Speech-to-Text Azure Speech Services (Coming Soon) Amazon Transcribe (Coming Soon) GPT-4o Realtime (Coming Soon) Flicker (Coming Soon) mic STT API Key / Credentials key
settings_voice STT Advanced Settings Configure speech recognition parameters
Speech Timeout (ms) timer Silence duration to end speech (500-5000ms) Noise Reduction Level Off Low Medium High noise_aware VAD Sensitivity graphic_eq Voice activity detection sensitivity (0=low, 1=high) Language Turkish (tr-TR) English (en-US) German (de-DE) French (fr-FR) Spanish (es-ES) language Model Latest Long (Best for conversations) Command & Search (Short queries) Phone Call (Telephony) Video (Multiple speakers) model_training
Use Enhanced Model info Automatic Punctuation Show Interim Results
info
Google Cloud Setup Required:
  1. Create a Google Cloud project
  2. Enable Speech-to-Text API
  3. Create service account & download JSON key
  4. Upload JSON key file as STT API Key

Cost: ~$0.024/minute (standard), ~$0.036/minute (enhanced)

psychology Internal System Prompt Advanced configuration for LLM Internal Prompt This prompt will be prepended to all project prompts
`, styles: [` .environment-container { max-width: 800px; margin: 0 auto; } mat-card-header { margin-bottom: 24px; mat-card-title { display: flex; align-items: center; gap: 8px; font-size: 24px; mat-icon { font-size: 28px; width: 28px; height: 28px; } } } .info-card { margin-bottom: 20px; background-color: #e3f2fd; mat-card-content { display: flex; gap: 16px; align-items: flex-start; mat-icon { color: #1976d2; margin-top: 4px; } p { margin: 4px 0; font-size: 14px; } } } .full-width { width: 100%; margin-bottom: 20px; } .engine-row { display: flex; gap: 16px; align-items: flex-start; margin-bottom: 20px; .engine-field { flex: 1; } .api-key-field { flex: 1.5; } } .prompt-panel { margin-bottom: 20px; mat-expansion-panel-header { mat-panel-title { display: flex; align-items: center; gap: 8px; mat-icon { color: #666; } } } } .form-actions { display: flex; gap: 16px; margin-top: 24px; padding-top: 24px; border-top: 1px solid #e0e0e0; button { mat-spinner { margin-right: 8px; vertical-align: middle; // Spinner'ı hizalamak için ekleyin } mat-icon { vertical-align: middle; // Icon'u hizalamak için ekleyin margin-right: 4px; // Icon ile text arasına boşluk } } } .stt-settings-panel { margin-bottom: 20px; .stt-settings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; .full-width { grid-column: 1 / -1; } .checkbox-group { grid-column: 1 / -1; display: flex; flex-direction: column; gap: 12px; mat-checkbox { display: flex; align-items: center; .info-icon { font-size: 18px; margin-left: 8px; color: #666; cursor: help; } } } } .stt-info-card { margin-top: 16px; padding: 16px; background-color: #e3f2fd; border-radius: 4px; display: flex; gap: 16px; mat-icon { color: #1976d2; flex-shrink: 0; } ol { margin: 8px 0; padding-left: 20px; } .cost-info { margin-top: 8px; font-size: 14px; color: #666; } } } ::ng-deep { .mat-mdc-form-field-icon-prefix { padding-right: 12px; } .mat-mdc-progress-spinner { --mdc-circular-progress-active-indicator-color: white; } .mat-expansion-panel-body { padding: 16px 0 !important; } } `] }) export class EnvironmentComponent implements OnInit { private apiService = inject(ApiService); private snackBar = inject(MatSnackBar); private environmentService = inject(EnvironmentService); environment: Environment = { work_mode: 'hfcloud', cloud_token: '', spark_endpoint: '', internal_prompt: '', tts_engine: 'no_tts', tts_engine_api_key: '', stt_engine: 'no_stt', stt_engine_api_key: '', stt_settings: { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true } }; sttSettingsExpanded = false; loading = true; saving = false; ngOnInit() { console.log('EnvironmentComponent ngOnInit started'); try { this.loadEnvironment(); } catch (error) { console.error('Error in ngOnInit:', error); console.error('Stack trace:', error.stack); } } ngAfterViewInit() { console.log('EnvironmentComponent ngAfterViewInit'); console.log('Current environment:', this.environment); console.log('STT settings:', this.environment.stt_settings); } loadEnvironment() { console.log('loadEnvironment called'); this.loading = true; this.apiService.getEnvironment().subscribe({ next: (env) => { console.log('Environment loaded from API:', env); this.environment = env; // Debug check console.log('Checking stt_settings:', this.environment.stt_settings); if (!this.environment.stt_settings) { console.log('No stt_settings found, creating defaults...'); this.environment.stt_settings = { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true }; } console.log('Final environment:', this.environment); this.loading = false; }, error: (err) => { console.error('Error loading environment:', err); this.snackBar.open('Failed to load environment configuration', 'Close', { duration: 5000, panelClass: 'error-snackbar' }); this.loading = false; } }); } onSTTCredentialsFileSelected(event: any) { const file = event.target.files[0]; if (file && file.type === 'application/json') { const reader = new FileReader(); reader.onload = (e: any) => { try { // Validate it's a valid JSON const jsonContent = JSON.parse(e.target.result); // Store the entire JSON content as the API key this.environment.stt_engine_api_key = e.target.result; this.snackBar.open('Google credentials loaded successfully', 'Close', { duration: 3000 }); } catch (error) { this.snackBar.open('Invalid JSON file', 'Close', { duration: 3000, panelClass: 'error-snackbar' }); } }; reader.readAsText(file); } } updateSTTSetting(key: string, value: any) { if (!this.environment.stt_settings) { this.environment.stt_settings = { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true }; } (this.environment.stt_settings as any)[key] = value; } getTokenLabel(): string { switch(this.environment.work_mode) { case 'gpt4o': case 'gpt4o-mini': return 'OpenAI API Key'; case 'hfcloud': case 'cloud': return 'Cloud Token'; default: return 'Cloud Token'; } } getTokenPlaceholder(): string { switch(this.environment.work_mode) { case 'gpt4o': case 'gpt4o-mini': return 'Enter OpenAI API key (sk-...)'; case 'hfcloud': case 'cloud': return 'Enter cloud token'; default: return 'Enter cloud token'; } } isGPTMode(): boolean { return this.environment.work_mode === 'gpt4o' || this.environment.work_mode === 'gpt4o-mini'; } onWorkModeChange() { if (this.environment.work_mode === 'on-premise') { this.environment.cloud_token = ''; } } onSTTEngineChange() { console.log('onSTTEngineChange called with:', this.environment.stt_engine); console.log('Current stt_settings:', this.environment.stt_settings); try { if (this.environment.stt_engine === 'no_stt') { this.environment.stt_engine_api_key = ''; this.sttSettingsExpanded = false; } else { // Debug log console.log('Setting up STT settings...'); if (!this.environment.stt_settings) { console.log('Creating new stt_settings...'); this.environment.stt_settings = { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true }; } this.sttSettingsExpanded = true; console.log('STT settings after setup:', this.environment.stt_settings); } } catch (error) { console.error('Error in onSTTEngineChange:', error); console.error('Stack trace:', error.stack); } } formatVAD(value: number): string { return value.toFixed(1); } getSTTKeyPlaceholder(): string { switch(this.environment.stt_engine) { case 'google': return 'Google service account JSON content'; case 'azure': return 'Azure subscription key'; case 'amazon': return 'AWS access key'; case 'gpt4o_realtime': return 'OpenAI API key'; default: return 'Enter API key'; } } onSTTEngineChange() { if (this.environment.stt_engine === 'no_stt') { this.environment.stt_engine_api_key = ''; this.sttSettingsExpanded = false; } else { // Ensure stt_settings exists when enabling STT if (!this.environment.stt_settings) { this.environment.stt_settings = { speech_timeout_ms: 2000, noise_reduction_level: 2, vad_sensitivity: 0.5, language: 'tr-TR', model: 'latest_long', use_enhanced: true, enable_punctuation: true, interim_results: true }; } this.sttSettingsExpanded = true; } } save() { this.saving = true; this.apiService.updateEnvironment(this.environment).subscribe({ next: () => { // Environment service'i güncelle this.environmentService.updateEnvironment(this.environment); this.snackBar.open('Environment configuration saved successfully', 'Close', { duration: 3000 }); this.saving = false; }, error: (err) => { this.snackBar.open( err.error?.detail || 'Failed to save configuration', 'Close', { duration: 5000, panelClass: 'error-snackbar' } ); this.saving = false; } }); } testConnection() { this.snackBar.open('Testing connection to Spark endpoint...', undefined, { duration: 2000 }); // TODO: Implement actual connection test setTimeout(() => { this.snackBar.open('Connection successful!', 'Close', { duration: 3000 }); }, 2000); } reloadFromSpark() { if (this.isGPTMode()) { return; } this.snackBar.open('Reloading configuration from Spark...', undefined, { duration: 2000 }); setTimeout(() => { this.loadEnvironment(); this.snackBar.open('Configuration reloaded', 'Close', { duration: 3000 }); }, 1000); } }