feat: release v1.0.1 CADWorld 网站与 LeKiwi 智能抓放
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (push) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (push) Has been cancelled
web-platform-ci / Playwright E2E (push) Has been cancelled
lekiwi-compatibility / cpu-compatibility (push) Has been cancelled
web-platform-ci / Standalone decision service (no cloud credentials) (pull_request) Has been cancelled
web-platform-ci / TypeScript, lint, unit, build (pull_request) Has been cancelled
web-platform-ci / Playwright E2E (pull_request) Has been cancelled
lekiwi-compatibility / cpu-compatibility (pull_request) Has been cancelled
集成同源 BYOK 会话隔离、精简模型设置、官方订阅入口和 HTTPS 发布运维;保留本地训练/调参与控制能力。同步 npm 版本及 CHANGELOG,记录公网真实 API 验收仍待用户凭据。
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
"""Bounded, non-redirecting HTTP. No SDK retries or environment credential discovery."""
|
||||
|
||||
import asyncio
|
||||
import math
|
||||
|
||||
import aiohttp
|
||||
|
||||
from ..protocol import DecisionError, loads
|
||||
|
||||
|
||||
async def post(session, connection, path, payload):
|
||||
try:
|
||||
async with session.post(
|
||||
connection.base_url + path,
|
||||
json=payload,
|
||||
headers={"Authorization": "Bearer " + connection.key},
|
||||
allow_redirects=False,
|
||||
timeout=aiohttp.ClientTimeout(total=45),
|
||||
) as response:
|
||||
if response.status != 200:
|
||||
raise DecisionError(f"upstream_http_{response.status}", 502)
|
||||
# read(n) may return a partial chunk: accumulate with an explicit byte bound.
|
||||
data = bytearray()
|
||||
async for chunk in response.content.iter_chunked(16384):
|
||||
data.extend(chunk)
|
||||
if len(data) > 262144:
|
||||
raise DecisionError("upstream_response_too_large", 502)
|
||||
try:
|
||||
result = loads(data.decode("utf-8"))
|
||||
except UnicodeError as exc:
|
||||
raise DecisionError("invalid_upstream_encoding", 502) from exc
|
||||
if not isinstance(result, dict):
|
||||
raise DecisionError("invalid_upstream_response", 502)
|
||||
return result
|
||||
except TimeoutError as exc:
|
||||
raise DecisionError("upstream_timeout", 504) from exc
|
||||
except (aiohttp.ClientError, OSError) as exc:
|
||||
raise DecisionError("upstream_transport_error", 502) from exc
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
|
||||
|
||||
def usage(result):
|
||||
"""Only real numeric counters, no inferred price, upstream strings or raw body."""
|
||||
raw = result.get("usage", {})
|
||||
if not isinstance(raw, dict):
|
||||
return {}
|
||||
return {
|
||||
k: v
|
||||
for k, v in raw.items()
|
||||
if k
|
||||
in (
|
||||
"input_tokens",
|
||||
"output_tokens",
|
||||
"total_tokens",
|
||||
"prompt_tokens",
|
||||
"completion_tokens",
|
||||
"cost",
|
||||
)
|
||||
and type(v) in (int, float)
|
||||
and math.isfinite(v)
|
||||
and 0 <= v <= 1e9
|
||||
}
|
||||
Reference in New Issue
Block a user