Files

305 lines
11 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
xc_validation_strategy_vllm_submit — 主入口
启动后通过 /api/adapt/task/add 接口xc-Token 认证)批量提交
vLLM 模型适配任务ppu_zw_810e之后保持 HTTP 服务存活。
同时暴露 /healthK8s 探活)和 /status运行状态
部署框架与 xc_validation_strategy 一致。
"""
import json
import os
import signal
import threading
from datetime import datetime
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from typing import List
import requests
# ══════════════════════════════════════════════════════════
# 配置
# ══════════════════════════════════════════════════════════
BASE_URL = os.environ.get("BASE_URL", "https://modelhub.org.cn")
ADD_TASK_ENDPOINT = "/api/adapt/task/add"
# fanyi 账号的 xc-Token该接口使用 xc-Token 认证,无需登录)
USER_ACCOUNT = "fanyi"
XC_TOKEN = "f2d501c9ae6543a589cd6cb789108c41"
GPU_TYPE = "ppu_zw_810e"
TASK_TYPE = "text-generation"
STRATEGY_ID = os.environ.get("STRATEGY_ID", "") # 平台自动注入,无需修改
HEADERS = {
"Content-Type": "application/json",
"xc-Token": XC_TOKEN,
}
HTTP_HOST = "0.0.0.0"
HTTP_PORT = 8080
# ══════════════════════════════════════════════════════════
# 模型列表
# ══════════════════════════════════════════════════════════
ALL_MODEL_IDS = [
"Hyeji0101/qwen2_5_1_5b_demo",
"GenueAI/geode-onyx",
"GM77/qwen3-4b-verilog-grpo",
"ChuGyouk/F_R13_T2",
"ChuGyouk/R17",
"Ingingdo/bit-0.5b-final-logic",
"beomi/Llama-3-Open-Ko-8B",
"Fiscus/trinitite_safe_rl_base_model",
"ChuGyouk/F_R12_T3",
"ChuGyouk/F_R12_T2",
"xw1234gan/cnk12_Main_fixed_SFTanchor_3B_step_9",
"xw1234gan/cnk12_Main_fixed_SFTanchor_3B_step_10",
"xw1234gan/cnk12_Main_fixed_BaseAnchor_3B_step_1",
"kmseong/llama3_2_3b-instruct-math-safedelta-scale0.99",
"opencompass/anah-v2",
"ChuGyouk/R14",
"trishajean/qwen-math-cebuano-1.5b-merged",
"GyanAISystems/Gyan-AI-G1-Official",
"Divij/Qwen2.5-3B-Instruct-sft-without-thoughts",
"Divij/Qwen2.5-3B-Instruct-sft-with-thoughts",
"ChuGyouk/R5_1",
"ChuGyouk/R18_1",
"ChuGyouk/R19_1",
"ChuGyouk/R12",
"ChuGyouk/F_R11_T4",
"ChuGyouk/F_R12",
"ChuGyouk/F_R11_T2",
"ChuGyouk/F_R11_T3",
"ChuGyouk/F_R13_1_T1",
"ChuGyouk/F_R12_T4",
"automerger/T3qm7xNeuralsirkrishna-7B",
"Ford91/clifford-ai-v2",
"ChuGyouk/R16_1",
"ChuGyouk/R15_1",
"nkatara/gita-text-generation-gpt2",
"HINT-lab/Qwen2.5-7B-Instruct-Self-Calibration",
"thirdeyeai/Qwen2.5-1.5B-Instruct-uncensored",
"karaselerm/qwen2.5-1.5b-instruct-ru-abliterated-hw6",
"xw1234gan/cnk12_Main_fixed_BaseAnchor_3B_step_2",
"ontocord/wide_3b_sft_stage1.1-ss1-with_intr_math.no_issue",
"mncai/Foundation_Law_epoch4",
"gauri0508/med-record-audit-qwen2.5-3b-grpo",
"unsloth/Phi-4-mini-instruct",
"E-motionAssistant/qwen-2.5-3b-tamil-therapy-merged",
"EscapeJeju/qwen2_5_1_5b_demo",
"AgPerry/Qwen3-8B-fim-v2v3pt-swe-lego-posttrain",
"ChuGyouk/F_R11",
"ChuGyouk/F_R11_1_T1",
"LorenaYannnnn/general_reward-Qwen3-0.6B-OURS_self-seed_1",
"Vortex5/Crimson-Constellation-12B",
"cloudyu/mistral_11B_instruct_v0.1",
"pkupie/Qwen2.5-3B-ug-cpt",
"iproskurina/qwen-hf-fewshot-iter-np-iter3",
"ontocord/wide_3b_sft_stage1.2-ss1-expert_wiki",
"kmseong/llama3_2_3b-instruct-math-safedelta-scale2",
"Thrillcrazyer/Qwen-2.5-1.5B_TAC_Teacher_Qwen32B",
"nyu-dice-lab/VeriThoughts-Reasoning-7B",
"ontocord/wide_3b",
"silvercoder67/Mistral-7b-instruct-v0.2-summ-sft-e2m",
"lihaoxin2020/qwen3-4b-sft-gpt54-ep2-instance-rubric-gpt54-step200",
"lihaoxin2020/qwen3-4b-sft-gpt54-ep2-instance-rubric-gpt54-step150",
"lihaoxin2020/qwen3-4b-sft-gpt54-ep2-evolving-rubric-gem3-flash-step150",
"Guilherme34/Firefly-V3",
]
# ══════════════════════════════════════════════════════════
# 全局状态(供 /status 展示)
# ══════════════════════════════════════════════════════════
_state = {
"strategy_id": STRATEGY_ID,
"phase": "starting", # starting | submitting | done | error
"total": len(ALL_MODEL_IDS),
"submitted": 0,
"failed": 0,
"started_at": None,
"finished_at": None,
}
_shutdown = threading.Event()
# ══════════════════════════════════════════════════════════
# HTTP 服务
# ══════════════════════════════════════════════════════════
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == "/health":
self._json({"status": "ok"})
elif self.path == "/status":
self._json(_state)
else:
self._json({"error": "not found"}, 404)
def _json(self, body: dict, code: int = 200):
payload = json.dumps(body, default=str).encode()
self.send_response(code)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(payload)))
self.end_headers()
self.wfile.write(payload)
def log_message(self, fmt, *args):
print(f"[http] {self.address_string()} {fmt % args}", flush=True)
def _run_http():
server = ThreadingHTTPServer((HTTP_HOST, HTTP_PORT), Handler)
server.timeout = 1
print(f"[http] 监听 {HTTP_HOST}:{HTTP_PORT}", flush=True)
while not _shutdown.is_set():
server.handle_request()
server.server_close()
print("[http] 已关闭", flush=True)
# ══════════════════════════════════════════════════════════
# 业务逻辑
# ══════════════════════════════════════════════════════════
def submit_task(model_id: str) -> bool:
config_content = f"""
gpu_type: ppu_zw_810e
framework: vllm
docker_image: harbor.4pd.io/hardcore-tech/asllm:1.10.1-pytorch2.10.0-ubuntu24.04-sail2.1.0-cuda13.0-sglang0.5.10-vllm0.19.0-py312
nv_docker_image: harbor-contest.4pd.io/sunruoxi/vllm-openai-fix-tokenizer:v0.11.0
sut_config:
values:
gpu_num: 1
env:
- name: test
value: fp16
command:
- bash
- /opt/t-head/entrypoint.sh
- python3
- -m
- asllm.entrypoints.api_server
- --model
- /model
- --port
- '30000'
- --host
- 0.0.0.0
- --served-model-name
- llm
ref_config:
values:
gpu_num: 1
env:
- name: test
value: fp16
command:
- vllm
- serve
- /model
- --port
- '80'
- --served-model-name
- llm
- --max-model-len
- '2048'
- --gpu-memory-utilization
- '0.9'
- --enforce-eager
- --trust-remote-code
- -tp
- '1'
"""
payload = {
"configParams": config_content,
"framework": "vllm",
"modelAddress": f"https://huggingface.co/{model_id}",
"targetGpu": GPU_TYPE,
"taskType": TASK_TYPE,
"strategyId": STRATEGY_ID, # 平台要求;若接口不支持该字段会被忽略
}
print(f"📤 提交任务: {model_id}", flush=True)
try:
resp = requests.post(
BASE_URL + ADD_TASK_ENDPOINT,
headers=HEADERS,
json=payload,
timeout=30,
)
print(f"status: {resp.status_code}", flush=True)
result = resp.json()
print(result, flush=True)
if result.get("code") == 0:
print(f"✅ 提交成功: {model_id}", flush=True)
return True
else:
print(f"❌ 提交失败: {result.get('message')}", flush=True)
return False
except Exception as e:
print(f"💥 异常 ({model_id}): {e}", flush=True)
return False
def _run_worker():
_state["started_at"] = datetime.utcnow().isoformat()
_state["phase"] = "submitting"
successful: List[str] = []
for model_id in ALL_MODEL_IDS:
if _shutdown.is_set():
break
if submit_task(model_id):
_state["submitted"] += 1
successful.append(model_id)
else:
_state["failed"] += 1
# 写入结果文件
try:
with open("submitted_adapt_tasks.txt", "w", encoding="utf-8") as f:
for mid in successful:
f.write(f"{mid}\n")
except Exception:
pass
_state["finished_at"] = datetime.utcnow().isoformat()
_state["phase"] = "done"
print(
f"[worker] 完成 submitted={_state['submitted']} failed={_state['failed']} total={_state['total']}",
flush=True,
)
# 提交完成后继续保持进程存活,等待平台停止
# ══════════════════════════════════════════════════════════
# 入口
# ══════════════════════════════════════════════════════════
def _handle_signal(signum, _frame):
print(f"[main] 收到信号 {signum},正在关闭...", flush=True)
_shutdown.set()
def main():
signal.signal(signal.SIGTERM, _handle_signal)
signal.signal(signal.SIGINT, _handle_signal)
# HTTP 服务线程
http_thread = threading.Thread(target=_run_http, daemon=False)
http_thread.start()
# 提交任务线程
worker_thread = threading.Thread(target=_run_worker, daemon=True)
worker_thread.start()
# 主线程等待 shutdown
_shutdown.wait()
print("[main] 等待 HTTP 服务关闭...", flush=True)
http_thread.join(timeout=5)
print("[main] 退出", flush=True)
if __name__ == "__main__":
main()