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
audex/lifespan.py ADDED
@@ -0,0 +1,75 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import types
5
+ import typing as t
6
+
7
+ from audex.helper.mixin import AsyncContextMixin
8
+ from audex.helper.mixin import AsyncLifecycleMixin
9
+ from audex.helper.mixin import ContextMixin
10
+ from audex.helper.mixin import LifecycleMixin
11
+ from audex.helper.mixin import LoggingMixin
12
+
13
+
14
+ class LifeSpan(LoggingMixin):
15
+ __logtag__ = "audex.lifespan"
16
+
17
+ def __init__(self, *contexts: object) -> None:
18
+ super().__init__()
19
+ self.contexts = contexts
20
+
21
+ def append(self, context: object) -> None:
22
+ self.contexts += (context,)
23
+
24
+ async def startup(self) -> t.Self:
25
+ atasks: list[t.Coroutine[None, None, None]] = []
26
+ for ctx in self.contexts:
27
+ if isinstance(ctx, ContextMixin):
28
+ self.logger.info(f"Initializing context: {ctx!r}")
29
+ ctx.init()
30
+ elif isinstance(ctx, AsyncContextMixin):
31
+ self.logger.info(f"Async initializing context: {ctx!r}")
32
+ atasks.append(ctx.init())
33
+
34
+ if isinstance(ctx, LifecycleMixin):
35
+ self.logger.info(f"Starting lifecycle: {ctx!r}")
36
+ ctx.start()
37
+ elif isinstance(ctx, AsyncLifecycleMixin):
38
+ self.logger.info(f"Async starting lifecycle: {ctx!r}")
39
+ atasks.append(ctx.start())
40
+
41
+ if atasks:
42
+ await asyncio.gather(*atasks)
43
+
44
+ return self
45
+
46
+ async def __aenter__(self) -> t.Self:
47
+ return await self.startup()
48
+
49
+ async def shutdown(self) -> None:
50
+ atasks: list[t.Coroutine[None, None, None]] = []
51
+ for ctx in self.contexts:
52
+ if isinstance(ctx, ContextMixin):
53
+ self.logger.info(f"Closing context: {ctx!r}")
54
+ ctx.close()
55
+ elif isinstance(ctx, AsyncContextMixin):
56
+ self.logger.info(f"Async closing context: {ctx!r}")
57
+ atasks.append(ctx.close())
58
+
59
+ if isinstance(ctx, LifecycleMixin):
60
+ self.logger.info(f"Stopping lifecycle: {ctx!r}")
61
+ ctx.stop()
62
+ elif isinstance(ctx, AsyncLifecycleMixin):
63
+ self.logger.info(f"Async stopping lifecycle: {ctx!r}")
64
+ atasks.append(ctx.stop())
65
+
66
+ if atasks:
67
+ await asyncio.gather(*atasks)
68
+
69
+ async def __aexit__(
70
+ self,
71
+ exc_type: type[BaseException] | None,
72
+ exc_value: BaseException | None,
73
+ traceback: types.TracebackType | None,
74
+ ) -> None:
75
+ await self.shutdown()
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import typing as t
4
+
5
+ from audex.helper.mixin import LoggingMixin
6
+ from audex.lib.cache import KVCache
7
+ from audex.lib.repos.doctor import DoctorRepository
8
+ from audex.lib.session import SessionManager
9
+
10
+
11
+ class BaseService(LoggingMixin):
12
+ __logtag__ = "audex.service"
13
+
14
+ def __init_subclass__(cls, **kwargs: t.Any) -> None:
15
+ cls.__logtag__ = f"audex.service:{cls.__name__}"
16
+ super().__init_subclass__(**kwargs)
17
+
18
+ def __init__(
19
+ self,
20
+ session_manager: SessionManager,
21
+ cache: KVCache,
22
+ doctor_repo: DoctorRepository,
23
+ ):
24
+ super().__init__()
25
+ self.session_manager = session_manager
26
+ self.cache = cache
27
+ self.doctor_repo = doctor_repo
@@ -0,0 +1,73 @@
1
+ from __future__ import annotations
2
+
3
+ import functools as ft
4
+ import typing as t
5
+
6
+ from audex.exceptions import PermissionDeniedError
7
+
8
+ if t.TYPE_CHECKING:
9
+ from audex.service import BaseService
10
+
11
+ ServiceMethodT = t.TypeVar("ServiceMethodT", bound=t.Callable[..., t.Awaitable[t.Any]])
12
+
13
+
14
+ def require_auth(func: ServiceMethodT) -> ServiceMethodT:
15
+ """Decorator to require authentication for service methods.
16
+
17
+ This decorator checks if the user is authenticated before allowing
18
+ access to the decorated service method. If the user is not authenticated,
19
+ an exception is raised.
20
+
21
+ Args:
22
+ func: The service method to decorate.
23
+
24
+ Returns:
25
+ The decorated service method with authentication check.
26
+ """
27
+
28
+ @ft.wraps(func)
29
+ async def wrapper(self: BaseService, *args: t.Any, **kwargs: t.Any) -> t.Any:
30
+ if doctor_id := await self.session_manager.get_doctor_id():
31
+ if await self.cache.contains(self.cache.key_builder.build("doctor", doctor_id)):
32
+ return await func(self, *args, **kwargs)
33
+ if (await self.doctor_repo.read(doctor_id)) is not None:
34
+ await self.cache.setx(self.cache.key_builder.build("doctor", doctor_id), True)
35
+ return await func(self, *args, **kwargs)
36
+ await self.session_manager.logout()
37
+ await self.cache.set_negative(self.cache.key_builder.build("doctor", doctor_id))
38
+ raise PermissionDeniedError("Authentication required to access this method.")
39
+ raise PermissionDeniedError("Authentication required to access this method.")
40
+
41
+ return wrapper # type: ignore
42
+
43
+
44
+ def log_call(func: ServiceMethodT) -> ServiceMethodT:
45
+ """Decorator to log calls to service methods.
46
+
47
+ This decorator logs the invocation of the decorated service method,
48
+ including its name and arguments.
49
+
50
+ Args:
51
+ func: The service method to decorate.
52
+
53
+ Returns:
54
+ The decorated service method with logging.
55
+ """
56
+
57
+ @ft.wraps(func)
58
+ async def wrapper(self: BaseService, *args: t.Any, **kwargs: t.Any) -> t.Any:
59
+ op = func.__name__
60
+ msg = f"Calling {op} with args={args} kwargs={kwargs}"
61
+ if doc_id := self.session_manager.get_doctor_id():
62
+ msg += f" [Doctor ID: {doc_id}]"
63
+
64
+ self.logger.info(msg)
65
+ try:
66
+ result = await func(self, *args, **kwargs)
67
+ self.logger.info(f"{op} completed successfully.")
68
+ return result
69
+ except Exception as e:
70
+ self.logger.error(f"{op} failed with error: {e}")
71
+ raise
72
+
73
+ return wrapper # type: ignore