notex-python 0.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.
notex/__init__.py ADDED
@@ -0,0 +1,105 @@
1
+ """Public API for the NoteX Python SDK."""
2
+
3
+ from notex_sdk import (
4
+ API_V1,
5
+ API_V2,
6
+ CREDITS_ME_ENDPOINT,
7
+ CREDITS_QUOTA_ENDPOINT,
8
+ DEFAULT_BASE_URL,
9
+ FLASHCARDS_CREATE_ENDPOINT,
10
+ MINDMAP_CREATE_ENDPOINT,
11
+ NOTE_CREATE_ENDPOINT,
12
+ NOTE_VALIDATE_ENDPOINT,
13
+ PODCAST_CREATE_ENDPOINT,
14
+ PRESIGNED_URL_ENDPOINT,
15
+ QUIZ_CREATE_ENDPOINT,
16
+ QUIZ_VIDEO_CREATE_ENDPOINT,
17
+ SHORTS_CREATE_ENDPOINT,
18
+ SLIDE_CREATE_ENDPOINT,
19
+ TASK_RESULT_ENDPOINT,
20
+ TRANSLATE_CREATE_ENDPOINT,
21
+ USER_NOTES_ENDPOINT,
22
+ USER_PROFILE_ENDPOINT,
23
+ AsyncNotexClient,
24
+ Credits,
25
+ Flashcard,
26
+ FlashcardSet,
27
+ GeneratedNote,
28
+ Mindmap,
29
+ MindmapNode,
30
+ NoteItem,
31
+ NotesPage,
32
+ NotexAPIError,
33
+ NotexAuthenticationError,
34
+ NotexClient,
35
+ NotexPermissionError,
36
+ NotexRateLimitError,
37
+ NotexTaskError,
38
+ NotexUploadError,
39
+ Podcast,
40
+ QuizQuestion,
41
+ QuizSet,
42
+ Quota,
43
+ RetryPolicy,
44
+ SlideDeck,
45
+ SourceValidation,
46
+ TaskResult,
47
+ TaskStatus,
48
+ TaskSubmission,
49
+ UrllibTransport,
50
+ UserProfile,
51
+ Video,
52
+ )
53
+
54
+ __all__ = [
55
+ "NotexClient",
56
+ "AsyncNotexClient",
57
+ "NotexAPIError",
58
+ "NotexAuthenticationError",
59
+ "NotexPermissionError",
60
+ "NotexRateLimitError",
61
+ "NotexUploadError",
62
+ "NotexTaskError",
63
+ "Credits",
64
+ "GeneratedNote",
65
+ "Flashcard",
66
+ "FlashcardSet",
67
+ "QuizQuestion",
68
+ "QuizSet",
69
+ "MindmapNode",
70
+ "Mindmap",
71
+ "Podcast",
72
+ "Video",
73
+ "SlideDeck",
74
+ "Quota",
75
+ "UserProfile",
76
+ "NoteItem",
77
+ "NotesPage",
78
+ "SourceValidation",
79
+ "TaskSubmission",
80
+ "TaskResult",
81
+ "TaskStatus",
82
+ "RetryPolicy",
83
+ "UrllibTransport",
84
+ "DEFAULT_BASE_URL",
85
+ "API_V1",
86
+ "API_V2",
87
+ "CREDITS_ME_ENDPOINT",
88
+ "CREDITS_QUOTA_ENDPOINT",
89
+ "USER_PROFILE_ENDPOINT",
90
+ "USER_NOTES_ENDPOINT",
91
+ "TASK_RESULT_ENDPOINT",
92
+ "PRESIGNED_URL_ENDPOINT",
93
+ "NOTE_CREATE_ENDPOINT",
94
+ "NOTE_VALIDATE_ENDPOINT",
95
+ "FLASHCARDS_CREATE_ENDPOINT",
96
+ "MINDMAP_CREATE_ENDPOINT",
97
+ "PODCAST_CREATE_ENDPOINT",
98
+ "QUIZ_CREATE_ENDPOINT",
99
+ "SHORTS_CREATE_ENDPOINT",
100
+ "QUIZ_VIDEO_CREATE_ENDPOINT",
101
+ "SLIDE_CREATE_ENDPOINT",
102
+ "TRANSLATE_CREATE_ENDPOINT",
103
+ ]
104
+
105
+ __version__ = "0.1.0"
notex/py.typed ADDED
@@ -0,0 +1 @@
1
+
@@ -0,0 +1,323 @@
1
+ Metadata-Version: 2.4
2
+ Name: notex-python
3
+ Version: 0.1.0
4
+ Summary: Typed, dependency-free Python SDK for the NoteX API
5
+ Author: NoteX
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://notexapp.com
8
+ Project-URL: Documentation, https://be-docs.notexapp.com
9
+ Keywords: notex,ai,notes,sdk,api-client
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: Operating System :: OS Independent
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Programming Language :: Python :: 3 :: Only
15
+ Classifier: Programming Language :: Python :: 3.9
16
+ Classifier: Programming Language :: Python :: 3.10
17
+ Classifier: Programming Language :: Python :: 3.11
18
+ Classifier: Programming Language :: Python :: 3.12
19
+ Classifier: Programming Language :: Python :: 3.13
20
+ Classifier: Typing :: Typed
21
+ Requires-Python: >=3.9
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=7; extra == "test"
26
+ Provides-Extra: dev
27
+ Requires-Dist: build>=1.2; extra == "dev"
28
+ Requires-Dist: pytest>=7; extra == "dev"
29
+ Requires-Dist: pyright>=1.1.400; extra == "dev"
30
+ Requires-Dist: ruff>=0.12; extra == "dev"
31
+ Requires-Dist: twine>=6; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # NoteX Python SDK
35
+
36
+ Typed, dependency-free Python SDK for API-key-enabled NoteX endpoints.
37
+
38
+ ```bash
39
+ pip install notex-python
40
+ ```
41
+
42
+ ```python
43
+ from notex import NotexClient
44
+
45
+ client = NotexClient(api_key="ntx_live_xxx")
46
+ ```
47
+
48
+ Requires Python 3.9 or newer.
49
+
50
+ ## Naming convention
51
+
52
+ The public SDK has one flat, explicit naming convention:
53
+
54
+ | Operation | Convention | Examples |
55
+ | --- | --- | --- |
56
+ | Read one value | `get_<resource>()` | `get_profile()`, `get_task_result()` |
57
+ | Read a collection | `list_<resources>()` | `list_notes()` |
58
+ | Validate input | `validate_<resource>()` | `validate_source()` |
59
+ | Create content | `create_<resource>()` | `create_note()`, `create_quiz()` |
60
+ | Wait for an async operation | `wait_for_<resource>()` | `wait_for_task()` |
61
+
62
+ Sync and async clients expose the same method names. The async variants are
63
+ awaited.
64
+
65
+ ## Multi-user integration
66
+
67
+ Each client represents one user API key for one request or background job.
68
+ Do not mutate a singleton client's key between users.
69
+
70
+ ```python
71
+ from notex import NotexClient
72
+
73
+
74
+ def notex_for_connection(connection_id: str) -> NotexClient:
75
+ api_key = credential_store.decrypt(connection_id)
76
+ return NotexClient(api_key=api_key)
77
+ ```
78
+
79
+ The SDK does not create, list, delete, persist, or automatically load API
80
+ keys. The integrating backend owns credential storage and rotation.
81
+
82
+ ## Supported methods
83
+
84
+ ### Account and notes
85
+
86
+ ```python
87
+ credits = client.get_credits()
88
+ quota = client.get_quota()
89
+ profile = client.get_profile()
90
+ notes = client.list_notes(limit=20, sort_field="createdAt", sort_order=-1)
91
+ ```
92
+
93
+ Credit fields vary by account/plan. `Credits` exposes optional
94
+ `total_credits`, `reward_credits`, `purchased_credits`, `user_type`, and
95
+ `has_paid`, while `raw` preserves the complete backend payload. `balance` is
96
+ an optional compatibility alias for responses that provide `balance` or
97
+ `total_credits`.
98
+
99
+ ### Validate and create notes
100
+
101
+ Create a note from a web URL:
102
+
103
+ ```python
104
+ submission = client.create_note(
105
+ web_url="https://youtu.be/example",
106
+ language_hints=["en"],
107
+ )
108
+ ```
109
+
110
+ Convenience equivalent:
111
+
112
+ ```python
113
+ submission = client.create_note_from_url(
114
+ "https://youtu.be/example",
115
+ language_hints=["en"],
116
+ )
117
+ ```
118
+
119
+ Create a note from an existing NoteX file URL:
120
+
121
+ ```python
122
+ submission = client.create_note_from_file_url(
123
+ "audio/user-1/lecture.mp3",
124
+ language_hints=["en"],
125
+ )
126
+ ```
127
+
128
+ Create a note from a local file:
129
+
130
+ ```python
131
+ submission = client.create_note_from_file(
132
+ "./lecture.mp3",
133
+ upload_file_name="lecture.mp3",
134
+ language_hints=["en"],
135
+ content_type="audio/mpeg",
136
+ )
137
+ ```
138
+
139
+ The local-file method performs the complete internal flow:
140
+
141
+ 1. Request a presigned upload contract.
142
+ 2. Upload the file directly without the NoteX API key.
143
+ 3. Submit note creation using the returned `file_url`.
144
+
145
+ Presign and direct-upload helpers are intentionally private. Use
146
+ `upload_file_name` when the local filename contains characters rejected by the
147
+ target gateway or object storage.
148
+
149
+ Validate a source before spending credits:
150
+
151
+ ```python
152
+ validation = client.validate_source(web_url="https://youtu.be/example")
153
+ ```
154
+
155
+ Exactly one of `web_url` or `file_url` is accepted by `create_note()` and
156
+ `validate_source()`.
157
+
158
+ ### Create content from a note
159
+
160
+ All create methods return `TaskSubmission` with a `task_id`.
161
+
162
+ ```python
163
+ flashcards = client.create_flashcards(
164
+ "note-id",
165
+ num_cards=10,
166
+ difficulty="medium",
167
+ )
168
+ quiz = client.create_quiz("note-id", num_questions=10)
169
+ mindmap = client.create_mindmap("note-id")
170
+ podcast = client.create_podcast("note-id", duration=180)
171
+ shorts = client.create_shorts("note-id", voice_id="en-US-Standard-A")
172
+ quiz_video = client.create_quiz_video("note-id", voice_id="en-US-Standard-A")
173
+ slides = client.create_slide("note-id", template_id="default", language="en")
174
+ translation = client.create_translation("note-id", language="vi")
175
+ ```
176
+
177
+ ### Poll task results
178
+
179
+ Use `get_task_result()` when the integrating backend manages scheduling:
180
+
181
+ ```python
182
+ result = client.get_task_result(submission.task_id)
183
+ ```
184
+
185
+ Use `wait_for_task()` in a worker when a blocking helper is appropriate:
186
+
187
+ ```python
188
+ result = client.wait_for_task(
189
+ submission.task_id,
190
+ poll_interval=5,
191
+ timeout=120,
192
+ )
193
+ ```
194
+
195
+ Do not run file uploads or blocking task polling directly in a web request.
196
+ Use a durable queue or background worker.
197
+
198
+ Completed results can be parsed into feature-specific typed models:
199
+
200
+ ```python
201
+ from notex import FlashcardSet
202
+
203
+ result = client.wait_for_task(flashcards.task_id)
204
+ flashcard_set = FlashcardSet.from_task_result(result)
205
+ print(flashcard_set.cards[0].front)
206
+ ```
207
+
208
+ Available result models include `GeneratedNote`, `FlashcardSet`, `QuizSet`,
209
+ `Mindmap`, `Podcast`, `Video`, and `SlideDeck`.
210
+
211
+ ## Async client
212
+
213
+ `AsyncNotexClient` exposes the same names and runs blocking standard-library
214
+ I/O in worker threads so the event loop remains responsive.
215
+
216
+ ```python
217
+ from notex import AsyncNotexClient
218
+
219
+ client = AsyncNotexClient(api_key="ntx_live_xxx")
220
+
221
+ submission = await client.create_quiz("note-id", num_questions=10)
222
+ result = await client.wait_for_task(submission.task_id, timeout=120)
223
+ ```
224
+
225
+ ## Errors and retry behavior
226
+
227
+ ```python
228
+ from notex import NotexAuthenticationError, NotexRateLimitError
229
+
230
+ try:
231
+ client.get_credits()
232
+ except NotexAuthenticationError:
233
+ reconnect_notex_account()
234
+ except NotexRateLimitError as error:
235
+ reschedule_job(error.retry_after)
236
+ ```
237
+
238
+ Public errors:
239
+
240
+ - `NotexAPIError`
241
+ - `NotexAuthenticationError`
242
+ - `NotexPermissionError`
243
+ - `NotexRateLimitError`
244
+ - `NotexUploadError`
245
+ - `NotexTaskError`
246
+
247
+ GET and HEAD requests retry transient network failures and HTTP 429/5xx
248
+ responses, honoring `Retry-After`. Content-creating POST requests are not
249
+ retried by default because repeating them can create duplicate work.
250
+
251
+ ## API compatibility
252
+
253
+ Every high-level method accepts `endpoint=` and `base_url=` overrides. This
254
+ allows an integration to adopt a new backend version before the SDK releases
255
+ an update.
256
+
257
+ ```python
258
+ client.get_credits(endpoint="/v3/credits/me")
259
+ client.create_flashcards("note-id", endpoint="/v7/create/flashcards")
260
+ ```
261
+
262
+ For a documented endpoint that is not wrapped yet, use the low-level escape
263
+ hatch:
264
+
265
+ ```python
266
+ response = client.request(
267
+ "POST",
268
+ "/v10/feature",
269
+ form={"note_id": "note-id"},
270
+ headers={"Idempotency-Key": "internal-job-id"},
271
+ )
272
+ ```
273
+
274
+ ## Real API integration tests
275
+
276
+ Copy the safe template and put the real key/base URL in the local file:
277
+
278
+ ```powershell
279
+ Copy-Item .notex-test.env.example .notex-test.env
280
+ ```
281
+
282
+ Edit `.notex-test.env`:
283
+
284
+ ```dotenv
285
+ NOTEX_TEST_API_KEY=ntx_test_your_real_key
286
+ NOTEX_TEST_BASE_URL=https://api.notexapp.com
287
+ ```
288
+
289
+ The file is ignored by Git. Read-only tests cover profile, credits, quota, and
290
+ note listing:
291
+
292
+ ```bash
293
+ python -m pytest tests/test_staging_integration.py -v
294
+ ```
295
+
296
+ Creation tests can upload files and spend credits, so they require explicit
297
+ opt-in:
298
+
299
+ ```dotenv
300
+ NOTEX_RUN_WRITE_TESTS=1
301
+ NOTEX_TEST_WEB_URL=https://youtu.be/example
302
+ NOTEX_TEST_FILE=C:\path\to\lecture.mp3
303
+ NOTEX_TEST_NOTE_ID=existing-note-id
304
+ NOTEX_TEST_FEATURES=flashcards,quiz,mindmap,translation
305
+ ```
306
+
307
+ Optional feature configuration is documented in
308
+ `.notex-test.env.example`. Test output is not persisted by the suite; local
309
+ credentials and `.notex-test-results/` are both excluded from Git.
310
+
311
+ ## Development and release checks
312
+
313
+ ```bash
314
+ python -m pip install -e ".[dev]"
315
+ python -m ruff check .
316
+ python -m pyright
317
+ python -m pytest -q
318
+ python -m build
319
+ python -m twine check dist/*
320
+ ```
321
+
322
+ See [RELEASING.md](RELEASING.md) for the Trusted Publishing release flow.
323
+ Never log, commit, or return API keys to frontend clients.
@@ -0,0 +1,15 @@
1
+ notex/__init__.py,sha256=OBOztsFwlrmVvQ82zOyetq58UohSSsjuVcwu__dCugk,2220
2
+ notex/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
3
+ notex_python-0.1.0.dist-info/licenses/LICENSE,sha256=0r4I_CjDc3JvT4P7yEovJieS72PEtUVTtNbiiWEpQTg,1062
4
+ notex_sdk/__init__.py,sha256=8OGtE4hcOHrug2l8axHLFJOFHsYYgxzSa7tJMLtcq4U,2309
5
+ notex_sdk/async_client.py,sha256=scUJa3dCh8SRQ5DofNbSNkHlya7enOcsSXpeocW-eJI,4534
6
+ notex_sdk/client.py,sha256=LtJMlRydqecwo9gOaKOTx-nO9tGEbgUTqNYg085HrWw,21463
7
+ notex_sdk/config.py,sha256=g45ngEVeBkVgHUmEI_yC8ylntpVKkLScCR3kqG-LpY8,931
8
+ notex_sdk/errors.py,sha256=U2spHvwdDhEqzHeWmhmGEuVyW2u8e_MfGB4hB2euMpo,1260
9
+ notex_sdk/models.py,sha256=HrofQN5H3fs6OQN4nmYSIw_3yEFgq0BJ9hvCwfnrzHI,15794
10
+ notex_sdk/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
+ notex_sdk/transport.py,sha256=Fse4oU5jwKRqz_SCbq8u4Cm3H9V9VfovU_-GyMn813s,5148
12
+ notex_python-0.1.0.dist-info/METADATA,sha256=RvuaRYHtu391qrzvGqxaDK4HXElWJwQWGs2XaUU8liE,9111
13
+ notex_python-0.1.0.dist-info/WHEEL,sha256=K260EYznzXsJYBQGqmI8VTxEdiZYNvDZwW9cBh9-_MA,91
14
+ notex_python-0.1.0.dist-info/top_level.txt,sha256=grCQy8NrHm0nJ2DNQmu1uzZg2G56SRfPBbcHLSYjI7Q,16
15
+ notex_python-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (83.0.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 NoteX
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,2 @@
1
+ notex
2
+ notex_sdk
notex_sdk/__init__.py ADDED
@@ -0,0 +1,108 @@
1
+ """Python SDK for the NoteX API."""
2
+
3
+ from .async_client import AsyncNotexClient
4
+ from .client import NotexClient
5
+ from .config import (
6
+ API_V1,
7
+ API_V2,
8
+ CREDITS_ME_ENDPOINT,
9
+ CREDITS_QUOTA_ENDPOINT,
10
+ DEFAULT_BASE_URL,
11
+ FLASHCARDS_CREATE_ENDPOINT,
12
+ MINDMAP_CREATE_ENDPOINT,
13
+ NOTE_CREATE_ENDPOINT,
14
+ NOTE_VALIDATE_ENDPOINT,
15
+ PODCAST_CREATE_ENDPOINT,
16
+ PRESIGNED_URL_ENDPOINT,
17
+ QUIZ_CREATE_ENDPOINT,
18
+ QUIZ_VIDEO_CREATE_ENDPOINT,
19
+ SHORTS_CREATE_ENDPOINT,
20
+ SLIDE_CREATE_ENDPOINT,
21
+ TASK_RESULT_ENDPOINT,
22
+ TRANSLATE_CREATE_ENDPOINT,
23
+ USER_NOTES_ENDPOINT,
24
+ USER_PROFILE_ENDPOINT,
25
+ )
26
+ from .errors import (
27
+ NotexAPIError,
28
+ NotexAuthenticationError,
29
+ NotexPermissionError,
30
+ NotexRateLimitError,
31
+ NotexTaskError,
32
+ NotexUploadError,
33
+ )
34
+ from .models import (
35
+ Credits,
36
+ Flashcard,
37
+ FlashcardSet,
38
+ GeneratedNote,
39
+ Mindmap,
40
+ MindmapNode,
41
+ NoteItem,
42
+ NotesPage,
43
+ Podcast,
44
+ QuizQuestion,
45
+ QuizSet,
46
+ Quota,
47
+ SlideDeck,
48
+ SourceValidation,
49
+ TaskResult,
50
+ TaskStatus,
51
+ TaskSubmission,
52
+ UserProfile,
53
+ Video,
54
+ )
55
+ from .transport import RetryPolicy, UrllibTransport
56
+
57
+ __all__ = [
58
+ "NotexClient",
59
+ "AsyncNotexClient",
60
+ "NotexAPIError",
61
+ "NotexAuthenticationError",
62
+ "NotexPermissionError",
63
+ "NotexRateLimitError",
64
+ "NotexUploadError",
65
+ "NotexTaskError",
66
+ "Credits",
67
+ "GeneratedNote",
68
+ "Flashcard",
69
+ "FlashcardSet",
70
+ "QuizQuestion",
71
+ "QuizSet",
72
+ "MindmapNode",
73
+ "Mindmap",
74
+ "Podcast",
75
+ "Video",
76
+ "SlideDeck",
77
+ "Quota",
78
+ "UserProfile",
79
+ "NoteItem",
80
+ "NotesPage",
81
+ "SourceValidation",
82
+ "TaskSubmission",
83
+ "TaskResult",
84
+ "TaskStatus",
85
+ "RetryPolicy",
86
+ "UrllibTransport",
87
+ "DEFAULT_BASE_URL",
88
+ "API_V1",
89
+ "API_V2",
90
+ "CREDITS_ME_ENDPOINT",
91
+ "CREDITS_QUOTA_ENDPOINT",
92
+ "USER_PROFILE_ENDPOINT",
93
+ "USER_NOTES_ENDPOINT",
94
+ "TASK_RESULT_ENDPOINT",
95
+ "PRESIGNED_URL_ENDPOINT",
96
+ "NOTE_CREATE_ENDPOINT",
97
+ "NOTE_VALIDATE_ENDPOINT",
98
+ "FLASHCARDS_CREATE_ENDPOINT",
99
+ "MINDMAP_CREATE_ENDPOINT",
100
+ "PODCAST_CREATE_ENDPOINT",
101
+ "QUIZ_CREATE_ENDPOINT",
102
+ "SHORTS_CREATE_ENDPOINT",
103
+ "QUIZ_VIDEO_CREATE_ENDPOINT",
104
+ "SLIDE_CREATE_ENDPOINT",
105
+ "TRANSLATE_CREATE_ENDPOINT",
106
+ ]
107
+
108
+ __version__ = "0.1.0"
@@ -0,0 +1,100 @@
1
+ """Async adapter for the dependency-free synchronous NoteX client."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import asyncio
6
+ from pathlib import Path
7
+ from typing import Any, Mapping, Optional, Union
8
+
9
+ from .client import NotexClient
10
+ from .models import (
11
+ Credits,
12
+ NotesPage,
13
+ Quota,
14
+ SourceValidation,
15
+ TaskResult,
16
+ TaskSubmission,
17
+ UserProfile,
18
+ )
19
+
20
+
21
+ class AsyncNotexClient:
22
+ """Run a request-scoped :class:`NotexClient` without blocking an event loop.
23
+
24
+ This adapter delegates blocking I/O to a worker thread. It is intentionally
25
+ small; it keeps sync and async behavior identical without adding an HTTP
26
+ dependency to the SDK.
27
+ """
28
+
29
+ def __init__(self, client: Optional[NotexClient] = None, **client_options: Any) -> None:
30
+ if client is not None and client_options:
31
+ raise ValueError("pass either client or client options, not both")
32
+ self._client = client or NotexClient(**client_options)
33
+
34
+ @property
35
+ def sync_client(self) -> NotexClient:
36
+ return self._client
37
+
38
+ async def get_credits(self, **options: Any) -> Credits:
39
+ return await asyncio.to_thread(self._client.get_credits, **options)
40
+
41
+ async def get_quota(self, **options: Any) -> Quota:
42
+ return await asyncio.to_thread(self._client.get_quota, **options)
43
+
44
+ async def get_profile(self, **options: Any) -> UserProfile:
45
+ return await asyncio.to_thread(self._client.get_profile, **options)
46
+
47
+ async def list_notes(self, **options: Any) -> NotesPage:
48
+ return await asyncio.to_thread(self._client.list_notes, **options)
49
+
50
+ async def validate_source(self, **options: Any) -> SourceValidation:
51
+ return await asyncio.to_thread(self._client.validate_source, **options)
52
+
53
+ async def create_note(self, **options: Any) -> TaskSubmission:
54
+ return await asyncio.to_thread(self._client.create_note, **options)
55
+
56
+ async def create_note_from_url(self, web_url: str, **options: Any) -> TaskSubmission:
57
+ return await asyncio.to_thread(self._client.create_note_from_url, web_url, **options)
58
+
59
+ async def create_note_from_file_url(self, file_url: str, **options: Any) -> TaskSubmission:
60
+ return await asyncio.to_thread(self._client.create_note_from_file_url, file_url, **options)
61
+
62
+ async def create_note_from_file(
63
+ self, file_path: Union[str, Path], **options: Any
64
+ ) -> TaskSubmission:
65
+ return await asyncio.to_thread(self._client.create_note_from_file, file_path, **options)
66
+
67
+ async def create_flashcards(self, note_id: str, **options: Any) -> TaskSubmission:
68
+ return await asyncio.to_thread(self._client.create_flashcards, note_id, **options)
69
+
70
+ async def create_mindmap(self, note_id: str, **options: Any) -> TaskSubmission:
71
+ return await asyncio.to_thread(self._client.create_mindmap, note_id, **options)
72
+
73
+ async def create_podcast(self, note_id: str, duration: int, **options: Any) -> TaskSubmission:
74
+ return await asyncio.to_thread(self._client.create_podcast, note_id, duration, **options)
75
+
76
+ async def create_quiz(self, note_id: str, **options: Any) -> TaskSubmission:
77
+ return await asyncio.to_thread(self._client.create_quiz, note_id, **options)
78
+
79
+ async def create_shorts(self, note_id: str, voice_id: str, **options: Any) -> TaskSubmission:
80
+ return await asyncio.to_thread(self._client.create_shorts, note_id, voice_id, **options)
81
+
82
+ async def create_quiz_video(self, note_id: str, voice_id: str, **options: Any) -> TaskSubmission:
83
+ return await asyncio.to_thread(self._client.create_quiz_video, note_id, voice_id, **options)
84
+
85
+ async def create_slide(self, note_id: str, template_id: str, **options: Any) -> TaskSubmission:
86
+ return await asyncio.to_thread(self._client.create_slide, note_id, template_id, **options)
87
+
88
+ async def create_translation(self, note_id: str, language: str, **options: Any) -> TaskSubmission:
89
+ return await asyncio.to_thread(self._client.create_translation, note_id, language, **options)
90
+
91
+ async def get_task_result(self, task_id: str, **options: Any) -> TaskResult:
92
+ return await asyncio.to_thread(self._client.get_task_result, task_id, **options)
93
+
94
+ async def wait_for_task(self, task_id: str, **options: Any) -> TaskResult:
95
+ return await asyncio.to_thread(self._client.wait_for_task, task_id, **options)
96
+
97
+ async def request(
98
+ self, method: str, path: str, **options: Any
99
+ ) -> Mapping[str, Any]:
100
+ return await asyncio.to_thread(self._client.request, method, path, **options)