SumAI-Search / server /searchEndpointServerHook.ts
github-actions[bot]
Sync to HuggingFace Spaces
6b3405c
import { PreviewServer, ViteDevServer } from "vite";
import { RateLimiterMemory } from "rate-limiter-flexible";
import { argon2Verify } from "hash-wasm";
import { incrementSearchesSinceLastRestart } from "./searchesSinceLastRestart";
import { rankSearchResults } from "./rankSearchResults";
import { getSearchToken } from "./searchToken";
import { fetchSearXNG } from "./fetchSearXNG";
import { isVerifiedToken, addVerifiedToken } from "./verifiedTokens";
export function searchEndpointServerHook<
T extends ViteDevServer | PreviewServer,
>(server: T) {
const rateLimiter = new RateLimiterMemory({
points: 2,
duration: 10,
});
server.middlewares.use(async (request, response, next) => {
if (!request.url.startsWith("/search")) return next();
const { searchParams } = new URL(
request.url,
`http://${request.headers.host}`,
);
const limitParam = searchParams.get("limit");
const limit =
limitParam && Number(limitParam) > 0 ? Number(limitParam) : undefined;
const query = searchParams.get("q");
if (!query) {
response.statusCode = 400;
response.end("Missing the query parameter.");
return;
}
const token = searchParams.get("token");
if (!isVerifiedToken(token)) {
let isValidToken = false;
try {
isValidToken = await argon2Verify({
password: getSearchToken(),
hash: token,
});
} catch (error) {
void error;
}
if (isValidToken) {
addVerifiedToken(token);
} else {
response.statusCode = 401;
response.end("Unauthorized.");
return;
}
}
try {
await rateLimiter.consume(token);
} catch {
response.statusCode = 429;
response.end("Too many requests.");
return;
}
const { textResults, imageResults } = await fetchSearXNG(query, limit);
incrementSearchesSinceLastRestart();
if (textResults.length === 0 && imageResults.length === 0) {
response.setHeader("Content-Type", "application/json");
response.end(JSON.stringify({ textResults: [], imageResults: [] }));
return;
}
try {
const rankedTextResults = await rankSearchResults(query, textResults);
response.setHeader("Content-Type", "application/json");
response.end(
JSON.stringify({ textResults: rankedTextResults, imageResults }),
);
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : String(error);
console.error(`Error ranking search results: ${errorMessage}`);
response.setHeader("Content-Type", "application/json");
response.end(JSON.stringify({ textResults, imageResults }));
}
});
}