termux-diffusion 1.0.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.
- termux_diffusion/__init__.py +74 -0
- termux_diffusion/cli.py +112 -0
- termux_diffusion/core.py +240 -0
- termux_diffusion/exceptions.py +35 -0
- termux_diffusion/hub.py +332 -0
- termux_diffusion/installer.py +206 -0
- termux_diffusion/platform.py +220 -0
- termux_diffusion/py.typed +1 -0
- termux_diffusion-1.0.0.dist-info/LICENSE +21 -0
- termux_diffusion-1.0.0.dist-info/METADATA +199 -0
- termux_diffusion-1.0.0.dist-info/RECORD +14 -0
- termux_diffusion-1.0.0.dist-info/WHEEL +5 -0
- termux_diffusion-1.0.0.dist-info/entry_points.txt +4 -0
- termux_diffusion-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"""termux-diffusion: On-Device AI Image Generation Framework for Android Termux & Samsung Galaxy."""
|
|
2
|
+
|
|
3
|
+
from .core import GenerationResult, async_generate, generate
|
|
4
|
+
from .exceptions import (
|
|
5
|
+
InferenceTimeoutError,
|
|
6
|
+
ModelDownloadError,
|
|
7
|
+
ModelNotFoundError,
|
|
8
|
+
OOMRiskError,
|
|
9
|
+
PlatformNotSupportedError,
|
|
10
|
+
ProvisioningError,
|
|
11
|
+
TermuxDiffusionError,
|
|
12
|
+
)
|
|
13
|
+
from .hub import (
|
|
14
|
+
DEFAULT_PRESETS,
|
|
15
|
+
clear_cache,
|
|
16
|
+
download_model,
|
|
17
|
+
get_cache_dir,
|
|
18
|
+
is_model_cached,
|
|
19
|
+
list_cached_models,
|
|
20
|
+
list_presets,
|
|
21
|
+
register_model,
|
|
22
|
+
resolve_model_path,
|
|
23
|
+
set_cache_dir,
|
|
24
|
+
)
|
|
25
|
+
from .installer import locate_sd_cli, provision_engine, run_doctor
|
|
26
|
+
from .platform import (
|
|
27
|
+
TermuxWakeLock,
|
|
28
|
+
check_memory_safety,
|
|
29
|
+
export_to_android_gallery,
|
|
30
|
+
get_galaxy_gallery_dir,
|
|
31
|
+
get_memory_info,
|
|
32
|
+
get_optimal_thread_count,
|
|
33
|
+
is_android_termux,
|
|
34
|
+
is_arm64,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
__version__ = "1.0.0"
|
|
38
|
+
__author__ = "uno-km (쌩초보코딩단)"
|
|
39
|
+
__license__ = "MIT"
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"__version__",
|
|
43
|
+
"generate",
|
|
44
|
+
"async_generate",
|
|
45
|
+
"GenerationResult",
|
|
46
|
+
"download_model",
|
|
47
|
+
"resolve_model_path",
|
|
48
|
+
"register_model",
|
|
49
|
+
"set_cache_dir",
|
|
50
|
+
"get_cache_dir",
|
|
51
|
+
"is_model_cached",
|
|
52
|
+
"list_cached_models",
|
|
53
|
+
"clear_cache",
|
|
54
|
+
"list_presets",
|
|
55
|
+
"DEFAULT_PRESETS",
|
|
56
|
+
"locate_sd_cli",
|
|
57
|
+
"provision_engine",
|
|
58
|
+
"run_doctor",
|
|
59
|
+
"is_android_termux",
|
|
60
|
+
"is_arm64",
|
|
61
|
+
"check_memory_safety",
|
|
62
|
+
"get_memory_info",
|
|
63
|
+
"get_optimal_thread_count",
|
|
64
|
+
"get_galaxy_gallery_dir",
|
|
65
|
+
"export_to_android_gallery",
|
|
66
|
+
"TermuxWakeLock",
|
|
67
|
+
"TermuxDiffusionError",
|
|
68
|
+
"PlatformNotSupportedError",
|
|
69
|
+
"ModelNotFoundError",
|
|
70
|
+
"ModelDownloadError",
|
|
71
|
+
"ProvisioningError",
|
|
72
|
+
"OOMRiskError",
|
|
73
|
+
"InferenceTimeoutError",
|
|
74
|
+
]
|
termux_diffusion/cli.py
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Command-line interface entry points for termux-diffusion."""
|
|
2
|
+
|
|
3
|
+
import argparse
|
|
4
|
+
import sys
|
|
5
|
+
from typing import List, Optional
|
|
6
|
+
|
|
7
|
+
from .core import generate
|
|
8
|
+
from .hub import clear_cache, download_model, list_cached_models, list_presets
|
|
9
|
+
from .installer import provision_engine, run_doctor
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main(argv: Optional[List[str]] = None) -> int:
|
|
13
|
+
"""Main CLI router for termux-diffusion."""
|
|
14
|
+
if argv is None:
|
|
15
|
+
argv = sys.argv[1:]
|
|
16
|
+
|
|
17
|
+
parser = argparse.ArgumentParser(
|
|
18
|
+
prog="termux-diffusion",
|
|
19
|
+
description="Production On-Device AI Image Generation for Android Termux & Samsung Galaxy."
|
|
20
|
+
)
|
|
21
|
+
subparsers = parser.add_subparsers(dest="command", help="Available subcommands")
|
|
22
|
+
|
|
23
|
+
# generate command
|
|
24
|
+
gen_parser = subparsers.add_parser("generate", help="Generate an AI image from a text prompt")
|
|
25
|
+
gen_parser.add_argument("prompt", type=str, help="Text description of image")
|
|
26
|
+
gen_parser.add_argument("-m", "--model", type=str, default="realistic", help="Model preset or .gguf path (default: realistic)")
|
|
27
|
+
gen_parser.add_argument("-n", "--negative", type=str, default=None, help="Negative prompt")
|
|
28
|
+
gen_parser.add_argument("-s", "--steps", type=int, default=None, help="Denoising steps")
|
|
29
|
+
gen_parser.add_argument("-c", "--cfg", type=float, default=None, help="CFG guidance scale")
|
|
30
|
+
gen_parser.add_argument("-W", "--width", type=int, default=512, help="Image width (default: 512)")
|
|
31
|
+
gen_parser.add_argument("-H", "--height", type=int, default=512, help="Image height (default: 512)")
|
|
32
|
+
gen_parser.add_argument("-t", "--threads", type=int, default=None, help="CPU threads")
|
|
33
|
+
gen_parser.add_argument("-o", "--output", type=str, default=None, help="Output file path")
|
|
34
|
+
|
|
35
|
+
# install command
|
|
36
|
+
subparsers.add_parser("install", help="Provision and compile native Bionic C++ engine")
|
|
37
|
+
|
|
38
|
+
# doctor command
|
|
39
|
+
subparsers.add_parser("doctor", help="Run 7-tier pre-flight diagnostic checks")
|
|
40
|
+
|
|
41
|
+
# models command
|
|
42
|
+
subparsers.add_parser("models", help="List available model presets and locally cached weights")
|
|
43
|
+
|
|
44
|
+
# download command
|
|
45
|
+
dl_parser = subparsers.add_parser("download", help="Pre-download a model preset or HF repo")
|
|
46
|
+
dl_parser.add_argument("model", type=str, help="Model preset name (e.g. realistic, speed, sdxs, turbo, anime)")
|
|
47
|
+
|
|
48
|
+
# clear-cache command
|
|
49
|
+
subparsers.add_parser("clear-cache", help="Delete cached model files to reclaim storage")
|
|
50
|
+
|
|
51
|
+
if not argv:
|
|
52
|
+
parser.print_help()
|
|
53
|
+
return 0
|
|
54
|
+
|
|
55
|
+
args = parser.parse_args(argv)
|
|
56
|
+
|
|
57
|
+
if args.command == "generate":
|
|
58
|
+
res = generate(
|
|
59
|
+
prompt=args.prompt,
|
|
60
|
+
model=args.model,
|
|
61
|
+
negative_prompt=args.negative,
|
|
62
|
+
steps=args.steps,
|
|
63
|
+
cfg_scale=args.cfg,
|
|
64
|
+
width=args.width,
|
|
65
|
+
height=args.height,
|
|
66
|
+
threads=args.threads,
|
|
67
|
+
output=args.output
|
|
68
|
+
)
|
|
69
|
+
return 0 if res.path.exists() else 1
|
|
70
|
+
|
|
71
|
+
elif args.command == "install":
|
|
72
|
+
provision_engine(force=True)
|
|
73
|
+
return 0
|
|
74
|
+
|
|
75
|
+
elif args.command == "doctor":
|
|
76
|
+
ok = run_doctor()
|
|
77
|
+
return 0 if ok else 1
|
|
78
|
+
|
|
79
|
+
elif args.command == "models":
|
|
80
|
+
print("\n--- 🌟 Available Presets ---")
|
|
81
|
+
for k, v in list_presets().items():
|
|
82
|
+
print(f" • {k:12} : {v['description']} ({v.get('size_mb', 0)}MB)")
|
|
83
|
+
print("\n--- 💾 Locally Cached Models ---")
|
|
84
|
+
cached = list_cached_models()
|
|
85
|
+
if not cached:
|
|
86
|
+
print(" (No models cached yet. Run 'termux-diffusion download <model>' or generate)")
|
|
87
|
+
for m in cached:
|
|
88
|
+
print(f" • {m['name']:25} [{m['size_mb']} MB] -> {m['path']}")
|
|
89
|
+
print()
|
|
90
|
+
return 0
|
|
91
|
+
|
|
92
|
+
elif args.command == "download":
|
|
93
|
+
download_model(args.model)
|
|
94
|
+
return 0
|
|
95
|
+
|
|
96
|
+
elif args.command == "clear-cache":
|
|
97
|
+
removed = clear_cache()
|
|
98
|
+
print(f"🧹 Removed {removed} cached model files.")
|
|
99
|
+
return 0
|
|
100
|
+
|
|
101
|
+
parser.print_help()
|
|
102
|
+
return 0
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def run_install_cli():
|
|
106
|
+
"""Entry point for termux-diffusion-install."""
|
|
107
|
+
provision_engine(force=True)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def run_doctor_cli():
|
|
111
|
+
"""Entry point for termux-diffusion-doctor."""
|
|
112
|
+
run_doctor()
|
termux_diffusion/core.py
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
"""Core generation runner, argument builder, WakeLock wrapper, and gallery bridge."""
|
|
2
|
+
|
|
3
|
+
import asyncio
|
|
4
|
+
import logging
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
import time
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Optional, Union
|
|
12
|
+
|
|
13
|
+
from .exceptions import InferenceTimeoutError, OOMRiskError, ProvisioningError, TermuxDiffusionError
|
|
14
|
+
from .hub import DEFAULT_PRESETS, list_presets, resolve_model_path
|
|
15
|
+
from .installer import locate_sd_cli, provision_engine
|
|
16
|
+
from .platform import (
|
|
17
|
+
TermuxWakeLock,
|
|
18
|
+
check_memory_safety,
|
|
19
|
+
export_to_android_gallery,
|
|
20
|
+
get_galaxy_gallery_dir,
|
|
21
|
+
get_optimal_thread_count,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
logger = logging.getLogger("termux_diffusion.core")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class GenerationResult:
|
|
29
|
+
"""Encapsulates the output and metadata of an AI diffusion generation task."""
|
|
30
|
+
path: Path
|
|
31
|
+
gallery_path: Optional[Path]
|
|
32
|
+
prompt: str
|
|
33
|
+
negative_prompt: Optional[str]
|
|
34
|
+
model: str
|
|
35
|
+
device: str
|
|
36
|
+
steps: int
|
|
37
|
+
cfg_scale: float
|
|
38
|
+
width: int
|
|
39
|
+
height: int
|
|
40
|
+
seed: int
|
|
41
|
+
elapsed_sec: float
|
|
42
|
+
|
|
43
|
+
def __str__(self) -> str:
|
|
44
|
+
return f"<GenerationResult path='{self.path}' device='{self.device}' elapsed={self.elapsed_sec:.1f}s>"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def generate(
|
|
48
|
+
prompt: str,
|
|
49
|
+
model: str = "realistic",
|
|
50
|
+
negative_prompt: Optional[str] = (
|
|
51
|
+
"woman, girl, cartoon, anime, 3d render, plastic, illustration, b&w, lowres, blur, deformed hands, extra fingers, messy face, horror"
|
|
52
|
+
),
|
|
53
|
+
device: str = "cpu",
|
|
54
|
+
steps: Optional[int] = None,
|
|
55
|
+
cfg_scale: Optional[float] = None,
|
|
56
|
+
width: int = 512,
|
|
57
|
+
height: int = 512,
|
|
58
|
+
seed: int = -1,
|
|
59
|
+
threads: Optional[int] = None,
|
|
60
|
+
output: Optional[Union[str, Path]] = None,
|
|
61
|
+
export_gallery: bool = True,
|
|
62
|
+
wake_lock: bool = True,
|
|
63
|
+
low_ram_guard: bool = True,
|
|
64
|
+
timeout: int = 1800,
|
|
65
|
+
) -> GenerationResult:
|
|
66
|
+
"""Generate an AI image on Samsung Galaxy / Android Termux using Bionic native C++ diffusion.
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
prompt: Detailed text description of the desired image.
|
|
70
|
+
model: Preset keyword ('realistic', 'speed', 'sdxs', 'turbo', 'anime'), custom repo ('org/repo/file.gguf'), direct URL, or path to .gguf file.
|
|
71
|
+
negative_prompt: Negative text guidance describing elements to avoid.
|
|
72
|
+
device: Computing device ('cpu', 'gpu', 'opencl', 'vulkan'). Default is 'cpu'.
|
|
73
|
+
steps: Number of denoising steps (default determined by preset, e.g. 10).
|
|
74
|
+
cfg_scale: Classifier-Free Guidance scale (default determined by preset, e.g. 4.0).
|
|
75
|
+
width: Output image width in pixels (default: 512).
|
|
76
|
+
height: Output image height in pixels (default: 512).
|
|
77
|
+
seed: Sampling RNG seed (-1 for random).
|
|
78
|
+
threads: Number of CPU threads (defaults to optimal big-core cluster count, e.g. 4).
|
|
79
|
+
output: Destination output filename or path.
|
|
80
|
+
export_gallery: Whether to copy image to Samsung Gallery and broadcast media scanner intent.
|
|
81
|
+
wake_lock: Whether to acquire Android CPU WakeLock during generation.
|
|
82
|
+
low_ram_guard: Whether to verify available memory before starting inference.
|
|
83
|
+
timeout: Maximum inference timeout in seconds (default: 1800s / 30m).
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
GenerationResult: Object containing local path, gallery path, and inference metrics.
|
|
87
|
+
"""
|
|
88
|
+
if not prompt or not prompt.strip():
|
|
89
|
+
raise ValueError("Prompt must not be empty.")
|
|
90
|
+
|
|
91
|
+
device_mode = device.lower().strip()
|
|
92
|
+
if device_mode not in ("cpu", "gpu", "opencl", "vulkan", "auto"):
|
|
93
|
+
raise ValueError(f"Invalid device '{device}'. Options: 'cpu', 'gpu', 'opencl', 'vulkan'.")
|
|
94
|
+
|
|
95
|
+
# 1. Pre-flight Memory Safety Guard
|
|
96
|
+
if low_ram_guard:
|
|
97
|
+
safe, msg = check_memory_safety(required_mb=1000)
|
|
98
|
+
if not safe:
|
|
99
|
+
logger.warning("Low RAM Warning: %s", msg)
|
|
100
|
+
|
|
101
|
+
# 2. Resolve Model Path & Preset Hyperparameters (Validates model name first)
|
|
102
|
+
presets = list_presets()
|
|
103
|
+
model_path = resolve_model_path(model)
|
|
104
|
+
|
|
105
|
+
if steps is None:
|
|
106
|
+
steps = presets.get(model, {}).get("default_steps", 10)
|
|
107
|
+
if cfg_scale is None:
|
|
108
|
+
cfg_scale = presets.get(model, {}).get("default_cfg", 4.0)
|
|
109
|
+
if threads is None:
|
|
110
|
+
threads = get_optimal_thread_count()
|
|
111
|
+
|
|
112
|
+
# 3. Locate or Auto-provision Native sd-cli Engine
|
|
113
|
+
sd_cli = locate_sd_cli()
|
|
114
|
+
if not sd_cli:
|
|
115
|
+
logger.info("sd-cli binary not found in standard paths. Attempting auto-provisioning...")
|
|
116
|
+
sd_cli = provision_engine()
|
|
117
|
+
|
|
118
|
+
# 4. Determine Output Destination
|
|
119
|
+
timestamp = int(time.time())
|
|
120
|
+
if output:
|
|
121
|
+
out_path = Path(os.path.expanduser(str(output))).resolve()
|
|
122
|
+
else:
|
|
123
|
+
out_dir = get_galaxy_gallery_dir()
|
|
124
|
+
out_path = out_dir / f"ai_gen_{timestamp}.png"
|
|
125
|
+
|
|
126
|
+
out_path.parent.mkdir(parents=True, exist_ok=True)
|
|
127
|
+
|
|
128
|
+
# 5. Build Subprocess Command List (100% List argv, Zero Shell Injection Vector)
|
|
129
|
+
cmd = [
|
|
130
|
+
str(sd_cli),
|
|
131
|
+
"-m", str(model_path),
|
|
132
|
+
"-p", prompt,
|
|
133
|
+
"-W", str(width),
|
|
134
|
+
"-H", str(height),
|
|
135
|
+
"-t", str(threads),
|
|
136
|
+
"--steps", str(steps),
|
|
137
|
+
"--cfg-scale", str(cfg_scale),
|
|
138
|
+
"-o", str(out_path)
|
|
139
|
+
]
|
|
140
|
+
if negative_prompt:
|
|
141
|
+
cmd.extend(["-n", negative_prompt])
|
|
142
|
+
if seed >= 0:
|
|
143
|
+
cmd.extend(["-s", str(seed)])
|
|
144
|
+
if device_mode in ("gpu", "opencl", "vulkan"):
|
|
145
|
+
cmd.extend(["-ngl", "32"])
|
|
146
|
+
|
|
147
|
+
logger.info("Executing diffusion inference: %s", " ".join(cmd[:6]) + " ...")
|
|
148
|
+
print(f"[termux-diffusion] Processing inference with model='{model}' (steps={steps}, threads={threads}, device={device_mode})...")
|
|
149
|
+
|
|
150
|
+
start_time = time.time()
|
|
151
|
+
|
|
152
|
+
# 6. Execute with WakeLock protection
|
|
153
|
+
with TermuxWakeLock(enabled=wake_lock):
|
|
154
|
+
process = None
|
|
155
|
+
try:
|
|
156
|
+
process = subprocess.Popen(
|
|
157
|
+
cmd,
|
|
158
|
+
stdout=subprocess.PIPE,
|
|
159
|
+
stderr=subprocess.STDOUT,
|
|
160
|
+
text=True,
|
|
161
|
+
bufsize=1,
|
|
162
|
+
universal_newlines=True
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
# Stream real-time progress to terminal
|
|
166
|
+
if process.stdout:
|
|
167
|
+
for line in process.stdout:
|
|
168
|
+
line_str = line.strip()
|
|
169
|
+
if line_str:
|
|
170
|
+
if "step" in line_str.lower() or "%" in line_str or "sampling" in line_str.lower():
|
|
171
|
+
print(f" > {line_str}")
|
|
172
|
+
else:
|
|
173
|
+
logger.debug("sd-cli: %s", line_str)
|
|
174
|
+
|
|
175
|
+
process.wait(timeout=timeout)
|
|
176
|
+
if process.returncode != 0:
|
|
177
|
+
raise TermuxDiffusionError(f"Engine process failed with return code {process.returncode}")
|
|
178
|
+
except KeyboardInterrupt:
|
|
179
|
+
if process and process.poll() is None:
|
|
180
|
+
try:
|
|
181
|
+
process.kill()
|
|
182
|
+
process.wait(timeout=2.0)
|
|
183
|
+
except Exception:
|
|
184
|
+
pass
|
|
185
|
+
print("\n[termux-diffusion] Inference interrupted by user. Child processes terminated safely.")
|
|
186
|
+
raise
|
|
187
|
+
except subprocess.TimeoutExpired as exc:
|
|
188
|
+
if process and process.poll() is None:
|
|
189
|
+
try:
|
|
190
|
+
process.kill()
|
|
191
|
+
process.wait(timeout=2.0)
|
|
192
|
+
except Exception:
|
|
193
|
+
pass
|
|
194
|
+
raise InferenceTimeoutError(f"Diffusion generation timed out after {timeout} seconds") from exc
|
|
195
|
+
except Exception:
|
|
196
|
+
if process and process.poll() is None:
|
|
197
|
+
try:
|
|
198
|
+
process.kill()
|
|
199
|
+
process.wait(timeout=2.0)
|
|
200
|
+
except Exception:
|
|
201
|
+
pass
|
|
202
|
+
raise
|
|
203
|
+
|
|
204
|
+
elapsed = time.time() - start_time
|
|
205
|
+
|
|
206
|
+
if not out_path.is_file():
|
|
207
|
+
raise TermuxDiffusionError(f"Engine finished but output file was not created at: {out_path}")
|
|
208
|
+
|
|
209
|
+
# 7. Samsung Gallery Export & Media Scanner Broadcast
|
|
210
|
+
gallery_path = None
|
|
211
|
+
if export_gallery:
|
|
212
|
+
try:
|
|
213
|
+
gallery_path = export_to_android_gallery(out_path)
|
|
214
|
+
except Exception as e:
|
|
215
|
+
logger.warning("Could not export to Android gallery: %s", e)
|
|
216
|
+
|
|
217
|
+
print(f"[termux-diffusion] Artifact generated in {elapsed:.2f}s -> {out_path}")
|
|
218
|
+
if gallery_path:
|
|
219
|
+
print(f"[termux-diffusion] Synchronized to Android MediaStore: {gallery_path}")
|
|
220
|
+
|
|
221
|
+
return GenerationResult(
|
|
222
|
+
path=out_path,
|
|
223
|
+
gallery_path=gallery_path,
|
|
224
|
+
prompt=prompt,
|
|
225
|
+
negative_prompt=negative_prompt,
|
|
226
|
+
model=model,
|
|
227
|
+
device=device_mode,
|
|
228
|
+
steps=steps,
|
|
229
|
+
cfg_scale=cfg_scale,
|
|
230
|
+
width=width,
|
|
231
|
+
height=height,
|
|
232
|
+
seed=seed,
|
|
233
|
+
elapsed_sec=elapsed
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
async def async_generate(*args, **kwargs) -> GenerationResult:
|
|
238
|
+
"""Asynchronous wrapper for generate() to integrate seamlessly into asyncio event loops."""
|
|
239
|
+
loop = asyncio.get_running_loop()
|
|
240
|
+
return await loop.run_in_executor(None, lambda: generate(*args, **kwargs))
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Exceptions for the termux-diffusion framework."""
|
|
2
|
+
|
|
3
|
+
class TermuxDiffusionError(Exception):
|
|
4
|
+
"""Base exception for all termux-diffusion errors."""
|
|
5
|
+
pass
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PlatformNotSupportedError(TermuxDiffusionError):
|
|
9
|
+
"""Raised when running on an unsupported platform or non-ARM64 architecture."""
|
|
10
|
+
pass
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ModelNotFoundError(TermuxDiffusionError):
|
|
14
|
+
"""Raised when the specified model preset or file path cannot be located."""
|
|
15
|
+
pass
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
class ModelDownloadError(TermuxDiffusionError):
|
|
19
|
+
"""Raised when an error occurs during model downloading or checksum verification."""
|
|
20
|
+
pass
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class ProvisioningError(TermuxDiffusionError):
|
|
24
|
+
"""Raised when the native C++ engine (sd-cli) fails to build or provision."""
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class OOMRiskError(TermuxDiffusionError):
|
|
29
|
+
"""Raised when available system memory (RAM + zRAM) is insufficient for safe inference."""
|
|
30
|
+
pass
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class InferenceTimeoutError(TermuxDiffusionError):
|
|
34
|
+
"""Raised when diffusion inference exceeds the configured execution timeout."""
|
|
35
|
+
pass
|