amv-diffusion 2.1.0__py3-none-any.whl

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.
Files changed (39) hide show
  1. amv_diffusion-2.1.0.dist-info/METADATA +180 -0
  2. amv_diffusion-2.1.0.dist-info/RECORD +39 -0
  3. amv_diffusion-2.1.0.dist-info/WHEEL +5 -0
  4. amv_diffusion-2.1.0.dist-info/entry_points.txt +7 -0
  5. amv_diffusion-2.1.0.dist-info/licenses/LICENSE +21 -0
  6. amv_diffusion-2.1.0.dist-info/top_level.txt +1 -0
  7. termux_diffusion/__init__.py +185 -0
  8. termux_diffusion/__main__.py +7 -0
  9. termux_diffusion/_version.py +3 -0
  10. termux_diffusion/adapter.py +41 -0
  11. termux_diffusion/canvas.py +364 -0
  12. termux_diffusion/cli.py +492 -0
  13. termux_diffusion/cluster.py +340 -0
  14. termux_diffusion/control/__init__.py +5 -0
  15. termux_diffusion/control/component.py +309 -0
  16. termux_diffusion/control/status.py +15 -0
  17. termux_diffusion/core.py +2936 -0
  18. termux_diffusion/data/bootstrap-manifest.json +15 -0
  19. termux_diffusion/data/prompt_cache/108a7149c4e70550.json +10 -0
  20. termux_diffusion/data/release-public-keys.json +10 -0
  21. termux_diffusion/data/validated-vulkan-profiles.json +298 -0
  22. termux_diffusion/detailer.py +283 -0
  23. termux_diffusion/doctor.py +128 -0
  24. termux_diffusion/downloader.py +111 -0
  25. termux_diffusion/engine.py +226 -0
  26. termux_diffusion/exceptions.py +158 -0
  27. termux_diffusion/hardware.py +985 -0
  28. termux_diffusion/hub.py +686 -0
  29. termux_diffusion/installer.py +499 -0
  30. termux_diffusion/locking.py +134 -0
  31. termux_diffusion/manifest.py +128 -0
  32. termux_diffusion/npu.py +267 -0
  33. termux_diffusion/platform.py +533 -0
  34. termux_diffusion/purger.py +145 -0
  35. termux_diffusion/py.typed +1 -0
  36. termux_diffusion/safety.py +150 -0
  37. termux_diffusion/selftest.py +178 -0
  38. termux_diffusion/web.py +3370 -0
  39. termux_diffusion/workflow.py +1345 -0
@@ -0,0 +1,128 @@
1
+ # Copyright (c) 2026 Uno Kim / AMEVA Foundation. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0 OR Commercial-License
3
+ """Manifest schema v1 parsing, SHA-256 checksum verification, and release metadata handling."""
4
+
5
+ import hashlib
6
+ import json
7
+ import logging
8
+ from dataclasses import dataclass, field
9
+ from pathlib import Path
10
+ from typing import Dict, List, Optional, Any
11
+
12
+ from .exceptions import TermuxDiffusionError
13
+
14
+ logger = logging.getLogger("termux_diffusion.manifest")
15
+
16
+ MANIFEST_SCHEMA_VERSION = 1
17
+
18
+ class ManifestError(TermuxDiffusionError):
19
+ """Raised when manifest parsing, signature, or schema validation fails."""
20
+ pass
21
+
22
+
23
+ @dataclass
24
+ class ArtifactMetadata:
25
+ id: str
26
+ filename: str
27
+ url: str
28
+ sha256: str
29
+ size: int
30
+ compression: str = "tar.gz"
31
+
32
+
33
+ @dataclass
34
+ class PlatformRequirements:
35
+ os: str = "android"
36
+ abi: str = "arm64-v8a"
37
+ min_api: int = 26
38
+ max_api: Optional[int] = None
39
+ libc: str = "bionic"
40
+
41
+
42
+ @dataclass
43
+ class RuntimeRequirements:
44
+ backend: str = "auto"
45
+ cpu_features_required: List[str] = field(default_factory=list)
46
+ vulkan_required: bool = False
47
+ vulkan_min_version: str = "1.1"
48
+ shared_libraries: List[str] = field(default_factory=list)
49
+
50
+
51
+ @dataclass
52
+ class ReleaseManifest:
53
+ schema_version: int
54
+ package_version: str
55
+ release_id: str
56
+ channel: str
57
+ artifacts: Dict[str, ArtifactMetadata]
58
+ platform: PlatformRequirements
59
+ runtime: RuntimeRequirements
60
+ raw_data: Dict[str, Any] = field(default_factory=dict)
61
+
62
+ @classmethod
63
+ def from_dict(cls, data: Dict[str, Any]) -> "ReleaseManifest":
64
+ schema_ver = data.get("schema_version", 1)
65
+ if schema_ver != MANIFEST_SCHEMA_VERSION:
66
+ raise ManifestError(f"E_MANIFEST_SCHEMA: Unsupported manifest schema version {schema_ver}")
67
+
68
+ pkg_ver = data.get("package_version", "1.2.0")
69
+ release_id = data.get("release_id", "")
70
+ channel = data.get("channel", "stable")
71
+
72
+ plat_data = data.get("platform", {})
73
+ plat = PlatformRequirements(
74
+ os=plat_data.get("os", "android"),
75
+ abi=plat_data.get("abi", "arm64-v8a"),
76
+ min_api=plat_data.get("min_api", 26),
77
+ max_api=plat_data.get("max_api"),
78
+ libc=plat_data.get("libc", "bionic")
79
+ )
80
+
81
+ rt_data = data.get("runtime", {})
82
+ rt = RuntimeRequirements(
83
+ backend=rt_data.get("backend", "auto"),
84
+ cpu_features_required=rt_data.get("cpu_features_required", []),
85
+ vulkan_required=rt_data.get("vulkan_required", False),
86
+ vulkan_min_version=rt_data.get("vulkan_min_version", "1.1"),
87
+ shared_libraries=rt_data.get("shared_libraries", [])
88
+ )
89
+
90
+ artifacts_dict = {}
91
+ art_raw = data.get("artifacts", {})
92
+ for art_id, art_info in art_raw.items():
93
+ artifacts_dict[art_id] = ArtifactMetadata(
94
+ id=art_id,
95
+ filename=art_info.get("filename", f"{art_id}.tar.gz"),
96
+ url=art_info.get("url", ""),
97
+ sha256=art_info.get("sha256", ""),
98
+ size=art_info.get("size", 0),
99
+ compression=art_info.get("compression", "tar.gz")
100
+ )
101
+
102
+ return cls(
103
+ schema_version=schema_ver,
104
+ package_version=pkg_ver,
105
+ release_id=release_id,
106
+ channel=channel,
107
+ artifacts=artifacts_dict,
108
+ platform=plat,
109
+ runtime=rt,
110
+ raw_data=data
111
+ )
112
+
113
+
114
+ def compute_sha256(filepath: Path) -> str:
115
+ """Calculate hex SHA-256 hash of given file."""
116
+ h = hashlib.sha256()
117
+ with open(filepath, "rb") as f:
118
+ while chunk := f.read(65536):
119
+ h.update(chunk)
120
+ return h.hexdigest().lower()
121
+
122
+
123
+ def verify_file_sha256(filepath: Path, expected_hash: str) -> bool:
124
+ """Verify that file's SHA-256 matches expected_hash."""
125
+ if not filepath.is_file():
126
+ return False
127
+ actual = compute_sha256(filepath)
128
+ return actual == expected_hash.lower().strip()
@@ -0,0 +1,267 @@
1
+ # Copyright (c) 2026 Uno Kim / AMEVA Foundation. All rights reserved.
2
+ # SPDX-License-Identifier: Apache-2.0 OR Commercial-License
3
+ """Neural Processing Unit (NPU) and Tensor Processing Unit (TPU) hardware introspection module.
4
+
5
+ This module provides hardware probing, driver introspection, and capability reporting
6
+ for mobile NPU/TPU chipsets on Android Termux:
7
+ - Qualcomm Hexagon Tensor Processor (HTP / QNN NPU)
8
+ - Samsung Exynos NPU (ENN / Eden Engine)
9
+ - Google Tensor Edge TPU (Pixel Neural Core)
10
+ - Android Standard Neural Networks API (NNAPI)
11
+
12
+ Architectural Note:
13
+ In v1.3+, inference is driven by the native Bionic sd-cli engine using Vulkan GPU
14
+ compute and ARM64 NEON CPU acceleration. Direct Qualcomm QNN / Hexagon NPU subgraph
15
+ partitioning is the architectural blueprint for the upcoming v2.0 runtime.
16
+ """
17
+
18
+ import logging
19
+ import os
20
+ import platform
21
+ import subprocess
22
+ from dataclasses import dataclass, field
23
+ from enum import Enum
24
+ from pathlib import Path
25
+ from typing import Dict, List, Optional, Tuple
26
+
27
+ logger = logging.getLogger("termux_diffusion.npu")
28
+
29
+
30
+ class NPUVendor(Enum):
31
+ """Supported mobile Neural Processing Unit hardware architectures."""
32
+ QUALCOMM_HEXAGON = "qualcomm_hexagon" # Snapdragon HTP (Hexagon Tensor Processor)
33
+ SAMSUNG_EDEN = "samsung_eden" # Exynos Dual-NPU (ENN Engine)
34
+ GOOGLE_EDGE_TPU = "google_edge_tpu" # Google Tensor Edge TPU
35
+ ANDROID_NNAPI = "android_nnapi" # Android Generic Neural Networks API
36
+ NONE = "none"
37
+
38
+
39
+ @dataclass
40
+ class NPUProfile:
41
+ """Introspected mobile NPU/TPU hardware capability profile."""
42
+ available: bool = False
43
+ vendor: NPUVendor = NPUVendor.NONE
44
+ chipset_name: str = "Unknown"
45
+ driver_library: Optional[str] = None
46
+ dsp_architecture: str = "Unknown"
47
+ tops_rating: float = 0.0
48
+ supported_precisions: List[str] = field(default_factory=list)
49
+ delegate_type: str = "CPU_FALLBACK"
50
+ acceleration_status: str = "Not Available"
51
+
52
+
53
+ # ------------------------------------------------------------------------------
54
+ # NPU Driver Search Paths on Android Bionic Filesystems
55
+ # ------------------------------------------------------------------------------
56
+
57
+ QUALCOMM_QNN_LIBS = [
58
+ "/vendor/lib64/libQnnHtp.so",
59
+ "/vendor/lib64/libQnnHtpV75.so",
60
+ "/vendor/lib64/libQnnHtpV73.so",
61
+ "/vendor/lib64/libQnnHtpV69.so",
62
+ "/vendor/lib64/libQnnHtpV68.so",
63
+ "/vendor/lib64/libqnn-htp.so",
64
+ "/vendor/lib64/libQnnSystem.so",
65
+ "/vendor/lib64/libQnnCpu.so",
66
+ "/vendor/dsp/cdsp/libqnn_htp.so",
67
+ "/system/vendor/lib64/libQnnHtp.so",
68
+ ]
69
+
70
+ SAMSUNG_EDEN_LIBS = [
71
+ "/vendor/lib64/libenn_public_api.so",
72
+ "/vendor/lib64/libeden_nn.so",
73
+ "/vendor/lib64/libenn_engine.so",
74
+ "/system/vendor/lib64/libenn_public_api.so",
75
+ ]
76
+
77
+ GOOGLE_EDGETPU_LIBS = [
78
+ "/vendor/lib64/libedgetpu.so",
79
+ "/vendor/lib64/libtflite_edgetpu.so",
80
+ "/vendor/lib64/libgoogle_edgetpu.so",
81
+ "/system/vendor/lib64/libedgetpu.so",
82
+ ]
83
+
84
+ ANDROID_NNAPI_LIBS = [
85
+ "/system/lib64/libneuralnetworks.so",
86
+ "/apex/com.android.neuralnetworks/lib64/libneuralnetworks.so",
87
+ "/system/lib/libneuralnetworks.so",
88
+ ]
89
+
90
+
91
+ def _read_android_prop(key: str) -> str:
92
+ """Query Android system property via getprop.
93
+
94
+ 반환: 값 문자열, 실패/미지원 시 "" (fail-closed).
95
+ """
96
+ import logging as _logging
97
+ _npu_logger = _logging.getLogger("termux_diffusion.npu")
98
+ try:
99
+ res = subprocess.run(["getprop", key], capture_output=True, text=True, timeout=2.0)
100
+ val = res.stdout.strip()
101
+ if val and val != "unknown":
102
+ return val
103
+ except FileNotFoundError:
104
+ # getprop 바이너리 없음 — 비-Android 환경. fail-closed.
105
+ _npu_logger.debug("[npu] getprop not found (non-Android environment)")
106
+ except subprocess.TimeoutExpired:
107
+ _npu_logger.debug("[npu] getprop timed out for key=%s", key)
108
+ except OSError as _os_err:
109
+ _npu_logger.warning("[npu] getprop OSError for key=%s: %s", key, _os_err)
110
+ # 예상 밖 예외는 재발생
111
+ return ""
112
+
113
+
114
+
115
+
116
+ def _probe_first_existing_lib(paths: List[str]) -> Optional[str]:
117
+ """Check physical existence of runtime library on Android filesystem."""
118
+ for p in paths:
119
+ path_obj = Path(p)
120
+ try:
121
+ if path_obj.is_file() and path_obj.stat().st_size >= 1024:
122
+ return str(path_obj.resolve())
123
+ except (OSError, PermissionError):
124
+ continue
125
+ return None
126
+
127
+
128
+ def detect_npu_capabilities() -> NPUProfile:
129
+ """Inspect the device for Qualcomm Hexagon, Samsung Exynos NPU, Google Edge TPU, and NNAPI."""
130
+ soc_platform = _read_android_prop("ro.board.platform").lower()
131
+ chipname = _read_android_prop("ro.hardware.chipname").lower()
132
+ hardware = _read_android_prop("ro.hardware").lower()
133
+ product_board = _read_android_prop("ro.product.board").lower()
134
+
135
+ # 1. Qualcomm Snapdragon Hexagon HTP Probe
136
+ qnn_lib = _probe_first_existing_lib(QUALCOMM_QNN_LIBS)
137
+ is_qualcomm = any(q in soc_platform or q in hardware or q in product_board for q in ["qcom", "snapdragon", "sm8", "sm7", "lahaina", "taro", "kalama", "pineapple"])
138
+
139
+ if qnn_lib or is_qualcomm:
140
+ # Determine TOPS rating based on SoC generation
141
+ tops = 15.0
142
+ dsp_arch = "Hexagon Vector Extensions (HVX)"
143
+ if "sm8650" in soc_platform or "pineapple" in soc_platform: # Snapdragon 8 Gen 3
144
+ tops = 45.0
145
+ dsp_arch = "Hexagon v75 HTP (45 TOPS Generative AI NPU)"
146
+ elif "sm8550" in soc_platform or "kalama" in soc_platform: # Snapdragon 8 Gen 2
147
+ tops = 35.0
148
+ dsp_arch = "Hexagon v73 HTP (35 TOPS NPU)"
149
+ elif "sm8450" in soc_platform or "taro" in soc_platform: # Snapdragon 8 Gen 1
150
+ tops = 27.0
151
+ dsp_arch = "Hexagon v69 HTP (27 TOPS NPU)"
152
+
153
+ has_driver = qnn_lib is not None
154
+ return NPUProfile(
155
+ available=has_driver,
156
+ vendor=NPUVendor.QUALCOMM_HEXAGON,
157
+ chipset_name=f"Qualcomm Snapdragon ({soc_platform or hardware})",
158
+ driver_library=qnn_lib,
159
+ dsp_architecture=dsp_arch,
160
+ tops_rating=tops if has_driver else 0.0,
161
+ supported_precisions=["INT4", "INT8", "FP16"] if has_driver else [],
162
+ delegate_type="QNN_HTP_DELEGATE" if has_driver else None,
163
+ acceleration_status="Operational (Qualcomm Hexagon Tensor Core)" if has_driver else "SoC Detected (Driver inaccessible or SELinux restricted)",
164
+ )
165
+
166
+ # 2. Samsung Exynos NPU (ENN / Eden) Probe
167
+ eden_lib = _probe_first_existing_lib(SAMSUNG_EDEN_LIBS)
168
+ is_samsung_exynos = "exynos" in chipname or "s5e" in soc_platform or "universal" in hardware
169
+
170
+ if eden_lib or is_samsung_exynos:
171
+ tops = 17.0
172
+ dsp_arch = "Samsung Exynos Dual-NPU"
173
+ if "2400" in chipname or "9945" in soc_platform: # Exynos 2400
174
+ tops = 42.0
175
+ dsp_arch = "Samsung Generative AI NPU (42 TOPS)"
176
+ elif "1480" in chipname: # Exynos 1480
177
+ tops = 20.0
178
+ dsp_arch = "Exynos AI NPU (20 TOPS)"
179
+ elif "1380" in chipname: # Exynos 1380
180
+ tops = 4.9
181
+ dsp_arch = "Exynos 1380 NPU (4.9 TOPS)"
182
+
183
+ has_driver = eden_lib is not None
184
+ return NPUProfile(
185
+ available=has_driver,
186
+ vendor=NPUVendor.SAMSUNG_EDEN,
187
+ chipset_name=f"Samsung Exynos ({chipname or soc_platform})",
188
+ driver_library=eden_lib,
189
+ dsp_architecture=dsp_arch,
190
+ tops_rating=tops if has_driver else 0.0,
191
+ supported_precisions=["INT8", "FP16"] if has_driver else [],
192
+ delegate_type="EXYNOS_ENN_DELEGATE" if has_driver else None,
193
+ acceleration_status="Operational (Samsung Exynos NPU)" if has_driver else "SoC Detected (Driver inaccessible or SELinux restricted)",
194
+ )
195
+
196
+ # 3. Google Tensor Edge TPU (Pixel Neural Core) Probe
197
+ tpu_lib = _probe_first_existing_lib(GOOGLE_EDGETPU_LIBS)
198
+ is_google_tensor = any(t in hardware or t in product_board for t in ["zuma", "gs201", "gs101", "tensor", "cloudripper"])
199
+
200
+ if tpu_lib or is_google_tensor:
201
+ has_driver = tpu_lib is not None
202
+ return NPUProfile(
203
+ available=has_driver,
204
+ vendor=NPUVendor.GOOGLE_EDGE_TPU,
205
+ chipset_name=f"Google Tensor TPU ({hardware or product_board})",
206
+ driver_library=tpu_lib,
207
+ dsp_architecture="Google Edge TPU (Custom Tensor Core)",
208
+ tops_rating=20.0 if has_driver else 0.0,
209
+ supported_precisions=["INT8", "FP16"] if has_driver else [],
210
+ delegate_type="EDGETPU_DELEGATE" if has_driver else None,
211
+ acceleration_status="Operational (Google Edge TPU Core)" if has_driver else "SoC Detected (Driver inaccessible or SELinux restricted)",
212
+ )
213
+
214
+ # 4. Android Generic NNAPI Runtime Probe
215
+ nnapi_lib = _probe_first_existing_lib(ANDROID_NNAPI_LIBS)
216
+ if nnapi_lib:
217
+ return NPUProfile(
218
+ available=True,
219
+ vendor=NPUVendor.ANDROID_NNAPI,
220
+ chipset_name="Android Generic NNAPI",
221
+ driver_library=nnapi_lib,
222
+ dsp_architecture="Android Neural Networks Hardware Abstraction Layer (HAL)",
223
+ tops_rating=5.0,
224
+ supported_precisions=["INT8", "FP16"],
225
+ delegate_type="NNAPI_DELEGATE",
226
+ acceleration_status="Operational (Android NNAPI HAL)",
227
+ )
228
+
229
+ return NPUProfile(
230
+ available=False,
231
+ vendor=NPUVendor.NONE,
232
+ chipset_name="Generic Host",
233
+ driver_library=None,
234
+ dsp_architecture="No Dedicated NPU / TPU Detected",
235
+ tops_rating=0.0,
236
+ supported_precisions=[],
237
+ delegate_type="CPU_FALLBACK",
238
+ acceleration_status="Unavailable (CPU/GPU pipeline active)",
239
+ )
240
+
241
+
242
+ def get_optimal_heterogeneous_pipeline(device: str = "auto") -> Dict[str, str]:
243
+ """Determine the compute processor allocation for each diffusion pipeline component.
244
+
245
+ Note:
246
+ In v1.3+, diffusion inference is executed via the native Bionic sd-cli engine using
247
+ Vulkan GPU compute and ARM64 NEON CPU math. Direct Qualcomm QNN / Hexagon
248
+ NPU subgraph partitioning is the architectural target for the upcoming v2.0 runtime.
249
+ """
250
+ req = device.lower().strip()
251
+
252
+ if req == "cpu":
253
+ return {
254
+ "text_encoder": "CPU (ARM NEON FP16)",
255
+ "denoiser_unet": "CPU (ARM NEON DotProd/I8MM)",
256
+ "vae_decoder": "CPU (ARM NEON FP16)",
257
+ "scheduler": "CPU (Single-Core Fast Math)",
258
+ "summary": "CPU-Only [ARM NEON Pipeline]"
259
+ }
260
+ else:
261
+ return {
262
+ "text_encoder": "CPU / GPU (ARM NEON / Vulkan)",
263
+ "denoiser_unet": "GPU (Vulkan Compute Shader Pipeline)",
264
+ "vae_decoder": "GPU (Vulkan Compute FP16)",
265
+ "scheduler": "CPU (Single-Core Fast Math)",
266
+ "summary": "GPU-Accelerated [Vulkan Compute Shader Pipeline]"
267
+ }