Spaces:
Building
Building
// 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); | |
} | |
} |