|
|
|
|
|
|
|
|
|
|
|
|
|
import { qwen3Client } from './qwen3Client'; |
|
|
|
interface TextGenerationClient { |
|
predict(endpoint: string, params: any[]): Promise<{data: any[]}>; |
|
testConnection?(): Promise<boolean>; |
|
} |
|
|
|
class TextGenerationManager { |
|
private primaryClient: TextGenerationClient; |
|
private fallbackClient: TextGenerationClient | null = null; |
|
private useQwen3: boolean = true; |
|
private connectionTested: boolean = false; |
|
|
|
constructor() { |
|
this.primaryClient = qwen3Client; |
|
} |
|
|
|
|
|
|
|
|
|
setFallbackClient(client: TextGenerationClient) { |
|
this.fallbackClient = client; |
|
} |
|
|
|
|
|
|
|
|
|
async initialize(): Promise<void> { |
|
if (this.connectionTested) return; |
|
|
|
console.log('π Testing Qwen3 connection with improved verification...'); |
|
|
|
try { |
|
if (this.primaryClient.testConnection) { |
|
|
|
const connectionTestPromise = this.primaryClient.testConnection(); |
|
const timeoutPromise = new Promise<boolean>((_, reject) => { |
|
setTimeout(() => reject(new Error('Connection test timeout')), 15000); |
|
}); |
|
|
|
const qwen3Available = await Promise.race([connectionTestPromise, timeoutPromise]); |
|
|
|
if (qwen3Available) { |
|
console.log('β
Qwen3 client is available and will be used for text generation'); |
|
this.useQwen3 = true; |
|
|
|
|
|
await this.performSecondaryValidation(); |
|
} else { |
|
console.log('β οΈ Qwen3 client is not available, falling back to Zephyr-7B'); |
|
this.useQwen3 = false; |
|
} |
|
} |
|
} catch (error) { |
|
console.error('Failed to test Qwen3 connection:', error); |
|
console.log('β οΈ Falling back to Zephyr-7B due to connection error'); |
|
this.useQwen3 = false; |
|
} |
|
|
|
this.connectionTested = true; |
|
} |
|
|
|
|
|
|
|
|
|
private async performSecondaryValidation(): Promise<void> { |
|
try { |
|
console.log('π§ Performing secondary validation of Qwen3 functionality...'); |
|
|
|
|
|
const validationResult = await Promise.race([ |
|
this.primaryClient.predict('/chat', [ |
|
'Respond with exactly this text: "VALIDATION_SUCCESS"', |
|
[], |
|
'You are a helpful assistant. Follow instructions exactly as given.', |
|
20, |
|
0.1, |
|
0.9, |
|
10, |
|
1.0 |
|
]), |
|
new Promise<any>((_, reject) => { |
|
setTimeout(() => reject(new Error('Validation timeout')), 10000); |
|
}) |
|
]); |
|
|
|
const response = validationResult?.data?.[0] || ''; |
|
const isValidResponse = typeof response === 'string' && |
|
response.length > 0 && |
|
!response.includes('temporarily unavailable') && |
|
!response.includes('using_fallback'); |
|
|
|
if (!isValidResponse) { |
|
console.warn('β οΈ Secondary validation failed - Qwen3 responses seem invalid, switching to fallback'); |
|
this.useQwen3 = false; |
|
} else { |
|
console.log('β
Secondary validation passed - Qwen3 is fully functional'); |
|
} |
|
} catch (error) { |
|
console.warn('β οΈ Secondary validation failed with error, switching to fallback:', error); |
|
this.useQwen3 = false; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
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; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
async predict(endpoint: string, params: any[]): Promise<{data: any[]}> { |
|
|
|
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 (this.useQwen3 && this.fallbackClient) { |
|
console.log('π Qwen3 failed, trying fallback to Zephyr-7B...'); |
|
try { |
|
const fallbackResult = await this.fallbackClient.predict(endpoint, params); |
|
|
|
this.useQwen3 = false; |
|
return fallbackResult; |
|
} catch (fallbackError) { |
|
console.error('Fallback client also failed:', fallbackError); |
|
throw new Error(`Both primary (${clientName}) and fallback clients failed`); |
|
} |
|
} |
|
|
|
throw error; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
useQwen3Client() { |
|
this.useQwen3 = true; |
|
console.log('π Switched to Qwen3 client'); |
|
} |
|
|
|
|
|
|
|
|
|
useFallbackClient() { |
|
if (this.fallbackClient) { |
|
this.useQwen3 = false; |
|
console.log('π Switched to fallback (Zephyr-7B) client'); |
|
} else { |
|
console.warn('No fallback client available'); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
getStatus() { |
|
return { |
|
usingQwen3: this.useQwen3, |
|
hasFallback: this.fallbackClient !== null, |
|
connectionTested: this.connectionTested, |
|
activeClient: this.useQwen3 ? 'Qwen3' : 'Zephyr-7B' |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
resetConnectionTest() { |
|
this.connectionTested = false; |
|
console.log('π Connection test reset - will re-test on next prediction'); |
|
} |
|
|
|
|
|
|
|
|
|
async retestConnection(): Promise<void> { |
|
this.connectionTested = false; |
|
await this.initialize(); |
|
} |
|
} |
|
|
|
|
|
export const textGenerationManager = new TextGenerationManager(); |