pythonhere 0.3.0__py3-none-any.whl → 0.4.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.
- pythonhere/.agents/skills/pythonhere/SKILL.md +18 -5
- pythonhere/.agents/skills/pythonhere/references/litert.md +121 -0
- pythonhere/ml_here/__init__.py +17 -0
- pythonhere/ml_here/huggingface.py +998 -0
- pythonhere/ml_here/storage.py +145 -0
- pythonhere/version_here.py +1 -1
- {pythonhere-0.3.0.dist-info → pythonhere-0.4.0.dist-info}/METADATA +5 -2
- {pythonhere-0.3.0.dist-info → pythonhere-0.4.0.dist-info}/RECORD +11 -7
- {pythonhere-0.3.0.dist-info → pythonhere-0.4.0.dist-info}/WHEEL +0 -0
- {pythonhere-0.3.0.dist-info → pythonhere-0.4.0.dist-info}/licenses/LICENSE +0 -0
- {pythonhere-0.3.0.dist-info → pythonhere-0.4.0.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
"""Find ML model files managed by PythonHere."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import sys
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _android_models_directory():
|
|
8
|
+
"""Return the model directory belonging to the running Android app."""
|
|
9
|
+
|
|
10
|
+
from jnius import autoclass
|
|
11
|
+
|
|
12
|
+
PythonActivity = autoclass("org.kivy.android.PythonActivity")
|
|
13
|
+
activity = PythonActivity.mActivity
|
|
14
|
+
if activity is None:
|
|
15
|
+
raise RuntimeError("A running PythonHere activity is required")
|
|
16
|
+
|
|
17
|
+
external_files = activity.getExternalFilesDir(None)
|
|
18
|
+
if external_files is None:
|
|
19
|
+
raise RuntimeError("Android external app storage is unavailable")
|
|
20
|
+
|
|
21
|
+
return os.path.join(str(external_files.getAbsolutePath()), "models")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _is_android():
|
|
25
|
+
return sys.platform == "android" or "ANDROID_ARGUMENT" in os.environ
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def models_directory(create=False):
|
|
29
|
+
"""Return PythonHere's platform-specific model directory.
|
|
30
|
+
|
|
31
|
+
Android uses the app-specific external files directory. Linux uses
|
|
32
|
+
PythonHere's per-user application data directory.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
if _is_android():
|
|
36
|
+
path = _android_models_directory()
|
|
37
|
+
else:
|
|
38
|
+
path = os.path.expanduser("~/.local/share/pythonhere/models")
|
|
39
|
+
|
|
40
|
+
path = os.path.abspath(path)
|
|
41
|
+
if create:
|
|
42
|
+
os.makedirs(path, exist_ok=True)
|
|
43
|
+
return path
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _relative_parts(value, label):
|
|
47
|
+
"""Return safe POSIX-style path components for a remote identifier."""
|
|
48
|
+
|
|
49
|
+
parts = value.split("/")
|
|
50
|
+
if not value or any(part in {"", ".", ".."} for part in parts):
|
|
51
|
+
raise ValueError(f"{label} must be a relative path without dot components")
|
|
52
|
+
return parts
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def model_path(repo_id, filename):
|
|
56
|
+
"""Return the local path for a model identified by repository and file."""
|
|
57
|
+
|
|
58
|
+
path = os.path.join(
|
|
59
|
+
models_directory(),
|
|
60
|
+
*_relative_parts(repo_id, "repo_id"),
|
|
61
|
+
*_relative_parts(filename, "filename"),
|
|
62
|
+
)
|
|
63
|
+
return os.path.abspath(path)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def require_model(repo_id, filename):
|
|
67
|
+
"""Return an installed model path, or raise ``FileNotFoundError``."""
|
|
68
|
+
|
|
69
|
+
path = model_path(repo_id, filename)
|
|
70
|
+
if not os.path.isfile(path):
|
|
71
|
+
raise FileNotFoundError(
|
|
72
|
+
f"ML model is not installed: {repo_id}/{filename} ({path})"
|
|
73
|
+
)
|
|
74
|
+
return path
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _model_extensions(extensions):
|
|
78
|
+
"""Normalize an optional model-extension filter."""
|
|
79
|
+
|
|
80
|
+
if extensions is None:
|
|
81
|
+
return None
|
|
82
|
+
if isinstance(extensions, str):
|
|
83
|
+
extensions = (extensions,)
|
|
84
|
+
|
|
85
|
+
normalized = set()
|
|
86
|
+
for extension in extensions:
|
|
87
|
+
if not isinstance(extension, str) or not extension:
|
|
88
|
+
raise ValueError("extensions must contain non-empty strings")
|
|
89
|
+
normalized_extension = extension.lower()
|
|
90
|
+
normalized.add(
|
|
91
|
+
normalized_extension
|
|
92
|
+
if normalized_extension.startswith(".")
|
|
93
|
+
else f".{normalized_extension}"
|
|
94
|
+
)
|
|
95
|
+
return tuple(sorted(normalized))
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _discover_directory(directory, extensions):
|
|
99
|
+
"""Yield model files recursively beneath a directory."""
|
|
100
|
+
|
|
101
|
+
path = os.path.abspath(os.fspath(directory))
|
|
102
|
+
if not os.path.isdir(path):
|
|
103
|
+
return
|
|
104
|
+
|
|
105
|
+
def ignore_error(_error):
|
|
106
|
+
pass
|
|
107
|
+
|
|
108
|
+
for root, directories, files in os.walk(path, onerror=ignore_error):
|
|
109
|
+
directories.sort(key=str.casefold)
|
|
110
|
+
for filename in files:
|
|
111
|
+
lower_filename = filename.lower()
|
|
112
|
+
if lower_filename.endswith((".part", ".part.json")):
|
|
113
|
+
continue
|
|
114
|
+
if extensions is None or lower_filename.endswith(extensions):
|
|
115
|
+
yield os.path.abspath(os.path.join(root, filename))
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def discover_models(extra_directories=(), *, extensions=".litertlm"):
|
|
119
|
+
"""Find local model files, optionally filtered by filename extension.
|
|
120
|
+
|
|
121
|
+
``extensions`` may be one extension or an iterable, with or without the
|
|
122
|
+
leading dot. The default finds LiteRT-LM models. Pass ``None`` to return
|
|
123
|
+
all completed files. Temporary files belonging to an in-progress download
|
|
124
|
+
are always ignored.
|
|
125
|
+
"""
|
|
126
|
+
|
|
127
|
+
if isinstance(extra_directories, (str, bytes, os.PathLike)):
|
|
128
|
+
extra_directories = (extra_directories,)
|
|
129
|
+
extensions = _model_extensions(extensions)
|
|
130
|
+
|
|
131
|
+
models = []
|
|
132
|
+
seen = set()
|
|
133
|
+
for directory in (models_directory(), *extra_directories):
|
|
134
|
+
for discovered_path in _discover_directory(directory, extensions):
|
|
135
|
+
key = os.path.normcase(discovered_path)
|
|
136
|
+
if key not in seen:
|
|
137
|
+
seen.add(key)
|
|
138
|
+
models.append(discovered_path)
|
|
139
|
+
return sorted(
|
|
140
|
+
models,
|
|
141
|
+
key=lambda path: (os.path.basename(path).casefold(), path.casefold()),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
__all__ = ("discover_models", "model_path", "models_directory", "require_model")
|
pythonhere/version_here.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.
|
|
1
|
+
__version__ = "0.4.0"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pythonhere
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.0
|
|
4
4
|
Summary: Here is the Kivy based app to run code from the Jupyter magic %there
|
|
5
5
|
Author-email: b3b <ash.b3b@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -16,10 +16,13 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
16
16
|
Requires-Python: >=3.10
|
|
17
17
|
Description-Content-Type: text/x-rst
|
|
18
18
|
License-File: LICENSE
|
|
19
|
-
Requires-Dist: herethere[magic]>=0.3.
|
|
19
|
+
Requires-Dist: herethere[magic]>=0.3.2
|
|
20
20
|
Requires-Dist: ipython
|
|
21
21
|
Requires-Dist: ipywidgets
|
|
22
22
|
Requires-Dist: Pillow
|
|
23
|
+
Provides-Extra: litert
|
|
24
|
+
Requires-Dist: litert-lm-api==0.16.0; extra == "litert"
|
|
25
|
+
Requires-Dist: requests; extra == "litert"
|
|
23
26
|
Dynamic: license-file
|
|
24
27
|
|
|
25
28
|
PythonHere
|
|
@@ -10,9 +10,9 @@ pythonhere/patches_here.py,sha256=zB7Ohbk5PIXt0imnnrV5Mtl-Y7jpD_p5IBPlijQcCCQ,17
|
|
|
10
10
|
pythonhere/pythonhere.kv,sha256=x1xwiKvJAevqBhtXGLb_axIf-VRos4V_jM9Q2i44f2U,1453
|
|
11
11
|
pythonhere/server_here.py,sha256=dhNMJj1Abz6RZq6SGqkh8-PVOxKThpI519Msoy5WCgM,1862
|
|
12
12
|
pythonhere/tools_here.py,sha256=RWPBX309d7E4mjkiszzsoJwdaSwXZIqb7ODcRBljC0Y,11437
|
|
13
|
-
pythonhere/version_here.py,sha256=
|
|
13
|
+
pythonhere/version_here.py,sha256=42STGor_9nKYXumfeV5tiyD_M8VdcddX7CEexmibPBk,22
|
|
14
14
|
pythonhere/window_here.py,sha256=oFPoNMGafGo4Eij3iU1WwaftmRa05Thm1jzuEAQIwK8,2584
|
|
15
|
-
pythonhere/.agents/skills/pythonhere/SKILL.md,sha256=
|
|
15
|
+
pythonhere/.agents/skills/pythonhere/SKILL.md,sha256=sZruiB7DaMeFLNAm2YLrPE7emmHELj2SEieMfxGrGJw,11080
|
|
16
16
|
pythonhere/.agents/skills/pythonhere/agents/openai.yaml,sha256=LuAs_jPFRl9Mhvb8bU8E8JSnCc8uc5JYFqYxlhd5elw,210
|
|
17
17
|
pythonhere/.agents/skills/pythonhere/references/able.md,sha256=3KFblzcGy8VDmriqgcWtqyfZZXoYfDV7kZyKIESCZ_c,22918
|
|
18
18
|
pythonhere/.agents/skills/pythonhere/references/android-media.md,sha256=vM55sxJmvkLQmKAjHZYL_z0F0SR__PjOHSXtGIgP1BI,6631
|
|
@@ -22,6 +22,7 @@ pythonhere/.agents/skills/pythonhere/references/android-runtime.md,sha256=VCZkyw
|
|
|
22
22
|
pythonhere/.agents/skills/pythonhere/references/jnius.md,sha256=lyjdGUsZXw2lS-0eppS2-JNTVgEED30z1DglzT6H0D8,14999
|
|
23
23
|
pythonhere/.agents/skills/pythonhere/references/kivy-kv.md,sha256=9PQR4j-LT66cOUKYCM6AuHXIs5ywmutOQKfxr3frDYw,8546
|
|
24
24
|
pythonhere/.agents/skills/pythonhere/references/kivy-runtime.md,sha256=ggPCmea5lkdg4p6LlxIVUstJhxC40SbrysqXXQ7-lmM,14616
|
|
25
|
+
pythonhere/.agents/skills/pythonhere/references/litert.md,sha256=MAchOo-acMlSwkmtSkAizNMdwKJHzIe87gFyzq6hyZE,4238
|
|
25
26
|
pythonhere/.agents/skills/pythonhere/references/midi.md,sha256=1rB4t7LWnMi139Ou896FzgU-6CGFSNVO1QF9kRBvUgo,10934
|
|
26
27
|
pythonhere/.agents/skills/pythonhere/references/plyer.md,sha256=FYqumbRo826aLrOiRGckS8Oq26v_PoVrSTVbTBZRBs8,6713
|
|
27
28
|
pythonhere/data/logo/logo-128.png,sha256=4sitDJcVBHOU5UPxicmrzc6YqFY7_xtYrc_ULyrw9ks,4161
|
|
@@ -41,6 +42,9 @@ pythonhere/magic_here/prompts/kivy-kv.md,sha256=ajIDSo6PG1_7gHcgfNrOARQOUlUEPUae
|
|
|
41
42
|
pythonhere/magic_here/prompts/kivy-runtime.md,sha256=cAgOF0uE3RKYdKQus7h4lklKtANaLPcOYilGShjNtgM,14621
|
|
42
43
|
pythonhere/magic_here/prompts/midi.md,sha256=2rKvgrwlmeA4MfdnRH9xnTSN0OFOm4mTxtgdYdMAd3Q,10611
|
|
43
44
|
pythonhere/magic_here/prompts/plyer.md,sha256=wplCHPXkN1vU_thGIxvALuYPB6QDdjCHFhoc93ppvAE,6708
|
|
45
|
+
pythonhere/ml_here/__init__.py,sha256=TiAtiBcGl5jkTmm3Rbt1mlPWRFo4BQTcgHHAzYOs_i0,346
|
|
46
|
+
pythonhere/ml_here/huggingface.py,sha256=857iOkJh90jbxhwyTo1EJ2enVwql3rI8-wUvK04UM9s,33030
|
|
47
|
+
pythonhere/ml_here/storage.py,sha256=JlKIad1bjVR7OSY2KFkyujyQA0dTH2DQPFJvFGH7AEE,4606
|
|
44
48
|
pythonhere/ui_here/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
49
|
pythonhere/ui_here/actionbar_here.kv,sha256=cOjY4ByOyBDUbeS9kbI3JAhi_X3kJ3Pb5h4RL58urwU,214
|
|
46
50
|
pythonhere/ui_here/common_here.kv,sha256=vnNyDwAKKNbRKvh0QKMbTvR0jNDKiY8DdGRnoEEexSc,324
|
|
@@ -51,8 +55,8 @@ pythonhere/ui_here/server_screen_here.kv,sha256=x0Se8hmgjS57gFIPa1r2lf6yJchs3lXO
|
|
|
51
55
|
pythonhere/ui_here/server_screen_here.py,sha256=2zQv1YFmiKNxa__7UZDYbAAAwYFLoZPSZPhr7vjCAkU,925
|
|
52
56
|
pythonhere/ui_here/settings_here.kv,sha256=stMcDq8dCYjay4idK30_7EUu5edkMDAQVPv0H0GuAcM,710
|
|
53
57
|
pythonhere/ui_here/settings_here.py,sha256=7NflZBUqY2ANZaSEuubaX9wIKniqbekcNQkUbqhhmto,4093
|
|
54
|
-
pythonhere-0.
|
|
55
|
-
pythonhere-0.
|
|
56
|
-
pythonhere-0.
|
|
57
|
-
pythonhere-0.
|
|
58
|
-
pythonhere-0.
|
|
58
|
+
pythonhere-0.4.0.dist-info/licenses/LICENSE,sha256=nW9_eVi3dSMOkr6xghsobAovBEJiffjl_5WjujJTa74,1071
|
|
59
|
+
pythonhere-0.4.0.dist-info/METADATA,sha256=_Fwxkb2YFoMe4IHOHzOaRLEmWsHjUi8A6JGiLKzN3-4,5470
|
|
60
|
+
pythonhere-0.4.0.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
|
|
61
|
+
pythonhere-0.4.0.dist-info/top_level.txt,sha256=dvkfRGF1tFbkjXzD9vwqXTge1Znkv7ga5fRJy5yhJsE,11
|
|
62
|
+
pythonhere-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|