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:
科林_Cyril Pilgrim
2026-02-17 13:59:08 +08:00
parent b58e134c05
commit d46e3df8a4
2 changed files with 36 additions and 20 deletions
+2
View File
@@ -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
View File
@@ -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,