Spaces:
Running on Zero
Running on Zero
chore(01-02): bootstrap Python 3.12 toolchain, Git LFS and package skeleton
Browse files- Pin Python 3.12.12 (.python-version) to match the ZeroGPU runtime; 3.11 and
3.13 are both invalid there
- Arm Git LFS for .vrm/.vvm/.wav/.onnx before any binary lands in the repo
- Add pyproject.toml with pytest ini options, ruff config and a dev extra
- Create src/japanese_avatar package skeleton (ui, voice, telemetry) and tests/
- Add tests/test_scaffold.py proving interpreter version, importability, config
and LFS arming
- Commit uv.lock so Space rebuilds are reproducible
- .gitattributes +4 -0
- .gitignore +9 -0
- .python-version +1 -0
- pyproject.toml +50 -0
- src/japanese_avatar/__init__.py +1 -0
- src/japanese_avatar/telemetry/__init__.py +0 -0
- src/japanese_avatar/ui/__init__.py +0 -0
- src/japanese_avatar/voice/__init__.py +0 -0
- tests/__init__.py +0 -0
- tests/e2e/__init__.py +0 -0
- tests/test_scaffold.py +34 -0
- uv.lock +0 -0
.gitattributes
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.vrm filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.vvm filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.wav filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
.gitignore
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
*.pyc
|
| 4 |
+
.pytest_cache/
|
| 5 |
+
.ruff_cache/
|
| 6 |
+
node_modules/
|
| 7 |
+
.env
|
| 8 |
+
voicevox_runtime/
|
| 9 |
+
test-results/
|
.python-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
3.12.12
|
pyproject.toml
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
[project]
|
| 2 |
+
name = "japanese-learning-avatar"
|
| 3 |
+
version = "0.1.0"
|
| 4 |
+
description = "A lip-synced VRM avatar that speaks and hears Japanese, on a Hugging Face Space"
|
| 5 |
+
requires-python = ">=3.12,<3.13"
|
| 6 |
+
dependencies = [
|
| 7 |
+
"gradio==6.22.0",
|
| 8 |
+
"spaces==0.51.1",
|
| 9 |
+
"huggingface_hub==1.28.0",
|
| 10 |
+
]
|
| 11 |
+
|
| 12 |
+
[project.optional-dependencies]
|
| 13 |
+
dev = [
|
| 14 |
+
"pytest>=8.0",
|
| 15 |
+
"pytest-playwright>=0.5",
|
| 16 |
+
"playwright>=1.48",
|
| 17 |
+
"ruff>=0.6",
|
| 18 |
+
"numpy>=1.26",
|
| 19 |
+
"requests>=2.32",
|
| 20 |
+
]
|
| 21 |
+
|
| 22 |
+
[build-system]
|
| 23 |
+
requires = ["hatchling"]
|
| 24 |
+
build-backend = "hatchling.build"
|
| 25 |
+
|
| 26 |
+
[tool.hatch.build.targets.wheel]
|
| 27 |
+
packages = ["src/japanese_avatar"]
|
| 28 |
+
|
| 29 |
+
[tool.pytest.ini_options]
|
| 30 |
+
testpaths = ["tests"]
|
| 31 |
+
pythonpath = ["src", "."]
|
| 32 |
+
addopts = "-q --strict-markers"
|
| 33 |
+
markers = [
|
| 34 |
+
"deployed: requires a live Space; skipped unless --space-url is given",
|
| 35 |
+
"slow: takes more than ~10s",
|
| 36 |
+
]
|
| 37 |
+
|
| 38 |
+
[tool.ruff]
|
| 39 |
+
line-length = 100
|
| 40 |
+
target-version = "py312"
|
| 41 |
+
# ruff 0.16+ lints and formats Python code blocks embedded in Markdown. Planning docs,
|
| 42 |
+
# research notes and design snippets are prose, not source: excluding *.md keeps the lint
|
| 43 |
+
# gate about shipped Python and stops doc snippets from failing `ruff format --check`.
|
| 44 |
+
extend-exclude = ["avatar/vendor", "*.md"]
|
| 45 |
+
|
| 46 |
+
[tool.ruff.lint]
|
| 47 |
+
select = ["E", "F", "I", "UP", "B", "SIM"]
|
| 48 |
+
|
| 49 |
+
[tool.ruff.format]
|
| 50 |
+
quote-style = "double"
|
src/japanese_avatar/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
__version__ = "0.1.0"
|
src/japanese_avatar/telemetry/__init__.py
ADDED
|
File without changes
|
src/japanese_avatar/ui/__init__.py
ADDED
|
File without changes
|
src/japanese_avatar/voice/__init__.py
ADDED
|
File without changes
|
tests/__init__.py
ADDED
|
File without changes
|
tests/e2e/__init__.py
ADDED
|
File without changes
|
tests/test_scaffold.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Proves the toolchain works before any real code exists."""
|
| 2 |
+
|
| 3 |
+
import subprocess
|
| 4 |
+
import sys
|
| 5 |
+
from pathlib import Path
|
| 6 |
+
|
| 7 |
+
|
| 8 |
+
def test_python_version_matches_space_runtime():
|
| 9 |
+
assert sys.version_info[:2] == (3, 12), (
|
| 10 |
+
"ZeroGPU provides only Python 3.10.13 and 3.12.12; this project pins 3.12.12"
|
| 11 |
+
)
|
| 12 |
+
|
| 13 |
+
|
| 14 |
+
def test_package_importable():
|
| 15 |
+
import japanese_avatar
|
| 16 |
+
|
| 17 |
+
assert japanese_avatar.__version__
|
| 18 |
+
|
| 19 |
+
|
| 20 |
+
def test_ruff_and_pytest_configured():
|
| 21 |
+
import tomllib
|
| 22 |
+
|
| 23 |
+
cfg = tomllib.loads(Path("pyproject.toml").read_text(encoding="utf-8"))
|
| 24 |
+
assert cfg["tool"]["ruff"]["target-version"] == "py312"
|
| 25 |
+
assert "pytest" in cfg["tool"]
|
| 26 |
+
|
| 27 |
+
|
| 28 |
+
def test_lfs_armed_before_any_binary_lands():
|
| 29 |
+
"""Plans 01-01 and 01-04 commit tens of megabytes. A non-LFS push of that size is rejected."""
|
| 30 |
+
for path in ("avatar/assets/tutor.vrm", "voicevox/model/zundamon.vvm", "tests/fixtures/x.wav"):
|
| 31 |
+
out = subprocess.run(
|
| 32 |
+
["git", "check-attr", "filter", "--", path], capture_output=True, text=True, check=True
|
| 33 |
+
).stdout
|
| 34 |
+
assert "filter: lfs" in out, f"{path} is not LFS-tracked; see .gitattributes"
|
uv.lock
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|