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.
- audex/__init__.py +9 -0
- audex/__main__.py +7 -0
- audex/cli/__init__.py +189 -0
- audex/cli/apis/__init__.py +12 -0
- audex/cli/apis/init/__init__.py +34 -0
- audex/cli/apis/init/gencfg.py +130 -0
- audex/cli/apis/init/setup.py +330 -0
- audex/cli/apis/init/vprgroup.py +125 -0
- audex/cli/apis/serve.py +141 -0
- audex/cli/args.py +356 -0
- audex/cli/exceptions.py +44 -0
- audex/cli/helper/__init__.py +0 -0
- audex/cli/helper/ansi.py +193 -0
- audex/cli/helper/display.py +288 -0
- audex/config/__init__.py +64 -0
- audex/config/core/__init__.py +30 -0
- audex/config/core/app.py +29 -0
- audex/config/core/audio.py +45 -0
- audex/config/core/logging.py +163 -0
- audex/config/core/session.py +11 -0
- audex/config/helper/__init__.py +1 -0
- audex/config/helper/client/__init__.py +1 -0
- audex/config/helper/client/http.py +28 -0
- audex/config/helper/client/websocket.py +21 -0
- audex/config/helper/provider/__init__.py +1 -0
- audex/config/helper/provider/dashscope.py +13 -0
- audex/config/helper/provider/unisound.py +18 -0
- audex/config/helper/provider/xfyun.py +23 -0
- audex/config/infrastructure/__init__.py +31 -0
- audex/config/infrastructure/cache.py +51 -0
- audex/config/infrastructure/database.py +48 -0
- audex/config/infrastructure/recorder.py +32 -0
- audex/config/infrastructure/store.py +19 -0
- audex/config/provider/__init__.py +18 -0
- audex/config/provider/transcription.py +109 -0
- audex/config/provider/vpr.py +99 -0
- audex/container.py +40 -0
- audex/entity/__init__.py +468 -0
- audex/entity/doctor.py +109 -0
- audex/entity/doctor.pyi +51 -0
- audex/entity/fields.py +401 -0
- audex/entity/segment.py +115 -0
- audex/entity/segment.pyi +38 -0
- audex/entity/session.py +133 -0
- audex/entity/session.pyi +47 -0
- audex/entity/utterance.py +142 -0
- audex/entity/utterance.pyi +48 -0
- audex/entity/vp.py +68 -0
- audex/entity/vp.pyi +35 -0
- audex/exceptions.py +157 -0
- audex/filters/__init__.py +692 -0
- audex/filters/generated/__init__.py +21 -0
- audex/filters/generated/doctor.py +987 -0
- audex/filters/generated/segment.py +723 -0
- audex/filters/generated/session.py +978 -0
- audex/filters/generated/utterance.py +939 -0
- audex/filters/generated/vp.py +815 -0
- audex/helper/__init__.py +1 -0
- audex/helper/hash.py +33 -0
- audex/helper/mixin.py +65 -0
- audex/helper/net.py +19 -0
- audex/helper/settings/__init__.py +830 -0
- audex/helper/settings/fields.py +317 -0
- audex/helper/stream.py +153 -0
- audex/injectors/__init__.py +1 -0
- audex/injectors/config.py +12 -0
- audex/injectors/lifespan.py +7 -0
- audex/lib/__init__.py +1 -0
- audex/lib/cache/__init__.py +383 -0
- audex/lib/cache/inmemory.py +513 -0
- audex/lib/database/__init__.py +83 -0
- audex/lib/database/sqlite.py +406 -0
- audex/lib/exporter.py +189 -0
- audex/lib/injectors/__init__.py +1 -0
- audex/lib/injectors/cache.py +25 -0
- audex/lib/injectors/container.py +47 -0
- audex/lib/injectors/exporter.py +26 -0
- audex/lib/injectors/recorder.py +33 -0
- audex/lib/injectors/server.py +17 -0
- audex/lib/injectors/session.py +18 -0
- audex/lib/injectors/sqlite.py +24 -0
- audex/lib/injectors/store.py +13 -0
- audex/lib/injectors/transcription.py +42 -0
- audex/lib/injectors/usb.py +12 -0
- audex/lib/injectors/vpr.py +65 -0
- audex/lib/injectors/wifi.py +7 -0
- audex/lib/recorder.py +844 -0
- audex/lib/repos/__init__.py +149 -0
- audex/lib/repos/container.py +23 -0
- audex/lib/repos/database/__init__.py +1 -0
- audex/lib/repos/database/sqlite.py +672 -0
- audex/lib/repos/decorators.py +74 -0
- audex/lib/repos/doctor.py +286 -0
- audex/lib/repos/segment.py +302 -0
- audex/lib/repos/session.py +285 -0
- audex/lib/repos/tables/__init__.py +70 -0
- audex/lib/repos/tables/doctor.py +137 -0
- audex/lib/repos/tables/segment.py +113 -0
- audex/lib/repos/tables/session.py +140 -0
- audex/lib/repos/tables/utterance.py +131 -0
- audex/lib/repos/tables/vp.py +102 -0
- audex/lib/repos/utterance.py +288 -0
- audex/lib/repos/vp.py +286 -0
- audex/lib/restful.py +251 -0
- audex/lib/server/__init__.py +97 -0
- audex/lib/server/auth.py +98 -0
- audex/lib/server/handlers.py +248 -0
- audex/lib/server/templates/index.html.j2 +226 -0
- audex/lib/server/templates/login.html.j2 +111 -0
- audex/lib/server/templates/static/script.js +68 -0
- audex/lib/server/templates/static/style.css +579 -0
- audex/lib/server/types.py +123 -0
- audex/lib/session.py +503 -0
- audex/lib/store/__init__.py +238 -0
- audex/lib/store/localfile.py +411 -0
- audex/lib/transcription/__init__.py +33 -0
- audex/lib/transcription/dashscope.py +525 -0
- audex/lib/transcription/events.py +62 -0
- audex/lib/usb.py +554 -0
- audex/lib/vpr/__init__.py +38 -0
- audex/lib/vpr/unisound/__init__.py +185 -0
- audex/lib/vpr/unisound/types.py +469 -0
- audex/lib/vpr/xfyun/__init__.py +483 -0
- audex/lib/vpr/xfyun/types.py +679 -0
- audex/lib/websocket/__init__.py +8 -0
- audex/lib/websocket/connection.py +485 -0
- audex/lib/websocket/pool.py +991 -0
- audex/lib/wifi.py +1146 -0
- audex/lifespan.py +75 -0
- audex/service/__init__.py +27 -0
- audex/service/decorators.py +73 -0
- audex/service/doctor/__init__.py +652 -0
- audex/service/doctor/const.py +36 -0
- audex/service/doctor/exceptions.py +96 -0
- audex/service/doctor/types.py +54 -0
- audex/service/export/__init__.py +236 -0
- audex/service/export/const.py +17 -0
- audex/service/export/exceptions.py +34 -0
- audex/service/export/types.py +21 -0
- audex/service/injectors/__init__.py +1 -0
- audex/service/injectors/container.py +53 -0
- audex/service/injectors/doctor.py +34 -0
- audex/service/injectors/export.py +27 -0
- audex/service/injectors/session.py +49 -0
- audex/service/session/__init__.py +754 -0
- audex/service/session/const.py +34 -0
- audex/service/session/exceptions.py +67 -0
- audex/service/session/types.py +91 -0
- audex/types.py +39 -0
- audex/utils.py +287 -0
- audex/valueobj/__init__.py +81 -0
- audex/valueobj/common/__init__.py +1 -0
- audex/valueobj/common/auth.py +84 -0
- audex/valueobj/common/email.py +16 -0
- audex/valueobj/common/ops.py +22 -0
- audex/valueobj/common/phone.py +84 -0
- audex/valueobj/common/version.py +72 -0
- audex/valueobj/session.py +19 -0
- audex/valueobj/utterance.py +15 -0
- audex/view/__init__.py +51 -0
- audex/view/container.py +17 -0
- audex/view/decorators.py +303 -0
- audex/view/pages/__init__.py +1 -0
- audex/view/pages/dashboard/__init__.py +286 -0
- audex/view/pages/dashboard/wifi.py +407 -0
- audex/view/pages/login.py +110 -0
- audex/view/pages/recording.py +348 -0
- audex/view/pages/register.py +202 -0
- audex/view/pages/sessions/__init__.py +196 -0
- audex/view/pages/sessions/details.py +224 -0
- audex/view/pages/sessions/export.py +443 -0
- audex/view/pages/settings.py +374 -0
- audex/view/pages/voiceprint/__init__.py +1 -0
- audex/view/pages/voiceprint/enroll.py +195 -0
- audex/view/pages/voiceprint/update.py +195 -0
- audex/view/static/css/dashboard.css +452 -0
- audex/view/static/css/glass.css +22 -0
- audex/view/static/css/global.css +541 -0
- audex/view/static/css/login.css +386 -0
- audex/view/static/css/recording.css +439 -0
- audex/view/static/css/register.css +293 -0
- audex/view/static/css/sessions/styles.css +501 -0
- audex/view/static/css/settings.css +186 -0
- audex/view/static/css/voiceprint/enroll.css +43 -0
- audex/view/static/css/voiceprint/styles.css +209 -0
- audex/view/static/css/voiceprint/update.css +44 -0
- audex/view/static/images/logo.svg +95 -0
- audex/view/static/js/recording.js +42 -0
- audex-1.0.7a3.dist-info/METADATA +361 -0
- audex-1.0.7a3.dist-info/RECORD +192 -0
- audex-1.0.7a3.dist-info/WHEEL +4 -0
- 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
|