forked from luopingyi/xc_agent_platform_demo
61 lines
2.7 KiB
Python
61 lines
2.7 KiB
Python
|
|
"""Explicit configuration generation; import performs no I/O.
|
||
|
|
|
||
|
|
Returns YAML on success, otherwise raises BuildConfigError with safe attribution
|
||
|
|
and HTTP/platform status. Server messages and transport details are never exposed.
|
||
|
|
"""
|
||
|
|
import json
|
||
|
|
import os
|
||
|
|
import urllib.error
|
||
|
|
import urllib.parse
|
||
|
|
import urllib.request
|
||
|
|
from src.task_add_client import resolve_token
|
||
|
|
|
||
|
|
|
||
|
|
class BuildConfigError(RuntimeError):
|
||
|
|
def __init__(self, reason, http_status=None, platform_code=None):
|
||
|
|
self.error_attribution = reason
|
||
|
|
self.http_status = http_status
|
||
|
|
self.platform_code = platform_code
|
||
|
|
super().__init__('build-config: ' + reason)
|
||
|
|
|
||
|
|
|
||
|
|
def build_config(gpu_type, framework='vllm', task_type='text-generation'):
|
||
|
|
try:
|
||
|
|
token = resolve_token()
|
||
|
|
except (ValueError, OSError):
|
||
|
|
raise BuildConfigError('missing/invalid credential') from None
|
||
|
|
if not isinstance(gpu_type, str) or not gpu_type.strip() or '<' in gpu_type:
|
||
|
|
raise BuildConfigError('gpu_type required (platform enum)')
|
||
|
|
query = urllib.parse.urlencode(dict(gpuType=gpu_type, framework=framework, taskType=task_type))
|
||
|
|
header = 'Authorization' if os.environ.get('BUILD_CONFIG_USE_AUTHORIZATION') == '1' else 'Xc-Token'
|
||
|
|
try:
|
||
|
|
request = urllib.request.Request(
|
||
|
|
os.environ.get('MODELHUB_API_BASE', 'https://www.modelhub.org.cn').rstrip('/')
|
||
|
|
+ '/api/adapt/task/build-config?' + query,
|
||
|
|
headers={header: token, 'Accept': 'application/json'}, method='POST')
|
||
|
|
with urllib.request.urlopen(request, timeout=30) as response:
|
||
|
|
status, raw = response.status, response.read()
|
||
|
|
except urllib.error.HTTPError as error:
|
||
|
|
status, raw = error.code, error.read()
|
||
|
|
except (OSError, urllib.error.URLError, ValueError):
|
||
|
|
raise BuildConfigError('transport/timeout') from None
|
||
|
|
try:
|
||
|
|
body = json.loads(raw)
|
||
|
|
except (ValueError, UnicodeError):
|
||
|
|
raise BuildConfigError('invalid JSON response', status) from None
|
||
|
|
if not isinstance(body, dict):
|
||
|
|
raise BuildConfigError('invalid response object', status)
|
||
|
|
code = body.get('code')
|
||
|
|
# Only numeric codes are retained; arbitrary server strings may echo secrets.
|
||
|
|
code = code if type(code) is int else None
|
||
|
|
if code in (40100, 40101):
|
||
|
|
raise BuildConfigError({40100: '40100 NOT_LOGIN_ERROR', 40101: '40101 NO_AUTH_ERROR'}[code], status, code)
|
||
|
|
if not 200 <= status < 300 or code != 0:
|
||
|
|
raise BuildConfigError('other HTTP/platform code', status, code)
|
||
|
|
data = body.get('data')
|
||
|
|
if not isinstance(data, str) or not data.strip():
|
||
|
|
raise BuildConfigError('empty/non-str data', status, code)
|
||
|
|
if token in data:
|
||
|
|
raise BuildConfigError('credential echoed in data', status, code)
|
||
|
|
return data
|