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,185 @@
1
+ from __future__ import annotations
2
+
3
+ import base64
4
+ import hashlib
5
+ import typing as t
6
+ import uuid
7
+
8
+ from httpx import URL
9
+ from httpx import AsyncClient
10
+
11
+ from audex import utils
12
+ from audex.lib.restful import RESTfulMixin
13
+ from audex.lib.vpr import VPR
14
+ from audex.lib.vpr import VPRError
15
+ from audex.lib.vpr.unisound.types import ConfirmFeatureRequest
16
+ from audex.lib.vpr.unisound.types import ConfirmFeatureResponse
17
+ from audex.lib.vpr.unisound.types import CreateFeatureRequest
18
+ from audex.lib.vpr.unisound.types import CreateFeatureResponse
19
+ from audex.lib.vpr.unisound.types import CreateGroupRequest
20
+ from audex.lib.vpr.unisound.types import CreateGroupResponse
21
+ from audex.lib.vpr.unisound.types import UpdateFeatureRequest
22
+ from audex.lib.vpr.unisound.types import UpdateFeatureResponse
23
+
24
+
25
+ class UnisoundVPR(RESTfulMixin, VPR):
26
+ __logtag__ = "audex.lib.vpr.unisound"
27
+
28
+ def __init__(
29
+ self,
30
+ *,
31
+ appkey: str,
32
+ secret: str,
33
+ group_id: str | None = None,
34
+ base_url: str = "https://ai-vpr.hivoice.cn",
35
+ proxy: str | URL | None = None,
36
+ timeout: float = 10.0,
37
+ http_client: AsyncClient | None = None,
38
+ default_headers: dict[str, str] | None = None,
39
+ default_params: dict[str, t.Any] | None = None,
40
+ ):
41
+ self.appkey = appkey
42
+ self.secret = secret
43
+ self.group_id = group_id
44
+ super().__init__(
45
+ base_url=base_url,
46
+ proxy=proxy,
47
+ timeout=timeout,
48
+ http_client=http_client,
49
+ default_headers=default_headers,
50
+ default_params=default_params,
51
+ )
52
+
53
+ def _generate_sign(self, timestamp: int, nonce: str) -> str:
54
+ """Generate signature for authentication."""
55
+ sign_str = f"{self.appkey}{timestamp}{self.secret}{nonce}"
56
+ return hashlib.sha256(sign_str.encode("utf-8")).hexdigest().upper()
57
+
58
+ def _build_auth_params(self) -> dict[str, t.Any]:
59
+ """Build authentication parameters."""
60
+ timestamp = int(utils.utcnow().timestamp() * 1000)
61
+ nonce = uuid.uuid4().hex
62
+ sign = self._generate_sign(timestamp, nonce)
63
+ return {
64
+ "appkey": self.appkey,
65
+ "timestamp": timestamp,
66
+ "nonce": nonce,
67
+ "sign": sign,
68
+ }
69
+
70
+ async def create_group(self, name: str, gid: str | None = None) -> str:
71
+ if self.group_id:
72
+ raise VPRError("Group already exists, cannot create a new one.")
73
+ group_id = gid or utils.gen_id()
74
+ auth_params = self._build_auth_params()
75
+
76
+ response = await self.request(
77
+ endpoint="/vpr/v1/createGroup",
78
+ method="POST",
79
+ json=CreateGroupRequest(
80
+ **auth_params,
81
+ groupId=group_id,
82
+ groupInfo=name,
83
+ ).model_dump(by_alias=True),
84
+ cast_to=CreateGroupResponse,
85
+ )
86
+
87
+ if response.code != 0:
88
+ raise VPRError(f"Failed to create group: [{response.code}] {response.msg}")
89
+
90
+ if not response.data or response.data.group_id != group_id:
91
+ raise VPRError("Group ID mismatch after creation.")
92
+
93
+ self.group_id = group_id
94
+ return self.group_id
95
+
96
+ async def enroll(self, data: bytes, sr: int, uid: str | None = None) -> str:
97
+ if not self.group_id:
98
+ raise VPRError("Group ID is not set. Cannot enroll feature.")
99
+
100
+ uid = uid or utils.gen_id()
101
+ auth_params = self._build_auth_params()
102
+
103
+ audio_data = base64.b64encode(data).decode("utf-8")
104
+
105
+ response = await self.request(
106
+ endpoint="/vpr/v1/createFeature",
107
+ method="POST",
108
+ json=CreateFeatureRequest(
109
+ **auth_params,
110
+ groupId=self.group_id,
111
+ featureId=uid,
112
+ featureInfo=f"Feature {uid}",
113
+ audioData=audio_data,
114
+ audioSampleRate=sr,
115
+ audioFormat="pcm",
116
+ ).model_dump(by_alias=True),
117
+ cast_to=CreateFeatureResponse,
118
+ )
119
+
120
+ if response.code != 0:
121
+ raise VPRError(f"Failed to enroll feature: [{response.code}] {response.msg}")
122
+
123
+ if not response.data or response.data.feature_id != uid:
124
+ raise VPRError("Feature ID mismatch after registration.")
125
+
126
+ return uid
127
+
128
+ async def update(self, uid: str, data: bytes, sr: int) -> None:
129
+ if not self.group_id:
130
+ raise VPRError("Group ID is not set. Cannot update feature.")
131
+
132
+ auth_params = self._build_auth_params()
133
+
134
+ audio_data = base64.b64encode(data).decode("utf-8")
135
+
136
+ response = await self.request(
137
+ endpoint="/vpr/v1/updateFeatureById",
138
+ method="POST",
139
+ json=UpdateFeatureRequest(
140
+ **auth_params,
141
+ groupId=self.group_id,
142
+ featureId=uid,
143
+ featureInfo=f"Updated feature {uid}",
144
+ audioData=audio_data,
145
+ audioSampleRate=sr,
146
+ audioFormat="pcm",
147
+ ).model_dump(by_alias=True),
148
+ cast_to=UpdateFeatureResponse,
149
+ )
150
+
151
+ if response.code != 0:
152
+ raise VPRError(f"Failed to update feature: [{response.code}] {response.msg}")
153
+
154
+ if not response.data or not response.data.result:
155
+ raise VPRError("Feature update failed.")
156
+
157
+ async def verify(self, uid: str, data: bytes, sr: int) -> float:
158
+ if not self.group_id:
159
+ raise VPRError("Group ID is not set. Cannot verify feature.")
160
+
161
+ auth_params = self._build_auth_params()
162
+
163
+ audio_data = base64.b64encode(data).decode("utf-8")
164
+
165
+ response = await self.request(
166
+ endpoint="/vpr/v1/confirmFeature",
167
+ method="POST",
168
+ json=ConfirmFeatureRequest(
169
+ **auth_params,
170
+ groupId=self.group_id,
171
+ featureId=uid,
172
+ audioData=audio_data,
173
+ audioSampleRate=sr,
174
+ audioFormat="pcm",
175
+ ).model_dump(by_alias=True),
176
+ cast_to=ConfirmFeatureResponse,
177
+ )
178
+
179
+ if response.code != 0:
180
+ raise VPRError(f"Failed to verify feature: [{response.code}] {response.msg}")
181
+
182
+ if not response.data:
183
+ raise VPRError("No verification data returned.")
184
+
185
+ return response.data.score # type: ignore
@@ -0,0 +1,469 @@
1
+ from __future__ import annotations
2
+
3
+ import typing as t
4
+
5
+ from pydantic import BaseModel
6
+ from pydantic import Field
7
+
8
+
9
+ # Base Authentication Parameters
10
+ class AuthParams(BaseModel):
11
+ appkey: str = Field(
12
+ ...,
13
+ description="Application key",
14
+ )
15
+ timestamp: int = Field(
16
+ ...,
17
+ description="Access timestamp in milliseconds (UNIX timestamp)",
18
+ )
19
+ nonce: str = Field(
20
+ ...,
21
+ description="Random nonce, must change for each request",
22
+ )
23
+ sign: str = Field(
24
+ ...,
25
+ description="Signature for authentication",
26
+ )
27
+
28
+
29
+ # Base Response
30
+ DataT = t.TypeVar("DataT")
31
+
32
+
33
+ class UnisoundResponse(BaseModel, t.Generic[DataT]):
34
+ code: int = Field(
35
+ ...,
36
+ description="Error code, 0 indicates success",
37
+ )
38
+ msg: str = Field(
39
+ ...,
40
+ description="Response message",
41
+ )
42
+ sid: str = Field(
43
+ ...,
44
+ description="Unique session identifier",
45
+ )
46
+ data: DataT | None = Field(
47
+ None,
48
+ description="Response data body",
49
+ )
50
+
51
+
52
+ # Create Group
53
+ class CreateGroupRequest(AuthParams):
54
+ group_id: str = Field(
55
+ ...,
56
+ alias="groupId",
57
+ serialization_alias="groupId",
58
+ description="Voiceprint group ID",
59
+ )
60
+ group_info: str = Field(
61
+ ...,
62
+ alias="groupInfo",
63
+ serialization_alias="groupInfo",
64
+ description="Voiceprint group information",
65
+ )
66
+
67
+
68
+ class CreateGroupData(BaseModel):
69
+ group_id: str = Field(
70
+ ...,
71
+ alias="groupId",
72
+ serialization_alias="groupId",
73
+ description="Voiceprint group ID",
74
+ )
75
+ group_info: str = Field(
76
+ ...,
77
+ alias="groupInfo",
78
+ serialization_alias="groupInfo",
79
+ description="Voiceprint group information",
80
+ )
81
+
82
+
83
+ class CreateGroupResponse(BaseModel):
84
+ code: int
85
+ msg: str
86
+ sid: str
87
+ data: CreateGroupData | None = None
88
+
89
+
90
+ # Create Feature
91
+ class CreateFeatureRequest(AuthParams):
92
+ group_id: str = Field(
93
+ ...,
94
+ alias="groupId",
95
+ serialization_alias="groupId",
96
+ description="Voiceprint group ID",
97
+ )
98
+ feature_id: str = Field(
99
+ ...,
100
+ alias="featureId",
101
+ serialization_alias="featureId",
102
+ description="Voiceprint feature ID",
103
+ )
104
+ feature_info: str = Field(
105
+ ...,
106
+ alias="featureInfo",
107
+ serialization_alias="featureInfo",
108
+ description="Voiceprint feature description",
109
+ )
110
+ audio_data: str = Field(
111
+ ...,
112
+ alias="audioData",
113
+ serialization_alias="audioData",
114
+ description="Base64 encoded audio data",
115
+ )
116
+ audio_sample_rate: int = Field(
117
+ ...,
118
+ alias="audioSampleRate",
119
+ serialization_alias="audioSampleRate",
120
+ description="Audio sample rate",
121
+ )
122
+ audio_format: t.Literal["pcm", "mp3", "opus", "adpcm"] = Field(
123
+ ...,
124
+ alias="audioFormat",
125
+ serialization_alias="audioFormat",
126
+ description="Audio format",
127
+ )
128
+
129
+
130
+ class CreateFeatureData(BaseModel):
131
+ feature_id: str = Field(
132
+ ...,
133
+ alias="featureId",
134
+ serialization_alias="featureId",
135
+ description="Voiceprint feature ID",
136
+ )
137
+ feature_info: str = Field(
138
+ ...,
139
+ alias="featureInfo",
140
+ serialization_alias="featureInfo",
141
+ description="Voiceprint feature information",
142
+ )
143
+
144
+
145
+ class CreateFeatureResponse(BaseModel):
146
+ code: int
147
+ msg: str
148
+ sid: str
149
+ data: CreateFeatureData | None = None
150
+
151
+
152
+ # Update Feature
153
+ class UpdateFeatureRequest(AuthParams):
154
+ group_id: str = Field(
155
+ ...,
156
+ alias="groupId",
157
+ serialization_alias="groupId",
158
+ description="Voiceprint group ID",
159
+ )
160
+ feature_id: str = Field(
161
+ ...,
162
+ alias="featureId",
163
+ serialization_alias="featureId",
164
+ description="Voiceprint feature ID",
165
+ )
166
+ feature_info: str | None = Field(
167
+ None,
168
+ alias="featureInfo",
169
+ serialization_alias="featureInfo",
170
+ description="Voiceprint feature description",
171
+ )
172
+ audio_data: str = Field(
173
+ ...,
174
+ alias="audioData",
175
+ serialization_alias="audioData",
176
+ description="Base64 encoded audio data",
177
+ )
178
+ audio_sample_rate: int = Field(
179
+ ...,
180
+ alias="audioSampleRate",
181
+ serialization_alias="audioSampleRate",
182
+ description="Audio sample rate",
183
+ )
184
+ audio_format: t.Literal["pcm", "mp3", "opus", "adpcm"] = Field(
185
+ ...,
186
+ alias="audioFormat",
187
+ serialization_alias="audioFormat",
188
+ description="Audio format",
189
+ )
190
+
191
+
192
+ class UpdateFeatureData(BaseModel):
193
+ result: bool = Field(
194
+ ...,
195
+ description="Update result, true for success, false for failure",
196
+ )
197
+
198
+
199
+ class UpdateFeatureResponse(BaseModel):
200
+ code: int
201
+ msg: str
202
+ sid: str
203
+ data: UpdateFeatureData | None = None
204
+
205
+
206
+ # Confirm Feature (1:1 Verification)
207
+ class ConfirmFeatureRequest(AuthParams):
208
+ group_id: str = Field(
209
+ ...,
210
+ alias="groupId",
211
+ serialization_alias="groupId",
212
+ description="Voiceprint group ID",
213
+ )
214
+ feature_id: str = Field(
215
+ ...,
216
+ alias="featureId",
217
+ serialization_alias="featureId",
218
+ description="Voiceprint feature ID",
219
+ )
220
+ audio_data: str = Field(
221
+ ...,
222
+ alias="audioData",
223
+ serialization_alias="audioData",
224
+ description="Base64 encoded audio data",
225
+ )
226
+ audio_sample_rate: int = Field(
227
+ ...,
228
+ alias="audioSampleRate",
229
+ serialization_alias="audioSampleRate",
230
+ description="Audio sample rate",
231
+ )
232
+ audio_format: t.Literal["pcm", "mp3", "opus", "adpcm"] = Field(
233
+ ...,
234
+ alias="audioFormat",
235
+ serialization_alias="audioFormat",
236
+ description="Audio format",
237
+ )
238
+
239
+
240
+ class ConfirmFeatureData(BaseModel):
241
+ score: float = Field(
242
+ ...,
243
+ description="Similarity score, 0 indicates no match",
244
+ )
245
+ feature_id: str = Field(
246
+ ...,
247
+ alias="featureId",
248
+ serialization_alias="featureId",
249
+ description="Voiceprint feature ID",
250
+ )
251
+ feature_info: str = Field(
252
+ ...,
253
+ alias="featureInfo",
254
+ serialization_alias="featureInfo",
255
+ description="Voiceprint feature information",
256
+ )
257
+
258
+
259
+ class ConfirmFeatureResponse(BaseModel):
260
+ code: int
261
+ msg: str
262
+ sid: str
263
+ data: ConfirmFeatureData | None = None
264
+
265
+
266
+ # Identify Feature by Group ID (1:N Identification)
267
+ class IdentifyFeatureByGroupIdRequest(AuthParams):
268
+ group_id: str = Field(
269
+ ...,
270
+ alias="groupId",
271
+ serialization_alias="groupId",
272
+ description="Voiceprint group ID",
273
+ )
274
+ top_n: int = Field(
275
+ ...,
276
+ alias="topN",
277
+ serialization_alias="topN",
278
+ ge=1,
279
+ le=10,
280
+ description="Number of top results to return",
281
+ )
282
+ audio_data: str = Field(
283
+ ...,
284
+ alias="audioData",
285
+ serialization_alias="audioData",
286
+ description="Base64 encoded audio data",
287
+ )
288
+ audio_sample_rate: t.Literal[8000, 16000] = Field(
289
+ ...,
290
+ alias="audioSampleRate",
291
+ serialization_alias="audioSampleRate",
292
+ description="Audio sample rate",
293
+ )
294
+ audio_format: t.Literal["pcm", "mp3", "opus", "adpcm"] = Field(
295
+ ...,
296
+ alias="audioFormat",
297
+ serialization_alias="audioFormat",
298
+ description="Audio format",
299
+ )
300
+
301
+
302
+ class IdentifyFeatureResult(BaseModel):
303
+ score: float = Field(
304
+ ...,
305
+ description="Similarity score, 0 indicates no match",
306
+ )
307
+ feature_id: str = Field(
308
+ ...,
309
+ alias="featureId",
310
+ serialization_alias="featureId",
311
+ description="Voiceprint feature ID",
312
+ )
313
+ feature_info: str = Field(
314
+ ...,
315
+ alias="featureInfo",
316
+ serialization_alias="featureInfo",
317
+ description="Voiceprint feature information",
318
+ )
319
+
320
+
321
+ class IdentifyFeatureByGroupIdResponse(BaseModel):
322
+ code: int
323
+ msg: str
324
+ sid: str
325
+ data: list[IdentifyFeatureResult] | None = None
326
+
327
+
328
+ # Identify Feature by IDs (1:N Identification)
329
+ class FeatureListItem(BaseModel):
330
+ group_id: str = Field(
331
+ ...,
332
+ alias="groupId",
333
+ serialization_alias="groupId",
334
+ description="Voiceprint group ID",
335
+ )
336
+ feature_id: str = Field(
337
+ ...,
338
+ alias="featureId",
339
+ serialization_alias="featureId",
340
+ description="Voiceprint feature ID",
341
+ )
342
+
343
+
344
+ class IdentifyFeatureByIdsRequest(AuthParams):
345
+ feature_list: list[FeatureListItem] = Field(
346
+ ...,
347
+ alias="featureList",
348
+ serialization_alias="featureList",
349
+ description="List of voiceprint feature IDs",
350
+ )
351
+ top_n: int = Field(
352
+ ...,
353
+ alias="topN",
354
+ serialization_alias="topN",
355
+ ge=1,
356
+ le=10,
357
+ description="Number of top results to return",
358
+ )
359
+ audio_data: str = Field(
360
+ ...,
361
+ alias="audioData",
362
+ serialization_alias="audioData",
363
+ description="Base64 encoded audio data",
364
+ )
365
+ audio_sample_rate: t.Literal[8000, 16000] = Field(
366
+ ...,
367
+ alias="audioSampleRate",
368
+ serialization_alias="audioSampleRate",
369
+ description="Audio sample rate",
370
+ )
371
+ audio_format: t.Literal["pcm", "mp3", "opus", "adpcm"] = Field(
372
+ ...,
373
+ alias="audioFormat",
374
+ serialization_alias="audioFormat",
375
+ description="Audio format",
376
+ )
377
+
378
+
379
+ class IdentifyFeatureByIdsResponse(BaseModel):
380
+ code: int
381
+ msg: str
382
+ sid: str
383
+ data: list[IdentifyFeatureResult] | None = None
384
+
385
+
386
+ # Delete Feature
387
+ class DeleteFeatureRequest(AuthParams):
388
+ group_id: str = Field(
389
+ ...,
390
+ alias="groupId",
391
+ serialization_alias="groupId",
392
+ description="Voiceprint group ID",
393
+ )
394
+ feature_id: str = Field(
395
+ ...,
396
+ alias="featureId",
397
+ serialization_alias="featureId",
398
+ description="Voiceprint feature ID",
399
+ )
400
+
401
+
402
+ class DeleteFeatureData(BaseModel):
403
+ result: bool = Field(
404
+ ...,
405
+ description="Deletion result, true for success, false for failure",
406
+ )
407
+
408
+
409
+ class DeleteFeatureResponse(BaseModel):
410
+ code: int
411
+ msg: str
412
+ sid: str
413
+ data: DeleteFeatureData | None = None
414
+
415
+
416
+ # Delete Group
417
+ class DeleteGroupRequest(AuthParams):
418
+ group_id: str = Field(
419
+ ...,
420
+ alias="groupId",
421
+ serialization_alias="groupId",
422
+ description="Voiceprint group ID",
423
+ )
424
+
425
+
426
+ class DeleteGroupData(BaseModel):
427
+ result: bool = Field(
428
+ ...,
429
+ description="Deletion result, true for success, false for failure",
430
+ )
431
+
432
+
433
+ class DeleteGroupResponse(BaseModel):
434
+ code: int
435
+ msg: str
436
+ sid: str
437
+ data: DeleteGroupData | None = None
438
+
439
+
440
+ # Query Feature List
441
+ class QueryFeatureListRequest(AuthParams):
442
+ group_id: str = Field(
443
+ ...,
444
+ alias="groupId",
445
+ serialization_alias="groupId",
446
+ description="Voiceprint group ID",
447
+ )
448
+
449
+
450
+ class FeatureInfo(BaseModel):
451
+ feature_id: str = Field(
452
+ ...,
453
+ alias="featureId",
454
+ serialization_alias="featureId",
455
+ description="Voiceprint feature ID",
456
+ )
457
+ feature_info: str = Field(
458
+ ...,
459
+ alias="featureInfo",
460
+ serialization_alias="featureInfo",
461
+ description="Voiceprint feature information",
462
+ )
463
+
464
+
465
+ class QueryFeatureListResponse(BaseModel):
466
+ code: int
467
+ msg: str
468
+ sid: str
469
+ data: list[FeatureInfo] | None = None