Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
60036587a6 | ||
|
|
b37c350096 |
@@ -0,0 +1,3 @@
|
||||
# Safe local defaults. Do not add credentials, customer data, or production paths.
|
||||
BRAIN_DEVICE=auto
|
||||
BRAIN_LOG_LEVEL=INFO
|
||||
@@ -0,0 +1 @@
|
||||
3.11.15
|
||||
@@ -0,0 +1,90 @@
|
||||
# YoVision Brain
|
||||
|
||||
Brain 是无界面的独立推理交付单元。本骨架只提供可安装 Python 包、命令入口和运行时探测;尚不包含视频、模型、规则、事件或部署能力,也不依赖 Sense、Bell 在线。
|
||||
|
||||
## 冻结基线
|
||||
|
||||
| 项目 | 版本 / 选择 |
|
||||
|---|---|
|
||||
| Python | CPython `3.11.15`(`.python-version`;本机由 uv 隔离管理) |
|
||||
| 环境与包管理 | Python `venv` + pip `26.2.1`;可用 uv `0.11.6` 取得固定 Python |
|
||||
| 构建后端 | setuptools `80.9.0` |
|
||||
| 测试 | pytest `8.4.2` |
|
||||
| 数组运行时 | NumPy `2.3.3` |
|
||||
| 推理运行时 | PyTorch `2.12.1` |
|
||||
| CPU wheel | PyTorch 官方 `https://download.pytorch.org/whl/cpu` |
|
||||
| NVIDIA wheel | PyTorch 官方 CUDA 12.6 `https://download.pytorch.org/whl/cu126` |
|
||||
|
||||
选择 Python 3.11 是因为 PyTorch 的 Windows 支持范围包含 Python 3.9–3.12,并且本机已有隔离的 CPython 3.11.15。选择 `torch 2.12.1 + cu126` 是因为 PyTorch 官方为 Linux/Windows 同时发布该固定组合;NVIDIA 的 CUDA 12.x 兼容表要求 Windows 驱动至少为 528.33,本机驱动 566.24 满足运行 CUDA 12.6 wheel 的驱动前提。
|
||||
|
||||
本机安装的 CUDA Toolkit 11.2 不参与 PyTorch wheel 构建,也不因本项目而修改。驱动满足最低版本只是兼容前提,不等于 GPU 已验证;必须以 `--smoke cuda` 的真实结果为准。
|
||||
|
||||
官方依据:
|
||||
|
||||
- [PyTorch - Start Locally](https://docs.pytorch.org/get-started/locally/)
|
||||
- [PyTorch - Previous Versions](https://pytorch.org/get-started/previous-versions/)
|
||||
- [NVIDIA CUDA 12.6 Release Notes](https://docs.nvidia.com/cuda/archive/12.6.0/cuda-toolkit-release-notes/index.html)
|
||||
- [Python 3.11.15](https://www.python.org/downloads/release/python-31115/)
|
||||
|
||||
## 创建隔离环境
|
||||
|
||||
从仓库根目录执行。无需激活虚拟环境,也不需要更改 PowerShell 执行策略:
|
||||
|
||||
```powershell
|
||||
uv python install 3.11.15
|
||||
uv venv --python 3.11.15 Brain/.venv
|
||||
Brain\.venv\Scripts\python.exe -m pip install pip==26.2.1 --index-url https://pypi.org/simple
|
||||
Brain\.venv\Scripts\python.exe -m pip install -e "Brain[dev]" --index-url https://pypi.org/simple
|
||||
```
|
||||
|
||||
若不使用 uv,也可以让已安装的 Python 3.11.15 创建环境:
|
||||
|
||||
```powershell
|
||||
py -V:3.11 -m venv Brain/.venv
|
||||
Brain\.venv\Scripts\python.exe -m pip install pip==26.2.1 --index-url https://pypi.org/simple
|
||||
Brain\.venv\Scripts\python.exe -m pip install -e "Brain[dev]" --index-url https://pypi.org/simple
|
||||
```
|
||||
|
||||
## 安装运行时
|
||||
|
||||
CPU 环境使用 PyTorch 官方 CPU 索引:
|
||||
|
||||
```powershell
|
||||
Brain\.venv\Scripts\python.exe -m pip install numpy==2.3.3 --index-url https://pypi.org/simple
|
||||
Brain\.venv\Scripts\python.exe -m pip install torch==2.12.1 --index-url https://download.pytorch.org/whl/cpu
|
||||
```
|
||||
|
||||
目标 NVIDIA 环境使用官方 CUDA 12.6 wheel。该 wheel 自带所需 CUDA 用户态运行库,不要求把系统 Toolkit 改成 12.6:
|
||||
|
||||
```powershell
|
||||
Brain\.venv\Scripts\python.exe -m pip install numpy==2.3.3 --index-url https://pypi.org/simple
|
||||
Brain\.venv\Scripts\python.exe -m pip install torch==2.12.1 --index-url https://download.pytorch.org/whl/cu126
|
||||
```
|
||||
|
||||
不要在同一环境混装 CPU 与 CUDA wheel;切换后端时重建 `.venv`。
|
||||
|
||||
## 运行和验证
|
||||
|
||||
入口的帮助与版本查询不导入 PyTorch,因此未安装运行时时也可用:
|
||||
|
||||
```powershell
|
||||
Brain\.venv\Scripts\python.exe -m yovision_brain --help
|
||||
Brain\.venv\Scripts\python.exe -m yovision_brain --version
|
||||
```
|
||||
|
||||
安装相应运行时后执行:
|
||||
|
||||
```powershell
|
||||
Brain\.venv\Scripts\python.exe -m pytest Brain/tests/test_package.py -q
|
||||
Brain\.venv\Scripts\python.exe -m yovision_brain --runtime-info
|
||||
Brain\.venv\Scripts\python.exe -m yovision_brain --smoke cpu
|
||||
Brain\.venv\Scripts\python.exe -m yovision_brain --smoke cuda
|
||||
```
|
||||
|
||||
`--runtime-info` 只输出 Python、PyTorch 和设备能力,不读取或显示环境变量值。`--smoke cuda` 在 CUDA wheel、驱动或设备不可用时以非零状态退出,不会回退 CPU 后伪称成功。
|
||||
|
||||
## 配置与安全边界
|
||||
|
||||
`.env.example` 只有无秘密默认值。Brain 不接收用户会话,不持有账户、RBAC、Alert 或通知状态。不得把 token、摄像头凭据、客户数据、内部文件路径或未经授权的人脸信息写入配置、日志或事件。
|
||||
|
||||
第三方许可证与来源见 [THIRD_PARTY_NOTICES.md](THIRD_PARTY_NOTICES.md)。
|
||||
@@ -0,0 +1,17 @@
|
||||
# Third-party notices
|
||||
|
||||
本文件记录 Brain 骨架直接固定或明确依赖的第三方软件。具体安装包内许可证文本仍是最终依据。
|
||||
|
||||
| 组件 | 固定版本 | 许可证 | 来源 |
|
||||
|---|---:|---|---|
|
||||
| CPython | 3.11.15 | Python Software Foundation License | https://www.python.org/downloads/release/python-31115/ |
|
||||
| pip | 26.2.1 | MIT | https://github.com/pypa/pip/tree/26.2.1 |
|
||||
| uv(可选 Python 获取工具,不随 Brain 分发) | 0.11.6 | Apache-2.0 OR MIT | https://github.com/astral-sh/uv/tree/0.11.6 |
|
||||
| python-build-standalone(uv 管理的 Python 分发来源,不随 Brain 分发) | 2026 系列 | MPL-2.0;分发包内另含 CPython 与组件许可证 | https://github.com/astral-sh/python-build-standalone |
|
||||
| setuptools | 80.9.0 | MIT | https://github.com/pypa/setuptools/tree/v80.9.0 |
|
||||
| pytest | 8.4.2 | MIT | https://github.com/pytest-dev/pytest/tree/8.4.2 |
|
||||
| NumPy | 2.3.3 | BSD-3-Clause | https://github.com/numpy/numpy/tree/v2.3.3 |
|
||||
| PyTorch | 2.12.1 | BSD-3-Clause | https://github.com/pytorch/pytorch/tree/v2.12.1 |
|
||||
| NVIDIA CUDA runtime(随官方 PyTorch CUDA wheel 分发) | 12.6 系列 | NVIDIA CUDA Toolkit End User License Agreement | https://docs.nvidia.com/cuda/eula/index.html |
|
||||
|
||||
PyTorch 及后续模型可能带来额外第三方依赖与模型许可。本骨架未选择或分发任何模型;引入模型前必须另行核对商用、再分发、数据和输出限制,不能把框架许可证视为模型许可证。
|
||||
@@ -0,0 +1,27 @@
|
||||
[build-system]
|
||||
requires = ["setuptools==80.9.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "yovision-brain"
|
||||
version = "0.1.0"
|
||||
description = "Headless inference delivery unit for YoVision"
|
||||
readme = "README.md"
|
||||
requires-python = "==3.11.*"
|
||||
dependencies = []
|
||||
|
||||
[project.optional-dependencies]
|
||||
# The wheel backend is selected by the official PyTorch index documented in
|
||||
# README.md. Keeping one pinned requirement here prevents CPU/CUDA drift.
|
||||
runtime = ["numpy==2.3.3", "torch==2.12.1"]
|
||||
dev = ["pytest==8.4.2"]
|
||||
|
||||
[project.scripts]
|
||||
yovision-brain = "yovision_brain.__main__:main"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
testpaths = ["tests"]
|
||||
addopts = "--strict-markers"
|
||||
@@ -0,0 +1,5 @@
|
||||
"""YoVision Brain package."""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
||||
__all__ = ["__version__"]
|
||||
@@ -0,0 +1,112 @@
|
||||
"""Command-line entry point for safe Brain runtime diagnostics."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import platform
|
||||
from collections.abc import Sequence
|
||||
from typing import Any
|
||||
|
||||
from yovision_brain import __version__
|
||||
|
||||
|
||||
def _load_torch() -> Any:
|
||||
try:
|
||||
import torch
|
||||
except ImportError as exc:
|
||||
raise RuntimeError(
|
||||
"PyTorch runtime is not installed; install the pinned CPU or CUDA wheel "
|
||||
"from Brain/README.md"
|
||||
) from exc
|
||||
return torch
|
||||
|
||||
|
||||
def runtime_info() -> dict[str, object]:
|
||||
"""Return non-sensitive interpreter and compute-runtime facts."""
|
||||
info: dict[str, object] = {
|
||||
"python": platform.python_version(),
|
||||
"torch_installed": False,
|
||||
"torch_version": None,
|
||||
"cuda_build": None,
|
||||
"cuda_available": False,
|
||||
"cuda_device_count": 0,
|
||||
}
|
||||
try:
|
||||
torch = _load_torch()
|
||||
except RuntimeError:
|
||||
return info
|
||||
|
||||
cuda_available = bool(torch.cuda.is_available())
|
||||
info.update(
|
||||
{
|
||||
"torch_installed": True,
|
||||
"torch_version": torch.__version__,
|
||||
"cuda_build": torch.version.cuda,
|
||||
"cuda_available": cuda_available,
|
||||
"cuda_device_count": torch.cuda.device_count() if cuda_available else 0,
|
||||
}
|
||||
)
|
||||
return info
|
||||
|
||||
|
||||
def smoke(device: str) -> dict[str, object]:
|
||||
"""Run a deterministic tensor operation on exactly the requested device."""
|
||||
torch = _load_torch()
|
||||
if device == "cuda" and not torch.cuda.is_available():
|
||||
raise RuntimeError("CUDA was requested but PyTorch reports no available CUDA device")
|
||||
|
||||
tensor = torch.tensor([[1.0, 2.0], [3.0, 4.0]], device=device)
|
||||
result = tensor @ tensor
|
||||
expected = torch.tensor([[7.0, 10.0], [15.0, 22.0]], device=device)
|
||||
if not torch.equal(result, expected):
|
||||
raise RuntimeError("tensor smoke result did not match the expected value")
|
||||
|
||||
return {
|
||||
"status": "ok",
|
||||
"device": device,
|
||||
"torch_version": torch.__version__,
|
||||
"cuda_build": torch.version.cuda,
|
||||
}
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="yovision-brain",
|
||||
description="YoVision Brain runtime diagnostics",
|
||||
)
|
||||
parser.add_argument("--version", action="version", version=f"%(prog)s {__version__}")
|
||||
action = parser.add_mutually_exclusive_group()
|
||||
action.add_argument(
|
||||
"--runtime-info",
|
||||
action="store_true",
|
||||
help="print non-sensitive Python/PyTorch/CUDA capability information",
|
||||
)
|
||||
action.add_argument(
|
||||
"--smoke",
|
||||
choices=("cpu", "cuda"),
|
||||
help="run a tensor smoke test on exactly the selected device",
|
||||
)
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv: Sequence[str] | None = None) -> int:
|
||||
args = build_parser().parse_args(argv)
|
||||
try:
|
||||
if args.runtime_info:
|
||||
payload = runtime_info()
|
||||
elif args.smoke:
|
||||
payload = smoke(args.smoke)
|
||||
else:
|
||||
build_parser().print_help()
|
||||
return 0
|
||||
except RuntimeError as exc:
|
||||
print(json.dumps({"status": "error", "message": str(exc)}, ensure_ascii=False))
|
||||
return 2
|
||||
|
||||
print(json.dumps(payload, ensure_ascii=False, sort_keys=True))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
@@ -0,0 +1,46 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
|
||||
from yovision_brain import __version__
|
||||
from yovision_brain.__main__ import main, runtime_info, smoke
|
||||
|
||||
|
||||
def test_package_version() -> None:
|
||||
assert __version__ == "0.1.0"
|
||||
|
||||
|
||||
def test_module_help_runs_without_other_products() -> None:
|
||||
result = subprocess.run(
|
||||
[sys.executable, "-m", "yovision_brain", "--help"],
|
||||
check=False,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
)
|
||||
assert result.returncode == 0
|
||||
assert "YoVision Brain runtime diagnostics" in result.stdout
|
||||
|
||||
|
||||
def test_runtime_info_is_non_sensitive(capsys: pytest.CaptureFixture[str]) -> None:
|
||||
assert main(["--runtime-info"]) == 0
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
assert set(payload) == {
|
||||
"cuda_available",
|
||||
"cuda_build",
|
||||
"cuda_device_count",
|
||||
"python",
|
||||
"torch_installed",
|
||||
"torch_version",
|
||||
}
|
||||
assert payload == runtime_info()
|
||||
|
||||
|
||||
def test_cpu_tensor_smoke() -> None:
|
||||
pytest.importorskip("torch")
|
||||
result = smoke("cpu")
|
||||
assert result["status"] == "ok"
|
||||
assert result["device"] == "cpu"
|
||||
Reference in New Issue
Block a user