Spaces:
Paused
Paused
| // environment.service.ts | |
| // Path: /flare-ui/src/app/services/environment.service.ts | |
| import { Injectable } from '@angular/core'; | |
| import { BehaviorSubject, Observable } from 'rxjs'; | |
| import { Environment, ProviderSettings } from './api.service'; | |
| export interface EnvironmentError { | |
| type: 'validation' | 'update' | 'unknown'; | |
| message: string; | |
| details?: any; | |
| } | |
| ({ | |
| providedIn: 'root' | |
| }) | |
| export class EnvironmentService { | |
| private environmentSubject = new BehaviorSubject<Environment | null>(null); | |
| public environment$ = this.environmentSubject.asObservable(); | |
| private ttsEnabledSource = new BehaviorSubject<boolean>(false); | |
| private sttEnabledSource = new BehaviorSubject<boolean>(false); | |
| private errorSubject = new BehaviorSubject<EnvironmentError | null>(null); | |
| public error$ = this.errorSubject.asObservable(); | |
| // Local storage keys | |
| private readonly TTS_KEY = 'flare_tts_enabled'; | |
| private readonly STT_KEY = 'flare_stt_enabled'; | |
| ttsEnabled$ = this.ttsEnabledSource.asObservable(); | |
| sttEnabled$ = this.sttEnabledSource.asObservable(); | |
| constructor() { | |
| this.loadPreferences(); | |
| } | |
| private loadPreferences(): void { | |
| try { | |
| const savedTTS = localStorage.getItem(this.TTS_KEY); | |
| if (savedTTS !== null) { | |
| this.ttsEnabledSource.next(savedTTS === 'true'); | |
| } | |
| const savedSTT = localStorage.getItem(this.STT_KEY); | |
| if (savedSTT !== null) { | |
| this.sttEnabledSource.next(savedSTT === 'true'); | |
| } | |
| } catch (error) { | |
| console.error('Error loading preferences:', error); | |
| this.ttsEnabledSource.next(false); | |
| this.sttEnabledSource.next(false); | |
| } | |
| } | |
| setTTSEnabled(enabled: boolean): void { | |
| try { | |
| if (typeof enabled !== 'boolean') { | |
| throw new Error('TTS enabled must be a boolean value'); | |
| } | |
| this.ttsEnabledSource.next(enabled); | |
| try { | |
| localStorage.setItem(this.TTS_KEY, enabled.toString()); | |
| } catch (error) { | |
| console.warn('Failed to save TTS preference:', error); | |
| } | |
| console.log(`TTS ${enabled ? 'enabled' : 'disabled'}`); | |
| } catch (error) { | |
| this.handleError('validation', 'Invalid TTS setting', error); | |
| } | |
| } | |
| setSTTEnabled(enabled: boolean): void { | |
| try { | |
| if (typeof enabled !== 'boolean') { | |
| throw new Error('STT enabled must be a boolean value'); | |
| } | |
| this.sttEnabledSource.next(enabled); | |
| try { | |
| localStorage.setItem(this.STT_KEY, enabled.toString()); | |
| } catch (error) { | |
| console.warn('Failed to save STT preference:', error); | |
| } | |
| console.log(`STT ${enabled ? 'enabled' : 'disabled'}`); | |
| } catch (error) { | |
| this.handleError('validation', 'Invalid STT setting', error); | |
| } | |
| } | |
| isTTSEnabled(): boolean { | |
| return this.ttsEnabledSource.value; | |
| } | |
| isSTTEnabled(): boolean { | |
| return this.sttEnabledSource.value; | |
| } | |
| updateEnvironment(env: Environment | null): void { | |
| try { | |
| this.environmentSubject.next(env); | |
| this.errorSubject.next(null); | |
| if (env) { | |
| console.log('Environment updated:', { | |
| llm_provider: env.llm_provider.name, | |
| tts_provider: env.tts_provider.name, | |
| stt_provider: env.stt_provider.name | |
| }); | |
| // Update TTS/STT enabled states based on provider | |
| if (env.tts_provider.name !== 'no_tts') { | |
| this.setTTSEnabled(true); | |
| } | |
| if (env.stt_provider.name !== 'no_stt') { | |
| this.setSTTEnabled(true); | |
| } | |
| } | |
| } catch (error: any) { | |
| this.handleError('update', error.message || 'Failed to update environment', error); | |
| } | |
| } | |
| getEnvironment(): Environment | null { | |
| return this.environmentSubject.value; | |
| } | |
| getCurrentLLMProvider(): ProviderSettings | null { | |
| const env = this.environmentSubject.value; | |
| return env?.llm_provider || null; | |
| } | |
| getCurrentTTSProvider(): ProviderSettings | null { | |
| const env = this.environmentSubject.value; | |
| return env?.tts_provider || null; | |
| } | |
| getCurrentSTTProvider(): ProviderSettings | null { | |
| const env = this.environmentSubject.value; | |
| return env?.stt_provider || null; | |
| } | |
| isGPTMode(): boolean { | |
| try { | |
| const env = this.environmentSubject.value; | |
| const llmName = env?.llm_provider?.name?.toLowerCase(); | |
| return llmName?.startsWith('gpt4o') || false; | |
| } catch (error) { | |
| console.error('Error checking GPT mode:', error); | |
| return false; | |
| } | |
| } | |
| getWorkMode(): string | null { | |
| const env = this.environmentSubject.value; | |
| return env?.llm_provider?.name || null; | |
| } | |
| isTTSAvailable(): boolean { | |
| const env = this.environmentSubject.value; | |
| return env?.tts_provider?.name !== 'no_tts' && env?.tts_provider?.name !== undefined; | |
| } | |
| isSTTAvailable(): boolean { | |
| const env = this.environmentSubject.value; | |
| return env?.stt_provider?.name !== 'no_stt' && env?.stt_provider?.name !== undefined; | |
| } | |
| // Check if environment supports a specific feature | |
| supportsFeature(feature: 'tts' | 'stt' | 'realtime' | 'streaming'): boolean { | |
| const env = this.environmentSubject.value; | |
| if (!env) return false; | |
| switch (feature) { | |
| case 'tts': | |
| return this.isTTSAvailable() && this.isTTSEnabled(); | |
| case 'stt': | |
| return this.isSTTAvailable() && this.isSTTEnabled(); | |
| case 'realtime': | |
| return this.isGPTMode(); | |
| case 'streaming': | |
| return true; | |
| default: | |
| return false; | |
| } | |
| } | |
| // Get available providers | |
| getAvailableProviders(type: 'llm' | 'tts' | 'stt'): any[] { | |
| const env = this.environmentSubject.value; | |
| if (!env?.providers) return []; | |
| return env.providers.filter(p => p.type === type); | |
| } | |
| // Reset all settings | |
| reset(): void { | |
| try { | |
| this.environmentSubject.next(null); | |
| this.setTTSEnabled(false); | |
| this.setSTTEnabled(false); | |
| this.errorSubject.next(null); | |
| try { | |
| localStorage.removeItem(this.TTS_KEY); | |
| localStorage.removeItem(this.STT_KEY); | |
| } catch (error) { | |
| console.warn('Failed to clear preferences:', error); | |
| } | |
| console.log('Environment service reset'); | |
| } catch (error) { | |
| this.handleError('unknown', 'Failed to reset environment', error); | |
| } | |
| } | |
| // Get configuration summary | |
| getConfigSummary(): { | |
| llmProvider: string | null; | |
| ttsProvider: string | null; | |
| sttProvider: string | null; | |
| ttsEnabled: boolean; | |
| sttEnabled: boolean; | |
| features: string[]; | |
| } { | |
| const env = this.environmentSubject.value; | |
| const features: string[] = []; | |
| if (this.supportsFeature('tts')) features.push('TTS'); | |
| if (this.supportsFeature('stt')) features.push('STT'); | |
| if (this.supportsFeature('realtime')) features.push('Realtime'); | |
| if (this.supportsFeature('streaming')) features.push('Streaming'); | |
| return { | |
| llmProvider: env?.llm_provider?.name || null, | |
| ttsProvider: env?.tts_provider?.name || null, | |
| sttProvider: env?.stt_provider?.name || null, | |
| ttsEnabled: this.isTTSEnabled(), | |
| sttEnabled: this.isSTTEnabled(), | |
| features | |
| }; | |
| } | |
| private handleError(type: EnvironmentError['type'], message: string, details?: any): void { | |
| const error: EnvironmentError = { | |
| type, | |
| message, | |
| details | |
| }; | |
| console.error(`Environment error [${type}]:`, message, details); | |
| this.errorSubject.next(error); | |
| } | |
| // Observable to check if environment is ready | |
| isReady(): Observable<boolean> { | |
| return new Observable(subscriber => { | |
| const sub = this.environment$.subscribe(env => { | |
| // Environment is ready if we have all providers configured | |
| const isReady = !!( | |
| env && | |
| env.llm_provider && | |
| env.tts_provider && | |
| env.stt_provider | |
| ); | |
| subscriber.next(isReady); | |
| }); | |
| return () => sub.unsubscribe(); | |
| }); | |
| } | |
| // Get error state | |
| hasError(): boolean { | |
| return this.errorSubject.value !== null; | |
| } | |
| clearError(): void { | |
| this.errorSubject.next(null); | |
| } | |
| } |