Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions reports/tinypose-media-portal-browser.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
{
"config": {
"argv": [
"C:\\nvm4w\\nodejs\\node.exe",
"F:\\git\\00_chenmohan\\github\\chenmohan123.github.io\\.worktrees\\tinypose-media-portal\\node_modules\\playwright\\cli.js",
"test",
"--grep",
"TinyPose 0.3.0",
"--reporter=json",
"--output=reports/tinypose-media-portal/screenshots"
],
"configFile": "F:\\git\\00_chenmohan\\github\\chenmohan123.github.io\\.worktrees\\tinypose-media-portal\\playwright.config.ts",
"rootDir": "F:/git/00_chenmohan/github/chenmohan123.github.io/.worktrees/tinypose-media-portal/tests",
"failOnFlakyTests": false,
"forbidOnly": false,
"fullyParallel": false,
"globalSetup": null,
"globalTeardown": null,
"globalTimeout": 0,
"grep": {},
"grepInvert": null,
"maxFailures": 0,
"metadata": {
"actualWorkers": 1
},
"preserveOutput": "always",
"projects": [
{
"outputDir": "F:/git/00_chenmohan/github/chenmohan123.github.io/.worktrees/tinypose-media-portal/reports/tinypose-media-portal/screenshots",
"repeatEach": 1,
"retries": 0,
"metadata": {
"actualWorkers": 1
},
"id": "",
"name": "",
"testDir": "F:/git/00_chenmohan/github/chenmohan123.github.io/.worktrees/tinypose-media-portal/tests",
"testIgnore": [],
"testMatch": [
"**/*.@(spec|test).?(c|m)[jt]s?(x)"
],
"timeout": 30000
}
],
"quiet": false,
"reporter": [
[
"json"
]
],
"reportSlowTests": {
"max": 5,
"threshold": 300000
},
"shard": null,
"tags": [],
"updateSnapshots": "missing",
"updateSourceMethod": "patch",
"version": "1.62.1",
"workers": 6,
"webServer": {
"command": "node ./node_modules/astro/bin/astro.mjs dev --host 127.0.0.1",
"env": {
"ASTRO_DEV_BACKGROUND": "0"
},
"port": 4321,
"reuseExistingServer": true
}
},
"suites": [
{
"title": "portal.spec.ts",
"file": "portal.spec.ts",
"column": 0,
"line": 0,
"specs": [
{
"title": "TinyPose 0.3.0 在 1280px 展示三项资产、媒体边界和独立 SDK 链接",
"ok": true,
"tags": [],
"tests": [
{
"timeout": 30000,
"annotations": [],
"expectedStatus": "passed",
"projectId": "",
"projectName": "",
"results": [
{
"workerIndex": 0,
"parallelIndex": 0,
"status": "passed",
"duration": 1607,
"errors": [],
"stdout": [],
"stderr": [],
"retry": 0,
"startTime": "2026-09-17T17:34:03.177Z",
"annotations": [],
"attachments": []
}
],
"status": "expected"
}
],
"id": "291f6c0e7fe47579f0c2-6a287430ab4380b9977c",
"file": "portal.spec.ts",
"line": 4,
"column": 3
},
{
"title": "TinyPose 0.3.0 在 390px 展示三项资产、媒体边界和独立 SDK 链接",
"ok": true,
"tags": [],
"tests": [
{
"timeout": 30000,
"annotations": [],
"expectedStatus": "passed",
"projectId": "",
"projectName": "",
"results": [
{
"workerIndex": 0,
"parallelIndex": 0,
"status": "passed",
"duration": 782,
"errors": [],
"stdout": [],
"stderr": [],
"retry": 0,
"startTime": "2026-09-17T17:34:05.736Z",
"annotations": [],
"attachments": []
}
],
"status": "expected"
}
],
"id": "291f6c0e7fe47579f0c2-57ec3d4f5a422e9bb7e3",
"file": "portal.spec.ts",
"line": 4,
"column": 3
}
]
}
],
"errors": [],
"stats": {
"startTime": "2026-09-17T17:33:58.688Z",
"duration": 8208.078,
"expected": 2,
"skipped": 0,
"unexpected": 0,
"flaky": 0
}
}
9 changes: 9 additions & 0 deletions reports/tinypose-media-portal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# TinyPose 0.3.0 门户同步

2026-09-18(北京时间),门户登记已经发布的 TinyPose 0.3.0,补充图片、本地视频及摄像头 Demo 能力。SDK 输入仍为单帧 Blob/RGBA/region,三项模型身份、默认来源与独立链接保持原契约。

- 本地65项单测通过;Astro检查0错误、0警告,保留7项既有提示;14页构建成功。
- `../tinypose-media-portal-browser.json`:1280px与390px两项浏览器检查通过,覆盖目录筛选、详情、三项资产、版本、边界、独立链接及无横向溢出。
- 发布后的线上截图、浏览器回读与GitHub部署提交归档于SDK的 `reports/2026-09-17-media/release/portal-*`。

媒体12组合385帧和图片24组合是桌面验证;摄像头使用Chromium fake-device,不声明物理摄像头、手机、微信或NPU兼容。门户不复制推理runtime。
15 changes: 8 additions & 7 deletions src/content/models/pp-tinypose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ name: PP-TinyPose
brand: baidu
task: pose-estimation
status: available
summary: 在浏览器本地估计单人人体姿态,提供 256×192 与 128×96 两种输入规格;支持单人图片或调用者提供的人体框,输出原图坐标的 17 个 COCO 关键点,并支持 CPU/WASM、GPU/WebGPU 和主线程/Worker。
summary: 在浏览器本地估计单人人体姿态,提供 256×192 与 128×96 两种输入规格和17个COCO关键点;SDK处理单帧或调用者人体框,独立Demo支持图片、本地视频与摄像头,提供CPU/WASM、GPU/WebGPU和主线程/Worker。
repository: https://github.com/chenmohan123/web-sdk-PP-TinyPose
license: Apache-2.0
package:
name: web-sdk-pp-tinypose
version: 0.2.0
version: 0.3.0
demo:
url: https://chenmohan123.github.io/web-sdk-PP-TinyPose/
localProcessing: true
Expand All @@ -21,11 +21,11 @@ runtime:
- browser: Chromium 153.0.8010.12
os: Windows 11 10.0.26200
device: Intel Core i5-10400F / WASM,ModelScope/Hugging Face × 主线程/Worker
testedAt: 2026-09-17
testedAt: 2026-09-18
- browser: Chromium 153.0.8010.12
os: Windows 11 10.0.26200
device: NVIDIA Blackwell / WebGPU,ModelScope/Hugging Face × 主线程/Worker
testedAt: 2026-09-17
testedAt: 2026-09-18
io:
input: [Blob, RGBA, region(调用者提供的人体框)]
output: [17 个 COCO 关键点(原图坐标与 score), crop, image, runtime, model, timings]
Expand All @@ -46,10 +46,11 @@ assets:
url: https://www.modelscope.cn/models/chenmohan/web-sdk-pp-tinypose/resolve/97c04100baef646f1b9c4d83295d8e2f14b4324d/tinypose-128x96/0.2.0/w16a32/tinypose-128x96-w16a32.onnx
sha256: 8671c7b424d85d4f017b6410602de6095b1fbb9fffca38ad5489039dd2a0cfea
limitations:
- 当前处理单人图片或调用者提供的人体框,没有内置人体检测器、自动多人检测、相机、视频或跟踪能力;score 为热力图响应,不是可见性概率。
- SDK继续接收单帧Blob/RGBA或调用者人体框;视频解码、摄像头权限和帧调度属于独立Demo。固定人体框不跟踪运动,没有内置人体检测器、自动多人、跟踪或动作识别;score 为热力图响应,不是可见性概率。
- 默认 ModelScope,另可选择 Hugging Face;两个来源使用固定提交并提供相同 SHA-256 的模型,显式来源或后端失败不会静默切换。
- 2026-09-17 三模型 × 双源 × WASM/WebGPU × 主线程/Worker 的最终 24 组合已通过真实图片推理,并核验已发布 npm、Pages 与 GitHub Release 的 0.2.0;证据见 SDK reports/2026-09-17-variants/online-browser.json 与同目录 release/ 回执。
- 2026-09-18 三模型 × 双源 × WASM/WebGPU × 主线程/Worker 的24组合通过真实图片推理;连续帧12组合共385帧。已核验npm、Pages与GitHub Release的0.3.0,证据见SDK reports/2026-09-17-media/及release/回执。
- 视频支持播放/暂停、单帧、暂停定位和固定选框;摄像头仅由用户开启、不采集音频,停止或隐藏页面释放资源。线上默认配置的视频及Chromium fake-device摄像头通过双语/390px验收;模拟摄像头不代表物理设备兼容。
- W16A32 仅用于 128×96,以 FP16 权重存储并转回 FP32 计算,不是普通 FP16 推理;普通 FP16 与 256×192 W16A32 未通过质量门槛,未发布。
- 2026-09-17 固定 64 图/110 人 GT 框子集平均 OKS 仅用于同批次比较,不是全量 COCO AP;不能据此宣称压缩模型或 GPU 普遍更快。
- 手机、其他浏览器、微信 web-view 和 WebNN/NPU 尚未验证;390px 视口检查不代表实体手机验证。
- 物理摄像头、手机、其他浏览器、微信 web-view 和 WebNN/NPU 尚未验证;390px 视口检查不代表实体手机验证,变化人物图片测试素材不证明真实动作质量
- SDK 与模型遵循 Apache-2.0,模型再分发须保留 LICENSE、NOTICE 和 PaddleDetection 上游归属;npm 包不包含 ONNX 权重。
8 changes: 5 additions & 3 deletions src/content/models/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { parse } from "yaml";
import { modelSchema } from "../../lib/registry/schema";

describe("model registry", () => {
it("登记 TinyPose 0.2.0 的三项稳定资产并保留桌面验证边界", () => {
it("登记 TinyPose 0.3.0 并保留单帧SDK与媒体Demo边界", () => {
const models = readdirSync("src/content/models")
.filter((file) => file.endsWith(".yaml"))
.map((file) => modelSchema.parse(parse(readFileSync(`src/content/models/${file}`, "utf8"))));
expect(models).toHaveLength(5);
const model = models.find((entry) => entry.id === "pp-tinypose");
expect(model).toBeDefined();
expect(model?.task).toBe("pose-estimation");
expect(model?.package).toEqual({ name: "web-sdk-pp-tinypose", version: "0.2.0" });
expect(model?.package).toEqual({ name: "web-sdk-pp-tinypose", version: "0.3.0" });
expect(model?.runtime.backends).toEqual([
{ name: "wasm", status: "stable" },
{ name: "webgpu", status: "stable" },
Expand Down Expand Up @@ -42,7 +42,9 @@ describe("model registry", () => {
},
]);
expect(model?.runtime.verifiedEnvironments).toHaveLength(2);
expect(model?.runtime.verifiedEnvironments.every((environment) => environment.testedAt === "2026-09-17")).toBe(true);
expect(model?.runtime.verifiedEnvironments.every((environment) => environment.testedAt === "2026-09-18")).toBe(true);
expect(model?.limitations.join(" ")).toContain("视频解码、摄像头权限和帧调度属于独立Demo");
expect(model?.limitations.join(" ")).toContain("模拟摄像头不代表物理设备兼容");
expect(model?.io.input).toEqual(["Blob", "RGBA", "region(调用者提供的人体框)"]);
expect(model?.io.output).toContain("17 个 COCO 关键点(原图坐标与 score)");
});
Expand Down
2 changes: 1 addition & 1 deletion src/pages/models/[slug].astro
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ const npmUrl = `https://www.npmjs.com/package/${data.package.name}`;
<SiteLayout title={`${data.name} · Web Model SDK`} description={data.summary}>
<header class="page-heading"><p class="eyebrow">{data.brand} · {taskDisplayNames[data.task] ?? data.task}</p><h1>{data.name}</h1><p>{data.summary}</p><p class="model-links"><a href={data.repository}>GitHub 仓库</a><a href={npmUrl}>npm 包</a></p></header>
{model.id === 'pp-detection' && <p><a href="/models/pp-detection/compare/">模型选型与对比 →</a></p>}
{model.id === 'pp-tinypose' && <p><a href="https://github.com/chenmohan123/web-sdk-PP-TinyPose/blob/v0.2.0/README.md">规格与精度对比 →</a></p>}
{model.id === 'pp-tinypose' && <p><a href="https://github.com/chenmohan123/web-sdk-PP-TinyPose/blob/v0.3.0/README.md">规格与精度对比 →</a></p>}
<div class="detail-grid"><article><h2>运行能力</h2><BackendTable runtime={data.runtime} /><h2>模型资源</h2><ul>{data.assets.map((asset) => <li><strong>{asset.id}</strong> · {mib(asset.bytes)} · SHA-256 已记录</li>)}</ul><h2>限制</h2><ul>{data.limitations.map((item) => <li>{item}</li>)}</ul><InstallBlock package={data.package} /></article><DemoPanel demo={data.demo} /></div>
</SiteLayout>
10 changes: 6 additions & 4 deletions tests/portal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { test, expect } from "@playwright/test";

for (const width of [1280, 390]) {
test(`TinyPose 0.2.0 在 ${width}px 展示三项资产、发布边界和独立 SDK 链接`, async ({ page }) => {
test(`TinyPose 0.3.0 在 ${width}px 展示三项资产、媒体边界和独立 SDK 链接`, async ({ page }) => {
await page.setViewportSize({ width, height: 844 });
await page.goto("/");
await expect(page.locator('astro-island[component-url*="ModelDirectory"]')).not.toHaveAttribute("ssr", "");
Expand All @@ -15,20 +15,22 @@ for (const width of [1280, 390]) {
await page.getByRole("link", { name: "PP-TinyPose", exact: true }).click();
await expect(page.getByRole("heading", { level: 1 })).toHaveText("PP-TinyPose");
await expect(page.getByText("baidu · 人体姿态", { exact: true })).toBeVisible();
await expect(page.getByText("web-sdk-pp-tinypose@0.2.0", { exact: true })).toBeVisible();
await expect(page.getByText("web-sdk-pp-tinypose@0.3.0", { exact: true })).toBeVisible();
await expect(page.getByText(/256×192.*128×96/)).toBeVisible();
await expect(page.getByRole("listitem").filter({ hasText: "tinypose-256x192-fp32" })).toContainText("5.42 MiB");
await expect(page.getByRole("listitem").filter({ has: page.getByText("tinypose-enhance-128x96", { exact: true }) })).toContainText("5.42 MiB");
await expect(page.getByRole("listitem").filter({ has: page.getByText("tinypose-enhance-128x96-w16a32", { exact: true }) })).toContainText("3.00 MiB");
await expect(page.getByRole("link", { name: "GitHub 仓库", exact: true })).toHaveAttribute("href", "https://github.com/chenmohan123/web-sdk-PP-TinyPose");
await expect(page.getByRole("link", { name: "npm 包", exact: true })).toHaveAttribute("href", "https://www.npmjs.com/package/web-sdk-pp-tinypose");
await expect(page.getByRole("link", { name: "打开在线 Demo", exact: true })).toHaveAttribute("href", "https://chenmohan123.github.io/web-sdk-PP-TinyPose/");
await expect(page.getByRole("link", { name: "规格与精度对比 →", exact: true })).toHaveAttribute("href", "https://github.com/chenmohan123/web-sdk-PP-TinyPose/blob/v0.2.0/README.md");
await expect(page.getByRole("link", { name: "规格与精度对比 →", exact: true })).toHaveAttribute("href", "https://github.com/chenmohan123/web-sdk-PP-TinyPose/blob/v0.3.0/README.md");
await expect(page.getByText(/score 为热力图响应,不是可见性概率/)).toBeVisible();
await expect(page.getByText(/默认 ModelScope.*Hugging Face/)).toBeVisible();
await expect(page.getByText(/W16A32.*FP16 权重.*FP32 计算/)).toBeVisible();
await expect(page.getByText(/普通 FP16.*256×192 W16A32.*未发布/)).toBeVisible();
await expect(page.getByText(/24 组合.*0\.2\.0/)).toBeVisible();
await expect(page.getByText(/24组合.*0\.3\.0/)).toBeVisible();
await expect(page.getByText(/视频解码、摄像头权限和帧调度属于独立Demo/)).toBeVisible();
await expect(page.getByText(/模拟摄像头不代表物理设备兼容/)).toBeVisible();
await expect(page.getByText(/GT 框子集平均 OKS.*不是全量 COCO AP/)).toBeVisible();
await expect(page.getByText(/手机.*尚未验证/)).toBeVisible();
expect(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth)).toBe(true);
Expand Down
Loading