优化重试机制
This commit is contained in:
@@ -17,8 +17,8 @@ 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_RETRY_COUNT = 3
|
||||||
MAX_REQUESTS_PER_ERROR = 15
|
MAX_REQUESTS_PER_ERROR = 10
|
||||||
|
|
||||||
ThinkingMode = Literal["enable", "disable", "default"]
|
ThinkingMode = Literal["enable", "disable", "default"]
|
||||||
|
|
||||||
@@ -154,6 +154,7 @@ class Agent:
|
|||||||
system_prompt = self.system_prompt
|
system_prompt = self.system_prompt
|
||||||
if pre_send_handler:
|
if pre_send_handler:
|
||||||
system_prompt, prompt = pre_send_handler(system_prompt, prompt)
|
system_prompt, prompt = pre_send_handler(system_prompt, prompt)
|
||||||
|
# print(f"system_prompt:\n{system_prompt}")
|
||||||
|
|
||||||
headers, data = self._prepare_request_data(prompt, system_prompt)
|
headers, data = self._prepare_request_data(prompt, system_prompt)
|
||||||
should_retry = False
|
should_retry = False
|
||||||
@@ -183,7 +184,7 @@ class Agent:
|
|||||||
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
self.logger.error(f"AI请求HTTP状态错误 (async): {e.response.status_code} - {e.response.text}")
|
self.logger.error(f"AI请求HTTP状态错误 (async): {e.response.status_code} - {e.response.text}")
|
||||||
print(f"prompt:\n{prompt}")
|
# print(f"prompt:\n{prompt}")
|
||||||
should_retry = True
|
should_retry = True
|
||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
self.logger.error(f"AI请求连接错误 (async): {repr(e)}")
|
self.logger.error(f"AI请求连接错误 (async): {repr(e)}")
|
||||||
@@ -298,16 +299,14 @@ class Agent:
|
|||||||
|
|
||||||
return result if result_handler is None else result_handler(result, prompt, self.logger)
|
return result if result_handler is None else result_handler(result, prompt, self.logger)
|
||||||
|
|
||||||
# --- MODIFICATION START ---
|
|
||||||
except PartialTranslationError as e:
|
except PartialTranslationError as e:
|
||||||
self.logger.error(f"收到部分翻译结果,将尝试重试: {e}")
|
self.logger.error(f"收到部分翻译结果,将尝试重试: {e}")
|
||||||
current_partial_result = e.partial_result
|
current_partial_result = e.partial_result
|
||||||
should_retry = True
|
should_retry = True
|
||||||
# --- MODIFICATION END ---
|
|
||||||
|
|
||||||
except httpx.HTTPStatusError as e:
|
except httpx.HTTPStatusError as e:
|
||||||
self.logger.error(f"AI请求HTTP状态错误 (sync): {e.response.status_code} - {e.response.text}")
|
self.logger.error(f"AI请求HTTP状态错误 (sync): {e.response.status_code} - {e.response.text}")
|
||||||
print(f"prompt:\n{prompt}")
|
# print(f"prompt:\n{prompt}")
|
||||||
should_retry = True
|
should_retry = True
|
||||||
except httpx.RequestError as e:
|
except httpx.RequestError as e:
|
||||||
self.logger.error(f"AI请求连接错误 (sync): {repr(e)}\nprompt:{prompt}")
|
self.logger.error(f"AI请求连接错误 (sync): {repr(e)}\nprompt:{prompt}")
|
||||||
@@ -316,10 +315,8 @@ class Agent:
|
|||||||
self.logger.error(f"AI响应格式或值错误 (sync), 将尝试重试: {repr(e)}")
|
self.logger.error(f"AI响应格式或值错误 (sync), 将尝试重试: {repr(e)}")
|
||||||
should_retry = True
|
should_retry = True
|
||||||
|
|
||||||
# --- MODIFICATION START ---
|
|
||||||
if current_partial_result:
|
if current_partial_result:
|
||||||
best_partial_result = current_partial_result
|
best_partial_result = current_partial_result
|
||||||
# --- MODIFICATION END ---
|
|
||||||
|
|
||||||
if should_retry and retry and retry_count < MAX_RETRY_COUNT:
|
if should_retry and retry and retry_count < MAX_RETRY_COUNT:
|
||||||
if retry_count == 0:
|
if retry_count == 0:
|
||||||
@@ -343,11 +340,9 @@ class Agent:
|
|||||||
if should_retry:
|
if should_retry:
|
||||||
self.logger.error(f"所有重试均失败,已达到重试次数上限。")
|
self.logger.error(f"所有重试均失败,已达到重试次数上限。")
|
||||||
|
|
||||||
# --- MODIFICATION START ---
|
|
||||||
if best_partial_result:
|
if best_partial_result:
|
||||||
self.logger.info("所有重试失败,但存在部分翻译结果,将使用该结果。")
|
self.logger.info("所有重试失败,但存在部分翻译结果,将使用该结果。")
|
||||||
return best_partial_result
|
return best_partial_result
|
||||||
# --- MODIFICATION END ---
|
|
||||||
|
|
||||||
return prompt if error_result_handler is None else error_result_handler(prompt, self.logger)
|
return prompt if error_result_handler is None else error_result_handler(prompt, self.logger)
|
||||||
|
|
||||||
|
|||||||
@@ -27,27 +27,28 @@ class SegmentsTranslateAgent(Agent):
|
|||||||
super().__init__(config)
|
super().__init__(config)
|
||||||
self.system_prompt = f"""
|
self.system_prompt = f"""
|
||||||
# Role
|
# Role
|
||||||
You are a professional machine translation engine.
|
- You are a professional machine translation engine.
|
||||||
# Task
|
# Task
|
||||||
You will receive a sequence of segments to be translated, represented in JSON format. The keys are the segment IDs, and the values are the segments for translation.
|
- You will receive a sequence of segments to be translated, represented in JSON format. The keys are the segment IDs, and the values are the segments for translation.
|
||||||
You need to translate these segments into the target language.
|
- You need to translate these segments into the target language.
|
||||||
Target language: {config.to_lang}
|
- Target language: {config.to_lang}
|
||||||
# Requirements
|
# Requirements
|
||||||
The translation must be professional and accurate.
|
- The translation must be professional and accurate.
|
||||||
Do not output any explanations or annotations.
|
- Do not output any explanations or annotations.
|
||||||
The format of the translated segments should be as close as possible to the source format.
|
- The format of the translated segments should be as close as possible to the source format.
|
||||||
For personal names and proper nouns, use the most commonly used words for translation. If there are multiple common translations, choose the word that comes first in dictionary order.
|
- For personal names and proper nouns, use the most commonly used words for translation.
|
||||||
For special tags or other non-translatable elements (like codes, brand names, specific jargon), keep them in their original form.
|
- For special tags or other non-translatable elements (like codes, brand names, specific jargon), keep them in their original form.
|
||||||
If a segment is already in the target language, keep it as is.
|
- If a segment is already in the target language({config.to_lang}), keep it as is.
|
||||||
# Output
|
# Output
|
||||||
The translated sequence of segments, represented as JSON text (note: not a code block). The keys are the segment IDs, and the values are the translated segments.
|
- The translated sequence of segments, represented as JSON text (note: not a code block). The keys are the segment IDs, and the values are the translated segments.
|
||||||
The returned JSON text must be parsable by json.loads into a dictionary of the form {r'{"segment_id": "translation"}'}.
|
- The returned JSON text must be a dictionary of the form {{<segment_id>: <translation>}}.
|
||||||
|
- The segment IDs in the output must **exactly** match those in the input. And all segment IDs in input must appear in the output.
|
||||||
# Example
|
# Example
|
||||||
## Input
|
## Input
|
||||||
{r'{"0":"hello","1":"apple","2":true,"3":"false"}'}
|
{r'{"10":"hello","11":"apple","12":true,"13":"false","14":null}'}
|
||||||
## Output
|
## Output(Assuming the target language is Chinese)
|
||||||
{r'{"0":"你好","1":"苹果","2":true,"3":"错误"}'}
|
{r'{"10":"你好","11":"苹果","12":true,"13":"错误","14":null}'}
|
||||||
Warning: Never wrap the entire JSON object in quotes to make it a single string. Never wrap the JSON text in ```.
|
> Warning: Never wrap the JSON text in ```.
|
||||||
"""
|
"""
|
||||||
self.custom_prompt = config.custom_prompt
|
self.custom_prompt = config.custom_prompt
|
||||||
if config.custom_prompt:
|
if config.custom_prompt:
|
||||||
@@ -149,7 +150,6 @@ Warning: Never wrap the entire JSON object in quotes to make it a single string.
|
|||||||
continue
|
continue
|
||||||
for key, val in chunk.items():
|
for key, val in chunk.items():
|
||||||
if key in indexed_translated:
|
if key in indexed_translated:
|
||||||
# 此处不再需要 str(val)
|
|
||||||
indexed_translated[key] = val
|
indexed_translated[key] = val
|
||||||
else:
|
else:
|
||||||
self.logger.warning(f"在结果chunk中发现未知键 '{key}',已忽略。")
|
self.logger.warning(f"在结果chunk中发现未知键 '{key}',已忽略。")
|
||||||
@@ -214,4 +214,4 @@ Warning: Never wrap the entire JSON object in quotes to make it a single string.
|
|||||||
if self.glossary_dict is None:
|
if self.glossary_dict is None:
|
||||||
self.glossary_dict = {}
|
self.glossary_dict = {}
|
||||||
if update_dict is not None:
|
if update_dict is not None:
|
||||||
self.glossary_dict = update_dict | self.glossary_dict
|
self.glossary_dict = update_dict | self.glossary_dict
|
||||||
|
|||||||
Reference in New Issue
Block a user