22 Commits

Author SHA1 Message Date
z3st
0a4ba2e146 feat: standalone cancel-all version - startup auto cancels all waiting/running tasks 2026-07-24 18:53:24 +08:00
z3st
2222e1545b feat: cancel-all mode - cancel all waiting/running tasks on startup 2026-07-24 18:51:51 +08:00
z3st
441b540e47 feat: filter out GPTQ/AWQ formats and Qwen3.5 arch (incompatible with Iluvatar) 2026-07-24 18:50:21 +08:00
z3st
afbda884ad feat: multi-page search, filter downloads 50-5000 for cold models 2026-07-24 00:10:32 +08:00
z3st
68c7a99e68 fix: replace gpu variable with TARGET_GPU in submit record 2026-07-24 00:02:35 +08:00
z3st
8e8fd50927 chore: switch target GPU to Iluvatar_bi-150 2026-07-23 23:51:28 +08:00
z3st
5a6862f8da fix: revert to ModelScope search (HF unreachable in container), fix ACCOUNTS reference 2026-07-23 23:32:33 +08:00
z3st
727f0f678f feat: single GPU, HuggingFace only, vllm only
- Target single GPU (ppu_zw_810e) instead of 4 GPUs
- Search only from HuggingFace API (removed ModelScope)
- Framework fixed to vllm (removed llama.cpp)
- Filter out GGUF format models
- Simplified config and functions
2026-07-23 23:19:20 +08:00
z3st
207d44b8f2 fix: add nv_framework back for API safety 2026-07-23 22:43:22 +08:00
z3st
1d33394dac fix: remove nv_framework, let platform auto-assign 2026-07-23 22:42:45 +08:00
z3st
1811a66aee fix: match platform auto-generated configParams format
- Remove /bin/bash -ic wrapper from sut_config.command
- Use list format for all command arguments (matches platform auto-gen)
- Add nv_framework field
- Remove unnecessary fields: docker_image, nv_docker_image, modelFormat, model, cpu_num
- Fix ref_config to match platform format (port 80, max_model_len 4096)
2026-07-23 22:35:50 +08:00
z3st
12bf6d637f fix: move gpu_num/cpu_num outside values block to match API spec 2026-07-23 22:10:17 +08:00
z3st
85c456afe0 fix: yaml.dump width=1000 to prevent command string wrapping 2026-07-22 22:43:35 +08:00
z3st
b3b52848c2 fix: verifyResult can be None, ensure dict return 2026-07-22 01:39:33 +08:00
z3st
d6e9f2e7a0 fix: page_size limit 50 for ModelScope API 2026-07-22 01:13:26 +08:00
z3st
821edbc8f5 debug: add logging to search function 2026-07-22 01:08:03 +08:00
z3st
5e2df178e1 feat: re-enable auto-run pipeline after connectivity test 2026-07-21 20:45:26 +08:00
z3st
761e74ff82 feat: auto-run connectivity test on startup, print results to logs 2026-07-21 20:31:23 +08:00
z3st
09ac80f1ec feat: add /test endpoint for connectivity check, disable auto-run 2026-07-21 19:53:28 +08:00
z3st
3975a3370a fix: correct ModelScope API endpoint and field names 2026-07-21 19:31:35 +08:00
z3st
7313f8da67 feat: auto-run pipeline on startup 2026-07-21 19:09:41 +08:00
z3st
2955a57e2e feat: full cloud pipeline - search, filter, submit 2026-07-21 19:04:43 +08:00
3 changed files with 191 additions and 46 deletions

View File

@@ -1,16 +1,33 @@
# ModelHub 提交智能体 # ModelHub 全云端提交智能体
用于获取 `strategyId` 的最小化智能体 部署在平台容器中,从内网直接提交验证任务
## 功能 ## API
- `GET /health` → 健康检查 | 端点 | 方法 | 说明 |
- `GET /` → 显示 strategyId |------|------|------|
| `/health` | GET | 健康检查 |
| `/` | GET | 智能体信息 |
| `/status` | GET | 运行状态 |
| `/logs?lines=50` | GET | 查看日志 |
| `/run` | POST | 触发一次完整流程 |
## 平台要求 ## POST /run 请求体
- ✅ 根目录 Dockerfile ```json
- ✅ 暴露 8080 端口 {
-`/health` 端点返回 200 "gpus": ["Kunlunxin_p-800", "hygon_k100-ai"],
- ✅ 处理 SIGTERM 信号 "limit": 30
- ✅ 读取 `STRATEGY_ID` 环境变量 }
```
- `gpus`: 目标 GPU 列表(可选,默认全部)
- `limit`: 每 GPU 最大提交数(可选,默认 30
## 流程
1. 搜索 ModelScopeQwen 系列关键词)
2. 下载量 ≥ 50 筛选
3. 架构检查config.json
4. 平台验证状态查重
5. 提交到 ModelHub

195
main.py
View File

@@ -1,74 +1,201 @@
""" """
ModelHub 提交智能体(代理模式) ModelHub Cancel-All 智能体
用途:获取 strategyId本地脚本直接调用 ModelHub API 启动后自动取消当前账号所有 waiting/running 状态的验证任务
用法:推送此版本到平台,选择对应 tag 运行即可
""" """
import json import json
import os import os
import signal import signal
import time
import threading
from datetime import datetime
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
import requests
# ============================================================
# 配置
# ============================================================
HOST = "0.0.0.0" HOST = "0.0.0.0"
PORT = 8080 PORT = 8080
shutdown_requested = False
# 目标GPU和Token跟提交版本保持一致
TARGET_GPU = "Iluvatar_bi-150"
TARGET_TOKEN = "f45f1aae2c094426be237c88b1085015"
MODELHUB_API = "https://modelhub.org.cn/api"
BATCH_SIZE = 50 # 每批取消数量API上限
# ============================================================
# 全局状态
# ============================================================
state = {'running': False, 'last_run': None, 'logs': []}
state_lock = threading.Lock()
def _config() -> dict: def log(msg: str):
strategy_id = os.getenv("STRATEGY_ID", "") ts = datetime.now().strftime('%H:%M:%S')
return { line = f"[{ts}] {msg}"
"strategy_id": strategy_id, print(line, flush=True)
"status": "running", with state_lock:
state['logs'].append(line)
if len(state['logs']) > 500:
state['logs'] = state['logs'][-300:]
def cancel_all_tasks():
"""取消所有 waiting 和 running 状态的任务"""
headers = {
'Xc-Token': TARGET_TOKEN,
'Accept': 'application/json',
'Content-Type': 'application/json',
} }
log("=" * 50)
log("开始取消所有任务")
log(f"目标GPU: {TARGET_GPU}")
class Handler(BaseHTTPRequestHandler): # 1. 查询所有任务
def do_GET(self) -> None: all_tasks = []
if self.path == "/health": page = 1
self._send_json({"status": "ok"}) while True:
try:
resp = requests.get(
f"{MODELHUB_API}/adapt/task/page",
headers={'Xc-Token': TARGET_TOKEN, 'Accept': 'application/json'},
params={'current': page, 'pageSize': 100, 'onlyMine': 'true',
'gpuType': TARGET_GPU},
timeout=15
)
data = resp.json()
if data.get('code') != 0:
log(f"查询失败: code={data.get('code')}")
break
records = data['data'].get('records', [])
if not records:
break
all_tasks.extend(records)
total = data['data'].get('total', 0)
log(f"{page}页: {len(records)} 条, 累计 {len(all_tasks)} / {total}")
if len(all_tasks) >= int(total):
break
page += 1
except Exception as e:
log(f" 查询异常: {e}")
return return
if self.path == "/": # 2. 筛选 waiting/running 状态
self._send_json({ cancellable = [t for t in all_tasks if t.get('status') in ('waiting', 'running')]
"name": "modelhub-submit-agent", if not cancellable:
"config": _config(), log(f" 没有可取消的任务 (总任务 {len(all_tasks)} 个)")
log("=" * 50)
return
task_ids = [int(t.get('taskId')) for t in cancellable if t.get('taskId')]
log(f" 总任务 {len(all_tasks)} 个, 可取消 {len(task_ids)}")
# 3. 分批取消
url = f"{MODELHUB_API}/async/task/stop-create-contest-task"
cancelled = 0
for i in range(0, len(task_ids), BATCH_SIZE):
batch = task_ids[i:i + BATCH_SIZE]
try:
resp = requests.put(url, headers=headers, json={'taskIds': batch}, timeout=15)
data = resp.json()
if data.get('code') == 0:
cancelled += len(batch)
log(f" 批次 {i // BATCH_SIZE + 1}: 取消 {len(batch)} 个 OK")
else:
log(f" 批次 {i // BATCH_SIZE + 1}: 失败 code={data.get('code')} msg={data.get('message', '')[:80]}")
except Exception as e:
log(f" 批次 {i // BATCH_SIZE + 1}: 异常 {e}")
time.sleep(1)
log(f" 取消完成: {cancelled} / {len(task_ids)}")
log("=" * 50)
# ============================================================
# HTTP 服务
# ============================================================
class AgentHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/health':
self._json({'status': 'ok'})
elif self.path == '/':
self._json({
'name': 'modelhub-cancel-all',
'gpu': TARGET_GPU,
'status': 'running' if state['running'] else 'idle',
'last_result': state.get('last_result'),
}) })
return elif self.path.startswith('/logs'):
lines = 100
self._json({'logs': state['logs'][-lines:]})
else:
self._json({'error': 'not found'}, 404)
self._send_json({"error": "not found"}, status=404) def _json(self, body: dict, status: int = 200):
payload = json.dumps(body, ensure_ascii=False).encode()
def log_message(self, fmt: str, *args: object) -> None:
print(f"{self.address_string()} - {fmt % args}", flush=True)
def _send_json(self, body: dict, status: int = 200) -> None:
payload = json.dumps(body).encode()
self.send_response(status) self.send_response(status)
self.send_header("Content-Type", "application/json") self.send_header('Content-Type', 'application/json; charset=utf-8')
self.send_header("Content-Length", str(len(payload))) self.send_header('Content-Length', str(len(payload)))
self.end_headers() self.end_headers()
self.wfile.write(payload) self.wfile.write(payload)
def log_message(self, fmt, *args):
pass
def _handle_signal(signum: int, _frame: object) -> None:
# ============================================================
# 启动
# ============================================================
shutdown_requested = False
def _handle_signal(signum, _frame):
global shutdown_requested global shutdown_requested
shutdown_requested = True shutdown_requested = True
print(f"received signal {signum}, shutting down", flush=True) log(f"收到信号 {signum},准备关闭")
def main() -> None: def main():
signal.signal(signal.SIGTERM, _handle_signal) signal.signal(signal.SIGTERM, _handle_signal)
signal.signal(signal.SIGINT, _handle_signal) signal.signal(signal.SIGINT, _handle_signal)
server = ThreadingHTTPServer((HOST, PORT), Handler) server = ThreadingHTTPServer((HOST, PORT), AgentHandler)
server.timeout = 1 server.timeout = 1
strategy_id = os.getenv("STRATEGY_ID", "NOT_SET") log(f"Cancel-All 智能体启动 | {HOST}:{PORT}")
print(f"modelhub-submit-agent listening on {HOST}:{PORT}", flush=True) log(f"目标GPU: {TARGET_GPU}")
print(f"STRATEGY_ID: {strategy_id}", flush=True)
# 启动后自动取消所有任务
def _auto_cancel():
time.sleep(2)
try:
state['running'] = True
state['last_run'] = datetime.now().isoformat()
cancel_all_tasks()
state['last_result'] = {'success': True}
except Exception as e:
log(f"异常: {e}")
state['last_result'] = {'error': str(e)}
finally:
state['running'] = False
threading.Thread(target=_auto_cancel, daemon=True).start()
while not shutdown_requested: while not shutdown_requested:
server.handle_request() server.handle_request()
server.server_close() server.server_close()
log("智能体已关闭")
if __name__ == "__main__": if __name__ == '__main__':
main() main()

View File

@@ -1 +1,2 @@
# No external dependencies needed requests>=2.28.0
pyyaml>=6.0