/** * Service to interact with the Python algorithm backend */ const API_BASE = '/api/algorithms' export interface CSPRecommendation { budget: number user_inputs: Record } export interface CSPSolution { [category: string]: { id: number name: string price: number category: string } } export interface UpgradeRecommendation { current_component: string recommended_upgrade: string | null new_price: number | null upgrade_cost?: number | null } /** * Get component recommendations using CSP algorithm with pagination */ export async function getCSPRecommendations( budget: number, userInputs: Record, page: number = 0, limit: number = 10, performanceCategory?: string ): Promise<{ solutions: CSPSolution[], hasMore: boolean, page: number }> { try { // Create AbortController for client-side timeout (2-3 minutes) const controller = new AbortController() const timeoutId = setTimeout(() => controller.abort(), 180000) // 180 seconds = 3 minutes // Ensure userInputs is a plain object without circular references const cleanUserInputs: Record = {} for (const [key, value] of Object.entries(userInputs)) { if (typeof value === 'number' && !isNaN(value) && isFinite(value)) { cleanUserInputs[key] = value } } // Prepare request body const requestBody: any = { budget: typeof budget === 'number' && !isNaN(budget) && isFinite(budget) ? budget : 0, user_inputs: cleanUserInputs, page: typeof page === 'number' && !isNaN(page) && isFinite(page) ? page : 0, limit: typeof limit === 'number' && !isNaN(limit) && isFinite(limit) ? limit : 10, } // Add performance category if specified if (performanceCategory && performanceCategory !== 'all') { requestBody.performance_category = performanceCategory } let requestBodyString: string try { requestBodyString = JSON.stringify(requestBody) } catch (error: any) { console.error('Error stringifying request body:', error) throw new Error('Failed to prepare request data. Please check your selected components.') } const response = await fetch(`${API_BASE}/csp`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: requestBodyString, signal: controller.signal, }) clearTimeout(timeoutId) // Check content-type to ensure we're getting JSON const contentType = response.headers.get('content-type') || '' const isJSON = contentType.includes('application/json') if (!response.ok) { let errorMessage = 'Failed to get CSP recommendations' try { const errorText = await response.text() // If response is HTML (error page), provide helpful message if (!isJSON || errorText.trim().startsWith(', budget?: number, compatibilityInfo?: { socket?: string memoryType?: string } ): Promise { try { const response = await fetch(`${API_BASE}/upgrade`, { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ current_build: currentBuild, budget: budget || null, compatibility_info: compatibilityInfo || null, }), }) // Check content-type to ensure we're getting JSON const contentType = response.headers.get('content-type') || '' const isJSON = contentType.includes('application/json') if (!response.ok) { // Try to get error message from response let errorMessage = 'Failed to get upgrade recommendations' try { const errorText = await response.text() // If response is HTML (error page), provide helpful message if (!isJSON || errorText.trim().startsWith('