Skip to content

Commit bb1d857

Browse files
committed
fix: 修复速率限制bug并添加日志
- 修复每分钟最大请求次数限制失效的问题 - 将时间戳更新从API调用前移到调用后,确保重试请求也被正确计入速率限制 - 添加速率限制等待日志,方便调试 - 影响翻译器:OpenAI、OpenAI HQ、Gemini、Gemini HQ
1 parent 36e759c commit bb1d857

5 files changed

Lines changed: 49 additions & 16 deletions

File tree

doc/CHANGELOG_v1.8.9.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@
1515
- 修复 web 模式缺少 nonce 和 start_instance 属性的错误
1616
- 修复 web 模式命令行参数未生效的问题
1717

18+
### 翻译器修复
19+
- **修复速率限制bug**:修复每分钟最大请求次数限制失效的问题
20+
- 问题:当API调用失败(网络错误、SSL错误等)时,时间戳在请求发送前就已更新,导致重试请求没有遵守速率限制
21+
- 修复:将时间戳更新移到API调用成功后,确保只有真正完成的请求才计入速率限制
22+
- 影响翻译器:OpenAI、OpenAI HQ、Gemini、Gemini HQ
23+
- **添加速率限制日志**:当触发速率限制等待时,会打印 `Ratelimit sleep: X.XXs` 日志,方便调试
24+
1825
## 🎯 新增功能
1926

2027
### API 功能增强

manga_translator/translators/gemini.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,18 @@ def generate_content_with_logging(**kwargs):
300300
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
301301
elapsed = now - GeminiTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
302302
if elapsed < delay:
303-
await asyncio.sleep(delay - elapsed)
304-
GeminiTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
303+
sleep_time = delay - elapsed
304+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
305+
await asyncio.sleep(sleep_time)
305306

306307
response = await asyncio.to_thread(
307308
generate_content_with_logging,
308309
**request_args
309310
)
311+
312+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
313+
if self._MAX_REQUESTS_PER_MINUTE > 0:
314+
GeminiTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
310315

311316
# 检查finish_reason,只有成功(1)才继续,其他都重试
312317
if hasattr(response, 'candidates') and response.candidates:

manga_translator/translators/gemini_hq.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -325,14 +325,18 @@ def generate_content_with_logging(**kwargs):
325325
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
326326
elapsed = now - GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
327327
if elapsed < delay:
328-
await asyncio.sleep(delay - elapsed)
329-
# 在请求前更新时间戳,确保下次计算的是从这次请求开始的间隔
330-
GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
328+
sleep_time = delay - elapsed
329+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
330+
await asyncio.sleep(sleep_time)
331331

332332
response = await asyncio.to_thread(
333333
generate_content_with_logging,
334334
**request_args
335335
)
336+
337+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
338+
if self._MAX_REQUESTS_PER_MINUTE > 0:
339+
GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
336340

337341
# 检查finish_reason,只有成功(1)才继续,其他都重试
338342
if hasattr(response, 'candidates') and response.candidates:
@@ -550,15 +554,19 @@ def generate_content_with_logging(**kwargs):
550554
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
551555
elapsed = now - GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
552556
if elapsed < delay:
553-
await asyncio.sleep(delay - elapsed)
554-
# 在请求前更新时间戳,确保下次计算的是从这次请求开始的间隔
555-
GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
557+
sleep_time = delay - elapsed
558+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
559+
await asyncio.sleep(sleep_time)
556560

557561
response = await asyncio.to_thread(
558562
generate_content_with_logging,
559563
**request_args
560564
)
561565

566+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
567+
if self._MAX_REQUESTS_PER_MINUTE > 0:
568+
GeminiHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
569+
562570
if response and response.text:
563571
result = response.text.strip()
564572
translations = result.split('\n')

manga_translator/translators/openai.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -228,15 +228,20 @@ async def _translate_batch(self, texts: List[str], source_lang: str, target_lang
228228
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
229229
elapsed = now - OpenAITranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
230230
if elapsed < delay:
231-
await asyncio.sleep(delay - elapsed)
232-
OpenAITranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
231+
sleep_time = delay - elapsed
232+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
233+
await asyncio.sleep(sleep_time)
233234

234235
response = await self.client.chat.completions.create(
235236
model=self.model,
236237
messages=messages,
237238
max_tokens=self.max_tokens,
238239
temperature=self.temperature
239240
)
241+
242+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
243+
if self._MAX_REQUESTS_PER_MINUTE > 0:
244+
OpenAITranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
240245

241246
# 检查成功条件
242247
if response.choices and response.choices[0].message.content and response.choices[0].finish_reason != 'content_filter':

manga_translator/translators/openai_hq.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -296,16 +296,20 @@ async def _translate_batch_high_quality(self, texts: List[str], batch_data: List
296296
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
297297
elapsed = now - OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
298298
if elapsed < delay:
299-
await asyncio.sleep(delay - elapsed)
300-
# 在请求前更新时间戳,确保下次计算的是从这次请求开始的间隔
301-
OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
299+
sleep_time = delay - elapsed
300+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
301+
await asyncio.sleep(sleep_time)
302302

303303
response = await self.client.chat.completions.create(
304304
model=self.model,
305305
messages=messages,
306306
max_tokens=self.max_tokens,
307307
temperature=self.temperature
308308
)
309+
310+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
311+
if self._MAX_REQUESTS_PER_MINUTE > 0:
312+
OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
309313

310314
# 检查成功条件
311315
if response.choices and response.choices[0].message.content and response.choices[0].finish_reason != 'content_filter':
@@ -485,9 +489,9 @@ async def _translate(self, from_lang: str, to_lang: str, queries: List[str], ctx
485489
delay = 60.0 / self._MAX_REQUESTS_PER_MINUTE
486490
elapsed = now - OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key]
487491
if elapsed < delay:
488-
await asyncio.sleep(delay - elapsed)
489-
# 在请求前更新时间戳,确保下次计算的是从这次请求开始的间隔
490-
OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
492+
sleep_time = delay - elapsed
493+
self.logger.info(f'Ratelimit sleep: {sleep_time:.2f}s')
494+
await asyncio.sleep(sleep_time)
491495

492496
response = await self.client.chat.completions.create(
493497
model=self.model,
@@ -496,6 +500,10 @@ async def _translate(self, from_lang: str, to_lang: str, queries: List[str], ctx
496500
temperature=self.temperature
497501
)
498502

503+
# 在API调用成功后立即更新时间戳,确保所有请求(包括重试)都被计入速率限制
504+
if self._MAX_REQUESTS_PER_MINUTE > 0:
505+
OpenAIHighQualityTranslator._GLOBAL_LAST_REQUEST_TS[self._last_request_ts_key] = time.time()
506+
499507
if response.choices and response.choices[0].message.content:
500508
result = response.choices[0].message.content.strip()
501509
translations = result.split('\n')

0 commit comments

Comments
 (0)