added descript
Browse files- App/TTS/Schemas.py +13 -0
- App/TTS/TTSRoutes.py +26 -1
- App/TTS/utils/Descript.py +373 -0
- App/app.py +3 -2
App/TTS/Schemas.py
CHANGED
@@ -19,6 +19,19 @@ class Speak(BaseModel):
|
|
19 |
)
|
20 |
super().__init__(**data)
|
21 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
class HeyGenTTSRequest(BaseModel):
|
24 |
voice_id: str = Field(default="d7bbcdd6964c47bdaae26decade4a933")
|
|
|
19 |
)
|
20 |
super().__init__(**data)
|
21 |
|
22 |
+
class DescriptSfxRequest(BaseModel):
|
23 |
+
query:str
|
24 |
+
|
25 |
+
class DescriptRequest(BaseModel):
|
26 |
+
text: str
|
27 |
+
speaker: Optional[str]=Field(default="Lawrance")
|
28 |
+
_voice_id: Optional[str]
|
29 |
+
|
30 |
+
class DescriptStatusRequest(BaseModel):
|
31 |
+
id:str
|
32 |
+
|
33 |
+
|
34 |
+
|
35 |
|
36 |
class HeyGenTTSRequest(BaseModel):
|
37 |
voice_id: str = Field(default="d7bbcdd6964c47bdaae26decade4a933")
|
App/TTS/TTSRoutes.py
CHANGED
@@ -1,9 +1,10 @@
|
|
1 |
from fastapi import APIRouter
|
2 |
|
3 |
|
4 |
-
from .Schemas import StatusRequest, TTSGenerateRequest, HeyGenTTSRequest
|
5 |
from .utils.Podcastle import PodcastleAPI
|
6 |
from .utils.HeyGen import HeygenAPI
|
|
|
7 |
import os
|
8 |
|
9 |
tts_router = APIRouter(tags=["TTS"])
|
@@ -14,6 +15,8 @@ data = {
|
|
14 |
"password": os.environ.get("HEYGEN_PASSWORD"),
|
15 |
"token": os.environ.get("HEYGEN_TOKEN"),
|
16 |
}
|
|
|
|
|
17 |
heyGentts = HeygenAPI(**data)
|
18 |
|
19 |
|
@@ -28,6 +31,28 @@ async def generate_heygen_voice(req: HeyGenTTSRequest):
|
|
28 |
print("hey gen here")
|
29 |
return await heyGentts.tts_request(req)
|
30 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
@tts_router.post("/status")
|
33 |
async def search_id(req: StatusRequest):
|
|
|
1 |
from fastapi import APIRouter
|
2 |
|
3 |
|
4 |
+
from .Schemas import StatusRequest, TTSGenerateRequest, HeyGenTTSRequest,DescriptRequest,DescriptStatusRequest,DescriptSfxRequest
|
5 |
from .utils.Podcastle import PodcastleAPI
|
6 |
from .utils.HeyGen import HeygenAPI
|
7 |
+
from .utils.Descript import DescriptTTS
|
8 |
import os
|
9 |
|
10 |
tts_router = APIRouter(tags=["TTS"])
|
|
|
15 |
"password": os.environ.get("HEYGEN_PASSWORD"),
|
16 |
"token": os.environ.get("HEYGEN_TOKEN"),
|
17 |
}
|
18 |
+
|
19 |
+
descript_tts=DescriptTTS()
|
20 |
heyGentts = HeygenAPI(**data)
|
21 |
|
22 |
|
|
|
31 |
print("hey gen here")
|
32 |
return await heyGentts.tts_request(req)
|
33 |
|
34 |
+
@tts_router.post("/descript_tts")
|
35 |
+
async def generate_descript_voice(req: DescriptRequest):
|
36 |
+
return await descript_tts.overdub_text(**req.__dict__)
|
37 |
+
|
38 |
+
|
39 |
+
@tts_router.post("/descript_status")
|
40 |
+
async def status_descript(req: DescriptStatusRequest):
|
41 |
+
return await descript_tts.request_status(req.id)
|
42 |
+
|
43 |
+
@tts_router.post("/descript_sfx")
|
44 |
+
async def descript_sfx(req: DescriptSfxRequest):
|
45 |
+
return await descript_tts.search_sound_effects(req.query)
|
46 |
+
|
47 |
+
@tts_router.post("/descript_unsplash")
|
48 |
+
async def descript_unsplash(req: DescriptSfxRequest):
|
49 |
+
return await descript_tts.search_unsplash_images(req.query)
|
50 |
+
|
51 |
+
|
52 |
+
|
53 |
+
@tts_router.get("/descript_voices")
|
54 |
+
async def voices_descript():
|
55 |
+
return await descript_tts.get_voices()
|
56 |
|
57 |
@tts_router.post("/status")
|
58 |
async def search_id(req: StatusRequest):
|
App/TTS/utils/Descript.py
ADDED
@@ -0,0 +1,373 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import aiohttp
|
2 |
+
import asyncio
|
3 |
+
import json, pprint, uuid, os, datetime
|
4 |
+
import tempfile, shutil
|
5 |
+
from typing import List, Optional
|
6 |
+
from datetime import datetime, timedelta
|
7 |
+
from pydantic import BaseModel, HttpUrl
|
8 |
+
|
9 |
+
|
10 |
+
class Metadata(BaseModel):
|
11 |
+
filename: str
|
12 |
+
type: str
|
13 |
+
|
14 |
+
|
15 |
+
class Artifact(BaseModel):
|
16 |
+
asset_id: str
|
17 |
+
created_at: datetime
|
18 |
+
file_extension: str
|
19 |
+
id: str
|
20 |
+
is_segmented: bool
|
21 |
+
lookup_key: HttpUrl
|
22 |
+
md5: str
|
23 |
+
metadata: Metadata
|
24 |
+
read_url: HttpUrl
|
25 |
+
size: int
|
26 |
+
status: str
|
27 |
+
uploaded_by: str
|
28 |
+
|
29 |
+
|
30 |
+
class TTSResponse(BaseModel):
|
31 |
+
artifacts: List[Artifact]
|
32 |
+
created_at: datetime
|
33 |
+
created_by: str
|
34 |
+
id: str
|
35 |
+
lookup_key: HttpUrl
|
36 |
+
metadata: Optional[dict]
|
37 |
+
|
38 |
+
|
39 |
+
class DescriptTTS:
|
40 |
+
def __init__(self, refresh_token=None):
|
41 |
+
self.client_id = "VDfu7rg4pdCELWsrQjcw2tG63a8Qlymi"
|
42 |
+
self.refresh_token_url = "https://auth0.descript.com/oauth/token"
|
43 |
+
self.project_id = "f734c6d7-e39d-4c1d-8f41-417f94cd37ce"
|
44 |
+
self.bearer_token = None
|
45 |
+
self.voice_ids = {
|
46 |
+
"Henry": "569fffb0-05a3-48a2-96a3-bf411c376477",
|
47 |
+
"Malcom": "75f8b86e-d05d-4862-a228-8d96fdf55258",
|
48 |
+
"Lawrance": "042460c0-98a5-41ae-9f31-33672ebb9016",
|
49 |
+
## de
|
50 |
+
}
|
51 |
+
|
52 |
+
self.refresh_token = refresh_token
|
53 |
+
self.tau_id = "90f9e0ad-594e-4203-9297-d4c7cc691e5x"
|
54 |
+
|
55 |
+
async def login_and_get_bearer_token(self):
|
56 |
+
# Step 1: Use refresh token to get a new access token
|
57 |
+
new_bearer_token, new_refresh_token = await self.refresh_access_token()
|
58 |
+
|
59 |
+
# Step 2: Update the new refresh token to the Firebase Realtime Database
|
60 |
+
await self.update_refresh_token(new_refresh_token)
|
61 |
+
|
62 |
+
# Step 3: Set the new bearer token for further use
|
63 |
+
self.bearer_token = new_bearer_token
|
64 |
+
self.refresh_token = new_refresh_token
|
65 |
+
|
66 |
+
async def refresh_access_token(self):
|
67 |
+
# Load the existing refresh token from Firebase
|
68 |
+
if self.refresh_token == None:
|
69 |
+
await self.load_existing_refresh_token()
|
70 |
+
|
71 |
+
# Prepare the payload for token refresh
|
72 |
+
payload = {
|
73 |
+
"grant_type": "refresh_token",
|
74 |
+
"refresh_token": self.refresh_token,
|
75 |
+
"client_id": self.client_id,
|
76 |
+
}
|
77 |
+
|
78 |
+
# Request a new access token using the refresh token
|
79 |
+
async with aiohttp.ClientSession() as session:
|
80 |
+
async with session.post(self.refresh_token_url, data=payload) as response:
|
81 |
+
if response.status == 200:
|
82 |
+
# Parse the response to get the new access token and refresh token
|
83 |
+
response_data = await response.json()
|
84 |
+
new_bearer_token = response_data.get("access_token")
|
85 |
+
new_refresh_token = response_data.get("refresh_token")
|
86 |
+
|
87 |
+
return new_bearer_token, new_refresh_token
|
88 |
+
else:
|
89 |
+
raise Exception(
|
90 |
+
f"Failed to refresh access token. Status code: {response.status}, Error: {await response.text()}"
|
91 |
+
)
|
92 |
+
|
93 |
+
async def load_existing_refresh_token(self):
|
94 |
+
# Load the existing refresh token from Firebase
|
95 |
+
async with aiohttp.ClientSession() as session:
|
96 |
+
async with session.get(
|
97 |
+
"https://herokuserver-185316.firebaseio.com/refresh_token_descript.json"
|
98 |
+
) as response:
|
99 |
+
if response.status == 200:
|
100 |
+
# Parse the response to get the existing refresh token
|
101 |
+
data = await response.json()
|
102 |
+
self.refresh_token = data.get("refresh_token")
|
103 |
+
else:
|
104 |
+
raise Exception(
|
105 |
+
f"Failed to load existing refresh token. Status code: {response.status}, Error: {await response.text()}"
|
106 |
+
)
|
107 |
+
|
108 |
+
async def download_and_store_file(self, access_url):
|
109 |
+
temp_dir = tempfile.mkdtemp()
|
110 |
+
# Generate a unique random filename
|
111 |
+
random_filename = str(uuid.uuid4()) + ".wav"
|
112 |
+
file_path = os.path.join(temp_dir, random_filename)
|
113 |
+
|
114 |
+
async with aiohttp.ClientSession() as session:
|
115 |
+
async with session.get(access_url) as response:
|
116 |
+
if response.status == 200:
|
117 |
+
with open(file_path, "wb") as file:
|
118 |
+
while True:
|
119 |
+
chunk = await response.content.read(1024)
|
120 |
+
if not chunk:
|
121 |
+
break
|
122 |
+
file.write(chunk)
|
123 |
+
|
124 |
+
# Schedule the file for deletion after 10 minutes
|
125 |
+
delete_time = datetime.now() + timedelta(minutes=10)
|
126 |
+
|
127 |
+
async def schedule_delete():
|
128 |
+
while datetime.now() < delete_time:
|
129 |
+
await asyncio.sleep(60) # Check every minute
|
130 |
+
shutil.rmtree(
|
131 |
+
temp_dir, ignore_errors=True
|
132 |
+
) # Delete the temporary directory
|
133 |
+
|
134 |
+
asyncio.ensure_future(schedule_delete())
|
135 |
+
|
136 |
+
return file_path
|
137 |
+
|
138 |
+
async def search_unsplash_images(self, query_terms):
|
139 |
+
url = "https://api.descript.com/v2/cloud_libraries/providers/unsplash/image/search"
|
140 |
+
data = {
|
141 |
+
'tracking_info': {'project_id': self.project_id},
|
142 |
+
'pagination_info': {'page': 2, 'page_size': 25},
|
143 |
+
'query': {'terms': query_terms}
|
144 |
+
}
|
145 |
+
|
146 |
+
try:
|
147 |
+
response = await self.make_authenticated_request(url, method="POST", data=data)
|
148 |
+
return response
|
149 |
+
except Exception as e:
|
150 |
+
print(f"Failed to search Unsplash images: {e}")
|
151 |
+
return None
|
152 |
+
|
153 |
+
|
154 |
+
|
155 |
+
|
156 |
+
async def search_sound_effects(self, query_terms):
|
157 |
+
url = "https://api.descript.com/v2/cloud_libraries/providers/stock-sfx/audio/search"
|
158 |
+
headers = {
|
159 |
+
'accept': 'application/json, text/plain, */*',
|
160 |
+
'accept-language': 'en-US,en;q=0.9',
|
161 |
+
'content-type': 'application/json',
|
162 |
+
|
163 |
+
'authorization': f'Bearer {self.bearer_token}', # Use the valid bearer token
|
164 |
+
}
|
165 |
+
data = {
|
166 |
+
'tracking_info': {'project_id': self.project_id},
|
167 |
+
'pagination_info': {'page': 1, 'page_size': 25},
|
168 |
+
'query': {'terms': query_terms}
|
169 |
+
}
|
170 |
+
|
171 |
+
try:
|
172 |
+
response = await self.make_authenticated_request(url, method="POST", data=data)
|
173 |
+
return response
|
174 |
+
except Exception as e:
|
175 |
+
print(f"Failed to search sound effects: {e}")
|
176 |
+
return {'status':str(e)}
|
177 |
+
|
178 |
+
|
179 |
+
async def get_voices(self):
|
180 |
+
url = "https://api.descript.com/v2/users/me/voices"
|
181 |
+
try:
|
182 |
+
response = await self.make_authenticated_request(url)
|
183 |
+
return response
|
184 |
+
except Exception as e:
|
185 |
+
print(f"Failed to fetch voices: {e}")
|
186 |
+
return None
|
187 |
+
|
188 |
+
|
189 |
+
async def start_token_refresh_schedule(self):
|
190 |
+
while True:
|
191 |
+
try:
|
192 |
+
new_bearer_token, new_refresh_token = await self.refresh_access_token()
|
193 |
+
self.bearer_token = new_bearer_token
|
194 |
+
self.refresh_token = new_refresh_token
|
195 |
+
|
196 |
+
# Step 2: Update the new refresh token to the Firebase Realtime Database
|
197 |
+
await self.update_refresh_token(new_refresh_token)
|
198 |
+
|
199 |
+
print("Token refreshed successfully")
|
200 |
+
except Exception as e:
|
201 |
+
print(f"Failed to refresh token: {e}")
|
202 |
+
|
203 |
+
# Wait for 24 hours before the next refresh
|
204 |
+
await asyncio.sleep(24 * 60 * 60)
|
205 |
+
|
206 |
+
|
207 |
+
async def update_refresh_token(self, new_refresh_token):
|
208 |
+
# Update the new refresh token to Firebase
|
209 |
+
data = {"refresh_token": new_refresh_token}
|
210 |
+
async with aiohttp.ClientSession() as session:
|
211 |
+
async with session.put(
|
212 |
+
"https://herokuserver-185316.firebaseio.com/refresh_token_descript.json",
|
213 |
+
json=data,
|
214 |
+
) as response:
|
215 |
+
if response.status != 200:
|
216 |
+
raise Exception(
|
217 |
+
f"Failed to update refresh token. Status code: {response.status}, Error: {await response.text()}"
|
218 |
+
)
|
219 |
+
|
220 |
+
async def make_authenticated_request(self, url, method="GET", data=None):
|
221 |
+
if not self.bearer_token:
|
222 |
+
await self.login_and_get_bearer_token() # Make sure we have a valid bearer token
|
223 |
+
|
224 |
+
headers = {
|
225 |
+
"authority": "api.descript.com",
|
226 |
+
"accept": "application/json, text/plain, */*",
|
227 |
+
"accept-language": "en-US,en;q=0.9",
|
228 |
+
"accept-version": "v1",
|
229 |
+
"authorization": f"Bearer {self.bearer_token}",
|
230 |
+
"cache-control": "no-cache",
|
231 |
+
"content-type": "application/json",
|
232 |
+
"origin": "https://web.descript.com",
|
233 |
+
"pragma": "no-cache",
|
234 |
+
"referer": "https://web.descript.com/",
|
235 |
+
"sec-ch-ua": '"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"',
|
236 |
+
"sec-ch-ua-mobile": "?0",
|
237 |
+
"sec-ch-ua-platform": '"Windows"',
|
238 |
+
"sec-fetch-dest": "empty",
|
239 |
+
"sec-fetch-mode": "cors",
|
240 |
+
"sec-fetch-site": "same-site",
|
241 |
+
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36",
|
242 |
+
"x-descript-app-build-number": "20231206.146",
|
243 |
+
"x-descript-app-build-type": "release",
|
244 |
+
"x-descript-app-id": "48db7358-5ebc-4866-b672-10b412ac39c1",
|
245 |
+
"x-descript-app-name": "web",
|
246 |
+
"x-descript-app-version": "78.2.4",
|
247 |
+
"x-descript-auth": "auth0",
|
248 |
+
}
|
249 |
+
|
250 |
+
async with aiohttp.ClientSession() as session:
|
251 |
+
async with session.request(
|
252 |
+
method, url, headers=headers, json=data
|
253 |
+
) as response:
|
254 |
+
if response.status < 300:
|
255 |
+
return await response.json()
|
256 |
+
elif response.status == 401:
|
257 |
+
# Retry the request after refreshing the token
|
258 |
+
await self.login_and_get_bearer_token()
|
259 |
+
headers["authorization"] = f"Bearer {self.bearer_token}"
|
260 |
+
async with session.request(
|
261 |
+
method, url, headers=headers, json=data
|
262 |
+
) as retry_response:
|
263 |
+
if retry_response.status == 200:
|
264 |
+
return await retry_response.json()
|
265 |
+
else:
|
266 |
+
raise Exception(
|
267 |
+
f"Request failed even after refreshing token. Status code: {retry_response.status}, Error: {await retry_response.text()}"
|
268 |
+
)
|
269 |
+
else:
|
270 |
+
raise Exception(
|
271 |
+
f"Request failed. Status code: {response.status}, Error: {await response.text()}"
|
272 |
+
)
|
273 |
+
|
274 |
+
async def get_assets(self):
|
275 |
+
url = "https://api.descript.com/v2/projects/f734c6d7-e39d-4c1d-8f41-417f94cd37ce/media_assets?include_artifacts=true&cursor=1702016922390&include_placeholder=true"
|
276 |
+
try:
|
277 |
+
result = await self.make_authenticated_request(url)
|
278 |
+
return result
|
279 |
+
except Exception as e:
|
280 |
+
print(f"Failed to get assets: {str(e)}")
|
281 |
+
|
282 |
+
async def overdub_text(self, text, speaker="Lawrance",_voice_id=None):
|
283 |
+
url = "https://api.descript.com/v2/projects/f734c6d7-e39d-4c1d-8f41-417f94cd37ce/overdub"
|
284 |
+
voice_id = _voice_id or self.voice_ids[speaker]
|
285 |
+
data = {
|
286 |
+
"text": text,
|
287 |
+
"voice_id": voice_id,
|
288 |
+
"concatenate_audio": True,
|
289 |
+
"tau_id": self.tau_id,
|
290 |
+
"allow_prefix_expansion": True,
|
291 |
+
"allow_suffix_expansion": True,
|
292 |
+
}
|
293 |
+
|
294 |
+
try:
|
295 |
+
result = await self.make_authenticated_request(
|
296 |
+
url, method="POST", data=data
|
297 |
+
)
|
298 |
+
return result
|
299 |
+
except Exception as e:
|
300 |
+
# Retry the request after refreshing the token if the failure is due to authorization
|
301 |
+
if "authorization" in str(e).lower():
|
302 |
+
await self.login_and_get_bearer_token()
|
303 |
+
result = await self.make_authenticated_request(
|
304 |
+
url, method="POST", data=data
|
305 |
+
)
|
306 |
+
print(result)
|
307 |
+
return result
|
308 |
+
else:
|
309 |
+
print(f"Failed to perform overdub: {str(e)}")
|
310 |
+
|
311 |
+
async def overdub_staus(self, id):
|
312 |
+
url = f"https://api.descript.com/v2/projects/f734c6d7-e39d-4c1d-8f41-417f94cd37ce/overdub/{id}"
|
313 |
+
|
314 |
+
try:
|
315 |
+
result = await self.make_authenticated_request(url, method="GET")
|
316 |
+
print(result)
|
317 |
+
return result
|
318 |
+
except Exception as e:
|
319 |
+
# Retry the request after refreshing the token if the failure is due to authorization
|
320 |
+
if "authorization" in str(e).lower():
|
321 |
+
await self.login_and_get_bearer_token()
|
322 |
+
result = await self.make_authenticated_request(
|
323 |
+
url, method="POST", data=data
|
324 |
+
)
|
325 |
+
print(result)
|
326 |
+
return result
|
327 |
+
else:
|
328 |
+
print(f"Failed to perform overdub: {str(e)}")
|
329 |
+
|
330 |
+
async def request_status(self, id):
|
331 |
+
status = await self.overdub_staus(id)
|
332 |
+
if status["state"] == "done":
|
333 |
+
asset_id=status["result"]["imputation_audio_asset_id"]
|
334 |
+
overdub = await self.get_assets()
|
335 |
+
for asset in overdub["data"]:
|
336 |
+
if asset["id"] == asset_id:
|
337 |
+
data = TTSResponse(**asset)
|
338 |
+
url = data.artifacts[0].read_url
|
339 |
+
return {'url':url,'status':'done'}
|
340 |
+
return status
|
341 |
+
|
342 |
+
|
343 |
+
|
344 |
+
async def say(self, text, speaker="Henry"):
|
345 |
+
overdub = await self.overdub_text(text, speaker=speaker)
|
346 |
+
|
347 |
+
asset_id = None
|
348 |
+
while True:
|
349 |
+
status = await self.overdub_staus(overdub["id"])
|
350 |
+
# print(status)
|
351 |
+
if status["state"] == "done":
|
352 |
+
# print(status)
|
353 |
+
asset_id = status["result"]["imputation_audio_asset_id"]
|
354 |
+
break
|
355 |
+
await asyncio.sleep(3)
|
356 |
+
|
357 |
+
overdub = await self.get_assets()
|
358 |
+
for asset in overdub["data"]:
|
359 |
+
if asset["id"] == asset_id:
|
360 |
+
data = TTSResponse(**asset)
|
361 |
+
url = data.artifacts[0].read_url
|
362 |
+
print(url)
|
363 |
+
path = await self.download_and_store_file(str(url))
|
364 |
+
return path, url
|
365 |
+
|
366 |
+
|
367 |
+
# async def example_usage():
|
368 |
+
# descript_tts = DescriptTTS()
|
369 |
+
# r=await descript_tts.say('Watch the world burn')
|
370 |
+
# print(r)
|
371 |
+
|
372 |
+
# # Run the example usage asynchronously
|
373 |
+
# asyncio.run(example_usage())
|
App/app.py
CHANGED
@@ -3,7 +3,7 @@ from fastapi import FastAPI
|
|
3 |
from fastapi.middleware.gzip import GZipMiddleware
|
4 |
|
5 |
from .TTS.TTSRoutes import tts_router
|
6 |
-
|
7 |
from .Embedding.EmbeddingRoutes import embeddigs_router
|
8 |
from .Chat.PoeChatrouter import chat_router
|
9 |
|
@@ -11,7 +11,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
11 |
|
12 |
from fastapi_cache import FastAPICache
|
13 |
from fastapi_cache.backends.inmemory import InMemoryBackend
|
14 |
-
|
15 |
import logging
|
16 |
|
17 |
|
@@ -39,6 +39,7 @@ app.add_middleware(GZipMiddleware, minimum_size=1000)
|
|
39 |
@app.on_event("startup")
|
40 |
async def startup():
|
41 |
FastAPICache.init(InMemoryBackend())
|
|
|
42 |
|
43 |
|
44 |
@app.get("/")
|
|
|
3 |
from fastapi.middleware.gzip import GZipMiddleware
|
4 |
|
5 |
from .TTS.TTSRoutes import tts_router
|
6 |
+
from .TTS.utils.Descript import DescriptTTS
|
7 |
from .Embedding.EmbeddingRoutes import embeddigs_router
|
8 |
from .Chat.PoeChatrouter import chat_router
|
9 |
|
|
|
11 |
|
12 |
from fastapi_cache import FastAPICache
|
13 |
from fastapi_cache.backends.inmemory import InMemoryBackend
|
14 |
+
tts_object=DescriptTTS()
|
15 |
import logging
|
16 |
|
17 |
|
|
|
39 |
@app.on_event("startup")
|
40 |
async def startup():
|
41 |
FastAPICache.init(InMemoryBackend())
|
42 |
+
await tts_object.start_token_refresh_schedule()
|
43 |
|
44 |
|
45 |
@app.get("/")
|