配置项增加重试次数

This commit is contained in:
xunbu
2025-09-09 20:20:42 +08:00
parent e82f6f1d15
commit e73c6a81cb
15 changed files with 57 additions and 27 deletions

View File

@@ -1,3 +1,3 @@
# SPDX-FileCopyrightText: 2025 QinHan # SPDX-FileCopyrightText: 2025 QinHan
# SPDX-License-Identifier: MPL-2.0 # SPDX-License-Identifier: MPL-2.0
__version__="1.4.2.post2" __version__="1.4.3"

View File

@@ -17,7 +17,6 @@ from docutranslate.global_values import USE_PROXY
from docutranslate.logger import global_logger from docutranslate.logger import global_logger
from docutranslate.utils.utils import get_httpx_proxies from docutranslate.utils.utils import get_httpx_proxies
MAX_RETRY_COUNT = 2
MAX_REQUESTS_PER_ERROR = 15 MAX_REQUESTS_PER_ERROR = 15
ThinkingMode = Literal["enable", "disable", "default"] ThinkingMode = Literal["enable", "disable", "default"]
@@ -48,6 +47,7 @@ class AgentConfig:
concurrent: int = 30 concurrent: int = 30
timeout: int = 1200 # 单位(秒)这个值是httpx.TimeOut中read的值,并非总的超时时间 timeout: int = 1200 # 单位(秒)这个值是httpx.TimeOut中read的值,并非总的超时时间
thinking: ThinkingMode = "default" thinking: ThinkingMode = "default"
retry: int = 2
class TotalErrorCounter: class TotalErrorCounter:
@@ -244,6 +244,8 @@ class Agent:
# 新增用于统计token使用情况 # 新增用于统计token使用情况
self.token_counter = TokenCounter(logger=self.logger) self.token_counter = TokenCounter(logger=self.logger)
self.retry = config.retry
def _add_thinking_mode(self, data: dict): def _add_thinking_mode(self, data: dict):
if self.domain not in self._think_factory: if self.domain not in self._think_factory:
return return
@@ -324,7 +326,7 @@ class Agent:
if retry_count > 0: if retry_count > 0:
self.logger.info( self.logger.info(
f"重试成功 (第 {retry_count}/{MAX_RETRY_COUNT} 次尝试)。" f"重试成功 (第 {retry_count}/{self.retry} 次尝试)。"
) )
# print(f"result:=============================================================\n{result}\n================\n") # print(f"result:=============================================================\n{result}\n================\n")
@@ -364,7 +366,7 @@ class Agent:
if current_partial_result: if current_partial_result:
best_partial_result = current_partial_result best_partial_result = current_partial_result
if should_retry and retry and retry_count < MAX_RETRY_COUNT: if should_retry and retry and retry_count < self.retry:
# 仅在硬错误时才增加总错误计数 # 仅在硬错误时才增加总错误计数
if is_hard_error: if is_hard_error:
if retry_count == 0: if retry_count == 0:
@@ -391,7 +393,7 @@ class Agent:
) )
) )
self.logger.info(f"正在重试第 {retry_count + 1}/{MAX_RETRY_COUNT} 次...") self.logger.info(f"正在重试第 {retry_count + 1}/{self.retry} 次...")
await asyncio.sleep(0.5) await asyncio.sleep(0.5)
return await self.send_async( return await self.send_async(
client, client,
@@ -545,7 +547,7 @@ class Agent:
if retry_count > 0: if retry_count > 0:
self.logger.info( self.logger.info(
f"重试成功 (第 {retry_count}/{MAX_RETRY_COUNT} 次尝试)。" f"重试成功 (第 {retry_count}/{self.retry} 次尝试)。"
) )
return ( return (
@@ -582,7 +584,7 @@ class Agent:
if current_partial_result: if current_partial_result:
best_partial_result = current_partial_result best_partial_result = current_partial_result
if should_retry and retry and retry_count < MAX_RETRY_COUNT: if should_retry and retry and retry_count < self.retry:
# 仅在硬错误时才增加总错误计数 # 仅在硬错误时才增加总错误计数
if is_hard_error: if is_hard_error:
if retry_count == 0: if retry_count == 0:
@@ -609,7 +611,7 @@ class Agent:
) )
) )
self.logger.info(f"正在重试第 {retry_count + 1}/{MAX_RETRY_COUNT} 次...") self.logger.info(f"正在重试第 {retry_count + 1}/{self.retry} 次...")
time.sleep(0.5) time.sleep(0.5)
return self.send( return self.send(
client, client,

View File

@@ -238,6 +238,7 @@ class GlossaryAgentConfigPayload(BaseModel):
concurrent: int = Field(default=30, description="Agent的最大并发请求数。") concurrent: int = Field(default=30, description="Agent的最大并发请求数。")
timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间") timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间")
thinking: ThinkingMode = Field(default="default", description="Agent的思考模式。") thinking: ThinkingMode = Field(default="default", description="Agent的思考模式。")
retry: int = Field(default=default_params["retry"], description="分块失败后的最大重试次数。")
# 1. 定义所有工作流共享的基础参数 # 1. 定义所有工作流共享的基础参数
@@ -259,6 +260,7 @@ class BaseWorkflowParams(BaseModel):
timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间") timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间")
thinking: ThinkingMode = Field(default=default_params["thinking"], description="Agent的思考模式。", thinking: ThinkingMode = Field(default=default_params["thinking"], description="Agent的思考模式。",
examples=["default", "enable", "disable"]) examples=["default", "enable", "disable"])
retry: int = Field(default=default_params["retry"], description="某个分块翻译失败后的最大重试次数。")
custom_prompt: Optional[str] = Field(None, description="用户自定义的翻译Prompt。", alias="custom_prompt") custom_prompt: Optional[str] = Field(None, description="用户自定义的翻译Prompt。", alias="custom_prompt")
glossary_dict: Optional[Dict[str, str]] = Field(None, description="术语表字典key为原文value为译文。") glossary_dict: Optional[Dict[str, str]] = Field(None, description="术语表字典key为原文value为译文。")
glossary_generate_enable: bool = Field(default=False, description="是否开启术语表自动生成。") glossary_generate_enable: bool = Field(default=False, description="是否开启术语表自动生成。")
@@ -423,6 +425,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
"glossary_generate_enable": False, "glossary_generate_enable": False,
"convert_engine": "mineru", "convert_engine": "mineru",
"mineru_token": "your-mineru-token-if-any", "mineru_token": "your-mineru-token-if-any",
@@ -445,6 +448,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
"glossary_generate_enable": False, "glossary_generate_enable": False,
"json_paths": ["$.product.name", "$.product.description", "$.features[*]"], "json_paths": ["$.product.name", "$.product.description", "$.features[*]"],
} }
@@ -464,6 +468,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
"glossary_generate_enable": False, "glossary_generate_enable": False,
"insert_mode": "replace", "insert_mode": "replace",
"separator": "\n", "separator": "\n",
@@ -483,6 +488,7 @@ class TranslateServiceRequest(BaseModel):
"api_key": "sk-your-main-translator-key", "api_key": "sk-your-main-translator-key",
"model_id": "gpt-4o", "model_id": "gpt-4o",
"to_lang": "中文", "to_lang": "中文",
"retry": default_params["retry"],
"glossary_generate_enable": True, "glossary_generate_enable": True,
"glossary_agent_config": { "glossary_agent_config": {
"base_url": "https://api.openai.com/v1", "base_url": "https://api.openai.com/v1",
@@ -492,7 +498,8 @@ class TranslateServiceRequest(BaseModel):
"temperature": 0.7, "temperature": 0.7,
"concurrent": 30, "concurrent": 30,
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default" "thinking": "default",
"retry": default_params["retry"]
} }
} }
}, },
@@ -513,6 +520,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
} }
}, },
{ {
@@ -532,6 +540,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
} }
}, },
{ {
@@ -551,6 +560,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
} }
}, },
{ {
@@ -570,6 +580,7 @@ class TranslateServiceRequest(BaseModel):
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": default_params["timeout"], "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"retry": default_params["retry"],
} }
} }
] ]
@@ -623,7 +634,7 @@ async def _perform_translation(
task_logger.info("构建 MarkdownBasedWorkflow 配置。") task_logger.info("构建 MarkdownBasedWorkflow 配置。")
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', 'timeout' 'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -650,7 +661,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', 'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict',
'insert_mode', 'separator', 'timeout' 'insert_mode', 'separator', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -668,7 +679,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', 'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict',
'json_paths', 'timeout' 'json_paths', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -686,7 +697,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'temperature', 'thinking', 'chunk_size', 'concurrent',
'insert_mode', 'separator', 'translate_regions', 'glossary_dict', 'timeout' 'insert_mode', 'separator', 'translate_regions', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -705,7 +716,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'temperature', 'thinking', 'chunk_size', 'concurrent',
'insert_mode', 'separator', 'glossary_dict', 'timeout' 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -724,7 +735,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'temperature', 'thinking', 'chunk_size', 'concurrent',
'insert_mode', 'separator', 'glossary_dict', 'timeout' 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -743,7 +754,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'temperature', 'thinking', 'chunk_size', 'concurrent',
'insert_mode', 'separator', 'glossary_dict', 'timeout' 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()
@@ -763,7 +774,7 @@ async def _perform_translation(
translator_args = payload.model_dump(include={ translator_args = payload.model_dump(include={
'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt',
'temperature', 'thinking', 'chunk_size', 'concurrent', 'temperature', 'thinking', 'chunk_size', 'concurrent',
'insert_mode', 'separator', 'glossary_dict', 'timeout' 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry'
}, exclude_none=True) }, exclude_none=True)
translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_generate_enable'] = payload.glossary_generate_enable
translator_args['glossary_agent_config'] = build_glossary_agent_config() translator_args['glossary_agent_config'] = build_glossary_agent_config()

File diff suppressed because one or more lines are too long

View File

@@ -4,4 +4,5 @@ default_params = {
"concurrent": 30, "concurrent": 30,
"temperature": 0.7, "temperature": 0.7,
"timeout": 1200, "timeout": 1200,
"retry": 2
} }

View File

@@ -54,6 +54,7 @@ class AiTranslator(Translator[T]):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
retry=config.retry
) )
self.glossary_agent = GlossaryAgent(glossary_agent_config) self.glossary_agent = GlossaryAgent(glossary_agent_config)

View File

@@ -52,7 +52,8 @@ class DocxTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -43,7 +43,8 @@ class EpubTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -100,7 +100,8 @@ class HtmlTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -33,7 +33,8 @@ class JsonTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.json_paths = config.json_paths self.json_paths = config.json_paths

View File

@@ -33,7 +33,8 @@ class MDTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict) glossary_dict=config.glossary_dict,
retry=config.retry)
self.translate_agent = MDTranslateAgent(agent_config) self.translate_agent = MDTranslateAgent(agent_config)
def translate(self, document: MarkdownDocument) -> Self: def translate(self, document: MarkdownDocument) -> Self:

View File

@@ -39,7 +39,8 @@ class SrtTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -57,7 +57,8 @@ class TXTTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -41,7 +41,8 @@ class XlsxTranslator(AiTranslator):
concurrent=config.concurrent, concurrent=config.concurrent,
timeout=config.timeout, timeout=config.timeout,
logger=self.logger, logger=self.logger,
glossary_dict=config.glossary_dict glossary_dict=config.glossary_dict,
retry=config.retry
) )
self.translate_agent = SegmentsTranslateAgent(agent_config) self.translate_agent = SegmentsTranslateAgent(agent_config)
self.insert_mode = config.insert_mode self.insert_mode = config.insert_mode

View File

@@ -1,5 +1,12 @@
更新日志 更新日志
---------------- ----------------
v1.4.3版 2025.9.6
特性
- 显示消耗的token数
- 可以设置重试次数
修复
- 修复未设置logger会报错的问题
----------------
v1.4.2版 2025.9.6 v1.4.2版 2025.9.6
优化 优化
- 降低漏翻、缺键概率 - 降低漏翻、缺键概率