|
import aiohttp |
|
import asyncio |
|
import os |
|
import uuid |
|
import tempfile |
|
from typing import List, Dict, Any |
|
|
|
from pydantic import BaseModel |
|
|
|
|
|
class AlignmentData(BaseModel): |
|
word: str |
|
start: float |
|
end: float |
|
|
|
def to_dict(self) -> dict: |
|
return { |
|
"word": self.word, |
|
"alignedWord": self.word, |
|
"startTime": self.start, |
|
"endTime": self.end, |
|
"hasFailedAlignment": False, |
|
} |
|
|
|
|
|
class CharacterAITTS: |
|
def __init__(self): |
|
self.api_url = "https://yakova-embedding.hf.space" |
|
self.dir = str(tempfile.mkdtemp()) |
|
self.descript = "https://yakova-embedding.hf.space" |
|
self.headers = {"Connection": "keep-alive", "Content-Type": "application/json"} |
|
|
|
async def _make_transcript(self, links, text): |
|
|
|
data = {"audio_url": links, "text": text, "file_extenstion": ".mp3"} |
|
response_data = await self._make_request( |
|
"post", "descript_transcript", json=data, external=self.descript |
|
) |
|
if not response_data: |
|
data["audio_url"] = data["audio_url"][0] |
|
print(data) |
|
response_data = await self.aligner( |
|
"post", |
|
"align/url", |
|
json=data, |
|
) |
|
print(response_data) |
|
response_data = self.process_alignments( |
|
data=response_data["alignment"], offset=0 |
|
) |
|
return response_data |
|
|
|
def process_alignments( |
|
self, data: List[Dict[str, Any]], offset: float = 0 |
|
) -> List[Dict[str, Any]]: |
|
alignments = [AlignmentData(**item) for item in data] |
|
return [alignment.to_dict() for alignment in alignments] |
|
|
|
async def aligner( |
|
self, |
|
method, |
|
endpoint, |
|
json=None, |
|
external="https://yakova-aligner.hf.space/align/url", |
|
): |
|
async with aiohttp.ClientSession() as session: |
|
if external: |
|
url = f"{external}" |
|
else: |
|
url = f"{self.api_url}/{endpoint}" |
|
async with getattr(session, method)(url=url, json=json) as response: |
|
return await response.json() |
|
|
|
async def _make_request(self, method, endpoint, json=None, external=None): |
|
async with aiohttp.ClientSession() as session: |
|
if external: |
|
url = f"{external}/{endpoint}" |
|
else: |
|
url = f"{self.api_url}/{endpoint}" |
|
async with getattr(session, method)(url=url, json=json) as response: |
|
return await response.json() |
|
|
|
async def say(self, text, speaker=None): |
|
|
|
data = {"text": text, "voice": speaker} |
|
|
|
response_data = await self._make_request("post", "cai_tts", json=data) |
|
|
|
audio_url = response_data["audio"] |
|
temp = await self.download_file(audio_url) |
|
return audio_url, temp |
|
|
|
async def download_file(self, url): |
|
filename = str(uuid.uuid4()) + ".mp3" |
|
os.makedirs(self.dir, exist_ok=True) |
|
save_path = os.path.join(self.dir, filename) |
|
async with aiohttp.ClientSession() as session: |
|
async with session.get(url) as response: |
|
if response.status == 200: |
|
with open(save_path, "wb") as file: |
|
while True: |
|
chunk = await response.content.read(1024) |
|
if not chunk: |
|
break |
|
file.write(chunk) |
|
|
|
return save_path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|