更新日志

This commit is contained in:
xunbu
2025-09-05 18:23:15 +08:00
parent c041559c4f
commit 8a9cb45f9e
5 changed files with 49 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.0" __version__="1.4.1"

View File

@@ -46,7 +46,7 @@ class AgentConfig:
model_id: str model_id: str
temperature: float = 0.7 temperature: float = 0.7
concurrent: int = 30 concurrent: int = 30
timeout: int = 2000 timeout: int = 1200 # 单位(秒)这个值是httpx.TimeOut中read的值,并非总的超时时间
thinking: ThinkingMode = "default" thinking: ThinkingMode = "default"
@@ -119,7 +119,7 @@ class Agent:
self.system_prompt = "" self.system_prompt = ""
self.temperature = config.temperature self.temperature = config.temperature
self.max_concurrent = config.concurrent self.max_concurrent = config.concurrent
self.timeout = config.timeout self.timeout = httpx.Timeout(connect=5, read=config.timeout, write=300, pool=10)
self.thinking = config.thinking self.thinking = config.thinking
self.logger = config.logger or global_logger self.logger = config.logger or global_logger
self.total_error_counter = TotalErrorCounter(logger=self.logger) self.total_error_counter = TotalErrorCounter(logger=self.logger)
@@ -272,7 +272,12 @@ class Agent:
proxies = get_httpx_proxies() if USE_PROXY else None proxies = get_httpx_proxies() if USE_PROXY else None
async with httpx.AsyncClient(trust_env=False, proxies=proxies, verify=False) as client: limits = httpx.Limits(
max_connections=self.max_concurrent * 2, # 为重试和并发预留空间
max_keepalive_connections=self.max_concurrent # 保持活动的连接数
)
async with httpx.AsyncClient(trust_env=False, proxies=proxies, verify=False, limits=limits) as client:
async def send_with_semaphore(p_text: str): async def send_with_semaphore(p_text: str):
async with semaphore: async with semaphore:
result = await self.send_async( result = await self.send_async(
@@ -419,9 +424,12 @@ class Agent:
pre_send_handlers = itertools.repeat(pre_send_handler, len(prompts)) pre_send_handlers = itertools.repeat(pre_send_handler, len(prompts))
result_handlers = itertools.repeat(result_handler, len(prompts)) result_handlers = itertools.repeat(result_handler, len(prompts))
error_result_handlers = itertools.repeat(error_result_handler, len(prompts)) error_result_handlers = itertools.repeat(error_result_handler, len(prompts))
limits = httpx.Limits(
max_connections=self.max_concurrent * 2, # 允许连接复用
max_keepalive_connections=self.max_concurrent # 保持活跃连接
)
proxies = get_httpx_proxies() if USE_PROXY else None proxies = get_httpx_proxies() if USE_PROXY else None
with httpx.Client(trust_env=False, proxies=proxies, verify=False) as client: with httpx.Client(trust_env=False, proxies=proxies, verify=False, limits=limits) as client:
clients = itertools.repeat(client, len(prompts)) clients = itertools.repeat(client, len(prompts))
with ThreadPoolExecutor(max_workers=self.max_concurrent) as executor: with ThreadPoolExecutor(max_workers=self.max_concurrent) as executor:
results_iterator = executor.map(self._send_prompt_count, clients, prompts, system_prompts, counters, results_iterator = executor.map(self._send_prompt_count, clients, prompts, system_prompts, counters,

View File

@@ -228,30 +228,35 @@ app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
# =================================================================== # ===================================================================
class GlossaryAgentConfigPayload(BaseModel): class GlossaryAgentConfigPayload(BaseModel):
base_url: str = Field(..., validation_alias=AliasChoices('base_url', 'baseurl'), description="用于术语表生成的Agent的LLM API基础URL。", examples=["https://api.openai.com/v1"]) base_url: str = Field(..., validation_alias=AliasChoices('base_url', 'baseurl'),
api_key: str = Field(..., validation_alias=AliasChoices('api_key', 'key'), description="用于术语表生成的Agent的LLM API密钥", examples=["sk-agent-api-key"]) description="用于术语表生成的Agent的LLM API基础URL", examples=["https://api.openai.com/v1"])
api_key: str = Field(..., validation_alias=AliasChoices('api_key', 'key'),
description="用于术语表生成的Agent的LLM API密钥。", examples=["sk-agent-api-key"])
model_id: str = Field(..., description="用于术语表生成的Agent的模型ID。", examples=["gpt-4-turbo"]) model_id: str = Field(..., description="用于术语表生成的Agent的模型ID。", examples=["gpt-4-turbo"])
to_lang: str = Field(..., description="术语表生成的目标语言。", examples=["简体中文", "English"]) to_lang: str = Field(..., description="术语表生成的目标语言。", examples=["简体中文", "English"])
temperature: float = Field(default=0.7, description="用于术语表生成的Agent的温度参数。") temperature: float = Field(default=0.7, description="用于术语表生成的Agent的温度参数。")
concurrent: int = Field(default=30, description="Agent的最大并发请求数。") concurrent: int = Field(default=30, description="Agent的最大并发请求数。")
timeout: int = Field(default=2000, description="Agent的API调用超时时间") timeout: int = Field(default=default_params["timeout"], description="等待API回复的时间")
thinking: ThinkingMode = Field(default="default", description="Agent的思考模式。") thinking: ThinkingMode = Field(default="default", description="Agent的思考模式。")
# 1. 定义所有工作流共享的基础参数 # 1. 定义所有工作流共享的基础参数
class BaseWorkflowParams(BaseModel): class BaseWorkflowParams(BaseModel):
skip_translate: bool = Field(default=False, description="是否跳过翻译步骤。如果为True则仅执行文档解析和格式转换。") skip_translate: bool = Field(default=False, description="是否跳过翻译步骤。如果为True则仅执行文档解析和格式转换。")
base_url: Optional[str] = Field(default=None, validation_alias=AliasChoices('base_url', 'baseurl'), description="LLM API的基础URL。当 `skip_translate` 为 `False` 时必填。", base_url: Optional[str] = Field(default=None, validation_alias=AliasChoices('base_url', 'baseurl'),
description="LLM API的基础URL。当 `skip_translate` 为 `False` 时必填。",
examples=["https://api.openai.com/v1"]) examples=["https://api.openai.com/v1"])
api_key: Optional[str] = Field(default=None, validation_alias=AliasChoices('api_key', 'key'), description="LLM API的密钥可选", api_key: Optional[str] = Field(default=None, validation_alias=AliasChoices('api_key', 'key'),
description="LLM API的密钥可选",
examples=["sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"]) examples=["sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxx"])
model_id: Optional[str] = Field(default=None, description="要使用的LLM模型ID。当 `skip_translate` 为 `False` 时必填。", model_id: Optional[str] = Field(default=None,
description="要使用的LLM模型ID。当 `skip_translate` 为 `False` 时必填。",
examples=["gpt-4o"]) examples=["gpt-4o"])
to_lang: str = Field(default="中文", description="目标翻译语言。", examples=["简体中文", "English"]) to_lang: str = Field(default="中文", description="目标翻译语言。", examples=["简体中文", "English"])
chunk_size: int = Field(default=default_params["chunk_size"], description="文本分割的块大小(字符)。") chunk_size: int = Field(default=default_params["chunk_size"], description="文本分割的块大小(字符)。")
concurrent: int = Field(default=default_params["concurrent"], description="并发请求数。") concurrent: int = Field(default=default_params["concurrent"], description="并发请求数。")
temperature: float = Field(default=default_params["temperature"], description="LLM温度参数。") temperature: float = Field(default=default_params["temperature"], description="LLM温度参数。")
timeout: int = Field(default=2000, 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"])
custom_prompt: Optional[str] = Field(None, description="用户自定义的翻译Prompt。", alias="custom_prompt") custom_prompt: Optional[str] = Field(None, description="用户自定义的翻译Prompt。", alias="custom_prompt")
@@ -416,7 +421,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"glossary_generate_enable": False, "glossary_generate_enable": False,
"convert_engine": "mineru", "convert_engine": "mineru",
@@ -438,7 +443,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"glossary_generate_enable": False, "glossary_generate_enable": False,
"json_paths": ["$.product.name", "$.product.description", "$.features[*]"], "json_paths": ["$.product.name", "$.product.description", "$.features[*]"],
@@ -457,7 +462,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
"glossary_generate_enable": False, "glossary_generate_enable": False,
"insert_mode": "replace", "insert_mode": "replace",
@@ -486,7 +491,7 @@ class TranslateServiceRequest(BaseModel):
"to_lang": "中文", "to_lang": "中文",
"temperature": 0.7, "temperature": 0.7,
"concurrent": 30, "concurrent": 30,
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default" "thinking": "default"
} }
} }
@@ -506,7 +511,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
} }
}, },
@@ -525,7 +530,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
} }
}, },
@@ -544,7 +549,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
} }
}, },
@@ -563,7 +568,7 @@ class TranslateServiceRequest(BaseModel):
"chunk_size": default_params["chunk_size"], "chunk_size": default_params["chunk_size"],
"concurrent": default_params["concurrent"], "concurrent": default_params["concurrent"],
"temperature": default_params["temperature"], "temperature": default_params["temperature"],
"timeout": 2000, "timeout": default_params["timeout"],
"thinking": "default", "thinking": "default",
} }
} }
@@ -1411,7 +1416,7 @@ async def service_content(
file_info = task_state.get("downloadable_files", {}).get(file_type) file_info = task_state.get("downloadable_files", {}).get(file_type)
if not file_info or not os.path.exists(file_info.get("path")): if not file_info or not os.path.exists(file_info.get("path")):
raise HTTPException(status_code=404, raise HTTPException(status_code=404,
detail=f"任务 '{task_id}' 不支持获取 '{file_type}' 类型内容,或文件已丢失。") detail=f"任务 '{task_id}' 不支持获取 '{file_type}' 类型内容,或文件已丢失。")
file_path = file_info["path"] file_path = file_info["path"]
filename = file_info["filename"] filename = file_info["filename"]

View File

@@ -3,4 +3,5 @@ default_params = {
"chunk_size": 3000, "chunk_size": 3000,
"concurrent": 30, "concurrent": 30,
"temperature": 0.7, "temperature": 0.7,
"timeout": 1200,
} }

View File

@@ -1,5 +1,13 @@
更新日志 更新日志
---------------- ----------------
v1.4.1版 2025.9.5
特性
- apikey现在是选填项
接口变化
- API新增timeout选项设置等待agent回复时间
- AgentConfig的max_concurrent字段改名为concurrent【breaking change】
----------------
v1.4.0版 2025.9.4 v1.4.0版 2025.9.4
特性 特性
- 更全面的异常处理机制和更少出现的漏翻 - 更全面的异常处理机制和更少出现的漏翻