-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapi_solve.js
More file actions
69 lines (60 loc) · 2.72 KB
/
api_solve.js
File metadata and controls
69 lines (60 loc) · 2.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
* /api/solve.js — Vercel Serverless Function
* Routes math expressions to Claude AI for solving
* Rate limited · POST-only · Input validated
*/
const RATE_WINDOW_MS = 10 * 60 * 1000; // 10 min
const RATE_LIMIT = 30;
const rateLimitMap = new Map();
function checkRateLimit(ip) {
const now = Date.now();
const e = rateLimitMap.get(ip);
if (!e || now - e.windowStart > RATE_WINDOW_MS) {
rateLimitMap.set(ip, { count: 1, windowStart: now });
if (rateLimitMap.size > 5000) for (const [k,v] of rateLimitMap) if (now-v.windowStart>RATE_WINDOW_MS) rateLimitMap.delete(k);
return true;
}
if (e.count >= RATE_LIMIT) return false;
e.count++;
return true;
}
export default async function handler(req, res) {
if (req.method !== 'POST') return res.status(405).json({ error: 'POST only' });
const ip = (req.headers['x-forwarded-for'] || req.socket?.remoteAddress || 'unknown').split(',')[0].trim();
if (!checkRateLimit(ip)) return res.status(429).json({ error: 'Rate limit exceeded' });
const { expression } = req.body || {};
if (!expression || typeof expression !== 'string' || expression.length > 2000) {
return res.status(400).json({ error: 'Invalid expression' });
}
const apiKey = process.env.ANTHROPIC_API_KEY;
if (!apiKey) return res.status(500).json({ error: 'Server configuration error' });
try {
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': apiKey,
'anthropic-version': '2023-06-01'
},
body: JSON.stringify({
model: 'claude-sonnet-4-20250514',
max_tokens: 1024,
system: `You are NEXUS, an elite mathematical computation engine. Solve with maximum precision and clarity. Always provide:
1. A concise final answer
2. Step-by-step solution using proper mathematical notation
Keep responses focused and mathematical.`,
messages: [{ role: 'user', content: `Solve this mathematical problem concisely:\n${expression}\n\nRespond ONLY in this JSON format (no markdown wrapper):\n{"result":"<final answer>","steps":"<step-by-step in markdown>"}` }]
})
});
if (!response.ok) throw new Error(`Anthropic API error: ${response.status}`);
const data = await response.json();
const text = data.content?.[0]?.text || '{}';
const clean = text.replace(/```json?|```/g, '').trim();
const parsed = JSON.parse(clean);
res.setHeader('Cache-Control', 'no-store');
res.status(200).json({ result: parsed.result || 'See steps', steps: parsed.steps || text });
} catch (err) {
console.error('[api/solve]', err.message);
res.status(500).json({ error: 'Solver unavailable', result: 'Error', steps: err.message });
}
}