news 2026/4/16 0:18:25

HY-Motion 1.0代码实例:RESTful API封装,支持HTTP POST提交提示词

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HY-Motion 1.0代码实例:RESTful API封装,支持HTTP POST提交提示词

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、不配nginxpython3 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 e

3.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.pyapi_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),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 18:10:09

Z-Image Turbo极速体验:无需显卡,8步生成惊艳国风插画

Z-Image Turbo极速体验&#xff1a;无需显卡&#xff0c;8步生成惊艳国风插画 你有没有试过在深夜灵感迸发时&#xff0c;想立刻把脑海里的水墨仕女、青瓦飞檐、竹影摇曳画出来&#xff0c;却卡在了“等显卡跑完30步”“显存爆红报错”“CUDA版本不兼容”的死循环里&#xff1…

作者头像 李华
网站建设 2026/4/16 12:42:27

DeerFlow研究助理体验:用AI自动完成市场调研报告

DeerFlow研究助理体验&#xff1a;用AI自动完成市场调研报告 你有没有过这样的经历&#xff1a;老板突然甩来一个需求——“三天内交一份关于新能源汽车充电桩市场的深度调研报告”&#xff0c;你立刻打开浏览器&#xff0c;疯狂搜索、整理资料、分析数据、撰写内容……最后熬…

作者头像 李华
网站建设 2026/4/16 18:13:13

动手试了Heygem系统,批量生成数字人视频太高效

动手试了Heygem系统&#xff0c;批量生成数字人视频太高效 最近在做短视频内容批量生产&#xff0c;需要把同一段口播音频适配到多个数字人形象上。试过不少方案&#xff1a;有的要反复上传、手动切换&#xff1b;有的导出后还得再剪辑&#xff1b;还有的根本没法批量处理&…

作者头像 李华
网站建设 2026/4/16 15:47:10

Qwen-Image-Edit效果实测:复杂遮挡场景下主体识别与局部编辑精度

Qwen-Image-Edit效果实测&#xff1a;复杂遮挡场景下主体识别与局部编辑精度 1. 一句话修图&#xff0c;真能“指哪打哪”吗&#xff1f; 你有没有试过这样修图&#xff1a;一张人站在树丛前的照片&#xff0c;树枝横斜着挡住半张脸&#xff0c;你想只把树枝去掉&#xff0c;…

作者头像 李华
网站建设 2026/4/16 14:23:24

bge-large-zh-v1.5实战手册:使用ONNX Runtime加速推理并降低GPU依赖

bge-large-zh-v1.5实战手册&#xff1a;使用ONNX Runtime加速推理并降低GPU依赖 1. 为什么需要换掉默认部署方式&#xff1f; 你可能已经用sglang成功跑起了bge-large-zh-v1.5&#xff0c;输入一段话就能拿到向量结果&#xff0c;看起来一切顺利。但当你开始批量处理几百条中…

作者头像 李华