mirror of
https://github.com/jina-ai/node-DeepResearch.git
synced 2025-12-26 06:28:56 +08:00
jina-ai: allow anonymous access with rate limit 3qpm
This commit is contained in:
parent
5350d27420
commit
d754762f73
@ -1,11 +1,11 @@
|
|||||||
import { ApplicationError, Prop, RPC_CALL_ENVIRONMENT } from "civkit/civ-rpc";
|
import { ApplicationError, OperationNotAllowedError, Prop, RPC_CALL_ENVIRONMENT } from "civkit/civ-rpc";
|
||||||
import { marshalErrorLike } from "civkit/lang";
|
import { marshalErrorLike } from "civkit/lang";
|
||||||
import { randomUUID } from "crypto";
|
import { randomUUID } from "crypto";
|
||||||
import { once } from "events";
|
import { once } from "events";
|
||||||
import type { NextFunction, Request, Response } from "express";
|
import type { NextFunction, Request, Response } from "express";
|
||||||
|
|
||||||
import { JinaEmbeddingsAuthDTO } from "./dto/jina-embeddings-auth";
|
import { JinaEmbeddingsAuthDTO } from "./dto/jina-embeddings-auth";
|
||||||
import rateLimitControl, { API_CALL_STATUS, RateLimitDesc } from "./rate-limit";
|
import rateLimitControl, { API_CALL_STATUS, APICall, RateLimitDesc } from "./rate-limit";
|
||||||
import asyncLocalContext from "./lib/async-context";
|
import asyncLocalContext from "./lib/async-context";
|
||||||
import globalLogger from "./lib/logger";
|
import globalLogger from "./lib/logger";
|
||||||
import { InsufficientBalanceError } from "./lib/errors";
|
import { InsufficientBalanceError } from "./lib/errors";
|
||||||
@ -86,27 +86,52 @@ export const jinaAiMiddleware = (req: Request, res: Response, next: NextFunction
|
|||||||
[RPC_CALL_ENVIRONMENT]: { req, res }
|
[RPC_CALL_ENVIRONMENT]: { req, res }
|
||||||
});
|
});
|
||||||
|
|
||||||
const user = await authDto.assertUser();
|
const uid = await authDto.solveUID();
|
||||||
const uid = await authDto.assertUID();
|
if (!uid && !ctx.ip) {
|
||||||
if (!(user.wallet.total_balance > 0)) {
|
throw new OperationNotAllowedError(`Missing IP information for anonymous user`);
|
||||||
throw new InsufficientBalanceError(`Account balance not enough to run this query, please recharge.`);
|
|
||||||
}
|
}
|
||||||
await rateLimitControl.serviceReady();
|
let rateLimitPolicy
|
||||||
const rateLimitPolicy = authDto.getRateLimits(appName) || [
|
if (uid) {
|
||||||
parseInt(user.metadata?.speed_level) >= 2 ?
|
const user = await authDto.assertUser();
|
||||||
|
if (!(user.wallet.total_balance > 0)) {
|
||||||
|
throw new InsufficientBalanceError(`Account balance not enough to run this query, please recharge.`);
|
||||||
|
}
|
||||||
|
rateLimitPolicy = authDto.getRateLimits(appName) || [
|
||||||
|
parseInt(user.metadata?.speed_level) >= 2 ?
|
||||||
|
RateLimitDesc.from({
|
||||||
|
occurrence: 30,
|
||||||
|
periodSeconds: 60
|
||||||
|
}) :
|
||||||
|
RateLimitDesc.from({
|
||||||
|
occurrence: 10,
|
||||||
|
periodSeconds: 60
|
||||||
|
})
|
||||||
|
];
|
||||||
|
} else {
|
||||||
|
rateLimitPolicy = [
|
||||||
RateLimitDesc.from({
|
RateLimitDesc.from({
|
||||||
occurrence: 30,
|
occurrence: 3,
|
||||||
periodSeconds: 60
|
|
||||||
}) :
|
|
||||||
RateLimitDesc.from({
|
|
||||||
occurrence: 10,
|
|
||||||
periodSeconds: 60
|
periodSeconds: 60
|
||||||
})
|
})
|
||||||
];
|
]
|
||||||
const criterions = rateLimitPolicy.map((c) => rateLimitControl.rateLimitDescToCriterion(c));
|
}
|
||||||
await Promise.all(criterions.map(([pointInTime, n]) => rateLimitControl.assertUidPeriodicLimit(uid, pointInTime, n, appName)));
|
|
||||||
|
|
||||||
const apiRoll = rateLimitControl.record({ uid, tags: [appName] })
|
const criterions = rateLimitPolicy.map((c) => rateLimitControl.rateLimitDescToCriterion(c));
|
||||||
|
await Promise.all(
|
||||||
|
criterions.map(
|
||||||
|
([pointInTime, n]) => uid ?
|
||||||
|
rateLimitControl.assertUidPeriodicLimit(uid, pointInTime, n, appName) :
|
||||||
|
rateLimitControl.assertIPPeriodicLimit(ctx.ip!, pointInTime, n, appName)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
const draftApiCall: Partial<APICall> = { tags: [appName] };
|
||||||
|
if (uid) {
|
||||||
|
draftApiCall.uid = uid;
|
||||||
|
} else {
|
||||||
|
draftApiCall.ip = ctx.ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
const apiRoll = rateLimitControl.record(draftApiCall);
|
||||||
apiRoll.save().catch((err) => logger.warn(`Failed to save rate limit record`, { err: marshalErrorLike(err) }));
|
apiRoll.save().catch((err) => logger.warn(`Failed to save rate limit record`, { err: marshalErrorLike(err) }));
|
||||||
|
|
||||||
const pResClose = once(res, 'close');
|
const pResClose = once(res, 'close');
|
||||||
@ -117,7 +142,7 @@ export const jinaAiMiddleware = (req: Request, res: Response, next: NextFunction
|
|||||||
const chargeAmount = ctx.chargeAmount;
|
const chargeAmount = ctx.chargeAmount;
|
||||||
if (chargeAmount) {
|
if (chargeAmount) {
|
||||||
authDto.reportUsage(chargeAmount, `reader-${appName}`).catch((err) => {
|
authDto.reportUsage(chargeAmount, `reader-${appName}`).catch((err) => {
|
||||||
logger.warn(`Unable to report usage for ${uid}`, { err: marshalErrorLike(err) });
|
logger.warn(`Unable to report usage for ${uid || ctx.ip}`, { err: marshalErrorLike(err) });
|
||||||
});
|
});
|
||||||
apiRoll.chargeAmount = chargeAmount;
|
apiRoll.chargeAmount = chargeAmount;
|
||||||
}
|
}
|
||||||
@ -125,10 +150,11 @@ export const jinaAiMiddleware = (req: Request, res: Response, next: NextFunction
|
|||||||
apiRoll.save().catch((err) => logger.warn(`Failed to save rate limit record`, { err: marshalErrorLike(err) }));
|
apiRoll.save().catch((err) => logger.warn(`Failed to save rate limit record`, { err: marshalErrorLike(err) }));
|
||||||
logger.info(`HTTP ${res.statusCode} for request ${ctx.traceId} after ${Date.now() - ctx.traceT0.valueOf()}ms`, {
|
logger.info(`HTTP ${res.statusCode} for request ${ctx.traceId} after ${Date.now() - ctx.traceT0.valueOf()}ms`, {
|
||||||
uid,
|
uid,
|
||||||
|
ip: ctx.ip,
|
||||||
chargeAmount,
|
chargeAmount,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (ctx.promptContext?.knowledge?.length) {
|
if (uid && ctx.promptContext.knowledge?.length) {
|
||||||
Promise.all(ctx.promptContext.knowledge.map((x: any) => KnowledgeItem.save(
|
Promise.all(ctx.promptContext.knowledge.map((x: any) => KnowledgeItem.save(
|
||||||
KnowledgeItem.from({
|
KnowledgeItem.from({
|
||||||
...x,
|
...x,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user