@@ -17,36 +17,52 @@ export function createRateLimiter(
1717 const dict = i18n ( localeFromRequest ( request ) )
1818
1919 const limits = Subscription . getFreeLimits ( )
20- const limitValue =
21- limits . checkHeader && ! request . headers . get ( limits . checkHeader )
22- ? limits . fallbackValue
23- : ( rateLimit ?? limits . dailyRequests )
20+ const headerExists = request . headers . has ( limits . checkHeader )
21+ const dailyLimit = ! headerExists ? limits . fallbackValue : ( rateLimit ?? limits . dailyRequests )
22+ const isDefaultModel = headerExists && ! rateLimit
2423
2524 const ip = ! rawIp . length ? "unknown" : rawIp
2625 const now = Date . now ( )
27- const interval = rateLimit ? `${ buildYYYYMMDD ( now ) } ${ modelId . substring ( 0 , 2 ) } ` : buildYYYYMMDD ( now )
26+ const lifetimeInterval = ""
27+ const dailyInterval = rateLimit ? `${ buildYYYYMMDD ( now ) } ${ modelId . substring ( 0 , 2 ) } ` : buildYYYYMMDD ( now )
28+
29+ let _isNew : boolean
2830
2931 return {
30- track : async ( ) => {
31- await Database . use ( ( tx ) =>
32- tx
33- . insert ( IpRateLimitTable )
34- . values ( { ip, interval, count : 1 } )
35- . onDuplicateKeyUpdate ( { set : { count : sql `${ IpRateLimitTable . count } + 1` } } ) ,
36- )
37- } ,
3832 check : async ( ) => {
3933 const rows = await Database . use ( ( tx ) =>
4034 tx
4135 . select ( { interval : IpRateLimitTable . interval , count : IpRateLimitTable . count } )
4236 . from ( IpRateLimitTable )
43- . where ( and ( eq ( IpRateLimitTable . ip , ip ) , inArray ( IpRateLimitTable . interval , [ interval ] ) ) ) ,
37+ . where (
38+ and (
39+ eq ( IpRateLimitTable . ip , ip ) ,
40+ isDefaultModel
41+ ? inArray ( IpRateLimitTable . interval , [ lifetimeInterval , dailyInterval ] )
42+ : inArray ( IpRateLimitTable . interval , [ dailyInterval ] ) ,
43+ ) ,
44+ ) ,
4445 )
45- const total = rows . reduce ( ( sum , r ) => sum + r . count , 0 )
46- logger . debug ( `rate limit total: ${ total } ` )
47- if ( total >= limitValue )
46+ const lifetimeCount = rows . find ( ( r ) => r . interval === lifetimeInterval ) ?. count ?? 0
47+ const dailyCount = rows . find ( ( r ) => r . interval === dailyInterval ) ?. count ?? 0
48+ logger . debug ( `rate limit lifetime: ${ lifetimeCount } , daily: ${ dailyCount } ` )
49+
50+ _isNew = isDefaultModel && lifetimeCount < dailyLimit * 7
51+
52+ if ( ( _isNew && dailyCount >= dailyLimit * 2 ) || ( ! _isNew && dailyCount >= dailyLimit ) )
4853 throw new FreeUsageLimitError ( dict [ "zen.api.error.rateLimitExceeded" ] , getRetryAfterDay ( now ) )
4954 } ,
55+ track : async ( ) => {
56+ await Database . use ( ( tx ) =>
57+ tx
58+ . insert ( IpRateLimitTable )
59+ . values ( [
60+ { ip, interval : dailyInterval , count : 1 } ,
61+ ...( _isNew ? [ { ip, interval : lifetimeInterval , count : 1 } ] : [ ] ) ,
62+ ] )
63+ . onDuplicateKeyUpdate ( { set : { count : sql `${ IpRateLimitTable . count } + 1` } } ) ,
64+ )
65+ } ,
5066 }
5167}
5268
0 commit comments