File tree Expand file tree Collapse file tree 2 files changed +62
-1
lines changed
packages/service/common/api
projects/app/src/pages/api/v1/chat Expand file tree Collapse file tree 2 files changed +62
-1
lines changed Original file line number Diff line number Diff line change 1+ import { getGlobalRedisConnection } from '../../common/redis' ;
2+ import { jsonRes } from '../../common/response' ;
3+ import type { NextApiResponse } from 'next' ;
4+
5+ type FrequencyLimitOption = {
6+ teamId : string ;
7+ seconds : number ;
8+ limit : number ;
9+ keyPrefix : string ;
10+ res : NextApiResponse ;
11+ } ;
12+
13+ export const teamFrequencyLimit = async ( {
14+ teamId,
15+ seconds,
16+ limit,
17+ keyPrefix,
18+ res
19+ } : FrequencyLimitOption ) => {
20+ const redis = getGlobalRedisConnection ( ) ;
21+ const key = `${ keyPrefix } :${ teamId } ` ;
22+
23+ const result = await redis
24+ . multi ( )
25+ . incr ( key )
26+ . expire ( key , seconds , 'NX' ) // 只在key不存在时设置过期时间
27+ . exec ( ) ;
28+
29+ if ( ! result ) {
30+ return Promise . reject ( new Error ( 'Redis connection error' ) ) ;
31+ }
32+
33+ const currentCount = result [ 0 ] [ 1 ] as number ;
34+
35+ if ( currentCount > limit ) {
36+ const remainingTime = await redis . ttl ( key ) ;
37+ jsonRes ( res , {
38+ code : 429 ,
39+ error : `Rate limit exceeded. Maximum ${ limit } requests per ${ seconds } seconds for this team. Please try again in ${ remainingTime } seconds.`
40+ } ) ;
41+ return false ;
42+ }
43+
44+ // 在响应头中添加限流信息
45+ res . setHeader ( 'X-RateLimit-Limit' , limit ) ;
46+ res . setHeader ( 'X-RateLimit-Remaining' , Math . max ( 0 , limit - currentCount ) ) ;
47+ res . setHeader ( 'X-RateLimit-Reset' , Date . now ( ) + seconds * 1000 ) ;
48+ return true ;
49+ } ;
Original file line number Diff line number Diff line change @@ -33,7 +33,6 @@ import {
3333 removeEmptyUserInput
3434} from '@fastgpt/global/core/chat/utils' ;
3535import { updateApiKeyUsage } from '@fastgpt/service/support/openapi/tools' ;
36- import { getUserChatInfo } from '@fastgpt/service/support/user/team/utils' ;
3736import { getRunningUserInfoByTmbId } from '@fastgpt/service/support/user/team/utils' ;
3837import { AuthUserTypeEnum } from '@fastgpt/global/support/permission/constant' ;
3938import { MongoApp } from '@fastgpt/service/core/app/schema' ;
@@ -61,6 +60,7 @@ import { getWorkflowToolInputsFromStoreNodes } from '@fastgpt/global/core/app/to
6160import { UserError } from '@fastgpt/global/common/error/utils' ;
6261import { getLocale } from '@fastgpt/service/common/middle/i18n' ;
6362import { formatTime2YMDHM } from '@fastgpt/global/common/string/time' ;
63+ import { teamFrequencyLimit } from '@fastgpt/service/common/api/frequencyLimit' ;
6464
6565type FastGptWebChatProps = {
6666 chatId ?: string ; // undefined: get histories from messages, '': new chat, 'xxxxx': get histories from db
@@ -185,6 +185,18 @@ async function handler(req: NextApiRequest, res: NextApiResponse) {
185185 chatId
186186 } ) ;
187187 } ) ( ) ;
188+
189+ if (
190+ ! ( await teamFrequencyLimit ( {
191+ teamId,
192+ keyPrefix : 'chat:completions' ,
193+ seconds : 60 ,
194+ limit : 5000 ,
195+ res
196+ } ) )
197+ ) {
198+ return { } ;
199+ }
188200 retainDatasetCite = retainDatasetCite && ! ! responseDetail ;
189201 const isPlugin = app . type === AppTypeEnum . workflowTool ;
190202
You can’t perform that action at this time.
0 commit comments