most-client 1.0.1__py3-none-any.whl → 1.0.3__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.
most/__init__.py CHANGED
@@ -1 +1,2 @@
1
1
  from .api import MostClient
2
+ from .async_api import AsyncMostClient
Binary file
Binary file
most/api.py CHANGED
@@ -2,7 +2,7 @@ from typing import List
2
2
  import json5
3
3
  import requests
4
4
  from adaptix import Retort
5
- from most.types import Audio, Result
5
+ from most.types import Audio, Result, Script, JobStatus
6
6
  from pathlib import Path
7
7
 
8
8
 
@@ -126,23 +126,46 @@ class MostClient(object):
126
126
  audio_list = resp.json()
127
127
  return self.retort.load(audio_list, List[Audio])
128
128
 
129
+ def get_model_script(self) -> Script:
130
+ if self.model_id is None:
131
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
132
+ resp = self.get(f"https://api.the-most.ai/api/external/{self.client_id}/model/{self.model_id}/script")
133
+ return self.retort.load(resp.json(), Script)
134
+
129
135
  def list_models(self):
130
136
  resp = self.get("https://api.the-most.ai/api/external/list_models")
131
137
  return [self.with_model(model['model'])
132
138
  for model in resp.json()]
133
139
 
134
140
  def apply(self, audio_id) -> Result:
141
+ if self.model_id is None:
142
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
135
143
  resp = self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply")
136
144
  return self.retort.load(resp.json(), Result)
137
145
 
138
- def apply_later(self, audio_id):
139
- raise NotImplementedError()
146
+ def apply_later(self, audio_id) -> Result:
147
+ if self.model_id is None:
148
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
149
+ resp = self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply_async")
150
+ return self.retort.load(resp.json(), Result)
151
+
152
+ def get_job_status(self, audio_id) -> JobStatus:
153
+ if self.model_id is None:
154
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
155
+ resp = self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply_status")
156
+ return self.retort.load(resp.json(), JobStatus)
140
157
 
141
158
  def fetch_results(self, audio_id) -> Result:
159
+ if self.model_id is None:
160
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
161
+
142
162
  resp = self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/results")
143
163
  return self.retort.load(resp.json(), Result)
144
164
 
145
165
  def fetch_text(self, audio_id) -> Result:
166
+ if self.model_id is None:
167
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
168
+
146
169
  resp = self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/text")
147
170
  return self.retort.load(resp.json(), Result)
148
171
 
most/async_api.py ADDED
@@ -0,0 +1,185 @@
1
+ from typing import List
2
+ import json5
3
+ from adaptix import Retort
4
+ from most.types import Audio, Result, Script, JobStatus
5
+ from pathlib import Path
6
+ import httpx
7
+
8
+
9
+ class AsyncMostClient(object):
10
+ retort = Retort()
11
+
12
+ def __init__(self,
13
+ client_id=None,
14
+ client_secret=None,
15
+ model_id=None):
16
+ super(AsyncMostClient, self).__init__()
17
+ self.client_id = client_id
18
+ self.client_secret = client_secret
19
+
20
+ if self.client_id is None:
21
+ credentials = self.load_credentials()
22
+ self.client_id = credentials.get('client_id')
23
+ self.client_secret = credentials.get('client_secret')
24
+
25
+ if self.client_id is None:
26
+ print("Visit: https://app.the-most.ai/integrations and get clientId, clientSecret")
27
+ self.client_id = input("Please enter your client ID: ")
28
+ self.client_secret = input("Please enter your client secret: ")
29
+ self.save_credentials()
30
+ else:
31
+ self.save_credentials()
32
+
33
+ self.session = httpx.AsyncClient()
34
+ self.access_token = None
35
+ self.model_id = model_id
36
+
37
+ async def __aenter__(self):
38
+ await self.session.__aenter__()
39
+ await self.refresh_access_token()
40
+ return self
41
+
42
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
43
+ await self.session.__aexit__(exc_type, exc_val, exc_tb)
44
+
45
+ @property
46
+ def cache_path(self):
47
+ path = Path.home() / ".most"
48
+ path.mkdir(parents=True, exist_ok=True)
49
+ return path
50
+
51
+ def load_credentials(self):
52
+ path = self.cache_path / "credentials.json"
53
+ if not path.exists():
54
+ return {}
55
+ else:
56
+ return json5.loads(path.read_text())
57
+
58
+ def save_credentials(self):
59
+ path = self.cache_path / "credentials.json"
60
+ path.write_text(json5.dumps({
61
+ "client_id": self.client_id,
62
+ "client_secret": self.client_secret,
63
+ }))
64
+
65
+ def clone(self):
66
+ client = AsyncMostClient(client_id=self.client_id,
67
+ client_secret=self.client_secret,
68
+ model_id=self.model_id)
69
+ client.access_token = self.access_token
70
+ client.session = self.session
71
+ return client
72
+
73
+ def with_model(self, model_id):
74
+ client = self.clone()
75
+ client.model_id = model_id
76
+ return client
77
+
78
+ async def refresh_access_token(self):
79
+ resp = await self.session.post("https://api.the-most.ai/api/external/access_token",
80
+ json={"client_id": self.client_id,
81
+ "client_secret": self.client_secret})
82
+ access_token = resp.json()
83
+ self.access_token = access_token
84
+
85
+ async def get(self, url, **kwargs):
86
+ if self.access_token is None:
87
+ await self.refresh_access_token()
88
+ headers = kwargs.pop("headers", {})
89
+ headers.update({"Authorization": "Bearer %s" % self.access_token})
90
+ resp = await self.session.get(url,
91
+ headers=headers,
92
+ **kwargs)
93
+ if resp.status_code == 401:
94
+ await self.refresh_access_token()
95
+ return await self.get(url,
96
+ headers=headers,
97
+ **kwargs)
98
+ return resp
99
+
100
+ async def post(self, url,
101
+ data=None,
102
+ json=None,
103
+ **kwargs):
104
+ if self.access_token is None:
105
+ await self.refresh_access_token()
106
+ headers = kwargs.pop("headers", {})
107
+ headers.update({"Authorization": "Bearer %s" % self.access_token})
108
+ resp = await self.session.post(url,
109
+ data=data,
110
+ json=json,
111
+ headers=headers,
112
+ **kwargs)
113
+ if resp.status_code == 401:
114
+ await self.refresh_access_token()
115
+ return await self.post(url,
116
+ data=data,
117
+ json=json,
118
+ headers=headers,
119
+ **kwargs)
120
+ return resp
121
+
122
+ async def upload_audio(self, audio_path) -> Audio:
123
+ with open(audio_path, mode='rb') as f:
124
+ resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/upload",
125
+ files={"audio_file": f},
126
+ timeout=None)
127
+ return self.retort.load(resp.json(), Audio)
128
+
129
+ async def list_audios(self,
130
+ offset: int = 0,
131
+ limit: int = 10) -> List[Audio]:
132
+ resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/list?offset={offset}&limit={limit}")
133
+ audio_list = resp.json()
134
+ return self.retort.load(audio_list, List[Audio])
135
+
136
+ async def get_model_script(self) -> Script:
137
+ if self.model_id is None:
138
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
139
+ resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/model/{self.model_id}/script")
140
+ return self.retort.load(resp.json(), Script)
141
+
142
+ async def list_models(self):
143
+ resp = await self.get("https://api.the-most.ai/api/external/list_models")
144
+ return [self.with_model(model['model'])
145
+ for model in resp.json()]
146
+
147
+ async def apply(self, audio_id) -> Result:
148
+ if self.model_id is None:
149
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
150
+ resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply",
151
+ timeout=None)
152
+ return self.retort.load(resp.json(), Result)
153
+
154
+ async def apply_later(self, audio_id):
155
+ if self.model_id is None:
156
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
157
+ resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply_async")
158
+ return self.retort.load(resp.json(), Result)
159
+
160
+ async def get_job_status(self, audio_id) -> JobStatus:
161
+ if self.model_id is None:
162
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
163
+ resp = await self.post(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/apply_status")
164
+ return self.retort.load(resp.json(), JobStatus)
165
+
166
+ async def fetch_results(self, audio_id) -> Result:
167
+ if self.model_id is None:
168
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
169
+
170
+ resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/results")
171
+ return self.retort.load(resp.json(), Result)
172
+
173
+ async def fetch_text(self, audio_id) -> Result:
174
+ if self.model_id is None:
175
+ raise RuntimeError("Please choose a model to apply. [try list_models()]")
176
+
177
+ resp = await self.get(f"https://api.the-most.ai/api/external/{self.client_id}/audio/{audio_id}/model/{self.model_id}/text")
178
+ return self.retort.load(resp.json(), Result)
179
+
180
+ async def __call__(self, audio_path: Path):
181
+ audio = await self.upload_audio(audio_path)
182
+ return await self.apply(audio.id)
183
+
184
+ def __repr__(self):
185
+ return "<AsyncMostClient(model_id='%s')>" % (self.model_id, )
most/types.py CHANGED
@@ -1,5 +1,5 @@
1
1
  from dataclasses import dataclass
2
- from typing import Optional, List
2
+ from typing import Optional, List, Literal
3
3
 
4
4
 
5
5
  @dataclass
@@ -27,3 +27,19 @@ class Result:
27
27
  text: Optional[str]
28
28
  url: Optional[str]
29
29
  results: Optional[List[ColumnResult]]
30
+
31
+
32
+ @dataclass
33
+ class Column:
34
+ name: str
35
+ subcolumns: List[str]
36
+
37
+
38
+ @dataclass
39
+ class Script:
40
+ columns: List[Column]
41
+
42
+
43
+ @dataclass
44
+ class JobStatus:
45
+ status: Literal["not_found", "pending", "completed", "error"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: most-client
3
- Version: 1.0.1
3
+ Version: 1.0.3
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
@@ -25,4 +25,5 @@ Requires-Dist: pylint
25
25
  Requires-Dist: pytest
26
26
  Requires-Dist: tox
27
27
  Requires-Dist: twine
28
+ Requires-Dist: httpx
28
29
 
@@ -0,0 +1,13 @@
1
+ most/__init__.py,sha256=62uFFeM_1VVR83K3bTYWK3PEoqnmFCy9aWYerQ6U4Ds,67
2
+ most/api.py,sha256=3B0G6qZUbAJtTKpQme0SdI2JnCsT-_fRDDWBZKKtmvA,7030
3
+ most/async_api.py,sha256=aepk9EXOv-tLVh8bNrACuTVkxGOtCZC5R3SBLi9qR90,7673
4
+ most/types.py,sha256=GP0i9ZtITz7k-_T5-SWMYevrRaN38vuNKRdxXEHgrFA,653
5
+ most/__pycache__/__init__.cpython-310.pyc,sha256=5RlgyJsgWSNkWEufVPFWDKxat0cEMCdwD8QFz5FvIj8,193
6
+ most/__pycache__/api.cpython-310.pyc,sha256=vAmUcfJHdL-59JuzcMpDfQedBaTk62nomDuzTt-thx0,5894
7
+ most/__pycache__/async_api.cpython-310.pyc,sha256=ng8wYkVziihVAMlv1ugFQQf-qFqP0NgAIfqKqE-K4k8,6615
8
+ most/__pycache__/types.cpython-310.pyc,sha256=OE7jIlp_0lo6XAwsnVnbsYsjjppGzTUcVo5ve6uHnQg,1492
9
+ most_client-1.0.3.dist-info/METADATA,sha256=msB8Kt-Cpr8u6FlMWtk0n2_jC3GwrHO4TXXEv1mbDgU,864
10
+ most_client-1.0.3.dist-info/WHEEL,sha256=bFJAMchF8aTQGUgMZzHJyDDMPTO3ToJ7x23SLJa1SVo,92
11
+ most_client-1.0.3.dist-info/top_level.txt,sha256=2g5fk02LKkM1hV3pVVti_LQ60TToLBcR2zQ3JEKGVk8,5
12
+ most_client-1.0.3.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
13
+ most_client-1.0.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.5.0)
2
+ Generator: bdist_wheel (0.45.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,11 +0,0 @@
1
- most/__init__.py,sha256=zfyI5dry-rsHP2Rr9YuPPo_fNFUtguZPAt-mbxDQ57I,28
2
- most/api.py,sha256=31uEaydLcJzDb4n8z0_NH-BkdM_79_2BqttedM51ffY,5676
3
- most/types.py,sha256=DtuMK8TgdjTDXYVtakqEN1ZLH6v1z_LR1jWya9CyCqI,428
4
- most/__pycache__/__init__.cpython-310.pyc,sha256=5RlgyJsgWSNkWEufVPFWDKxat0cEMCdwD8QFz5FvIj8,193
5
- most/__pycache__/api.cpython-310.pyc,sha256=LCury8Ch-FweUI4d91F_tVWRHWfJbFE_Jv0sLjWye5I,5473
6
- most/__pycache__/types.cpython-310.pyc,sha256=gwNy34k4XAZ8en1VT3S3QbJOoRuqAeUZEBJjgzSEpIg,1131
7
- most_client-1.0.1.dist-info/METADATA,sha256=qNNyQ0GvZAzPnADLWAEOMIECtrbYvu7uMnsQqgmmOb8,843
8
- most_client-1.0.1.dist-info/WHEEL,sha256=R06PA3UVYHThwHvxuRWMqaGcr-PuniXahwjmQRFMEkY,91
9
- most_client-1.0.1.dist-info/top_level.txt,sha256=2g5fk02LKkM1hV3pVVti_LQ60TToLBcR2zQ3JEKGVk8,5
10
- most_client-1.0.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
11
- most_client-1.0.1.dist-info/RECORD,,