seetapsych-face-ex 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- seetapsych_face_ex-0.0.2/.github/workflows/ci.yml +156 -0
- seetapsych_face_ex-0.0.2/.github/workflows/publish.yml +188 -0
- seetapsych_face_ex-0.0.2/.gitignore +37 -0
- seetapsych_face_ex-0.0.2/DEVELOPMENT.md +96 -0
- seetapsych_face_ex-0.0.2/LICENSE +15 -0
- seetapsych_face_ex-0.0.2/PKG-INFO +102 -0
- seetapsych_face_ex-0.0.2/README.md +51 -0
- seetapsych_face_ex-0.0.2/examples/test_pipeline.py +45 -0
- seetapsych_face_ex-0.0.2/pyproject.toml +128 -0
- seetapsych_face_ex-0.0.2/seetapsych_face_ex/__init__.py +13 -0
- seetapsych_face_ex-0.0.2/seetapsych_face_ex/_version.py +24 -0
- seetapsych_face_ex-0.0.2/seetapsych_face_ex/dense_landmarks/model.py +38 -0
- seetapsych_face_ex-0.0.2/seetapsych_face_ex/dense_landmarks/package.py +198 -0
- seetapsych_face_ex-0.0.2/seetapsych_face_ex/modules/dense_landmarks.yml +46 -0
- seetapsych_face_ex-0.0.2/tests/__init__.py +0 -0
- seetapsych_face_ex-0.0.2/tests/test_face_ex.py +57 -0
- seetapsych_face_ex-0.0.2/uv.lock +2594 -0
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- main
|
|
7
|
+
- workflows
|
|
8
|
+
- "workflows/**"
|
|
9
|
+
tags-ignore: ["r*"]
|
|
10
|
+
pull_request:
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
lint:
|
|
18
|
+
name: Lint & Type & Security
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- uses: actions/checkout@v4
|
|
22
|
+
with:
|
|
23
|
+
fetch-depth: 0
|
|
24
|
+
|
|
25
|
+
- name: Derive package directory
|
|
26
|
+
id: pkg
|
|
27
|
+
run: |
|
|
28
|
+
REPO_NAME="${{ github.event.repository.name }}"
|
|
29
|
+
PACKAGE_DIR="${REPO_NAME//-/_}"
|
|
30
|
+
echo "PACKAGE_DIR=$PACKAGE_DIR" >> "$GITHUB_OUTPUT"
|
|
31
|
+
shell: bash
|
|
32
|
+
|
|
33
|
+
- name: Set up Python
|
|
34
|
+
uses: actions/setup-python@v5
|
|
35
|
+
with:
|
|
36
|
+
python-version: "3.12"
|
|
37
|
+
|
|
38
|
+
- name: Install uv
|
|
39
|
+
uses: astral-sh/setup-uv@v3
|
|
40
|
+
with:
|
|
41
|
+
enable-cache: true
|
|
42
|
+
|
|
43
|
+
- name: Install dependencies
|
|
44
|
+
run: uv sync --group dev
|
|
45
|
+
|
|
46
|
+
- name: Run all lint/type/security checks (collect all failures)
|
|
47
|
+
env:
|
|
48
|
+
PACKAGE_DIR: ${{ steps.pkg.outputs.PACKAGE_DIR }}
|
|
49
|
+
run: |
|
|
50
|
+
set +e
|
|
51
|
+
EXIT_CODE=0
|
|
52
|
+
|
|
53
|
+
echo "=== ruff check ==="
|
|
54
|
+
uv run ruff check .
|
|
55
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
56
|
+
|
|
57
|
+
echo ""
|
|
58
|
+
echo "=== ruff format --check ==="
|
|
59
|
+
uv run ruff format --check .
|
|
60
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
61
|
+
|
|
62
|
+
echo ""
|
|
63
|
+
echo "=== mypy ==="
|
|
64
|
+
uv run mypy "$PACKAGE_DIR"
|
|
65
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
66
|
+
|
|
67
|
+
echo ""
|
|
68
|
+
echo "=== bandit ==="
|
|
69
|
+
uv run bandit -r "$PACKAGE_DIR" -c pyproject.toml
|
|
70
|
+
EC=$?; [ $EC -ne 0 ] && EXIT_CODE=$EC
|
|
71
|
+
|
|
72
|
+
exit $EXIT_CODE
|
|
73
|
+
shell: bash
|
|
74
|
+
|
|
75
|
+
test:
|
|
76
|
+
name: Test (Python ${{ matrix.python-version }} on ${{ matrix.os }})
|
|
77
|
+
runs-on: ${{ matrix.os }}
|
|
78
|
+
needs: lint
|
|
79
|
+
strategy:
|
|
80
|
+
fail-fast: false
|
|
81
|
+
matrix:
|
|
82
|
+
include:
|
|
83
|
+
- python-version: "3.10"
|
|
84
|
+
os: ubuntu-latest
|
|
85
|
+
- python-version: "3.10"
|
|
86
|
+
os: windows-latest
|
|
87
|
+
- python-version: "3.11"
|
|
88
|
+
os: ubuntu-latest
|
|
89
|
+
- python-version: "3.11"
|
|
90
|
+
os: windows-latest
|
|
91
|
+
- python-version: "3.12"
|
|
92
|
+
os: ubuntu-latest
|
|
93
|
+
- python-version: "3.12"
|
|
94
|
+
os: windows-latest
|
|
95
|
+
- python-version: "3.12"
|
|
96
|
+
os: macos-latest
|
|
97
|
+
- python-version: "3.13"
|
|
98
|
+
os: ubuntu-latest
|
|
99
|
+
- python-version: "3.13"
|
|
100
|
+
os: windows-latest
|
|
101
|
+
- python-version: "3.14"
|
|
102
|
+
os: ubuntu-latest
|
|
103
|
+
- python-version: "3.14"
|
|
104
|
+
os: windows-latest
|
|
105
|
+
|
|
106
|
+
steps:
|
|
107
|
+
- uses: actions/checkout@v4
|
|
108
|
+
with:
|
|
109
|
+
fetch-depth: 0
|
|
110
|
+
|
|
111
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
112
|
+
uses: actions/setup-python@v5
|
|
113
|
+
with:
|
|
114
|
+
python-version: ${{ matrix.python-version }}
|
|
115
|
+
|
|
116
|
+
- name: Install uv
|
|
117
|
+
uses: astral-sh/setup-uv@v3
|
|
118
|
+
with:
|
|
119
|
+
enable-cache: true
|
|
120
|
+
|
|
121
|
+
- name: Install dependencies
|
|
122
|
+
run: uv sync --group dev
|
|
123
|
+
|
|
124
|
+
- name: Run pytest
|
|
125
|
+
run: uv run pytest
|
|
126
|
+
|
|
127
|
+
build:
|
|
128
|
+
name: Build package
|
|
129
|
+
runs-on: ubuntu-latest
|
|
130
|
+
needs: test
|
|
131
|
+
|
|
132
|
+
steps:
|
|
133
|
+
- uses: actions/checkout@v4
|
|
134
|
+
with:
|
|
135
|
+
fetch-depth: 0
|
|
136
|
+
|
|
137
|
+
- name: Set up Python
|
|
138
|
+
uses: actions/setup-python@v5
|
|
139
|
+
with:
|
|
140
|
+
python-version: "3.12"
|
|
141
|
+
|
|
142
|
+
- name: Install build tools
|
|
143
|
+
run: python -m pip install --upgrade build twine
|
|
144
|
+
|
|
145
|
+
- name: Build package
|
|
146
|
+
run: python -m build
|
|
147
|
+
|
|
148
|
+
- name: Verify built artifacts
|
|
149
|
+
run: twine check dist/*
|
|
150
|
+
|
|
151
|
+
- name: Upload dist artifacts
|
|
152
|
+
uses: actions/upload-artifact@v4
|
|
153
|
+
with:
|
|
154
|
+
name: dist-artifacts
|
|
155
|
+
path: dist/
|
|
156
|
+
if-no-files-found: error
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
name: Publish to PyPI & GitHub Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "r*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
name: Pytest smoke gate
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
with:
|
|
15
|
+
fetch-depth: 0
|
|
16
|
+
|
|
17
|
+
- name: Set up Python
|
|
18
|
+
uses: actions/setup-python@v5
|
|
19
|
+
with:
|
|
20
|
+
python-version: "3.12"
|
|
21
|
+
|
|
22
|
+
- name: Install uv
|
|
23
|
+
uses: astral-sh/setup-uv@v3
|
|
24
|
+
with:
|
|
25
|
+
enable-cache: true
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync --group dev
|
|
29
|
+
|
|
30
|
+
- name: Run pytest (release gate)
|
|
31
|
+
run: uv run pytest
|
|
32
|
+
|
|
33
|
+
github-release:
|
|
34
|
+
name: Build and create GitHub Release
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
needs: test
|
|
37
|
+
permissions:
|
|
38
|
+
contents: write
|
|
39
|
+
|
|
40
|
+
steps:
|
|
41
|
+
- uses: actions/checkout@v4
|
|
42
|
+
with:
|
|
43
|
+
fetch-depth: 0
|
|
44
|
+
|
|
45
|
+
- name: Set up Python
|
|
46
|
+
uses: actions/setup-python@v5
|
|
47
|
+
with:
|
|
48
|
+
python-version: "3.12"
|
|
49
|
+
|
|
50
|
+
- name: Install build tools
|
|
51
|
+
run: python -m pip install --upgrade build twine
|
|
52
|
+
|
|
53
|
+
- name: Build package
|
|
54
|
+
run: python -m build
|
|
55
|
+
|
|
56
|
+
- name: Verify built artifacts
|
|
57
|
+
run: twine check dist/*
|
|
58
|
+
|
|
59
|
+
- name: Extract tag name
|
|
60
|
+
id: get_tag
|
|
61
|
+
run: echo "TAG=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
|
|
62
|
+
shell: bash
|
|
63
|
+
|
|
64
|
+
- name: Determine release type
|
|
65
|
+
id: release_type
|
|
66
|
+
run: |
|
|
67
|
+
TAG="${{ steps.get_tag.outputs.TAG }}"
|
|
68
|
+
if [[ "$TAG" == *-* ]]; then
|
|
69
|
+
echo "PYPI_PUBLISH=false" >> "$GITHUB_OUTPUT"
|
|
70
|
+
echo "PRERELEASE=true" >> "$GITHUB_OUTPUT"
|
|
71
|
+
else
|
|
72
|
+
echo "PYPI_PUBLISH=true" >> "$GITHUB_OUTPUT"
|
|
73
|
+
echo "PRERELEASE=false" >> "$GITHUB_OUTPUT"
|
|
74
|
+
fi
|
|
75
|
+
shell: bash
|
|
76
|
+
|
|
77
|
+
- name: Discover dist assets
|
|
78
|
+
id: assets
|
|
79
|
+
run: |
|
|
80
|
+
SDIST=$(ls dist/*.tar.gz | head -n1)
|
|
81
|
+
WHEEL=$(ls dist/*.whl | head -n1)
|
|
82
|
+
echo "SDIST=$SDIST" >> "$GITHUB_OUTPUT"
|
|
83
|
+
echo "WHEEL=$WHEEL" >> "$GITHUB_OUTPUT"
|
|
84
|
+
echo "SDIST_NAME=$(basename $SDIST)" >> "$GITHUB_OUTPUT"
|
|
85
|
+
echo "WHEEL_NAME=$(basename $WHEEL)" >> "$GITHUB_OUTPUT"
|
|
86
|
+
shell: bash
|
|
87
|
+
|
|
88
|
+
- name: Compose release body
|
|
89
|
+
id: release_body
|
|
90
|
+
env:
|
|
91
|
+
PYPI_PUBLISH: ${{ steps.release_type.outputs.PYPI_PUBLISH }}
|
|
92
|
+
REPO: ${{ github.repository }}
|
|
93
|
+
GITHUB_REF_NAME: ${{ github.ref_name }}
|
|
94
|
+
run: |
|
|
95
|
+
PROJ_NAME="${REPO#*/}"
|
|
96
|
+
VERSION="${GITHUB_REF_NAME#r}"
|
|
97
|
+
BODY_FILE=$(mktemp)
|
|
98
|
+
if [ "$PYPI_PUBLISH" = "true" ]; then
|
|
99
|
+
{
|
|
100
|
+
echo "Install from PyPI:"
|
|
101
|
+
echo ""
|
|
102
|
+
echo '```bash'
|
|
103
|
+
echo "pip install ${PROJ_NAME}==${VERSION}"
|
|
104
|
+
echo '```'
|
|
105
|
+
echo ""
|
|
106
|
+
echo "PyPI page: https://pypi.org/project/${PROJ_NAME}/${VERSION}/"
|
|
107
|
+
} >"$BODY_FILE"
|
|
108
|
+
else
|
|
109
|
+
{
|
|
110
|
+
echo "**Preview build** \u2014 available only from GitHub Assets."
|
|
111
|
+
echo ""
|
|
112
|
+
echo "This build is not published to PyPI."
|
|
113
|
+
echo ""
|
|
114
|
+
echo "To try it, download the wheel from the Assets section below and install:"
|
|
115
|
+
echo ""
|
|
116
|
+
echo '```bash'
|
|
117
|
+
echo "pip install ./${PROJ_NAME}-*.whl"
|
|
118
|
+
echo '```'
|
|
119
|
+
} >"$BODY_FILE"
|
|
120
|
+
fi
|
|
121
|
+
{
|
|
122
|
+
echo "BODY<<GITHUB_EOF_MARKER"
|
|
123
|
+
cat "$BODY_FILE"
|
|
124
|
+
echo "GITHUB_EOF_MARKER"
|
|
125
|
+
} >> "$GITHUB_OUTPUT"
|
|
126
|
+
rm -f "$BODY_FILE"
|
|
127
|
+
shell: bash
|
|
128
|
+
|
|
129
|
+
- name: Upload dist artifacts
|
|
130
|
+
uses: actions/upload-artifact@v4
|
|
131
|
+
with:
|
|
132
|
+
name: dist-artifacts-${{ steps.get_tag.outputs.TAG }}
|
|
133
|
+
path: dist/
|
|
134
|
+
if-no-files-found: error
|
|
135
|
+
|
|
136
|
+
- name: Create GitHub Release
|
|
137
|
+
id: create_release
|
|
138
|
+
uses: actions/create-release@v1
|
|
139
|
+
env:
|
|
140
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
141
|
+
with:
|
|
142
|
+
tag_name: ${{ steps.get_tag.outputs.TAG }}
|
|
143
|
+
release_name: Release ${{ steps.get_tag.outputs.TAG }}
|
|
144
|
+
body: ${{ steps.release_body.outputs.BODY }}
|
|
145
|
+
draft: false
|
|
146
|
+
prerelease: ${{ steps.release_type.outputs.PRERELEASE }}
|
|
147
|
+
|
|
148
|
+
- name: Upload sdist to GitHub Release
|
|
149
|
+
uses: actions/upload-release-asset@v1
|
|
150
|
+
env:
|
|
151
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
152
|
+
with:
|
|
153
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
154
|
+
asset_path: ${{ steps.assets.outputs.SDIST }}
|
|
155
|
+
asset_name: ${{ steps.assets.outputs.SDIST_NAME }}
|
|
156
|
+
asset_content_type: application/gzip
|
|
157
|
+
|
|
158
|
+
- name: Upload wheel to GitHub Release
|
|
159
|
+
uses: actions/upload-release-asset@v1
|
|
160
|
+
env:
|
|
161
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
162
|
+
with:
|
|
163
|
+
upload_url: ${{ steps.create_release.outputs.upload_url }}
|
|
164
|
+
asset_path: ${{ steps.assets.outputs.WHEEL }}
|
|
165
|
+
asset_name: ${{ steps.assets.outputs.WHEEL_NAME }}
|
|
166
|
+
asset_content_type: application/zip
|
|
167
|
+
|
|
168
|
+
pypi-publish:
|
|
169
|
+
name: Publish to PyPI
|
|
170
|
+
runs-on: ubuntu-latest
|
|
171
|
+
needs: github-release
|
|
172
|
+
if: startsWith(github.ref, 'refs/tags/r') && !contains(github.ref_name, '-')
|
|
173
|
+
environment:
|
|
174
|
+
name: pypi
|
|
175
|
+
url: https://pypi.org/p/${{ github.event.repository.name }}
|
|
176
|
+
permissions:
|
|
177
|
+
id-token: write
|
|
178
|
+
contents: read
|
|
179
|
+
|
|
180
|
+
steps:
|
|
181
|
+
- name: Download dist artifacts from github-release job
|
|
182
|
+
uses: actions/download-artifact@v4
|
|
183
|
+
with:
|
|
184
|
+
name: dist-artifacts-${{ github.ref_name }}
|
|
185
|
+
path: dist
|
|
186
|
+
|
|
187
|
+
- name: Publish package distributions to PyPI
|
|
188
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# project
|
|
2
|
+
/.idea/
|
|
3
|
+
/.venv/
|
|
4
|
+
/build/
|
|
5
|
+
/dist/
|
|
6
|
+
/*.egg-info/
|
|
7
|
+
/.eggs/
|
|
8
|
+
/.pytest_cache/
|
|
9
|
+
/.mypy_cache/
|
|
10
|
+
/.ruff_cache/
|
|
11
|
+
/.tox/
|
|
12
|
+
/.nox/
|
|
13
|
+
/htmlcov/
|
|
14
|
+
/.coverage
|
|
15
|
+
/coverage.xml
|
|
16
|
+
/.hypothesis/
|
|
17
|
+
/.cache/
|
|
18
|
+
/.upload/
|
|
19
|
+
/.streamlit/
|
|
20
|
+
/.ipynb_checkpoints/
|
|
21
|
+
*.log
|
|
22
|
+
.env
|
|
23
|
+
|
|
24
|
+
# generated files
|
|
25
|
+
seetapsych_face_ex/_version.py
|
|
26
|
+
|
|
27
|
+
# compiled files
|
|
28
|
+
*.pyc
|
|
29
|
+
__pycache__/
|
|
30
|
+
*.pyo
|
|
31
|
+
*.pyd
|
|
32
|
+
*.so
|
|
33
|
+
*$py.class
|
|
34
|
+
|
|
35
|
+
# models
|
|
36
|
+
*.onnx
|
|
37
|
+
*.safetensors
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Development Guide
|
|
2
|
+
|
|
3
|
+
## Local Verification (Before Creating a Release Tag)
|
|
4
|
+
|
|
5
|
+
Run these commands from the repository root. Make sure you have [`uv`](https://github.com/astral-sh/uv) installed.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Per-project: set PACKAGE to the top-level importable package directory
|
|
9
|
+
PACKAGE=seetapsych_face_ex
|
|
10
|
+
# For any seetapsych-* project, auto-detect instead:
|
|
11
|
+
# PACKAGE="$(ls -d seetapsych_* 2>/dev/null | head -n1)"
|
|
12
|
+
|
|
13
|
+
# 1. Sync dependencies (installs the package + dev tools)
|
|
14
|
+
uv sync --group dev
|
|
15
|
+
|
|
16
|
+
# 2. Lint (ruff) (use `ruff check . --fix` to fix)
|
|
17
|
+
uv run ruff check .
|
|
18
|
+
|
|
19
|
+
# 3. Format check (ruff format -- non-destructive; use `ruff format` to apply)
|
|
20
|
+
uv run ruff format --check .
|
|
21
|
+
|
|
22
|
+
# 4. Static type check (mypy, strict mode)
|
|
23
|
+
uv run mypy "$PACKAGE"
|
|
24
|
+
|
|
25
|
+
# 5. Security scan (bandit)
|
|
26
|
+
uv run bandit -r "$PACKAGE" -c pyproject.toml
|
|
27
|
+
|
|
28
|
+
# 6. Unit tests (pytest)
|
|
29
|
+
uv run pytest
|
|
30
|
+
|
|
31
|
+
# 7. Build the distribution packages + verify metadata
|
|
32
|
+
uv run python -m build
|
|
33
|
+
uv run twine check dist/*
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
If all seven steps pass, the code is ready to be tagged for release.
|
|
37
|
+
|
|
38
|
+
## Tag Naming and Release Pipeline
|
|
39
|
+
|
|
40
|
+
Tag format is managed by [`hatch-vcs`](https://github.com/ofek/hatch-vcs) with the following pattern in `pyproject.toml`:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
tag-pattern = "^r(?P<version>[^-]+)$"
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This separates tags into two classes that drive the GitHub Actions pipeline in `.github/workflows/publish.yml`:
|
|
47
|
+
|
|
48
|
+
### Class A — Official Release: `r<version>` (no `-`)
|
|
49
|
+
|
|
50
|
+
**Format**: `r` + a version string that contains **no hyphen** `-`.
|
|
51
|
+
|
|
52
|
+
Examples:
|
|
53
|
+
- `r0.1.0`
|
|
54
|
+
- `r2026.08.30`
|
|
55
|
+
- `r1.0.0.post1`
|
|
56
|
+
|
|
57
|
+
Pipeline behavior:
|
|
58
|
+
1. CI runs (lint + test + build).
|
|
59
|
+
2. `github-release` job builds sdist + wheel, **creates a GitHub Release** (`prerelease: false`), attaches both assets, and links to the PyPI version page.
|
|
60
|
+
3. `pypi-publish` job runs (`if: no '-' in tag`) and uploads the same sdist + wheel to PyPI via Trusted Publisher (OIDC, no API token required).
|
|
61
|
+
|
|
62
|
+
### Class B — Temporary / Pre-release: `r<version>-<suffix>`
|
|
63
|
+
|
|
64
|
+
**Format**: `r` + anything + **at least one hyphen** `-` + anything.
|
|
65
|
+
|
|
66
|
+
Examples:
|
|
67
|
+
- `r0.2.0-alpha`
|
|
68
|
+
- `r0.2.0-rc1`
|
|
69
|
+
- `r2026.08.30-tmp-hotfix-42`
|
|
70
|
+
- `r1.0.0-just-testing-release-flow`
|
|
71
|
+
|
|
72
|
+
Pipeline behavior:
|
|
73
|
+
1. CI still runs (same lint + test + build gates — everything must still pass).
|
|
74
|
+
2. `github-release` job builds sdist + wheel, creates a GitHub Release **marked as `prerelease: true`**, attaches both assets, and the release body clearly states "not published to PyPI".
|
|
75
|
+
3. `pypi-publish` job is **skipped** (`if:` condition fails because the tag contains `-`). Nothing is uploaded to PyPI.
|
|
76
|
+
|
|
77
|
+
### Quick Tagging Recipe
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# --- official release (PyPI + GitHub Release) ---
|
|
81
|
+
git tag r0.1.0
|
|
82
|
+
git push origin r0.1.0
|
|
83
|
+
|
|
84
|
+
# --- temp / pre-release (GitHub Release only, PyPI skipped) ---
|
|
85
|
+
git tag r0.1.0-alpha
|
|
86
|
+
git push origin r0.1.0-alpha
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Why the two classes?
|
|
90
|
+
|
|
91
|
+
Use Class B tags whenever you want to:
|
|
92
|
+
- exercise the full build + release-creation pipeline end-to-end without polluting PyPI,
|
|
93
|
+
- ship a throwaway build for QA or a staging consumer that can pull GitHub Release assets directly,
|
|
94
|
+
- share candidate wheels for a hotfix before cutting the final tag.
|
|
95
|
+
|
|
96
|
+
When the candidate is validated, re-tag without the suffix (e.g., `r0.1.0`) and push — the same CI gates run again, followed by the official PyPI publish.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
Copyright (c) 2026, Visual Information Processing and Learning (VIPL) group,
|
|
2
|
+
Institute of Computing Technology, Chinese Academy of Sciences, Beijing, China;
|
|
3
|
+
Southeast University, China;
|
|
4
|
+
Beijing Seetatech Co., Ltd.
|
|
5
|
+
All rights reserved.
|
|
6
|
+
|
|
7
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
12
|
+
|
|
13
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
14
|
+
|
|
15
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: seetapsych-face-ex
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Enhanced face modules for SeetaPsych
|
|
5
|
+
Project-URL: Homepage, https://github.com/seetapsych/seetapsych-face-ex
|
|
6
|
+
Project-URL: Repository, https://github.com/seetapsych/seetapsych-face-ex
|
|
7
|
+
Project-URL: Issues, https://github.com/seetapsych/seetapsych-face-ex/issues
|
|
8
|
+
License: Copyright (c) 2026, Visual Information Processing and Learning (VIPL) group,
|
|
9
|
+
Institute of Computing Technology, Chinese Academy of Sciences, Beijing, China;
|
|
10
|
+
Southeast University, China;
|
|
11
|
+
Beijing Seetatech Co., Ltd.
|
|
12
|
+
All rights reserved.
|
|
13
|
+
|
|
14
|
+
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
|
15
|
+
|
|
16
|
+
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
17
|
+
|
|
18
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
|
19
|
+
|
|
20
|
+
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
|
21
|
+
|
|
22
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Python: >=3.10
|
|
25
|
+
Requires-Dist: seetapsych-lib
|
|
26
|
+
Provides-Extra: all
|
|
27
|
+
Requires-Dist: numpy>=2.2.6; extra == 'all'
|
|
28
|
+
Requires-Dist: onnx>=1.20.1; extra == 'all'
|
|
29
|
+
Requires-Dist: onnxruntime-gpu<1.24; (sys_platform != 'darwin' and python_version <= '3.10') and extra == 'all'
|
|
30
|
+
Requires-Dist: onnxruntime-gpu>=1.24; (sys_platform != 'darwin' and python_version > '3.10') and extra == 'all'
|
|
31
|
+
Requires-Dist: onnxruntime<1.24; (sys_platform == 'darwin' and python_version <= '3.10') and extra == 'all'
|
|
32
|
+
Requires-Dist: onnxruntime>=1.24; (sys_platform == 'darwin' and python_version > '3.10') and extra == 'all'
|
|
33
|
+
Requires-Dist: opencv-python>=4.11.0.86; extra == 'all'
|
|
34
|
+
Requires-Dist: scikit-image>=0.25.2; extra == 'all'
|
|
35
|
+
Provides-Extra: dev
|
|
36
|
+
Requires-Dist: bandit>=1.7; extra == 'dev'
|
|
37
|
+
Requires-Dist: build>=1.4.4; extra == 'dev'
|
|
38
|
+
Requires-Dist: mypy>=1.11; extra == 'dev'
|
|
39
|
+
Requires-Dist: numpy>=2.2.6; extra == 'dev'
|
|
40
|
+
Requires-Dist: onnx>=1.20.1; extra == 'dev'
|
|
41
|
+
Requires-Dist: onnxruntime-gpu<1.24; (sys_platform != 'darwin' and python_version <= '3.10') and extra == 'dev'
|
|
42
|
+
Requires-Dist: onnxruntime-gpu>=1.24; (sys_platform != 'darwin' and python_version > '3.10') and extra == 'dev'
|
|
43
|
+
Requires-Dist: onnxruntime<1.24; (sys_platform == 'darwin' and python_version <= '3.10') and extra == 'dev'
|
|
44
|
+
Requires-Dist: onnxruntime>=1.24; (sys_platform == 'darwin' and python_version > '3.10') and extra == 'dev'
|
|
45
|
+
Requires-Dist: opencv-python>=4.11.0.86; extra == 'dev'
|
|
46
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
47
|
+
Requires-Dist: ruff>=0.6; extra == 'dev'
|
|
48
|
+
Requires-Dist: scikit-image>=0.25.2; extra == 'dev'
|
|
49
|
+
Requires-Dist: twine>=6.2.0; extra == 'dev'
|
|
50
|
+
Description-Content-Type: text/markdown
|
|
51
|
+
|
|
52
|
+
# SeetaPsych Face Enhanced
|
|
53
|
+
|
|
54
|
+
> Enhanced face modules for SeetaPsych
|
|
55
|
+
|
|
56
|
+
## Usage
|
|
57
|
+
|
|
58
|
+
This project is already included in the seetapsych-lib default configuration. Download and use it via `seetapsych-manager download`.
|
|
59
|
+
|
|
60
|
+
For usage, refer to [SeetaPsych](https://github.com/seetapsych/seetapsych-lib).
|
|
61
|
+
|
|
62
|
+
You can additionally add this algorithm module using the following methods.
|
|
63
|
+
|
|
64
|
+
### WebUI
|
|
65
|
+
|
|
66
|
+
Run `seetapsych-webui` with the `--dirs` argument to use it.
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
seetapsych-webui --files seetapsych_face_ex/modules/dense_landmarks.yml
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### Programmatic Usage
|
|
73
|
+
|
|
74
|
+
Add the following code in your program to use this algorithm module.
|
|
75
|
+
```python
|
|
76
|
+
from seetapsych_lib.runtime.factory import Factory
|
|
77
|
+
from seetapsych_lib.runtime.pipeline import Pipeline
|
|
78
|
+
|
|
79
|
+
factory = Factory()
|
|
80
|
+
factory.load_file_modules("seetapsych_face_ex/modules/dense_landmarks.yml")
|
|
81
|
+
|
|
82
|
+
pipeline = Pipeline(factory, ...)
|
|
83
|
+
|
|
84
|
+
pipeline.add_attributes("face/dense_landmarks")
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Introduction
|
|
88
|
+
|
|
89
|
+
### SeetaDenseLandmarks
|
|
90
|
+
|
|
91
|
+
ONNX-based dense facial landmark detection model by SeetaPsych, capable of detecting 280 2D landmarks. Accepts either a face bounding box or sparse landmarks (2/5/280 points) as input. When given a bbox, it first predicts an initial coarse set, then optionally runs a refinement pass aligned via 5-point similarity transform. Network input size is fixed at 192x192.
|
|
92
|
+
|
|
93
|
+
Module config: [dense_landmarks.yml](seetapsych_face_ex/modules/dense_landmarks.yml).
|
|
94
|
+
Provide Attributes: `face/dense_landmarks`.
|
|
95
|
+
|
|
96
|
+
Requires: `face/detection` (primary). Optionally leverages `face/landmarks` if available for better alignment.
|
|
97
|
+
|
|
98
|
+
Available model: `seeta-face-ex-dense-landmarks-280.onnx` (recommended).
|
|
99
|
+
|
|
100
|
+
Parameters:
|
|
101
|
+
- `refine` (bool, default `true`): Enable the second-pass refinement using 5-point similarity alignment.
|
|
102
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# SeetaPsych Face Enhanced
|
|
2
|
+
|
|
3
|
+
> Enhanced face modules for SeetaPsych
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
This project is already included in the seetapsych-lib default configuration. Download and use it via `seetapsych-manager download`.
|
|
8
|
+
|
|
9
|
+
For usage, refer to [SeetaPsych](https://github.com/seetapsych/seetapsych-lib).
|
|
10
|
+
|
|
11
|
+
You can additionally add this algorithm module using the following methods.
|
|
12
|
+
|
|
13
|
+
### WebUI
|
|
14
|
+
|
|
15
|
+
Run `seetapsych-webui` with the `--dirs` argument to use it.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
seetapsych-webui --files seetapsych_face_ex/modules/dense_landmarks.yml
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Programmatic Usage
|
|
22
|
+
|
|
23
|
+
Add the following code in your program to use this algorithm module.
|
|
24
|
+
```python
|
|
25
|
+
from seetapsych_lib.runtime.factory import Factory
|
|
26
|
+
from seetapsych_lib.runtime.pipeline import Pipeline
|
|
27
|
+
|
|
28
|
+
factory = Factory()
|
|
29
|
+
factory.load_file_modules("seetapsych_face_ex/modules/dense_landmarks.yml")
|
|
30
|
+
|
|
31
|
+
pipeline = Pipeline(factory, ...)
|
|
32
|
+
|
|
33
|
+
pipeline.add_attributes("face/dense_landmarks")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Introduction
|
|
37
|
+
|
|
38
|
+
### SeetaDenseLandmarks
|
|
39
|
+
|
|
40
|
+
ONNX-based dense facial landmark detection model by SeetaPsych, capable of detecting 280 2D landmarks. Accepts either a face bounding box or sparse landmarks (2/5/280 points) as input. When given a bbox, it first predicts an initial coarse set, then optionally runs a refinement pass aligned via 5-point similarity transform. Network input size is fixed at 192x192.
|
|
41
|
+
|
|
42
|
+
Module config: [dense_landmarks.yml](seetapsych_face_ex/modules/dense_landmarks.yml).
|
|
43
|
+
Provide Attributes: `face/dense_landmarks`.
|
|
44
|
+
|
|
45
|
+
Requires: `face/detection` (primary). Optionally leverages `face/landmarks` if available for better alignment.
|
|
46
|
+
|
|
47
|
+
Available model: `seeta-face-ex-dense-landmarks-280.onnx` (recommended).
|
|
48
|
+
|
|
49
|
+
Parameters:
|
|
50
|
+
- `refine` (bool, default `true`): Enable the second-pass refinement using 5-point similarity alignment.
|
|
51
|
+
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
|
|
5
|
+
import cv2
|
|
6
|
+
import numpy
|
|
7
|
+
from seetapsych_lib.runtime.factory import Factory
|
|
8
|
+
from seetapsych_lib.runtime.pipeline import Pipeline
|
|
9
|
+
from seetapsych_lib.runtime.runner import Runner
|
|
10
|
+
|
|
11
|
+
face_module_root = os.path.join(os.path.dirname(__file__), "../../seetapsych-face-hub/seetapsych_face_hub/modules")
|
|
12
|
+
face_open_module_root = os.path.join(os.path.dirname(__file__), "../../seetapsych-face-ex/seetapsych_face_ex/modules")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main():
|
|
16
|
+
factory = Factory()
|
|
17
|
+
factory.load_dir_modules(face_module_root)
|
|
18
|
+
factory.load_dir_modules(face_open_module_root)
|
|
19
|
+
|
|
20
|
+
pipeline = Pipeline(factory, attributes=["face/dense_landmarks"])
|
|
21
|
+
|
|
22
|
+
pipeline.solve()
|
|
23
|
+
|
|
24
|
+
print(pipeline.problem())
|
|
25
|
+
print(pipeline.satisfied())
|
|
26
|
+
|
|
27
|
+
runner = Runner(pipeline)
|
|
28
|
+
|
|
29
|
+
image = cv2.imread("data/huge.png")
|
|
30
|
+
report = runner.run(data={"default": image})
|
|
31
|
+
print(json.dumps(report, indent=2, ensure_ascii=False))
|
|
32
|
+
|
|
33
|
+
face_dense_landmarks = report["face_dense_landmarks"]
|
|
34
|
+
landmarks = face_dense_landmarks[0]["landmarks"]
|
|
35
|
+
|
|
36
|
+
landmarks = numpy.array(landmarks).reshape([-1, 2]).astype(numpy.int32)
|
|
37
|
+
|
|
38
|
+
for p in landmarks:
|
|
39
|
+
cv2.circle(image, p, 2, (0, 255, 0), -1)
|
|
40
|
+
|
|
41
|
+
cv2.imwrite("output.png", image)
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
if __name__ == "__main__":
|
|
45
|
+
main()
|