HY-Motion 1.0代码实例:RESTful API封装,支持HTTP POST提交提示词
1. 为什么需要封装API?——从可视化工作站到工程化集成
你可能已经试过在Gradio界面里输入一句英文提示词,点击生成,几秒后看到3D数字人流畅地完成蹲举、攀爬或起身伸展。这种体验很酷,但如果你正开发一个面向终端用户的数字人交互系统,或者想把动作生成能力嵌入到企业级内容平台中,光靠浏览器访问http://localhost:7860/显然不够。
真实场景中,你需要的是:
- 后端服务能稳定调用动作生成能力,不依赖图形界面;
- 多个业务模块(如AI客服后台、虚拟主播中控台、教育课件引擎)能通过标准协议统一接入;
- 提示词由前端用户输入、NLP模块解析或运营后台配置,动态构造并提交;
- 错误可捕获、状态可监控、响应可解析,真正融入CI/CD和运维体系。
HY-Motion 1.0原生提供Gradio接口,但它不是为生产环境设计的API服务。本文不讲理论、不堆参数,只做一件事:手把手带你把HY-Motion 1.0封装成一个轻量、可靠、开箱即用的RESTful服务,支持标准HTTP POST提交提示词,返回结构化动作数据(.npz或.bvh),全程无GUI依赖,纯命令行可验证。
你不需要重写模型推理逻辑,也不用改一行PyTorch代码——我们只做“最后一公里”的工程封装。
2. 封装思路:绕过Gradio,直连模型推理核心
HY-Motion 1.0的源码结构清晰,其核心推理入口位于inference.py或类似命名的脚本中(具体路径依部署版本而定,常见于/root/build/HY-Motion-1.0/inference/)。它接收文本提示、动作时长、随机种子等参数,输出骨骼关键帧序列。
我们的策略是:
不魔改模型:保留原始权重与推理流程,仅新增一层薄薄的服务胶水层;
不强依赖Web框架:避开Flask/FastAPI的复杂路由与中间件,用Python内置http.server实现最小可行服务;
零额外依赖:除PyTorch、NumPy、SciPy等模型必需库外,不引入新包;
兼容现有工作流:输出格式与原命令行脚本完全一致,.npz文件可直接被Unity、Blender或Three.js加载。
整个封装过程分三步走:准备推理函数 → 构建HTTP处理器 → 启动服务并测试。下面每一步都附可运行代码。
2.1 提取并封装推理函数
首先,我们需要一个干净的、可复用的推理函数。它应脱离Gradio上下文,只关心输入(prompt、length、seed)和输出(动作数据路径)。
假设你已按官方文档完成模型部署,路径为/root/build/HY-Motion-1.0/,且inference.py中存在类似generate_motion()的函数。我们新建一个api_core.py:
# api_core.py import os import torch import numpy as np from pathlib import Path # 假设这是从原inference.py中提取并简化的核心函数 def generate_motion_from_prompt( prompt: str, motion_length: int = 60, # 默认5秒(12fps) seed: int = 42, output_dir: str = "/tmp/hymotion_output" ) -> str: """ 根据文本提示生成3D动作序列,返回.npz文件路径 Args: prompt: 英文动作描述,如 "A person stands up from chair and stretches arms" motion_length: 动作总帧数(建议60=5秒,120=10秒) seed: 随机种子,控制动作变体 output_dir: 输出目录,自动创建 Returns: str: 生成的.npz文件绝对路径,如 "/tmp/hymotion_output/motion_123456.npz" """ # 1. 设置随机种子 torch.manual_seed(seed) np.random.seed(seed) # 2. 加载模型(此处为示意,实际需按HY-Motion加载逻辑) # model = load_hy_motion_model() # 你的加载逻辑 # tokenizer = load_tokenizer() # 你的分词器 # 3. 文本编码(示意) # text_emb = tokenizer.encode(prompt).to('cuda') # 4. 执行生成(示意) # motion_data = model.generate(text_emb, length=motion_length) # 关键:以下为模拟生成逻辑,**请替换为你实际的推理调用** # 实际使用时,请复制并精简原inference.py中的generate函数主体 # 重点保留:文本编码 → 模型前向 → 后处理 → 保存.npz # 模拟生成:创建一个假的60帧、22关节的随机动作数据(仅用于测试) n_joints = 22 fake_motion = np.random.randn(motion_length, n_joints, 3).astype(np.float32) # 创建输出目录 Path(output_dir).mkdir(parents=True, exist_ok=True) # 生成唯一文件名 import time timestamp = int(time.time() * 1000000) output_path = os.path.join(output_dir, f"motion_{timestamp}.npz") # 保存为.npz(HY-Motion标准格式) np.savez_compressed( output_path, rotations=fake_motion, # 关节旋转(B, J, 3) positions=np.zeros((motion_length, 3)), # 根节点位置(可选) mask=np.ones(motion_length, dtype=bool) # 有效帧掩码 ) return output_path** 重要提醒**:上面的
fake_motion仅为演示占位。你必须将注释部分# 关键:以下为模拟生成逻辑...替换为HY-Motion 1.0实际的推理调用。推荐做法是:打开原inference.py,找到主生成函数(通常含model.sample()或pipeline()调用),将其逻辑完整复制进generate_motion_from_prompt(),删去所有Gradio相关参数(如gr.Progress)、UI打印(如print("Generating...")),只保留纯计算与文件保存。
2.2 编写轻量HTTP服务处理器
接下来,我们用Python标准库http.server搭建一个极简REST服务。新建api_server.py:
# api_server.py from http.server import HTTPServer, BaseHTTPRequestHandler import json import urllib.parse import os from pathlib import Path from api_core import generate_motion_from_prompt class MotionAPIHandler(BaseHTTPRequestHandler): def do_OPTIONS(self): self.send_response(200) self.send_header('Access-Control-Allow-Origin', '*') self.send_header('Access-Control-Allow-Methods', 'POST, OPTIONS') self.send_header('Access-Control-Allow-Headers', 'Content-Type') self.end_headers() def do_POST(self): if self.path != '/generate': self.send_error(404, "Endpoint not found") return # 设置CORS头 self.send_response(200) self.send_header('Content-type', 'application/json') self.send_header('Access-Control-Allow-Origin', '*') self.end_headers() try: # 读取请求体 content_length = int(self.headers.get('Content-Length', 0)) post_data = self.rfile.read(content_length).decode('utf-8') data = json.loads(post_data) # 解析参数(全部可选,有默认值) prompt = data.get('prompt', '').strip() motion_length = int(data.get('motion_length', 60)) seed = int(data.get('seed', 42)) output_dir = data.get('output_dir', '/tmp/hymotion_api_output') # 校验必要参数 if not prompt: raise ValueError("Missing required field: 'prompt'") # 调用核心生成函数 npz_path = generate_motion_from_prompt( prompt=prompt, motion_length=motion_length, seed=seed, output_dir=output_dir ) # 构造成功响应 response = { "status": "success", "message": "Motion generated successfully", "output_path": npz_path, "prompt": prompt, "motion_length": motion_length, "seed": seed } except Exception as e: # 错误响应 self.send_response(400) self.send_header('Content-type', 'application/json') self.end_headers() response = { "status": "error", "message": str(e), "hint": "Check prompt format (English, <60 words), motion_length (e.g., 60 for 5s), and GPU memory" } # 发送JSON响应 self.wfile.write(json.dumps(response, ensure_ascii=False).encode('utf-8')) def run_server(host='0.0.0.0', port=8000): server = HTTPServer((host, port), MotionAPIHandler) print(f" HY-Motion API Server running on http://{host}:{port}") print(f" POST to http://{host}:{port}/generate with JSON body:") print(f' {{ "prompt": "A person walks forward and waves hand" }}') server.serve_forever() if __name__ == '__main__': run_server()这个服务只有两个关键点:
- 严格遵循REST约定:只响应
POST /generate,返回标准JSON; - 零外部依赖:不装
requests、不配nginx,python3 api_server.py即可启动。
优势:没有框架学习成本,无隐藏中间件,出问题一眼定位;
注意:生产环境建议用FastAPI(性能更高、文档自动生成),但本文目标是“最小可行”,故选用最简方案。
2.3 启动服务并首次测试
确保你已在服务器上完成以下准备:
- HY-Motion 1.0模型权重已下载并可加载;
api_core.py中已填入真实的推理逻辑(非fake);- Python环境已安装
torch,numpy,scipy等必要库; - 显存充足(至少24GB,推荐26GB以上)。
执行启动命令:
cd /root/build/HY-Motion-1.0 python3 api_server.py你会看到输出:
HY-Motion API Server running on http://0.0.0.0:8000 POST to http://0.0.0.0:8000/generate with JSON body: { "prompt": "A person walks forward and waves hand" }现在,用curl测试第一个请求:
curl -X POST http://localhost:8000/generate \ -H "Content-Type: application/json" \ -d '{"prompt": "A person stands up from chair and stretches arms", "motion_length": 60, "seed": 123}'成功响应示例:
{ "status": "success", "message": "Motion generated successfully", "output_path": "/tmp/hymotion_api_output/motion_1742345678901234.npz", "prompt": "A person stands up from chair and stretches arms", "motion_length": 60, "seed": 123 }服务通了!你已拥有了一个真正的、可编程调用的HY-Motion 1.0 API。
3. 生产就绪增强:日志、超时、资源管理
上述服务可运行,但离生产还有距离。以下是三个关键增强点,每项只需增加10行以内代码,却大幅提升稳定性。
3.1 添加请求日志与错误追踪
在api_server.py顶部添加日志模块,并在do_POST开头加入记录:
import logging import time # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler('/var/log/hymotion_api.log'), logging.StreamHandler() ] ) logger = logging.getLogger(__name__) # 在 do_POST 函数开头添加: start_time = time.time() logger.info(f"Received POST /generate | IP: {self.client_address[0]} | Body: {post_data[:100]}...") # 在响应发送后添加: duration = time.time() - start_time logger.info(f"Response sent in {duration:.2f}s | Status: {self._response_status}")日志帮你快速定位:是用户传了非法prompt?还是GPU OOM?还是网络超时?
3.2 设置请求超时与最大长度限制
在do_POST中,在解析参数后加入校验:
# 校验prompt长度(防恶意长文本拖垮服务) if len(prompt) > 200: raise ValueError("Prompt too long. Max 200 characters.") # 校验motion_length范围(防OOM) if not (30 <= motion_length <= 240): raise ValueError("motion_length must be between 30 and 240 (2.5s to 20s at 12fps).") # 设置全局超时(在generate_motion_from_prompt调用前加) import signal class TimeoutError(Exception): pass def timeout_handler(signum, frame): raise TimeoutError("Motion generation timed out (>120s)") signal.signal(signal.SIGALRM, timeout_handler) signal.alarm(120) # 2分钟超时 try: npz_path = generate_motion_from_prompt(...) signal.alarm(0) # 取消闹钟 except TimeoutError as e: raise e3.3 GPU显存保护:自动释放缓存
在generate_motion_from_prompt()函数末尾添加:
# 清理GPU缓存,防止多次请求累积OOM if torch.cuda.is_available(): torch.cuda.empty_cache() # 可选:同步确保清理完成(轻微性能损耗,但更稳妥) torch.cuda.synchronize()这三处增强,让服务从“能跑”升级为“敢上生产”。
4. 客户端调用实战:Python、JavaScript、命令行全覆盖
API的价值在于被调用。下面给出三种最常用客户端的调用示例,全部可直接复制运行。
4.1 Python客户端(推荐用于后端集成)
# client_python.py import requests import json API_URL = "http://localhost:8000/generate" def generate_motion(prompt: str, motion_length: int = 60, seed: int = 42): payload = { "prompt": prompt, "motion_length": motion_length, "seed": seed } response = requests.post(API_URL, json=payload, timeout=180) response.raise_for_status() return response.json() # 使用示例 if __name__ == "__main__": result = generate_motion( prompt="A person performs a squat, then pushes a barbell overhead", motion_length=120, # 10秒 seed=999 ) print(" Success! Motion saved to:", result["output_path"])4.2 JavaScript客户端(用于Web前端)
<!-- client_js.html --> <!DOCTYPE html> <html> <head><title>HY-Motion API Demo</title></head> <body> <input id="prompt" placeholder="Enter English prompt..." value="A person climbs upward, moving up the slope"> <button onclick="callAPI()">Generate Motion</button> <div id="result"></div> <script> async function callAPI() { const prompt = document.getElementById('prompt').value; const res = await fetch('http://localhost:8000/generate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt: prompt }) }); const data = await res.json(); document.getElementById('result').innerText = res.ok ? ` Generated: ${data.output_path}` : `❌ Error: ${data.message}`; } </script> </body> </html>注意:因浏览器同源策略,前端需与API同域,或后端开启CORS(我们的服务已默认支持
*)。
4.3 命令行客户端(DevOps友好)
# save as generate_motion.sh #!/bin/bash PROMPT="${1:-"A person stands up from chair and stretches arms"}" URL="http://localhost:8000/generate" echo "🎬 Generating motion for: $PROMPT" curl -s -X POST "$URL" \ -H "Content-Type: application/json" \ -d "{\"prompt\":\"$PROMPT\"}" | jq '.'赋予执行权限并运行:
chmod +x generate_motion.sh ./generate_motion.sh "A person walks forward and waves hand"5. 故障排查指南:高频问题与速查方案
即使封装完美,运行中仍可能遇到问题。以下是开发者最常问的5个问题及解决路径:
5.1 “Connection refused” 或 “Failed to connect”
- 检查服务是否在运行:
ps aux | grep api_server.py - 检查端口占用:
netstat -tuln | grep 8000 - 检查防火墙:
sudo ufw status(Ubuntu)或sudo firewall-cmd --list-ports(CentOS) - 若远程访问,确认
host='0.0.0.0'(非'127.0.0.1')
5.2 “CUDA out of memory”
- 立即生效:减小
motion_length(如从120→60); - 中期方案:在
api_core.py中强制设置torch.cuda.set_per_process_memory_fraction(0.8); - 长期方案:改用
HY-Motion-1.0-Lite(0.46B),显存需求降至24GB。
5.3 返回空JSON或500错误
- 查看日志:
tail -f /var/log/hymotion_api.log; - 检查
api_core.py中是否遗漏了真实的模型加载逻辑; - 确认所有路径(模型权重、tokenizer)在服务进程工作目录下可访问。
5.4 生成动作卡顿、不连贯
- 不是API问题,是模型能力边界:检查prompt是否违反《创意实验室指南》禁区(如含“angrily”、“wearing red dress”、“holding cup”);
- 优先使用经典案例库中的句式,例如:“A person performs a squat, then pushes a barbell overhead...”。
5.5 如何批量生成多个动作?
- API本身无批量接口,但客户端可循环调用:
prompts = ["A person walks", "A person jumps", "A person dances"] for p in prompts: result = generate_motion(p) print(f"{p} → {result['output_path']}")6. 总结:你已掌握HY-Motion 1.0工程化落地的关键一环
回顾本文,你完成了:
理解本质:RESTful API不是魔法,而是将模型能力暴露为标准HTTP接口;
动手封装:从零写出可运行的api_core.py与api_server.py,不依赖任何框架;
生产加固:加入日志、超时、显存管理,让服务稳如磐石;
多端调用:Python后端、JS前端、Shell脚本,一套API全场景覆盖;
自主排障:5大高频问题速查表,告别“报错就重启”。
HY-Motion 1.0的强大,不仅在于十亿参数与电影级连贯性,更在于它能无缝融入你的技术栈。今天你封装的不只是一个API,而是通往3D数字人应用生态的钥匙。
下一步,你可以:
➡ 将此服务容器化(Docker),一键部署到K8s集群;
➡ 对接消息队列(如RabbitMQ),实现异步生成与状态回调;
➡ 开发Web管理后台,让运营人员拖拽生成动作序列。
路已铺好,动作,由你定义。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。