/** * Text Generation Client Manager * Provides unified interface for text generation with automatic fallback * Primary: Qwen3 (Qwen/Qwen3-Demo), Fallback: Zephyr-7B (Fraser/zephyr-7b) */ import { qwen3Client } from './qwen3Client'; interface TextGenerationClient { predict(endpoint: string, params: any[]): Promise<{data: any[]}>; testConnection?(): Promise; } class TextGenerationManager { private primaryClient: TextGenerationClient; private fallbackClient: TextGenerationClient | null = null; private useQwen3: boolean = true; private connectionTested: boolean = false; constructor() { this.primaryClient = qwen3Client; } /** * Set the fallback client (Zephyr-7B) */ setFallbackClient(client: TextGenerationClient) { this.fallbackClient = client; } /** * Initialize without testing - assume Qwen3 is available and test on first real use */ async initialize(): Promise { if (this.connectionTested) return; console.log('🔧 Initializing text generation manager - using Qwen3 but will fallback to Zephyr-7B on failure'); // Default to using Qwen3, test will happen on first predict() call this.useQwen3 = true; this.connectionTested = true; console.log('✅ Text generation manager initialized - ready to use Qwen3 (with fallback to Zephyr-7B)'); } /** * Get the active client for text generation */ private getActiveClient(): TextGenerationClient { if (this.useQwen3) { return this.primaryClient; } else if (this.fallbackClient) { return this.fallbackClient; } else { console.warn('No fallback client available, using Qwen3 client'); return this.primaryClient; } } /** * Predict method with automatic fallback - tests on first failure */ async predict(endpoint: string, params: any[]): Promise<{data: any[]}> { // Ensure initialization has been attempted if (!this.connectionTested) { await this.initialize(); } const activeClient = this.getActiveClient(); const clientName = this.useQwen3 ? 'Qwen3' : 'Zephyr-7B'; console.log(`🤖 Using ${clientName} for text generation`); try { const result = await activeClient.predict(endpoint, params); return result; } catch (error) { console.error(`${clientName} prediction failed:`, error); // If primary client fails and we have a fallback, try it if (this.useQwen3 && this.fallbackClient) { console.log('🔄 Qwen3 failed, switching to fallback Zephyr-7B...'); try { const fallbackResult = await this.fallbackClient.predict(endpoint, params); // Mark for future calls to use fallback this.useQwen3 = false; console.log('✅ Fallback to Zephyr-7B successful - will use Zephyr-7B for future requests'); return fallbackResult; } catch (fallbackError) { console.error('Fallback client also failed:', fallbackError); throw new Error(`Both primary (${clientName}) and fallback clients failed`); } } throw error; } } /** * Force switch to Qwen3 */ useQwen3Client() { this.useQwen3 = true; console.log('🔄 Switched to Qwen3 client'); } /** * Force switch to fallback (Zephyr-7B) */ useFallbackClient() { if (this.fallbackClient) { this.useQwen3 = false; console.log('🔄 Switched to fallback (Zephyr-7B) client'); } else { console.warn('No fallback client available'); } } /** * Get current client status */ getStatus() { return { usingQwen3: this.useQwen3, hasFallback: this.fallbackClient !== null, connectionTested: this.connectionTested, activeClient: this.useQwen3 ? 'Qwen3' : 'Zephyr-7B' }; } /** * Reset connection testing to allow re-initialization */ resetConnectionTest() { this.connectionTested = false; console.log('🔄 Connection test reset - will re-test on next prediction'); } /** * Force re-test connection and re-initialize */ async retestConnection(): Promise { this.connectionTested = false; await this.initialize(); } } // Export singleton instance export const textGenerationManager = new TextGenerationManager();