most-client 1.0.14__tar.gz → 1.0.16__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: most-client
3
- Version: 1.0.14
3
+ Version: 1.0.16
4
4
  Summary: Most AI API for https://the-most.ai
5
5
  Home-page: https://github.com/the-most-ai/most-client
6
6
  Author: George Kasparyants
@@ -26,6 +26,7 @@ Requires-Dist: pytest
26
26
  Requires-Dist: tox
27
27
  Requires-Dist: twine
28
28
  Requires-Dist: httpx
29
+ Requires-Dist: pydub
29
30
  Dynamic: author
30
31
  Dynamic: author-email
31
32
  Dynamic: classifier
@@ -1,9 +1,23 @@
1
- from typing import List, Dict
1
+ import io
2
+ import os
3
+ from pathlib import Path
4
+ from typing import Dict, List
5
+
2
6
  import json5
3
7
  import requests
4
8
  from adaptix import Retort
5
- from most.types import Audio, Result, Script, JobStatus, Text, StoredAudioData, is_valid_id
6
- from pathlib import Path
9
+ from pydub import AudioSegment
10
+
11
+ from most.types import (
12
+ Audio,
13
+ DialogResult,
14
+ JobStatus,
15
+ Result,
16
+ Script,
17
+ StoredAudioData,
18
+ Text,
19
+ is_valid_id,
20
+ )
7
21
 
8
22
 
9
23
  class MostClient(object):
@@ -131,6 +145,14 @@ class MostClient(object):
131
145
  files={"audio_file": f})
132
146
  return self.retort.load(resp.json(), Audio)
133
147
 
148
+ def upload_audio_segment(self, audio: AudioSegment) -> Audio:
149
+ f = io.BytesIO()
150
+ audio.export(f, format="mp3")
151
+ f.seek(0)
152
+ resp = self.post(f"https://api.the-most.ai/api/external/{self.client_id}/upload",
153
+ files={"audio_file": f})
154
+ return self.retort.load(resp.json(), Audio)
155
+
134
156
  def upload_audio_url(self, audio_url) -> Audio:
135
157
  resp = self.post(f"https://api.the-most.ai/api/external/{self.client_id}/upload_url",
136
158
  json={"audio_url": audio_url})
@@ -205,6 +227,16 @@ class MostClient(object):
205
227
  resp = self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/text")
206
228
  return self.retort.load(resp.json(), Result)
207
229
 
230
+ def fetch_dialog(self, audio_id) -> DialogResult:
231
+ if not is_valid_id(self.model_id):
232
+ raise RuntimeError("Please choose valid model to apply. [try list_models()]")
233
+
234
+ if not is_valid_id(audio_id):
235
+ raise RuntimeError("Please use valid audio_id. [try audio.id from list_audios()]")
236
+
237
+ resp = self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/dialog")
238
+ return self.retort.load(resp.json(), DialogResult)
239
+
208
240
  def export(self, audio_ids: List[str]) -> str:
209
241
  if not is_valid_id(self.model_id):
210
242
  raise RuntimeError("Please choose valid model to apply. [try list_models()]")
@@ -238,3 +270,18 @@ class MostClient(object):
238
270
 
239
271
  def __repr__(self):
240
272
  return "<MostClient(model_id='%s')>" % (self.model_id, )
273
+
274
+ def get_audio_segment_by_url(self, audio_url,
275
+ format=None):
276
+ if format is None:
277
+ format = os.path.splitext(audio_url)[1]
278
+ format = format.strip().lower()
279
+
280
+ resp = self.session.get(audio_url,
281
+ timeout=None)
282
+ if resp.status_code >= 400:
283
+ raise RuntimeError("Audio url is not accessable")
284
+
285
+ audio = AudioSegment.from_file(io.BytesIO(resp.content),
286
+ format=format)
287
+ return audio
@@ -1,9 +1,23 @@
1
- from typing import List, Dict
2
- import json5
3
- from adaptix import Retort
4
- from most.types import Audio, Result, Script, JobStatus, Text, StoredAudioData, is_valid_id
1
+ import io
2
+ import os
5
3
  from pathlib import Path
4
+ from typing import Dict, List
5
+
6
6
  import httpx
7
+ import json5
8
+ from adaptix import Retort
9
+ from pydub import AudioSegment
10
+
11
+ from most.types import (
12
+ Audio,
13
+ DialogResult,
14
+ JobStatus,
15
+ Result,
16
+ Script,
17
+ StoredAudioData,
18
+ Text,
19
+ is_valid_id,
20
+ )
7
21
 
8
22
 
9
23
  class AsyncMostClient(object):
@@ -135,6 +149,14 @@ class AsyncMostClient(object):
135
149
  files={"audio_file": f})
136
150
  return self.retort.load(resp.json(), Audio)
137
151
 
152
+ async def upload_audio_segment(self, audio: AudioSegment) -> Audio:
153
+ f = io.BytesIO()
154
+ audio.export(f, format="mp3")
155
+ f.seek(0)
156
+ resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/upload",
157
+ files={"audio_file": f})
158
+ return self.retort.load(resp.json(), Audio)
159
+
138
160
  async def upload_text(self, text: str) -> Text:
139
161
  resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/upload_text",
140
162
  json={"text": text})
@@ -146,8 +168,8 @@ class AsyncMostClient(object):
146
168
  return self.retort.load(resp.json(), Audio)
147
169
 
148
170
  async def list_audios(self,
149
- offset: int = 0,
150
- limit: int = 10) -> List[Audio]:
171
+ offset: int = 0,
172
+ limit: int = 10) -> List[Audio]:
151
173
  resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/list?offset={offset}&limit={limit}")
152
174
  audio_list = resp.json()
153
175
  return self.retort.load(audio_list, List[Audio])
@@ -214,6 +236,16 @@ class AsyncMostClient(object):
214
236
  resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/text")
215
237
  return self.retort.load(resp.json(), Result)
216
238
 
239
+ async def fetch_dialog(self, audio_id) -> DialogResult:
240
+ if not is_valid_id(self.model_id):
241
+ raise RuntimeError("Please choose valid model to apply. [try list_models()]")
242
+
243
+ if not is_valid_id(audio_id):
244
+ raise RuntimeError("Please use valid audio_id. [try audio.id from list_audios()]")
245
+
246
+ resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/dialog")
247
+ return self.retort.load(resp.json(), DialogResult)
248
+
217
249
  async def export(self, audio_ids: List[str]) -> str:
218
250
  if not is_valid_id(self.model_id):
219
251
  raise RuntimeError("Please choose valid model to apply. [try list_models()]")
@@ -243,3 +275,18 @@ class AsyncMostClient(object):
243
275
 
244
276
  def __repr__(self):
245
277
  return "<AsyncMostClient(model_id='%s')>" % (self.model_id, )
278
+
279
+ async def get_audio_segment_by_url(self, audio_url,
280
+ format=None):
281
+ if format is None:
282
+ format = os.path.splitext(audio_url)[1]
283
+ format = format.strip().lower()
284
+
285
+ resp = await self.session.get(audio_url,
286
+ timeout=None)
287
+ if resp.status_code >= 400:
288
+ raise RuntimeError("Audio url is not accessable")
289
+
290
+ audio = AudioSegment.from_file(io.BytesIO(resp.content),
291
+ format=format)
292
+ return audio
@@ -1,7 +1,8 @@
1
1
  import re
2
2
  from dataclasses import dataclass
3
- from dataclasses_json import dataclass_json, DataClassJsonMixin
4
- from typing import Optional, List, Literal, Dict
3
+ from typing import Dict, List, Literal, Optional
4
+
5
+ from dataclasses_json import DataClassJsonMixin, dataclass_json
5
6
 
6
7
 
7
8
  @dataclass_json
@@ -76,6 +77,42 @@ class Result(DataClassJsonMixin):
76
77
  for column_result in self.results])
77
78
 
78
79
 
80
+ @dataclass_json
81
+ @dataclass
82
+ class DialogSegment(DataClassJsonMixin):
83
+ start_time_ms: int
84
+ end_time_ms: int
85
+ text: str
86
+ speaker: str
87
+ emotion: Optional[str] = None
88
+ intensity: Optional[float] = None
89
+
90
+ def to_text(self):
91
+ if self.emotion is None:
92
+ return f'{self.speaker}: {self.text}\n'
93
+ else:
94
+ return f'{self.speaker}: <emotion name="{self.emotion}" intensity="{self.intensity}">{self.text}</emotion>\n'
95
+
96
+
97
+ @dataclass_json
98
+ @dataclass
99
+ class Dialog(DataClassJsonMixin):
100
+ segments: List[DialogSegment]
101
+
102
+ def to_text(self):
103
+ return ''.join([segment.to_text()
104
+ for segment in self.segments])
105
+
106
+
107
+ @dataclass_json
108
+ @dataclass
109
+ class DialogResult(DataClassJsonMixin):
110
+ id: str
111
+ dialog: Optional[Dialog]
112
+ url: Optional[str]
113
+ results: Optional[List[ColumnResult]]
114
+
115
+
79
116
  def is_valid_objectid(oid: str) -> bool:
80
117
  """
81
118
  Check if a given string is a valid MongoDB ObjectId (24-character hex).
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: most-client
3
- Version: 1.0.14
3
+ Version: 1.0.16
4
4
  Summary: Most AI API for https://the-most.ai
5
5
  Home-page: https://github.com/the-most-ai/most-client
6
6
  Author: George Kasparyants
@@ -26,6 +26,7 @@ Requires-Dist: pytest
26
26
  Requires-Dist: tox
27
27
  Requires-Dist: twine
28
28
  Requires-Dist: httpx
29
+ Requires-Dist: pydub
29
30
  Dynamic: author
30
31
  Dynamic: author-email
31
32
  Dynamic: classifier
@@ -12,3 +12,4 @@ pytest
12
12
  tox
13
13
  twine
14
14
  httpx
15
+ pydub
@@ -12,3 +12,4 @@ pytest
12
12
  tox
13
13
  twine
14
14
  httpx
15
+ pydub
@@ -8,7 +8,7 @@ with open('requirements.txt', 'r') as f:
8
8
 
9
9
  setup(
10
10
  name='most-client',
11
- version='1.0.14',
11
+ version='1.0.16',
12
12
  python_requires=f'>=3.6',
13
13
  description='Most AI API for https://the-most.ai',
14
14
  url='https://github.com/the-most-ai/most-client',
File without changes
File without changes
File without changes