diff --git a/docutranslate/__init__.py b/docutranslate/__init__.py index 16b237d..8f54699 100644 --- a/docutranslate/__init__.py +++ b/docutranslate/__init__.py @@ -1,3 +1,3 @@ # SPDX-FileCopyrightText: 2025 QinHan # SPDX-License-Identifier: MPL-2.0 -__version__="1.4.2.post2" \ No newline at end of file +__version__="1.4.3" \ No newline at end of file diff --git a/docutranslate/agents/agent.py b/docutranslate/agents/agent.py index 61dbb98..4cc317f 100644 --- a/docutranslate/agents/agent.py +++ b/docutranslate/agents/agent.py @@ -17,7 +17,6 @@ from docutranslate.global_values import USE_PROXY from docutranslate.logger import global_logger from docutranslate.utils.utils import get_httpx_proxies -MAX_RETRY_COUNT = 2 MAX_REQUESTS_PER_ERROR = 15 ThinkingMode = Literal["enable", "disable", "default"] @@ -48,6 +47,7 @@ class AgentConfig: concurrent: int = 30 timeout: int = 1200 # 单位(秒),这个值是httpx.TimeOut中read的值,并非总的超时时间 thinking: ThinkingMode = "default" + retry: int = 2 class TotalErrorCounter: @@ -244,6 +244,8 @@ class Agent: # 新增:用于统计token使用情况 self.token_counter = TokenCounter(logger=self.logger) + self.retry = config.retry + def _add_thinking_mode(self, data: dict): if self.domain not in self._think_factory: return @@ -324,7 +326,7 @@ class Agent: if retry_count > 0: self.logger.info( - f"重试成功 (第 {retry_count}/{MAX_RETRY_COUNT} 次尝试)。" + f"重试成功 (第 {retry_count}/{self.retry} 次尝试)。" ) # print(f"result:=============================================================\n{result}\n================\n") @@ -364,7 +366,7 @@ class Agent: if 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 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) return await self.send_async( client, @@ -545,7 +547,7 @@ class Agent: if retry_count > 0: self.logger.info( - f"重试成功 (第 {retry_count}/{MAX_RETRY_COUNT} 次尝试)。" + f"重试成功 (第 {retry_count}/{self.retry} 次尝试)。" ) return ( @@ -582,7 +584,7 @@ class Agent: if 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 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) return self.send( client, diff --git a/docutranslate/app.py b/docutranslate/app.py index 42258c3..71e5527 100644 --- a/docutranslate/app.py +++ b/docutranslate/app.py @@ -238,6 +238,7 @@ class GlossaryAgentConfigPayload(BaseModel): concurrent: int = Field(default=30, description="Agent的最大并发请求数。") timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间(秒)。") thinking: ThinkingMode = Field(default="default", description="Agent的思考模式。") + retry: int = Field(default=default_params["retry"], description="分块失败后的最大重试次数。") # 1. 定义所有工作流共享的基础参数 @@ -259,6 +260,7 @@ class BaseWorkflowParams(BaseModel): timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间(秒)。") thinking: ThinkingMode = Field(default=default_params["thinking"], description="Agent的思考模式。", examples=["default", "enable", "disable"]) + retry: int = Field(default=default_params["retry"], description="某个分块翻译失败后的最大重试次数。") custom_prompt: Optional[str] = Field(None, description="用户自定义的翻译Prompt。", alias="custom_prompt") glossary_dict: Optional[Dict[str, str]] = Field(None, description="术语表字典,key为原文,value为译文。") glossary_generate_enable: bool = Field(default=False, description="是否开启术语表自动生成。") @@ -423,6 +425,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], "glossary_generate_enable": False, "convert_engine": "mineru", "mineru_token": "your-mineru-token-if-any", @@ -445,6 +448,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], "glossary_generate_enable": False, "json_paths": ["$.product.name", "$.product.description", "$.features[*]"], } @@ -464,6 +468,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], "glossary_generate_enable": False, "insert_mode": "replace", "separator": "\n", @@ -483,6 +488,7 @@ class TranslateServiceRequest(BaseModel): "api_key": "sk-your-main-translator-key", "model_id": "gpt-4o", "to_lang": "中文", + "retry": default_params["retry"], "glossary_generate_enable": True, "glossary_agent_config": { "base_url": "https://api.openai.com/v1", @@ -492,7 +498,8 @@ class TranslateServiceRequest(BaseModel): "temperature": 0.7, "concurrent": 30, "timeout": default_params["timeout"], - "thinking": "default" + "thinking": "default", + "retry": default_params["retry"] } } }, @@ -513,6 +520,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], } }, { @@ -532,6 +540,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], } }, { @@ -551,6 +560,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], } }, { @@ -570,6 +580,7 @@ class TranslateServiceRequest(BaseModel): "temperature": default_params["temperature"], "timeout": default_params["timeout"], "thinking": "default", + "retry": default_params["retry"], } } ] @@ -623,7 +634,7 @@ async def _perform_translation( task_logger.info("构建 MarkdownBasedWorkflow 配置。") translator_args = payload.model_dump(include={ '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) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -650,7 +661,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', - 'insert_mode', 'separator', 'timeout' + 'insert_mode', 'separator', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -668,7 +679,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', 'glossary_dict', - 'json_paths', 'timeout' + 'json_paths', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -686,7 +697,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', '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) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -705,7 +716,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', - 'insert_mode', 'separator', 'glossary_dict', 'timeout' + 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -724,7 +735,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', - 'insert_mode', 'separator', 'glossary_dict', 'timeout' + 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -743,7 +754,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', - 'insert_mode', 'separator', 'glossary_dict', 'timeout' + 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -763,7 +774,7 @@ async def _perform_translation( translator_args = payload.model_dump(include={ 'skip_translate', 'base_url', 'api_key', 'model_id', 'to_lang', 'custom_prompt', 'temperature', 'thinking', 'chunk_size', 'concurrent', - 'insert_mode', 'separator', 'glossary_dict', 'timeout' + 'insert_mode', 'separator', 'glossary_dict', 'timeout', 'retry' }, exclude_none=True) translator_args['glossary_generate_enable'] = payload.glossary_generate_enable translator_args['glossary_agent_config'] = build_glossary_agent_config() @@ -1558,4 +1569,4 @@ def run_app(port: int | None = None): if __name__ == "__main__": - run_app() + run_app() \ No newline at end of file diff --git a/docutranslate/static/index.html b/docutranslate/static/index.html index 64ecf1d..4bdbe51 100644 --- a/docutranslate/static/index.html +++ b/docutranslate/static/index.html @@ -1 +1 @@ - DocuTranslate - 交互式文档翻译

DocuTranslate

如果上传的文件本身是.md格式,此项可不选。
mineru VLM是更新的内测模型。

Base URL:

选择一个或多个CSV文件。文件需包含'src'和'dst'两列标题,分别代表原文和译文。

GitHub主页(欢迎star❤):
https://github.com/xunbu/docutranslate

交流QQ群: 1047781902

version:

任务列表

LOGO

当前没有任务,点击“新建任务”开始吧!

预览
原文
译文
\ No newline at end of file + DocuTranslate - 交互式文档翻译

DocuTranslate

如果上传的文件本身是.md格式,此项可不选。
mineru VLM是更新的内测模型。

Base URL:

选择一个或多个CSV文件。文件需包含'src'和'dst'两列标题,分别代表原文和译文。

GitHub主页(欢迎star❤):
https://github.com/xunbu/docutranslate

交流QQ群: 1047781902

version:

任务列表

LOGO

当前没有任务,点击“新建任务”开始吧!

预览
原文
译文
\ No newline at end of file diff --git a/docutranslate/translator/__init__.py b/docutranslate/translator/__init__.py index 35543bb..97a911c 100644 --- a/docutranslate/translator/__init__.py +++ b/docutranslate/translator/__init__.py @@ -4,4 +4,5 @@ default_params = { "concurrent": 30, "temperature": 0.7, "timeout": 1200, + "retry": 2 } diff --git a/docutranslate/translator/ai_translator/base.py b/docutranslate/translator/ai_translator/base.py index 89f71aa..9622149 100644 --- a/docutranslate/translator/ai_translator/base.py +++ b/docutranslate/translator/ai_translator/base.py @@ -54,6 +54,7 @@ class AiTranslator(Translator[T]): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, + retry=config.retry ) self.glossary_agent = GlossaryAgent(glossary_agent_config) diff --git a/docutranslate/translator/ai_translator/docx_translator.py b/docutranslate/translator/ai_translator/docx_translator.py index 3eebb88..3818f3a 100644 --- a/docutranslate/translator/ai_translator/docx_translator.py +++ b/docutranslate/translator/ai_translator/docx_translator.py @@ -52,7 +52,8 @@ class DocxTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/docutranslate/translator/ai_translator/epub_translator.py b/docutranslate/translator/ai_translator/epub_translator.py index ffacf55..6f59862 100644 --- a/docutranslate/translator/ai_translator/epub_translator.py +++ b/docutranslate/translator/ai_translator/epub_translator.py @@ -43,7 +43,8 @@ class EpubTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/docutranslate/translator/ai_translator/html_translator.py b/docutranslate/translator/ai_translator/html_translator.py index 2098020..1cbd7f4 100644 --- a/docutranslate/translator/ai_translator/html_translator.py +++ b/docutranslate/translator/ai_translator/html_translator.py @@ -100,7 +100,8 @@ class HtmlTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/docutranslate/translator/ai_translator/json_translator.py b/docutranslate/translator/ai_translator/json_translator.py index 014f85e..9862e12 100644 --- a/docutranslate/translator/ai_translator/json_translator.py +++ b/docutranslate/translator/ai_translator/json_translator.py @@ -33,7 +33,8 @@ class JsonTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.json_paths = config.json_paths diff --git a/docutranslate/translator/ai_translator/md_translator.py b/docutranslate/translator/ai_translator/md_translator.py index 20de634..0e961dc 100644 --- a/docutranslate/translator/ai_translator/md_translator.py +++ b/docutranslate/translator/ai_translator/md_translator.py @@ -33,7 +33,8 @@ class MDTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict) + glossary_dict=config.glossary_dict, + retry=config.retry) self.translate_agent = MDTranslateAgent(agent_config) def translate(self, document: MarkdownDocument) -> Self: diff --git a/docutranslate/translator/ai_translator/srt_translator.py b/docutranslate/translator/ai_translator/srt_translator.py index dfd0b41..fb4e527 100644 --- a/docutranslate/translator/ai_translator/srt_translator.py +++ b/docutranslate/translator/ai_translator/srt_translator.py @@ -39,7 +39,8 @@ class SrtTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/docutranslate/translator/ai_translator/txt_translator.py b/docutranslate/translator/ai_translator/txt_translator.py index bcb2ca3..701c448 100644 --- a/docutranslate/translator/ai_translator/txt_translator.py +++ b/docutranslate/translator/ai_translator/txt_translator.py @@ -57,7 +57,8 @@ class TXTTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/docutranslate/translator/ai_translator/xlsx_translator.py b/docutranslate/translator/ai_translator/xlsx_translator.py index 38c5c19..7373bd9 100644 --- a/docutranslate/translator/ai_translator/xlsx_translator.py +++ b/docutranslate/translator/ai_translator/xlsx_translator.py @@ -41,7 +41,8 @@ class XlsxTranslator(AiTranslator): concurrent=config.concurrent, timeout=config.timeout, logger=self.logger, - glossary_dict=config.glossary_dict + glossary_dict=config.glossary_dict, + retry=config.retry ) self.translate_agent = SegmentsTranslateAgent(agent_config) self.insert_mode = config.insert_mode diff --git a/更新日志.txt b/更新日志.txt index 4047f5e..bd0804c 100644 --- a/更新日志.txt +++ b/更新日志.txt @@ -1,5 +1,12 @@ 更新日志 ---------------- +v1.4.3版 2025.9.6 +特性 +- 显示消耗的token数 +- 可以设置重试次数 +修复 +- 修复未设置logger会报错的问题 +---------------- v1.4.2版 2025.9.6 优化 - 降低漏翻、缺键概率