fix(translator): add SSL context and retry for transient errors
Motivation: urllib.request.urlopen without explicit SSL context causes UNEXPECTED_EOF_WHILE_READING on some Python/env combos. Transient network errors also need graceful handling. Implementation: Added ssl.create_default_context() and 3-attempt retry loop for SSL/URLError/ConnectionError/TimeoutError in _call_api. Also added iFlow/心流 provider to LLM_Loader.
This commit is contained in:
@@ -12,6 +12,7 @@ _BASE_URL_MAPPING = {
|
||||
"MiniMax/MiniMax": "https://api.minimax.chat/v1",
|
||||
"StepFun/阶跃星辰": "https://api.stepfun.com/v1",
|
||||
"SenseChat/日日新": "https://api.sensenova.cn/compatible-mode/v1",
|
||||
"iFlow/心流": "https://apis.iflow.cn/v1",
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +36,7 @@ class LLM_Loader:
|
||||
"MiniMax/MiniMax",
|
||||
"StepFun/阶跃星辰",
|
||||
"SenseChat/日日新",
|
||||
"iFlow/心流",
|
||||
"Custom/自定义"
|
||||
], {
|
||||
"default": "Qwen/通义千问"
|
||||
|
||||
+34
-20
@@ -63,6 +63,8 @@ class LLMTranslator:
|
||||
temperature: float = 0.3
|
||||
) -> str:
|
||||
"""调用LLM API - 核心通信逻辑"""
|
||||
import ssl
|
||||
|
||||
base_url = llm_config.get("base_url", "").rstrip("/")
|
||||
model = llm_config.get("model", "")
|
||||
api_key = llm_config.get("api_key", "")
|
||||
@@ -80,27 +82,39 @@ class LLMTranslator:
|
||||
"max_tokens": 4096
|
||||
}
|
||||
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
headers=headers,
|
||||
method="POST"
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(req, timeout=60) as response:
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
|
||||
if "choices" not in data or not data["choices"]:
|
||||
raise ValueError("Empty response from API")
|
||||
|
||||
return data["choices"][0]["message"]["content"].strip()
|
||||
ctx = ssl.create_default_context()
|
||||
last_error = None
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode("utf-8", errors="ignore")
|
||||
raise Exception(f"HTTP Error {e.code}: {error_body}")
|
||||
except Exception as e:
|
||||
raise Exception(f"Translation failed: {str(e)}")
|
||||
for attempt in range(3):
|
||||
try:
|
||||
req = urllib.request.Request(
|
||||
url,
|
||||
data=json.dumps(payload).encode("utf-8"),
|
||||
headers=headers,
|
||||
method="POST"
|
||||
)
|
||||
|
||||
with urllib.request.urlopen(req, timeout=60, context=ctx) as response:
|
||||
data = json.loads(response.read().decode("utf-8"))
|
||||
|
||||
if "choices" not in data or not data["choices"]:
|
||||
raise ValueError("Empty response from API")
|
||||
|
||||
return data["choices"][0]["message"]["content"].strip()
|
||||
|
||||
except urllib.error.HTTPError as e:
|
||||
error_body = e.read().decode("utf-8", errors="ignore")
|
||||
raise Exception(f"HTTP Error {e.code}: {error_body}")
|
||||
except (ssl.SSLError, urllib.error.URLError, ConnectionError, TimeoutError) as e:
|
||||
last_error = e
|
||||
print(f"[LLMs_Toolkit] Translator attempt {attempt + 1}/3 failed: {e}")
|
||||
import time
|
||||
time.sleep(1)
|
||||
continue
|
||||
except Exception as e:
|
||||
raise Exception(f"Translation failed: {str(e)}")
|
||||
|
||||
raise Exception(f"Translation failed after 3 attempts: {last_error}")
|
||||
|
||||
def translate(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user