Skip to content

Commit c2489fa

Browse files
Bot-Rakshitclaude
andcommitted
Add old API as fallback when rate limited
- Primary: chess-api.com/v1 (depth 12, better analysis) - Fallback: eval.plc.hadron43.in (when rate limited) - Remembers rate limit state to avoid repeated 429s - Simplified code, removed CORS proxy complexity Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 4d58d0a commit c2489fa

File tree

1 file changed

+65
-83
lines changed

1 file changed

+65
-83
lines changed

src/app/evalbars/App.js

Lines changed: 65 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -151,105 +151,87 @@ function App() {
151151

152152
// Cache to prevent duplicate API calls (chess-api.com has 1000 calls/IP limit)
153153
const evalCacheRef = useRef(new Map());
154-
const proxyIndexRef = useRef(0);
155-
const rateLimitedRef = useRef(false);
154+
const useFallbackRef = useRef(false);
156155

157-
const fetchEvaluation = async (fen, retryCount = 0) => {
158-
// Check cache first to avoid duplicate calls
159-
if (evalCacheRef.current.has(fen)) {
160-
return evalCacheRef.current.get(fen);
161-
}
162-
163-
const endpoint = 'https://chess-api.com/v1';
164-
165-
// CORS proxies to rotate through when rate limited
166-
const corsProxies = [
167-
null, // Direct request first
168-
'https://corsproxy.io/?',
169-
'https://api.allorigins.win/raw?url=',
170-
'https://cors-anywhere.herokuapp.com/',
171-
];
156+
const fetchFromChessApi = async (fen) => {
157+
const response = await fetch('https://chess-api.com/v1', {
158+
method: 'POST',
159+
headers: { 'Content-Type': 'application/json' },
160+
body: JSON.stringify({ fen, depth: 12, maxThinkingTime: 50 }),
161+
});
172162

173-
const makeRequest = async (proxyUrl) => {
174-
const targetUrl = proxyUrl ? `${proxyUrl}${encodeURIComponent(endpoint)}` : endpoint;
175-
176-
const response = await fetch(targetUrl, {
177-
method: 'POST',
178-
headers: {
179-
'Content-Type': 'application/json',
180-
},
181-
body: JSON.stringify({
182-
fen: fen,
183-
depth: 12,
184-
maxThinkingTime: 50,
185-
}),
186-
});
163+
if (response.status === 429) {
164+
throw new Error('RATE_LIMITED');
165+
}
166+
if (!response.ok) {
167+
throw new Error(`chess-api.com failed: ${response.status}`);
168+
}
187169

188-
return response;
170+
const data = await response.json();
171+
return {
172+
evaluation: data.mate !== null ? (data.mate > 0 ? 100 : -100) : data.eval,
173+
bestMove: data.san || data.move || null,
174+
mate: data.mate,
175+
depth: data.depth,
176+
winChance: data.winChance,
189177
};
178+
};
190179

191-
try {
192-
// Start with current proxy index (remembers if we're rate limited)
193-
let response = await makeRequest(corsProxies[proxyIndexRef.current]);
194-
195-
// Handle rate limiting (429) or other errors - try next proxy
196-
if (response.status === 429 || !response.ok) {
197-
rateLimitedRef.current = true;
198-
199-
// Try each proxy until one works
200-
for (let i = 1; i < corsProxies.length && !response.ok; i++) {
201-
proxyIndexRef.current = i;
202-
console.log(`Rate limited, trying proxy ${i}...`);
203-
204-
// Small delay before retry
205-
await new Promise(resolve => setTimeout(resolve, 500 * i));
206-
207-
try {
208-
response = await makeRequest(corsProxies[i]);
209-
if (response.ok) break;
210-
} catch (e) {
211-
console.log(`Proxy ${i} failed:`, e.message);
212-
}
213-
}
214-
}
180+
const fetchFromFallback = async (fen) => {
181+
const encodedFen = encodeURIComponent(fen);
182+
const response = await fetch(`https://eval.plc.hadron43.in/eval-bars/?fen=${encodedFen}`);
215183

216-
if (!response.ok) {
217-
throw new Error(`All endpoints failed (status: ${response.status})`);
218-
}
184+
if (!response.ok) {
185+
throw new Error(`Fallback API failed: ${response.status}`);
186+
}
219187

220-
const data = await response.json();
188+
const data = await response.json();
189+
return {
190+
evaluation: data.evaluation,
191+
bestMove: null,
192+
};
193+
};
221194

222-
// chess-api.com response format:
223-
// { eval: number, move: string, san: string, mate: number|null, centipawns: string, ... }
224-
const result = {
225-
evaluation: data.mate !== null ? (data.mate > 0 ? 100 : -100) : data.eval,
226-
bestMove: data.san || data.move || null,
227-
mate: data.mate,
228-
depth: data.depth,
229-
winChance: data.winChance,
230-
};
195+
const fetchEvaluation = async (fen) => {
196+
// Check cache first to avoid duplicate calls
197+
if (evalCacheRef.current.has(fen)) {
198+
return evalCacheRef.current.get(fen);
199+
}
231200

232-
// Cache the result
233-
evalCacheRef.current.set(fen, result);
201+
let result;
234202

235-
// Limit cache size to prevent memory issues (keep last 500 positions)
236-
if (evalCacheRef.current.size > 500) {
237-
const firstKey = evalCacheRef.current.keys().next().value;
238-
evalCacheRef.current.delete(firstKey);
203+
try {
204+
// If we've been rate limited before, go straight to fallback
205+
if (useFallbackRef.current) {
206+
result = await fetchFromFallback(fen);
207+
} else {
208+
result = await fetchFromChessApi(fen);
239209
}
240-
241-
return result;
242210
} catch (error) {
243-
console.error("Failed to fetch evaluation:", error);
211+
// On rate limit or failure, try fallback API
212+
if (error.message === 'RATE_LIMITED') {
213+
console.log('Rate limited on chess-api.com, switching to fallback API');
214+
useFallbackRef.current = true;
215+
}
244216

245-
// Retry once with exponential backoff
246-
if (retryCount < 2) {
247-
await new Promise(resolve => setTimeout(resolve, 1000 * (retryCount + 1)));
248-
return fetchEvaluation(fen, retryCount + 1);
217+
try {
218+
result = await fetchFromFallback(fen);
219+
} catch (fallbackError) {
220+
console.error('Both APIs failed:', error.message, fallbackError.message);
221+
throw fallbackError;
249222
}
223+
}
250224

251-
throw error;
225+
// Cache the result
226+
evalCacheRef.current.set(fen, result);
227+
228+
// Limit cache size to prevent memory issues (keep last 500 positions)
229+
if (evalCacheRef.current.size > 500) {
230+
const firstKey = evalCacheRef.current.keys().next().value;
231+
evalCacheRef.current.delete(firstKey);
252232
}
233+
234+
return result;
253235
};
254236
const handleRemoveLink = (index) => {
255237
setLinks((prevLinks) => prevLinks.filter((link, i) => i !== index));

0 commit comments

Comments
 (0)