audex 1.0.7a3__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 (192) hide show
  1. audex/__init__.py +9 -0
  2. audex/__main__.py +7 -0
  3. audex/cli/__init__.py +189 -0
  4. audex/cli/apis/__init__.py +12 -0
  5. audex/cli/apis/init/__init__.py +34 -0
  6. audex/cli/apis/init/gencfg.py +130 -0
  7. audex/cli/apis/init/setup.py +330 -0
  8. audex/cli/apis/init/vprgroup.py +125 -0
  9. audex/cli/apis/serve.py +141 -0
  10. audex/cli/args.py +356 -0
  11. audex/cli/exceptions.py +44 -0
  12. audex/cli/helper/__init__.py +0 -0
  13. audex/cli/helper/ansi.py +193 -0
  14. audex/cli/helper/display.py +288 -0
  15. audex/config/__init__.py +64 -0
  16. audex/config/core/__init__.py +30 -0
  17. audex/config/core/app.py +29 -0
  18. audex/config/core/audio.py +45 -0
  19. audex/config/core/logging.py +163 -0
  20. audex/config/core/session.py +11 -0
  21. audex/config/helper/__init__.py +1 -0
  22. audex/config/helper/client/__init__.py +1 -0
  23. audex/config/helper/client/http.py +28 -0
  24. audex/config/helper/client/websocket.py +21 -0
  25. audex/config/helper/provider/__init__.py +1 -0
  26. audex/config/helper/provider/dashscope.py +13 -0
  27. audex/config/helper/provider/unisound.py +18 -0
  28. audex/config/helper/provider/xfyun.py +23 -0
  29. audex/config/infrastructure/__init__.py +31 -0
  30. audex/config/infrastructure/cache.py +51 -0
  31. audex/config/infrastructure/database.py +48 -0
  32. audex/config/infrastructure/recorder.py +32 -0
  33. audex/config/infrastructure/store.py +19 -0
  34. audex/config/provider/__init__.py +18 -0
  35. audex/config/provider/transcription.py +109 -0
  36. audex/config/provider/vpr.py +99 -0
  37. audex/container.py +40 -0
  38. audex/entity/__init__.py +468 -0
  39. audex/entity/doctor.py +109 -0
  40. audex/entity/doctor.pyi +51 -0
  41. audex/entity/fields.py +401 -0
  42. audex/entity/segment.py +115 -0
  43. audex/entity/segment.pyi +38 -0
  44. audex/entity/session.py +133 -0
  45. audex/entity/session.pyi +47 -0
  46. audex/entity/utterance.py +142 -0
  47. audex/entity/utterance.pyi +48 -0
  48. audex/entity/vp.py +68 -0
  49. audex/entity/vp.pyi +35 -0
  50. audex/exceptions.py +157 -0
  51. audex/filters/__init__.py +692 -0
  52. audex/filters/generated/__init__.py +21 -0
  53. audex/filters/generated/doctor.py +987 -0
  54. audex/filters/generated/segment.py +723 -0
  55. audex/filters/generated/session.py +978 -0
  56. audex/filters/generated/utterance.py +939 -0
  57. audex/filters/generated/vp.py +815 -0
  58. audex/helper/__init__.py +1 -0
  59. audex/helper/hash.py +33 -0
  60. audex/helper/mixin.py +65 -0
  61. audex/helper/net.py +19 -0
  62. audex/helper/settings/__init__.py +830 -0
  63. audex/helper/settings/fields.py +317 -0
  64. audex/helper/stream.py +153 -0
  65. audex/injectors/__init__.py +1 -0
  66. audex/injectors/config.py +12 -0
  67. audex/injectors/lifespan.py +7 -0
  68. audex/lib/__init__.py +1 -0
  69. audex/lib/cache/__init__.py +383 -0
  70. audex/lib/cache/inmemory.py +513 -0
  71. audex/lib/database/__init__.py +83 -0
  72. audex/lib/database/sqlite.py +406 -0
  73. audex/lib/exporter.py +189 -0
  74. audex/lib/injectors/__init__.py +1 -0
  75. audex/lib/injectors/cache.py +25 -0
  76. audex/lib/injectors/container.py +47 -0
  77. audex/lib/injectors/exporter.py +26 -0
  78. audex/lib/injectors/recorder.py +33 -0
  79. audex/lib/injectors/server.py +17 -0
  80. audex/lib/injectors/session.py +18 -0
  81. audex/lib/injectors/sqlite.py +24 -0
  82. audex/lib/injectors/store.py +13 -0
  83. audex/lib/injectors/transcription.py +42 -0
  84. audex/lib/injectors/usb.py +12 -0
  85. audex/lib/injectors/vpr.py +65 -0
  86. audex/lib/injectors/wifi.py +7 -0
  87. audex/lib/recorder.py +844 -0
  88. audex/lib/repos/__init__.py +149 -0
  89. audex/lib/repos/container.py +23 -0
  90. audex/lib/repos/database/__init__.py +1 -0
  91. audex/lib/repos/database/sqlite.py +672 -0
  92. audex/lib/repos/decorators.py +74 -0
  93. audex/lib/repos/doctor.py +286 -0
  94. audex/lib/repos/segment.py +302 -0
  95. audex/lib/repos/session.py +285 -0
  96. audex/lib/repos/tables/__init__.py +70 -0
  97. audex/lib/repos/tables/doctor.py +137 -0
  98. audex/lib/repos/tables/segment.py +113 -0
  99. audex/lib/repos/tables/session.py +140 -0
  100. audex/lib/repos/tables/utterance.py +131 -0
  101. audex/lib/repos/tables/vp.py +102 -0
  102. audex/lib/repos/utterance.py +288 -0
  103. audex/lib/repos/vp.py +286 -0
  104. audex/lib/restful.py +251 -0
  105. audex/lib/server/__init__.py +97 -0
  106. audex/lib/server/auth.py +98 -0
  107. audex/lib/server/handlers.py +248 -0
  108. audex/lib/server/templates/index.html.j2 +226 -0
  109. audex/lib/server/templates/login.html.j2 +111 -0
  110. audex/lib/server/templates/static/script.js +68 -0
  111. audex/lib/server/templates/static/style.css +579 -0
  112. audex/lib/server/types.py +123 -0
  113. audex/lib/session.py +503 -0
  114. audex/lib/store/__init__.py +238 -0
  115. audex/lib/store/localfile.py +411 -0
  116. audex/lib/transcription/__init__.py +33 -0
  117. audex/lib/transcription/dashscope.py +525 -0
  118. audex/lib/transcription/events.py +62 -0
  119. audex/lib/usb.py +554 -0
  120. audex/lib/vpr/__init__.py +38 -0
  121. audex/lib/vpr/unisound/__init__.py +185 -0
  122. audex/lib/vpr/unisound/types.py +469 -0
  123. audex/lib/vpr/xfyun/__init__.py +483 -0
  124. audex/lib/vpr/xfyun/types.py +679 -0
  125. audex/lib/websocket/__init__.py +8 -0
  126. audex/lib/websocket/connection.py +485 -0
  127. audex/lib/websocket/pool.py +991 -0
  128. audex/lib/wifi.py +1146 -0
  129. audex/lifespan.py +75 -0
  130. audex/service/__init__.py +27 -0
  131. audex/service/decorators.py +73 -0
  132. audex/service/doctor/__init__.py +652 -0
  133. audex/service/doctor/const.py +36 -0
  134. audex/service/doctor/exceptions.py +96 -0
  135. audex/service/doctor/types.py +54 -0
  136. audex/service/export/__init__.py +236 -0
  137. audex/service/export/const.py +17 -0
  138. audex/service/export/exceptions.py +34 -0
  139. audex/service/export/types.py +21 -0
  140. audex/service/injectors/__init__.py +1 -0
  141. audex/service/injectors/container.py +53 -0
  142. audex/service/injectors/doctor.py +34 -0
  143. audex/service/injectors/export.py +27 -0
  144. audex/service/injectors/session.py +49 -0
  145. audex/service/session/__init__.py +754 -0
  146. audex/service/session/const.py +34 -0
  147. audex/service/session/exceptions.py +67 -0
  148. audex/service/session/types.py +91 -0
  149. audex/types.py +39 -0
  150. audex/utils.py +287 -0
  151. audex/valueobj/__init__.py +81 -0
  152. audex/valueobj/common/__init__.py +1 -0
  153. audex/valueobj/common/auth.py +84 -0
  154. audex/valueobj/common/email.py +16 -0
  155. audex/valueobj/common/ops.py +22 -0
  156. audex/valueobj/common/phone.py +84 -0
  157. audex/valueobj/common/version.py +72 -0
  158. audex/valueobj/session.py +19 -0
  159. audex/valueobj/utterance.py +15 -0
  160. audex/view/__init__.py +51 -0
  161. audex/view/container.py +17 -0
  162. audex/view/decorators.py +303 -0
  163. audex/view/pages/__init__.py +1 -0
  164. audex/view/pages/dashboard/__init__.py +286 -0
  165. audex/view/pages/dashboard/wifi.py +407 -0
  166. audex/view/pages/login.py +110 -0
  167. audex/view/pages/recording.py +348 -0
  168. audex/view/pages/register.py +202 -0
  169. audex/view/pages/sessions/__init__.py +196 -0
  170. audex/view/pages/sessions/details.py +224 -0
  171. audex/view/pages/sessions/export.py +443 -0
  172. audex/view/pages/settings.py +374 -0
  173. audex/view/pages/voiceprint/__init__.py +1 -0
  174. audex/view/pages/voiceprint/enroll.py +195 -0
  175. audex/view/pages/voiceprint/update.py +195 -0
  176. audex/view/static/css/dashboard.css +452 -0
  177. audex/view/static/css/glass.css +22 -0
  178. audex/view/static/css/global.css +541 -0
  179. audex/view/static/css/login.css +386 -0
  180. audex/view/static/css/recording.css +439 -0
  181. audex/view/static/css/register.css +293 -0
  182. audex/view/static/css/sessions/styles.css +501 -0
  183. audex/view/static/css/settings.css +186 -0
  184. audex/view/static/css/voiceprint/enroll.css +43 -0
  185. audex/view/static/css/voiceprint/styles.css +209 -0
  186. audex/view/static/css/voiceprint/update.css +44 -0
  187. audex/view/static/images/logo.svg +95 -0
  188. audex/view/static/js/recording.js +42 -0
  189. audex-1.0.7a3.dist-info/METADATA +361 -0
  190. audex-1.0.7a3.dist-info/RECORD +192 -0
  191. audex-1.0.7a3.dist-info/WHEEL +4 -0
  192. audex-1.0.7a3.dist-info/entry_points.txt +3 -0
@@ -0,0 +1,383 @@
1
+ from __future__ import annotations
2
+
3
+ import abc
4
+ import typing as t
5
+
6
+ from audex import __title__
7
+ from audex.helper.mixin import AsyncContextMixin
8
+ from audex.helper.mixin import LoggingMixin
9
+
10
+
11
+ class Empty:
12
+ """Sentinel type representing an empty/missing value.
13
+
14
+ Used to distinguish between None (a valid value) and a truly missing value.
15
+ Always evaluates to False in boolean context.
16
+
17
+ Example:
18
+ ```python
19
+ async def get_value(key: str) -> str | Empty:
20
+ if key not in data:
21
+ return EMPTY
22
+ return data[key]
23
+
24
+
25
+ value = await get_value("missing")
26
+ if value is EMPTY:
27
+ print("Value not found")
28
+ ```
29
+ """
30
+
31
+ __slots__ = ()
32
+
33
+ def __repr__(self) -> str:
34
+ return "<EMPTY>"
35
+
36
+ __str__ = __repr__
37
+
38
+ def __bool__(self) -> bool:
39
+ return False
40
+
41
+ def __eq__(self, other: object) -> bool:
42
+ return isinstance(other, Empty)
43
+
44
+ def __hash__(self) -> int:
45
+ return hash("<EMPTY>")
46
+
47
+
48
+ EMPTY = Empty()
49
+
50
+
51
+ class Placeholder:
52
+ """Sentinel type representing a placeholder value.
53
+
54
+ Used to mark positions where a value will be provided later. Always
55
+ evaluates to True in boolean context.
56
+ """
57
+
58
+ __slots__ = ()
59
+
60
+ def __repr__(self) -> str:
61
+ return "<PLACEHOLDER>"
62
+
63
+ __str__ = __repr__
64
+
65
+ def __bool__(self) -> bool:
66
+ return True
67
+
68
+ def __getstate__(self) -> tuple[()]:
69
+ return ()
70
+
71
+ def __setstate__(self, state: tuple[()]) -> None:
72
+ pass
73
+
74
+ def __eq__(self, other: object) -> bool:
75
+ return isinstance(other, Placeholder)
76
+
77
+ def __hash__(self) -> int:
78
+ return hash("<PLACEHOLDER>")
79
+
80
+
81
+ PLACEHOLDER = Placeholder()
82
+
83
+
84
+ class CacheMiss:
85
+ """Sentinel type representing a cache miss.
86
+
87
+ Used to distinguish between cached None values and keys that don't
88
+ exist. Always evaluates to False in boolean context.
89
+ """
90
+
91
+ __slots__ = ()
92
+
93
+ def __repr__(self) -> str:
94
+ return "<CACHE_MISS>"
95
+
96
+ __str__ = __repr__
97
+
98
+ def __bool__(self) -> bool:
99
+ return False
100
+
101
+ def __eq__(self, other: object) -> bool:
102
+ return isinstance(other, CacheMiss)
103
+
104
+ def __hash__(self) -> int:
105
+ return hash("<CACHE_MISS>")
106
+
107
+ def __getstate__(self) -> tuple[()]:
108
+ return ()
109
+
110
+ def __setstate__(self, state: tuple[()]) -> None:
111
+ pass
112
+
113
+
114
+ CACHE_MISS = CacheMiss()
115
+
116
+
117
+ class Negative:
118
+ """Sentinel type representing a negative cache entry.
119
+
120
+ Used to mark keys that are known to be absent, preventing cache
121
+ penetration. Always evaluates to False in boolean context.
122
+ """
123
+
124
+ __slots__ = ()
125
+
126
+ def __repr__(self) -> str:
127
+ return "<NEGATIVE>"
128
+
129
+ __str__ = __repr__
130
+
131
+ def __bool__(self) -> bool:
132
+ return False
133
+
134
+ def __eq__(self, other: object) -> bool:
135
+ return isinstance(other, Negative)
136
+
137
+ def __hash__(self) -> int:
138
+ return hash("<NEGATIVE>")
139
+
140
+ def __getstate__(self) -> tuple[()]:
141
+ return ()
142
+
143
+ def __setstate__(self, state: tuple[()]) -> None:
144
+ pass
145
+
146
+
147
+ NEGATIVE = Negative()
148
+
149
+
150
+ class KeyBuilder:
151
+ """Utility class for building cache keys with a consistent format.
152
+
153
+ Provides methods to construct namespaced cache keys and validate key formats.
154
+
155
+ Attributes:
156
+ split_char: Character used to split parts of the key.
157
+ prefix: Prefix to prepend to all keys.
158
+
159
+ Args:
160
+ split_char: Separator character for key parts. Defaults to ":".
161
+ prefix: Namespace prefix for all keys. Defaults to normalized project title.
162
+
163
+ Example:
164
+ ```python
165
+ builder = KeyBuilder(prefix="myapp")
166
+
167
+ # Build keys
168
+ user_key = builder.build("user", "123") # "myapp:user:123"
169
+ session_key = builder.build(
170
+ "session", "abc"
171
+ ) # "myapp:session:abc"
172
+
173
+ # Validate keys
174
+ builder.validate("myapp:user:123") # True
175
+ builder.validate("other:user:123") # False
176
+ ```
177
+ """
178
+
179
+ __slots__ = ("prefix", "split_char")
180
+
181
+ def __init__(
182
+ self,
183
+ split_char: str = ":",
184
+ prefix: str = __title__.lower().replace(" ", "_"),
185
+ ) -> None:
186
+ self.split_char = split_char
187
+ self.prefix = prefix
188
+
189
+ def build(self, *parts: str) -> str:
190
+ """Build a cache key by joining the prefix and parts.
191
+
192
+ Args:
193
+ *parts: Parts to include in the key.
194
+
195
+ Returns:
196
+ The constructed cache key.
197
+ """
198
+ return self.split_char.join((self.prefix, *parts))
199
+
200
+ def validate(self, key: str) -> bool:
201
+ """Validate if a given key starts with the defined prefix.
202
+
203
+ Args:
204
+ key: The cache key to validate.
205
+
206
+ Returns:
207
+ True if the key starts with the prefix, False otherwise.
208
+ """
209
+ return key.startswith(self.prefix + self.split_char)
210
+
211
+ def __repr__(self) -> str:
212
+ return f"CACHE KEY BUILDER <{self.__class__.__name__} (prefix={self.prefix}, split_char={self.split_char})>"
213
+
214
+
215
+ T = t.TypeVar("T")
216
+ VT = t.TypeVar("VT")
217
+
218
+
219
+ class KVCache(LoggingMixin, AsyncContextMixin, abc.ABC):
220
+ """Abstract base class for async key-value cache implementations.
221
+
222
+ Provides an async dictionary-like interface for caching with support for TTL,
223
+ atomic operations (incr/decr), and key validation. Implementations can
224
+ use in-memory storage, Redis, or other backends.
225
+
226
+ The cache supports:
227
+ - Async dict operations (get, set, delete, etc.)
228
+ - Time-to-live (TTL) for automatic expiration
229
+ - Atomic increment/decrement operations
230
+ - Key namespace management via KeyBuilder
231
+
232
+ Example:
233
+ ```python
234
+ # Using a cache implementation
235
+ cache = await make_cache(config, logger)
236
+
237
+ # Basic operations
238
+ await cache.set("user:123", {"name": "Alice"})
239
+ user = await cache.get("user:123")
240
+
241
+ # With TTL
242
+ await cache.setx("session:abc", {"data": "..."}, ttl=3600)
243
+
244
+ # Atomic operations
245
+ await cache.incr("counter:visits")
246
+ await cache.decr("counter:remaining", amount=5)
247
+ ```
248
+ """
249
+
250
+ @property
251
+ @abc.abstractmethod
252
+ def key_builder(self) -> KeyBuilder:
253
+ """Get the KeyBuilder instance used for constructing cache
254
+ keys."""
255
+
256
+ @abc.abstractmethod
257
+ async def get_item(self, key: str) -> VT | Empty | Negative:
258
+ """Retrieve an item from the cache by key."""
259
+
260
+ @abc.abstractmethod
261
+ async def set_item(self, key: str, value: VT) -> None:
262
+ """Set an item in the cache with the specified key and value."""
263
+
264
+ @abc.abstractmethod
265
+ async def del_item(self, key: str) -> None:
266
+ """Delete an item from the cache by key."""
267
+
268
+ @abc.abstractmethod
269
+ def iter_keys(self) -> t.AsyncIterator[str]:
270
+ """Return an async iterator over the keys in the cache."""
271
+
272
+ @abc.abstractmethod
273
+ async def len(self) -> int:
274
+ """Return the number of items in the cache."""
275
+
276
+ @abc.abstractmethod
277
+ async def contains(self, key: str) -> bool:
278
+ """Check if the cache contains a specific key."""
279
+
280
+ @abc.abstractmethod
281
+ async def get(self, key: str, /, default: VT | T | None = None) -> VT | T | None:
282
+ """Get an item from the cache, returning default if the key does
283
+ not exist."""
284
+
285
+ @abc.abstractmethod
286
+ async def setdefault(self, key: str, default: VT | None = None, /) -> VT | None:
287
+ """Set a default value for a key if it does not exist in the
288
+ cache."""
289
+
290
+ @abc.abstractmethod
291
+ async def clear(self) -> None:
292
+ """Clear all items from the cache."""
293
+
294
+ @abc.abstractmethod
295
+ async def pop(self, key: str, /, default: VT | T | None = None) -> VT | T | None:
296
+ """Remove and return an item from the cache by key."""
297
+
298
+ @abc.abstractmethod
299
+ async def popitem(self) -> tuple[str, VT]:
300
+ """Remove and return an arbitrary (key, value) pair from the
301
+ cache."""
302
+
303
+ @abc.abstractmethod
304
+ async def set(self, key: str, value: VT) -> None:
305
+ """Set an item in the cache with the specified key and value."""
306
+
307
+ @abc.abstractmethod
308
+ async def setx(self, key: str, value: VT, ttl: int | None = None) -> None:
309
+ """Set an item in the cache with the specified key, value, and
310
+ optional TTL.
311
+
312
+ Args:
313
+ key: Cache key.
314
+ value: Value to store.
315
+ ttl: Time-to-live in seconds. None means use default TTL.
316
+ """
317
+
318
+ @abc.abstractmethod
319
+ async def set_negative(self, key: str, /) -> None:
320
+ """Store cache miss marker to prevent cache penetration.
321
+
322
+ Args:
323
+ key: Cache key.
324
+ """
325
+
326
+ @abc.abstractmethod
327
+ async def ttl(self, key: str) -> int | None:
328
+ """Get the time-to-live (TTL) for a specific key in the cache.
329
+
330
+ Args:
331
+ key: Cache key.
332
+
333
+ Returns:
334
+ Remaining TTL in seconds, or None if no TTL is set.
335
+ """
336
+
337
+ @abc.abstractmethod
338
+ async def expire(self, key: str, ttl: int | None = None) -> None:
339
+ """Set the time-to-live (TTL) for a specific key in the cache.
340
+
341
+ Args:
342
+ key: Cache key.
343
+ ttl: Time-to-live in seconds. None means use default TTL.
344
+ """
345
+
346
+ @abc.abstractmethod
347
+ async def incr(self, key: str, amount: int = 1) -> int:
348
+ """Increment the integer value of a key by the given amount.
349
+
350
+ Args:
351
+ key: Cache key.
352
+ amount: Amount to increment by. Defaults to 1.
353
+
354
+ Returns:
355
+ The new value after incrementing.
356
+ """
357
+
358
+ @abc.abstractmethod
359
+ async def decr(self, key: str, amount: int = 1) -> int:
360
+ """Decrement the integer value of a key by the given amount.
361
+
362
+ Args:
363
+ key: Cache key.
364
+ amount: Amount to decrement by. Defaults to 1.
365
+
366
+ Returns:
367
+ The new value after decrementing.
368
+ """
369
+
370
+ @abc.abstractmethod
371
+ async def keys(self) -> list[str]:
372
+ """Return a list of cache keys."""
373
+
374
+ @abc.abstractmethod
375
+ async def values(self) -> list[VT]:
376
+ """Return all cache values."""
377
+
378
+ @abc.abstractmethod
379
+ async def items(self) -> list[tuple[str, VT]]:
380
+ """Return all cache items as (key, value) pairs."""
381
+
382
+ def __repr__(self) -> str:
383
+ return f"ASYNC KV CACHE <{self.__class__.__name__}>"