Spaces:
Runtime error
Runtime error
import { Request, Response } from "express"; | |
import * as http from "http"; | |
import * as httpProxy from "http-proxy"; | |
import { logger } from "../logger"; | |
import { keys } from "../keys"; | |
/** Handle and rewrite response to proxied requests to OpenAI */ | |
export const handleResponse = ( | |
proxyRes: http.IncomingMessage, | |
req: Request, | |
res: Response | |
) => { | |
const statusCode = proxyRes.statusCode || 500; | |
if (statusCode >= 400) { | |
let body = ""; | |
proxyRes.on("data", (chunk) => (body += chunk)); | |
proxyRes.on("end", () => { | |
let errorPayload: any = { | |
error: "Proxy couldn't parse error from OpenAI", | |
}; | |
const canTryAgain = keys.anyAvailable() | |
? "You can try again to get a different key." | |
: "There are no more keys available."; | |
try { | |
errorPayload = JSON.parse(body); | |
} catch (err) { | |
logger.error({ error: err }, errorPayload.error); | |
res.json(errorPayload); | |
return; | |
} | |
if (statusCode === 401) { | |
// Key is invalid or was revoked | |
logger.warn( | |
`OpenAI key is invalid or revoked. Keyhash ${req.key?.hash}` | |
); | |
keys.disable(req.key!); | |
const message = `The OpenAI key is invalid or revoked. ${canTryAgain}`; | |
errorPayload.proxy_note = message; | |
} else if (statusCode === 429) { | |
// Rate limit exceeded | |
// Annoyingly they send this for: | |
// - Quota exceeded, key is totally dead | |
// - Rate limit exceeded, key is still good but backoff needed | |
// - Model overloaded, their server is overloaded | |
if (errorPayload.error?.type === "insufficient_quota") { | |
logger.warn(`OpenAI key is exhausted. Keyhash ${req.key?.hash}`); | |
keys.disable(req.key!); | |
const message = `The OpenAI key is exhausted. ${canTryAgain}`; | |
errorPayload.proxy_note = message; | |
} else { | |
logger.warn( | |
{ errorCode: errorPayload.error?.type }, | |
`OpenAI rate limit exceeded or model overloaded. Keyhash ${req.key?.hash}` | |
); | |
} | |
} | |
res.status(statusCode).json(errorPayload); | |
}); | |
} else { | |
// Increment key's usage count | |
keys.incrementPrompt(req.key?.hash); | |
Object.keys(proxyRes.headers).forEach((key) => { | |
res.setHeader(key, proxyRes.headers[key] as string); | |
}); | |
proxyRes.pipe(res); | |
} | |
}; | |
export const onError: httpProxy.ErrorCallback = (err, _req, res) => { | |
logger.error({ error: err }, "Error proxying to OpenAI"); | |
(res as http.ServerResponse).writeHead(500, { | |
"Content-Type": "application/json", | |
}); | |
res.end( | |
JSON.stringify({ | |
error: { | |
type: "proxy_error", | |
message: err.message, | |
proxy_note: | |
"Reverse proxy encountered an error before it could reach OpenAI.", | |
}, | |
}) | |
); | |
}; | |