nc-py-api 0.21.0__py3-none-any.whl → 0.21.1__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.
- nc_py_api/__init__.py +1 -0
- nc_py_api/_exceptions.py +4 -0
- nc_py_api/_version.py +1 -1
- nc_py_api/ex_app/integration_fastapi.py +98 -58
- {nc_py_api-0.21.0.dist-info → nc_py_api-0.21.1.dist-info}/METADATA +1 -1
- {nc_py_api-0.21.0.dist-info → nc_py_api-0.21.1.dist-info}/RECORD +9 -9
- {nc_py_api-0.21.0.dist-info → nc_py_api-0.21.1.dist-info}/WHEEL +0 -0
- {nc_py_api-0.21.0.dist-info → nc_py_api-0.21.1.dist-info}/licenses/AUTHORS +0 -0
- {nc_py_api-0.21.0.dist-info → nc_py_api-0.21.1.dist-info}/licenses/LICENSE.txt +0 -0
nc_py_api/__init__.py
CHANGED
nc_py_api/_exceptions.py
CHANGED
|
@@ -65,3 +65,7 @@ def check_error(response: Response, info: str = ""):
|
|
|
65
65
|
response.raise_for_status()
|
|
66
66
|
except HTTPError as e:
|
|
67
67
|
raise NextcloudException(status_code, reason=response.reason, info=info) from e
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class ModelFetchError(Exception):
|
|
71
|
+
"""Exception raised when model fetching fails."""
|
nc_py_api/_version.py
CHANGED
|
@@ -7,6 +7,7 @@ import hashlib
|
|
|
7
7
|
import json
|
|
8
8
|
import os
|
|
9
9
|
import typing
|
|
10
|
+
from traceback import format_exc
|
|
10
11
|
from urllib.parse import urlparse
|
|
11
12
|
|
|
12
13
|
import niquests
|
|
@@ -22,10 +23,10 @@ from fastapi.responses import JSONResponse, PlainTextResponse
|
|
|
22
23
|
from starlette.requests import HTTPConnection, Request
|
|
23
24
|
from starlette.types import ASGIApp, Receive, Scope, Send
|
|
24
25
|
|
|
26
|
+
from .._exceptions import ModelFetchError
|
|
25
27
|
from .._misc import get_username_secret_from_headers
|
|
26
28
|
from ..nextcloud import AsyncNextcloudApp, NextcloudApp
|
|
27
29
|
from ..talk_bot import TalkBotMessage
|
|
28
|
-
from .defs import LogLvl
|
|
29
30
|
from .misc import persistent_storage
|
|
30
31
|
|
|
31
32
|
|
|
@@ -70,9 +71,24 @@ def set_handlers(
|
|
|
70
71
|
|
|
71
72
|
.. note:: When this parameter is ``False``, the provision of ``models_to_fetch`` is not allowed.
|
|
72
73
|
|
|
73
|
-
:param models_to_fetch: Dictionary describing which models should be downloaded during `init
|
|
74
|
+
:param models_to_fetch: Dictionary describing which models should be downloaded during `init` of the form:
|
|
75
|
+
.. code-block:: python
|
|
76
|
+
{
|
|
77
|
+
"model_url_1": {
|
|
78
|
+
"save_path": "path_or_filename_to_save_the_model_to",
|
|
79
|
+
},
|
|
80
|
+
"huggingface_model_name_1": {
|
|
81
|
+
"max_workers": 4,
|
|
82
|
+
"cache_dir": "path_to_cache_dir",
|
|
83
|
+
"revision": "revision_to_fetch",
|
|
84
|
+
...
|
|
85
|
+
},
|
|
86
|
+
...
|
|
87
|
+
}
|
|
88
|
+
|
|
74
89
|
|
|
75
90
|
.. note:: ``huggingface_hub`` package should be present for automatic models fetching.
|
|
91
|
+
All model options are optional and can be left empty.
|
|
76
92
|
|
|
77
93
|
:param map_app_static: Should be folders ``js``, ``css``, ``l10n``, ``img`` automatically mounted in FastAPI or not.
|
|
78
94
|
|
|
@@ -121,74 +137,98 @@ def __map_app_static_folders(fast_api_app: FastAPI):
|
|
|
121
137
|
|
|
122
138
|
|
|
123
139
|
def fetch_models_task(nc: NextcloudApp, models: dict[str, dict], progress_init_start_value: int) -> None:
|
|
124
|
-
"""Use for cases when you want to define custom `/init` but still need to easy download models.
|
|
140
|
+
"""Use for cases when you want to define custom `/init` but still need to easy download models.
|
|
141
|
+
|
|
142
|
+
:param nc: NextcloudApp instance.
|
|
143
|
+
:param models_to_fetch: Dictionary describing which models should be downloaded of the form:
|
|
144
|
+
.. code-block:: python
|
|
145
|
+
{
|
|
146
|
+
"model_url_1": {
|
|
147
|
+
"save_path": "path_or_filename_to_save_the_model_to",
|
|
148
|
+
},
|
|
149
|
+
"huggingface_model_name_1": {
|
|
150
|
+
"max_workers": 4,
|
|
151
|
+
"cache_dir": "path_to_cache_dir",
|
|
152
|
+
"revision": "revision_to_fetch",
|
|
153
|
+
...
|
|
154
|
+
},
|
|
155
|
+
...
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.. note:: ``huggingface_hub`` package should be present for automatic models fetching.
|
|
159
|
+
All model options are optional and can be left empty.
|
|
160
|
+
|
|
161
|
+
:param progress_init_start_value: Integer value defining from which percent the progress should start.
|
|
162
|
+
|
|
163
|
+
:raises ModelFetchError: in case of a model download error.
|
|
164
|
+
:raises NextcloudException: in case of a network error reaching the Nextcloud server.
|
|
165
|
+
"""
|
|
125
166
|
if models:
|
|
126
167
|
current_progress = progress_init_start_value
|
|
127
168
|
percent_for_each = min(int((100 - progress_init_start_value) / len(models)), 99)
|
|
128
169
|
for model in models:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
170
|
+
try:
|
|
171
|
+
if model.startswith(("http://", "https://")):
|
|
172
|
+
models[model]["path"] = __fetch_model_as_file(
|
|
173
|
+
current_progress, percent_for_each, nc, model, models[model]
|
|
174
|
+
)
|
|
175
|
+
else:
|
|
176
|
+
models[model]["path"] = __fetch_model_as_snapshot(
|
|
177
|
+
current_progress, percent_for_each, nc, model, models[model]
|
|
178
|
+
)
|
|
179
|
+
current_progress += percent_for_each
|
|
180
|
+
except BaseException as e: # noqa pylint: disable=broad-exception-caught
|
|
181
|
+
nc.set_init_status(current_progress, f"Downloading of '{model}' failed: {e}: {format_exc()}")
|
|
182
|
+
raise ModelFetchError(f"Downloading of '{model}' failed.") from e
|
|
138
183
|
nc.set_init_status(100)
|
|
139
184
|
|
|
140
185
|
|
|
141
186
|
def __fetch_model_as_file(
|
|
142
187
|
current_progress: int, progress_for_task: int, nc: NextcloudApp, model_path: str, download_options: dict
|
|
143
|
-
) -> str
|
|
188
|
+
) -> str:
|
|
144
189
|
result_path = download_options.pop("save_path", urlparse(model_path).path.split("/")[-1])
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return result_path
|
|
184
|
-
except Exception as e: # noqa pylint: disable=broad-exception-caught
|
|
185
|
-
nc.log(LogLvl.ERROR, f"Downloading of '{model_path}' raised an exception: {e}")
|
|
186
|
-
|
|
187
|
-
return None
|
|
190
|
+
with niquests.get(model_path, stream=True) as response:
|
|
191
|
+
if not response.ok:
|
|
192
|
+
raise ModelFetchError(
|
|
193
|
+
f"Downloading of '{model_path}' failed, returned ({response.status_code}) {response.text}"
|
|
194
|
+
)
|
|
195
|
+
downloaded_size = 0
|
|
196
|
+
linked_etag = ""
|
|
197
|
+
for each_history in response.history:
|
|
198
|
+
linked_etag = each_history.headers.get("X-Linked-ETag", "")
|
|
199
|
+
if linked_etag:
|
|
200
|
+
break
|
|
201
|
+
if not linked_etag:
|
|
202
|
+
linked_etag = response.headers.get("X-Linked-ETag", response.headers.get("ETag", ""))
|
|
203
|
+
total_size = int(response.headers.get("Content-Length"))
|
|
204
|
+
try:
|
|
205
|
+
existing_size = os.path.getsize(result_path)
|
|
206
|
+
except OSError:
|
|
207
|
+
existing_size = 0
|
|
208
|
+
if linked_etag and total_size == existing_size:
|
|
209
|
+
with builtins.open(result_path, "rb") as file:
|
|
210
|
+
sha256_hash = hashlib.sha256()
|
|
211
|
+
for byte_block in iter(lambda: file.read(4096), b""):
|
|
212
|
+
sha256_hash.update(byte_block)
|
|
213
|
+
if f'"{sha256_hash.hexdigest()}"' == linked_etag:
|
|
214
|
+
nc.set_init_status(min(current_progress + progress_for_task, 99))
|
|
215
|
+
return result_path
|
|
216
|
+
|
|
217
|
+
with builtins.open(result_path, "wb") as file:
|
|
218
|
+
last_progress = current_progress
|
|
219
|
+
for chunk in response.iter_raw(-1):
|
|
220
|
+
downloaded_size += file.write(chunk)
|
|
221
|
+
if total_size:
|
|
222
|
+
new_progress = min(current_progress + int(progress_for_task * downloaded_size / total_size), 99)
|
|
223
|
+
if new_progress != last_progress:
|
|
224
|
+
nc.set_init_status(new_progress)
|
|
225
|
+
last_progress = new_progress
|
|
226
|
+
|
|
227
|
+
return result_path
|
|
188
228
|
|
|
189
229
|
|
|
190
230
|
def __fetch_model_as_snapshot(
|
|
191
|
-
current_progress: int, progress_for_task, nc: NextcloudApp,
|
|
231
|
+
current_progress: int, progress_for_task, nc: NextcloudApp, model_name: str, download_options: dict
|
|
192
232
|
) -> str:
|
|
193
233
|
from huggingface_hub import snapshot_download # noqa isort:skip pylint: disable=C0415 disable=E0401
|
|
194
234
|
from tqdm import tqdm # noqa isort:skip pylint: disable=C0415 disable=E0401
|
|
@@ -201,7 +241,7 @@ def __fetch_model_as_snapshot(
|
|
|
201
241
|
workers = download_options.pop("max_workers", 2)
|
|
202
242
|
cache = download_options.pop("cache_dir", persistent_storage())
|
|
203
243
|
return snapshot_download(
|
|
204
|
-
|
|
244
|
+
model_name, tqdm_class=TqdmProgress, **download_options, max_workers=workers, cache_dir=cache
|
|
205
245
|
)
|
|
206
246
|
|
|
207
247
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: nc-py-api
|
|
3
|
-
Version: 0.21.
|
|
3
|
+
Version: 0.21.1
|
|
4
4
|
Summary: Nextcloud Python Framework
|
|
5
5
|
Project-URL: Changelog, https://github.com/cloud-py-api/nc_py_api/blob/main/CHANGELOG.md
|
|
6
6
|
Project-URL: Documentation, https://cloud-py-api.github.io/nc_py_api/
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
nc_py_api/__init__.py,sha256=
|
|
1
|
+
nc_py_api/__init__.py,sha256=S5IytGqp8PkWnmcZXRFPSVEwfeb4iZ8xPeCmSf4sTFQ,460
|
|
2
2
|
nc_py_api/_deffered_error.py,sha256=BpEe_tBqflwfj2Zolb67nhW-K16XX-WbcY2IH_6u8fo,319
|
|
3
|
-
nc_py_api/_exceptions.py,sha256=
|
|
3
|
+
nc_py_api/_exceptions.py,sha256=_4k-uzpKdW5_WjqVE_saoGFJ1YqWx7W6kr-wgpBume0,2414
|
|
4
4
|
nc_py_api/_misc.py,sha256=dUzCP9VmyhtICTsn1aexlFAYUioBm40k6Zh-YE5WwCY,3333
|
|
5
5
|
nc_py_api/_preferences.py,sha256=OtovFZuGHnHYKjdDjSnUappO795tW8Oxj7qVaejHWpQ,2479
|
|
6
6
|
nc_py_api/_preferences_ex.py,sha256=Y6sDBrFJc7lk8BoDUfjC_iwOfjSbPPNPpcSxsL1fyIM,6391
|
|
7
7
|
nc_py_api/_session.py,sha256=u45U4USdgbegBj3oAnm-OErFng2fAyleH1dWgshJSso,22018
|
|
8
8
|
nc_py_api/_talk_api.py,sha256=0Uo7OduYniuuX3UQPb468RyGJJ-PWBCgJ5HoPuz5Qa0,51068
|
|
9
9
|
nc_py_api/_theming.py,sha256=hTr3nuOemSuRFZaPy9iXNmBM7rDgQHECH43tHMWGqEY,1870
|
|
10
|
-
nc_py_api/_version.py,sha256=
|
|
10
|
+
nc_py_api/_version.py,sha256=qWD6wPKnxx25NaWUPbzrV-OCufP6NS2579oj1jEc-ak,52
|
|
11
11
|
nc_py_api/activity.py,sha256=t9VDSnnaXRNOvALqOSGCeXSQZ-426pCOMSfQ96JHys4,9574
|
|
12
12
|
nc_py_api/apps.py,sha256=Us2y2lszdxXlD8t6kxwd5_Nrrmazc0EvZXIH9O-ol80,9315
|
|
13
13
|
nc_py_api/calendar_api.py,sha256=a2Q5EGf5_swWPYkUbHnoEg6h1S9KTEUQD7f7DljGHYY,1442
|
|
@@ -25,7 +25,7 @@ nc_py_api/weather_status.py,sha256=wAkjuJPjxc0Rxe4za0BzfwB0XeUmkCXoisJtTH3-qdQ,7
|
|
|
25
25
|
nc_py_api/webhooks.py,sha256=BGHRtankgbUkcqBRJTFShjRLpaVoFNcjLsrVitoNziM,8083
|
|
26
26
|
nc_py_api/ex_app/__init__.py,sha256=6Lwid4bBXOSrZf_ocf5m8qkkO1OgYxG0GTs4q6Nw72o,691
|
|
27
27
|
nc_py_api/ex_app/defs.py,sha256=FaQInH3jLugKxDUqpwrXdkMT-lBxmoqWmXJXc11fa6A,727
|
|
28
|
-
nc_py_api/ex_app/integration_fastapi.py,sha256=
|
|
28
|
+
nc_py_api/ex_app/integration_fastapi.py,sha256=mWMG8VrX_Q9yFw5hA3Wp996lyrybPnxTIT8sxp4GBrk,12636
|
|
29
29
|
nc_py_api/ex_app/logger.py,sha256=nAHLObuPvl3UBLrlqZulgoxxVaAJ661iP4F6bTW-V-Y,1475
|
|
30
30
|
nc_py_api/ex_app/misc.py,sha256=c7B0uE8isaIi4SQbxURGUuWjZaaXiLg3Ov6cqvRYplE,2298
|
|
31
31
|
nc_py_api/ex_app/occ_commands.py,sha256=hb2BJuvFKIigvLycSCyAe9v6hedq4Gfu2junQZTaK_M,5219
|
|
@@ -45,8 +45,8 @@ nc_py_api/files/_files.py,sha256=t7KBZE3fHmfVk0WZuQF9usCMY_b4rzX1ct1aIZx3RYw,143
|
|
|
45
45
|
nc_py_api/files/files.py,sha256=A05iT_s5cYMK1MtarqdjTZP9QA1l_SiINq805VLrzuY,24999
|
|
46
46
|
nc_py_api/files/files_async.py,sha256=GoTPswMgozcx3Vkbj4YSitNeP7vpPJ4lIbrCnj77rP4,25858
|
|
47
47
|
nc_py_api/files/sharing.py,sha256=VRZCl-TYK6dbu9rUHPs3_jcVozu1EO8bLGZwoRpiLsU,14439
|
|
48
|
-
nc_py_api-0.21.
|
|
49
|
-
nc_py_api-0.21.
|
|
50
|
-
nc_py_api-0.21.
|
|
51
|
-
nc_py_api-0.21.
|
|
52
|
-
nc_py_api-0.21.
|
|
48
|
+
nc_py_api-0.21.1.dist-info/METADATA,sha256=E0ZErYs8U1KOkOVjx_s1Gp4mExqOV6flkh-1Wm63qZI,8024
|
|
49
|
+
nc_py_api-0.21.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
|
50
|
+
nc_py_api-0.21.1.dist-info/licenses/AUTHORS,sha256=B2Q9q9XH3PAxJp0V3GiKQc1l0z7vtGDpDHqda-ISWKM,616
|
|
51
|
+
nc_py_api-0.21.1.dist-info/licenses/LICENSE.txt,sha256=OLEMh401fAumGHfRSna365MLIfnjdTcdOHZ6QOzMjkg,1551
|
|
52
|
+
nc_py_api-0.21.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|