From 4c255ebd59fd976528f9833790a8fa17d11aed41 Mon Sep 17 00:00:00 2001 From: Killua777 <1223086337@qq.com> Date: Sun, 9 Jun 2024 22:54:13 +0800 Subject: [PATCH] init --- app/__init__.py | 1 + app/abstract.py | 41 ++ app/concrete.py | 285 ++++++++++ app/model.py | 39 ++ app/public.py | 79 +++ app/schemas.py | 36 ++ config.py | 20 + main.py | 208 +++++++ takway.db | Bin 0 -> 61440 bytes test/example_recording.wav | Bin 0 -> 159788 bytes test/test.py | 68 +++ utils/__init__.py | 1 + utils/vits/__init__.py | 2 + .../vits/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 197 bytes .../vits/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 194 bytes .../__pycache__/attentions.cpython-38.pyc | Bin 0 -> 9569 bytes .../__pycache__/attentions.cpython-39.pyc | Bin 0 -> 9569 bytes utils/vits/__pycache__/commons.cpython-38.pyc | Bin 0 -> 6092 bytes utils/vits/__pycache__/commons.cpython-39.pyc | Bin 0 -> 6071 bytes utils/vits/__pycache__/models.cpython-38.pyc | Bin 0 -> 15256 bytes utils/vits/__pycache__/models.cpython-39.pyc | Bin 0 -> 15240 bytes utils/vits/__pycache__/modules.cpython-38.pyc | Bin 0 -> 11526 bytes utils/vits/__pycache__/modules.cpython-39.pyc | Bin 0 -> 11485 bytes .../__pycache__/transforms.cpython-38.pyc | Bin 0 -> 3934 bytes .../__pycache__/transforms.cpython-39.pyc | Bin 0 -> 3909 bytes utils/vits/__pycache__/utils.cpython-38.pyc | Bin 0 -> 7113 bytes utils/vits/__pycache__/utils.cpython-39.pyc | Bin 0 -> 7224 bytes utils/vits/attentions.py | 302 ++++++++++ utils/vits/commons.py | 172 ++++++ utils/vits/models.py | 535 ++++++++++++++++++ utils/vits/modules.py | 390 +++++++++++++ utils/vits/monotonic_align/__init__.py | 20 + .../__pycache__/__init__.cpython-38.pyc | Bin 0 -> 837 bytes .../__pycache__/__init__.cpython-39.pyc | Bin 0 -> 834 bytes .../__pycache__/core.cpython-38.pyc | Bin 0 -> 988 bytes .../__pycache__/core.cpython-39.pyc | Bin 0 -> 983 bytes utils/vits/monotonic_align/core.py | 36 ++ utils/vits/text/LICENSE | 19 + utils/vits/text/__init__.py | 57 ++ .../text/__pycache__/__init__.cpython-38.pyc | Bin 0 -> 2308 bytes .../text/__pycache__/__init__.cpython-39.pyc | Bin 0 -> 2281 bytes .../text/__pycache__/cleaners.cpython-38.pyc | Bin 0 -> 12645 bytes .../text/__pycache__/cleaners.cpython-39.pyc | Bin 0 -> 12600 bytes .../text/__pycache__/symbols.cpython-38.pyc | Bin 0 -> 427 bytes .../text/__pycache__/symbols.cpython-39.pyc | Bin 0 -> 424 bytes utils/vits/text/cleaners.py | 475 ++++++++++++++++ utils/vits/text/symbols.py | 39 ++ utils/vits/transforms.py | 193 +++++++ utils/vits/utils.py | 225 ++++++++ utils/vits_utils.py | 114 ++++ utils/xf_asr_utils.py | 67 +++ 51 files changed, 3424 insertions(+) create mode 100644 app/__init__.py create mode 100644 app/abstract.py create mode 100644 app/concrete.py create mode 100644 app/model.py create mode 100644 app/public.py create mode 100644 app/schemas.py create mode 100644 config.py create mode 100644 main.py create mode 100644 takway.db create mode 100644 test/example_recording.wav create mode 100644 test/test.py create mode 100644 utils/__init__.py create mode 100644 utils/vits/__init__.py create mode 100644 utils/vits/__pycache__/__init__.cpython-38.pyc create mode 100644 utils/vits/__pycache__/__init__.cpython-39.pyc create mode 100644 utils/vits/__pycache__/attentions.cpython-38.pyc create mode 100644 utils/vits/__pycache__/attentions.cpython-39.pyc create mode 100644 utils/vits/__pycache__/commons.cpython-38.pyc create mode 100644 utils/vits/__pycache__/commons.cpython-39.pyc create mode 100644 utils/vits/__pycache__/models.cpython-38.pyc create mode 100644 utils/vits/__pycache__/models.cpython-39.pyc create mode 100644 utils/vits/__pycache__/modules.cpython-38.pyc create mode 100644 utils/vits/__pycache__/modules.cpython-39.pyc create mode 100644 utils/vits/__pycache__/transforms.cpython-38.pyc create mode 100644 utils/vits/__pycache__/transforms.cpython-39.pyc create mode 100644 utils/vits/__pycache__/utils.cpython-38.pyc create mode 100644 utils/vits/__pycache__/utils.cpython-39.pyc create mode 100644 utils/vits/attentions.py create mode 100644 utils/vits/commons.py create mode 100644 utils/vits/models.py create mode 100644 utils/vits/modules.py create mode 100644 utils/vits/monotonic_align/__init__.py create mode 100644 utils/vits/monotonic_align/__pycache__/__init__.cpython-38.pyc create mode 100644 utils/vits/monotonic_align/__pycache__/__init__.cpython-39.pyc create mode 100644 utils/vits/monotonic_align/__pycache__/core.cpython-38.pyc create mode 100644 utils/vits/monotonic_align/__pycache__/core.cpython-39.pyc create mode 100644 utils/vits/monotonic_align/core.py create mode 100644 utils/vits/text/LICENSE create mode 100644 utils/vits/text/__init__.py create mode 100644 utils/vits/text/__pycache__/__init__.cpython-38.pyc create mode 100644 utils/vits/text/__pycache__/__init__.cpython-39.pyc create mode 100644 utils/vits/text/__pycache__/cleaners.cpython-38.pyc create mode 100644 utils/vits/text/__pycache__/cleaners.cpython-39.pyc create mode 100644 utils/vits/text/__pycache__/symbols.cpython-38.pyc create mode 100644 utils/vits/text/__pycache__/symbols.cpython-39.pyc create mode 100644 utils/vits/text/cleaners.py create mode 100644 utils/vits/text/symbols.py create mode 100644 utils/vits/transforms.py create mode 100644 utils/vits/utils.py create mode 100644 utils/vits_utils.py create mode 100644 utils/xf_asr_utils.py diff --git a/app/__init__.py b/app/__init__.py new file mode 100644 index 0000000..b974282 --- /dev/null +++ b/app/__init__.py @@ -0,0 +1 @@ +from . import * \ No newline at end of file diff --git a/app/abstract.py b/app/abstract.py new file mode 100644 index 0000000..8f64115 --- /dev/null +++ b/app/abstract.py @@ -0,0 +1,41 @@ +from abc import ABC, abstractmethod + +#------ 抽象 ASR, LLM, TTS 类 ------ # +class ASR(ABC): + @abstractmethod + async def stream_recognize(self, chunk): + pass + +class LLM(ABC): + @abstractmethod + def chat(self, assistant, prompt, db): + pass + +class TTS(ABC): + @abstractmethod + def synthetize(self, assistant, text): + pass +# --------------------------------- # + + +# ----------- 抽象服务类 ----------- # +class UserAudioService(ABC): + @abstractmethod + def user_audio_process(self, audio:str, **kwargs) -> str: + pass + +class PromptService(ABC): + @abstractmethod + def prompt_process(self, prompt:str, **kwargs) -> str: + pass + +class LLMMsgService(ABC): + @abstractmethod + def llm_msg_process(self, llm_chunk:list, **kwargs) -> list: + pass + +class TTSAudioService(ABC): + @abstractmethod + def tts_audio_process(self, audio:bytes, **kwargs) -> bytes: + pass +# --------------------------------- # \ No newline at end of file diff --git a/app/concrete.py b/app/concrete.py new file mode 100644 index 0000000..fb812df --- /dev/null +++ b/app/concrete.py @@ -0,0 +1,285 @@ +from utils.xf_asr_utils import xf_asr_websocket_factory, make_first_frame, make_continue_frame, make_last_frame, parse_xfasr_recv +from .model import Assistant +from .abstract import * +from .public import * +from utils.vits_utils import TextToSpeech +from config import Config +import aiohttp +import asyncio +import struct +import base64 +import json + +# ----------- 初始化vits ----------- # +vits = TextToSpeech() +# ---------------------------------- # + + + +#------ 具体 ASR, LLM, TTS 类 ------ # +FIRST_FRAME = 1 +CONTINUE_FRAME =2 +LAST_FRAME =3 + +class XF_ASR(ASR): + def __init__(self): + self.websocket = None + self.current_message = "" + self.audio = "" + self.status = FIRST_FRAME + self.segment_duration_threshold = 25 #超时时间为25秒 + self.segment_start_time = None + + async def stream_recognize(self, chunk): + if self.websocket is None: #如果websocket未建立,则建立一个新的连接 + self.websocket = await xf_asr_websocket_factory() + if self.segment_start_time is None: #如果是第一段,则记录开始时间 + self.segment_start_time = asyncio.get_event_loop().time() + if chunk['meta_info']['is_end']: + self.status = LAST_FRAME + audio_data = chunk['audio'] + self.audio += audio_data + + if self.status == FIRST_FRAME: #发送第一帧 + await self.websocket.send(make_first_frame(audio_data)) + self.status = CONTINUE_FRAME + elif self.status == CONTINUE_FRAME: #发送中间帧 + await self.websocket.send(make_continue_frame(audio_data)) + elif self.status == LAST_FRAME: #发送最后一帧 + await self.websocket.send(make_last_frame(audio_data)) + self.current_message += parse_xfasr_recv(json.loads(await self.websocket.recv())) + if self.current_message == "": + raise AsrResultNoneError() + await self.websocket.close() + print("语音识别结束,用户消息:", self.current_message) + return [{"text":self.current_message, "audio":self.audio}] + + current_time = asyncio.get_event_loop().time() + if current_time - self.segment_start_time > self.segment_duration_threshold: #超时,发送最后一帧并重置状态 + await self.websocket.send(make_last_frame()) + self.current_message += parse_xfasr_recv(await self.websocket.recv()) + await self.websocket.close() + self.websocket = await xf_asr_websocket_factory() + self.status = FIRST_FRAME + self.segment_start_time = current_time + return [] + +class MINIMAX_LLM(LLM): + def __init__(self): + self.token = 0 + + async def chat(self, assistant, prompt, db): + llm_info = json.loads(assistant.llm_info) + messages = json.loads(assistant.messages) + messages.append({"role":"user","content":prompt}) + assistant.messages = json.dumps(messages) + payload = json.dumps({ + "model": llm_info['model'], + "stream": True, + "messages": messages, + "max_tokens": llm_info['max_tokens'], + "temperature": llm_info['temperature'], + "top_p": llm_info['top_p'], + }) + headers = { + 'Authorization': f"Bearer {Config.MINIMAX_LLM.API_KEY}", + 'Content-Type': 'application/json' + } + async with aiohttp.ClientSession() as client: + async with client.post(Config.MINIMAX_LLM.URL, headers=headers, data=payload) as response: + async for chunk in response.content.iter_any(): + try: + chunk_msg = self.__parseChunk(chunk) + msg_frame = {"is_end":False,"code":200,"msg":chunk_msg} + yield msg_frame + except LLMResponseEnd: + msg_frame = {"is_end":True,"msg":""} + if self.token > llm_info['max_tokens'] * 0.8: + msg_frame['msg'] = 'max_token reached' + as_query = db.query(Assistant).filter(Assistant.id == assistant.id).first() + as_query.messages = json.dumps([{'role':'system','content':assistant.system_prompt},{'role':'user','content':prompt}]) + db.commit() + assistant.messages = as_query.messages + yield msg_frame + + + def __parseChunk(self, llm_chunk): + result = "" + data=json.loads(llm_chunk.decode('utf-8')[6:]) + if data["object"] == "chat.completion": #如果是结束帧 + self.token = data['usage']['total_tokens'] + raise LLMResponseEnd() + elif data['object'] == 'chat.completion.chunk': + for choice in data['choices']: + result += choice['delta']['content'] + else: + raise UnkownLLMFrame() + return result + +class VITS_TTS(TTS): + def __init__(self): + pass + + def synthetize(self, assistant, text): + tts_info = json.loads(assistant.tts_info) + return vits.synthesize(text, tts_info) +# --------------------------------- # + + + +# ------ ASR, LLM, TTS 工厂类 ------ # +class ASRFactory: + def create_asr(self,asr_type:str) -> ASR: + if asr_type == 'XF': + return XF_ASR() + +class LLMFactory: + def create_llm(self,llm_type:str) -> LLM: + if llm_type == 'MINIMAX': + return MINIMAX_LLM() + +class TTSFactory: + def create_tts(self,tts_type:str) -> TTS: + if tts_type == 'VITS': + return VITS_TTS() +# --------------------------------- # + + + +# ----------- 具体服务类 ----------- # +# 从单说话人的asr_results中取出第一个结果作为prompt +class BasicPromptService(PromptService): + def prompt_process(self, prompt:str, **kwargs): + if 'asr_result' in kwargs: + return kwargs['asr_result'][0]['text'], kwargs + else: + raise NoAsrResultsError() + +class UserAudioRecordService(UserAudioService): + def user_audio_process(self, audio:str, **kwargs): + audio_decoded = base64.b64decode(audio) + kwargs['recorder'].user_audio += audio_decoded + return audio,kwargs + +class TTSAudioRecordService(TTSAudioService): + def tts_audio_process(self, audio:bytes, **kwargs): + kwargs['recorder'].tts_audio += audio + return audio,kwargs +# --------------------------------- # + + + +# ------------ 服务链类 ----------- # +class UserAudioServiceChain: + def __init__(self): + self.services = [] + def add_service(self, service:UserAudioService): + self.services.append(service) + def user_audio_process(self, audio, **kwargs): + for service in self.services: + audio, kwargs = service.user_audio_process(audio, **kwargs) + return audio + +class PromptServiceChain: + def __init__(self): + self.services = [] + def add_service(self, service:PromptService): + self.services.append(service) + def prompt_process(self, asr_results): + kwargs = {"asr_result":asr_results} + prompt = "" + for service in self.services: + prompt, kwargs = service.prompt_process(prompt, **kwargs) + return prompt + +class LLMMsgServiceChain: + def __init__(self, ): + self.services = [] + self.spliter = SentenceSegmentation() + def add_service(self, service:LLMMsgService): + self.services.append(service) + def llm_msg_process(self, llm_msg): + kwargs = {} + llm_chunks = self.spliter.split(llm_msg) + for service in self.services: + llm_chunks , kwargs = service.llm_msg_process(llm_chunks, **kwargs) + return llm_chunks + +class TTSAudioServiceChain: + def __init__(self): + self.services = [] + def add_service(self, service:TTSAudioService): + self.services.append(service) + def tts_audio_process(self, audio, **kwargs): + for service in self.services: + audio, kwargs = service.tts_audio_process(audio, **kwargs) + return audio +# --------------------------------- # + +class Agent(): + def __init__(self, asr_type:str, llm_type:str, tts_type:str): + asrFactory = ASRFactory() + llmFactory = LLMFactory() + ttsFactory = TTSFactory() + self.recorder = None + + self.user_audio_service_chain = UserAudioServiceChain() #创建用户音频处理服务链 + self.user_audio_service_chain.add_service(UserAudioRecordService()) #添加用户音频记录服务 + + self.asr = asrFactory.create_asr(asr_type) + + self.prompt_service_chain = PromptServiceChain() + self.prompt_service_chain.add_service(BasicPromptService()) + + self.llm = llmFactory.create_llm(llm_type) + + self.llm_chunk_service_chain = LLMMsgServiceChain() + + self.tts = ttsFactory.create_tts(tts_type) + + self.tts_audio_service_chain = TTSAudioServiceChain() + self.tts_audio_service_chain.add_service(TTSAudioRecordService()) + + def init_recorder(self,user_id): + self.recorder = Recorder(user_id) + + # 对用户输入的音频进行预处理 + def user_audio_process(self, audio, db): + return self.user_audio_service_chain.user_audio_process(audio, recorder=self.recorder) + + # 进行流式语音识别 + async def stream_recognize(self, chunk, db): + return await self.asr.stream_recognize(chunk) + + # 进行Prompt加工 + def prompt_process(self, asr_results, db): + return self.prompt_service_chain.prompt_process(asr_results) + + # 进行大模型调用 + async def chat(self, assistant ,prompt, db): + return self.llm.chat(assistant, prompt, db) + + # 对大模型的返回进行处理 + def llm_msg_process(self, llm_chunk, db): + return self.llm_chunk_service_chain.llm_msg_process(llm_chunk) + + # 进行TTS合成 + def synthetize(self, assistant, text, db): + return self.tts.synthetize(assistant, text) + + # 对合成后的音频进行处理 + def tts_audio_process(self, audio, db): + return self.tts_audio_service_chain.tts_audio_process(audio, recorder=self.recorder) + + # 编码 + def encode(self, text, audio): + text_resp = {"type":"text","code":200,"msg":text} + text_resp_bytes = json.dumps(text_resp,ensure_ascii=False).encode('utf-8') + header = struct.pack('!II',len(text_resp_bytes),len(audio)) + final_resp = header + text_resp_bytes + audio + return final_resp + + # 保存音频 + def save(self): + self.recorder.write() + \ No newline at end of file diff --git a/app/model.py b/app/model.py new file mode 100644 index 0000000..84336d0 --- /dev/null +++ b/app/model.py @@ -0,0 +1,39 @@ +from sqlalchemy import create_engine, Column, Integer, String, CHAR +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker, Session +from config import Config + +engine = create_engine(Config.SQLITE_URL, connect_args={"check_same_thread": False}) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base = declarative_base() + +MESSAGE_LENGTH_LIMIT = 2**31-1 + +class User(Base): + __tablename__ = "user" + id = Column(CHAR(36), primary_key=True) + name = Column(String(32)) + email = Column(String(64)) + password = Column(String(128)) + +class Assistant(Base): + __tablename__ = "assistant" + id = Column(CHAR(36), primary_key=True) + user_id = Column(CHAR(36)) + name = Column(String(32)) + system_prompt = Column(String(512)) + messages = Column(String(MESSAGE_LENGTH_LIMIT)) + user_info = Column(String(256)) + llm_info = Column(String(256)) + tts_info = Column(String(256)) + token = Column(Integer) + +Base.metadata.create_all(bind=engine) + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + \ No newline at end of file diff --git a/app/public.py b/app/public.py new file mode 100644 index 0000000..0a886be --- /dev/null +++ b/app/public.py @@ -0,0 +1,79 @@ +from datetime import datetime +import wave +import json + +# -------------- 公共类 ------------ # +class AsrResultNoneError(Exception): + def __init__(self, message="Asr Result is None!"): + super().__init__(message) + self.message = message + +class NoAsrResultsError(Exception): + def __init__(self, message="No Asr Results!"): + super().__init__(message) + self.message = message + +class LLMResponseEnd(Exception): + def __init__(self, message="LLM Response End!"): + super().__init__(message) + self.message = message + +class UnkownLLMFrame(Exception): + def __init__(self, message="Unkown LLM Frame!"): + super().__init__(message) + self.message = message + +class TokenOutofRangeError(Exception): + def __init__(self, message="Token Out of Range!"): + super().__init__(message) + self.message = message + +class SentenceSegmentation(): + def __init__(self,): + self.is_first_sentence = True + self.cache = "" + + def __sentenceSegmentation(self, llm_frame): + results = [] + if llm_frame['is_end']: + if self.cache: + results.append(self.cache) + self.cache = "" + return results + for char in llm_frame['msg']: + self.cache += char + if self.is_first_sentence and char in ',.?!,。?!': + results.append(self.cache) + self.cache = "" + self.is_first_sentence = False + elif char in '。?!': + results.append(self.cache) + self.cache = "" + return results + + def split(self, llm_chunk): + return self.__sentenceSegmentation(llm_chunk) + +class Recorder: + def __init__(self, user_id): + self.input_wav_path = 'storage/wav/'+ datetime.now().strftime('%Y%m%d%H%M%S') + 'U' + user_id + 'i.wav' + self.output_wav_path = 'storage/wav/'+ datetime.now().strftime('%Y%m%d%H%M%S') + 'U' + user_id + 'o.wav' + self.out_put_text_path = 'storage/record/'+ datetime.now().strftime('%Y%m%d%H%M%S') + 'U' + user_id + 'o.txt' + self.input_sr = 16000 + self.output_sr = 22050 + self.user_audio = b'' + self.tts_audio = b'' + self.input_text = "" + self.output_text = "" + + def write(self): + record = {"input_wav":self.input_wav_path,"input_text":self.input_text,"input_sr":self.input_sr,"output_wav":self.output_wav_path,"output_text":self.output_text,"output_sr":self.output_sr} + with wave.open(self.input_wav_path, 'wb') as wav_file: + wav_file.setparams((1, 2, self.input_sr, 0, 'NONE', 'not compressed')) + wav_file.writeframes(self.user_audio) + with wave.open(self.output_wav_path, 'wb') as wav_file: + wav_file.setparams((1, 2, self.output_sr, 0, 'NONE', 'not compressed')) + wav_file.writeframes(self.tts_audio) + with open(self.out_put_text_path, 'w', encoding='utf-8') as file: + file.write(json.dumps(record, ensure_ascii=False)) +# ---------------------------------- # \ No newline at end of file diff --git a/app/schemas.py b/app/schemas.py new file mode 100644 index 0000000..f8ffe81 --- /dev/null +++ b/app/schemas.py @@ -0,0 +1,36 @@ +from pydantic import BaseModel + +class create_assistant_request(BaseModel): + user_id: str + name: str + system_prompt : str + user_info : str + llm_info : str + tts_info : str + +class update_assistant_request(BaseModel): + name: str + system_prompt : str + messages: str + user_info : str + llm_info : str + tts_info : str + +class create_user_request(BaseModel): + name: str + email: str + password: str + +class update_user_request(BaseModel): + name: str + email: str + password: str + +class update_assistant_system_prompt_request(BaseModel): + system_prompt:str + +class update_assistant_deatil_params_request(BaseModel): + model :str + temperature :float + speaker_id:int + length_scale:float \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..99431d2 --- /dev/null +++ b/config.py @@ -0,0 +1,20 @@ +class Config: + SQLITE_URL = 'sqlite:///takway.db' + ASR = "XF" #在此处选择语音识别引擎 + LLM = "MINIMAX" #在此处选择大模型 + TTS = "VITS" #在此处选择语音合成引擎 + class UVICORN: + HOST = '0.0.0.0' + PORT = 7878 + class XF_ASR: + APP_ID = "f1c121c1" #讯飞语音识别APP_ID + API_SECRET = "NjQwODA5MTA4OTc3YjIyODM2NmVlYWQ0" #讯飞语音识别API_SECRET + API_KEY = "36b316c7977fa534ae1e3bf52157bb92" #讯飞语音识别API_KEY + DOMAIN = "iat" + LANGUAGE = "zh_cn" + ACCENT = "mandarin" + VAD_EOS = 10000 + class MINIMAX_LLM: + API_KEY = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJHcm91cE5hbWUiOiLph5EiLCJVc2VyTmFtZSI6IumHkSIsIkFjY291bnQiOiIiLCJTdWJqZWN0SUQiOiIxNzY4NTM2NDM3MzE1MDgwODg2IiwiUGhvbmUiOiIxMzEzNjE0NzUyNyIsIkdyb3VwSUQiOiIxNzY4NTM2NDM3MzA2NjkyMjc4IiwiUGFnZU5hbWUiOiIiLCJNYWlsIjoiIiwiQ3JlYXRlVGltZSI6IjIwMjQtMDUtMTggMTY6MTQ6MDMiLCJpc3MiOiJtaW5pbWF4In0.LypYOkJXwKV6GzDM1dcNn4L0m19o8Q_Lvmn6SkMMb9WAfDJYxEnTc5odm-L4WAWfbur_gY0cQzgoHnI14t4XSaAvqfmcdCrKYpJbKoBmMse_RogJs7KOBt658je3wES4pBUKQll6NbogQB1f93lnA9IYv4aEVldfqglbCikd54XO8E9Ptn4gX9Mp8fUn3lCpZ6_OSlmgZsQySrmt1sDHHzi3DlkdXlFSI38TQSZIa5RhFpI8WSBLIbaKl84OhaDzo7v99k9DUCzb5JGh0eZOnUT0YswbKCPeV8rZ1XUiOVQrna1uiDLvqv54aIt3vsu-LypYmnHxtZ_z4u2gt87pZg" + URL = "https://api.minimax.chat/v1/text/chatcompletion_v2" + \ No newline at end of file diff --git a/main.py b/main.py new file mode 100644 index 0000000..ba5bea6 --- /dev/null +++ b/main.py @@ -0,0 +1,208 @@ +from fastapi import FastAPI, Depends, WebSocket, HTTPException +from fastapi.middleware.cors import CORSMiddleware +from config import Config +from app.concrete import Agent, AsrResultNoneError +from app.model import Assistant, User, get_db +from app.schemas import * +import uvicorn +import uuid +import json + +# 公共函数 ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +def update_messages(messages, llm_text): + messages = json.loads(messages) + messages.append({"role":"assistant","content":llm_text}) + return json.dumps(messages,ensure_ascii=False) +# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +# 创建FastAPI实例 +app = FastAPI() + +# 增删查改 assiatant---------------------------------------------------------------------------------------------------------------------------------------------------------------- +# 创建一个assistant +@app.post("/api/assistants") +async def create_assistant(request: create_assistant_request,db=Depends(get_db)): + id = str(uuid.uuid4()) + messages = json.dumps([{"role":"system","content":request.system_prompt}],ensure_ascii=False) + assistant = Assistant(id=id,user_id=request.user_id, name=request.name, system_prompt=request.system_prompt, messages=messages, + user_info=request.user_info, llm_info=request.llm_info, tts_info=request.tts_info, token=0) + db.add(assistant) + db.commit() + return {"code":200,"msg":"success","data":{"id":id}} + +# 删除一个assistant +@app.delete("/api/assistants/{id}") +async def delete_assistant(id: str,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + db.delete(assistant) + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + return {"code":404,'msg':"assistant not found","data":{}} + +# 更新一个assistant +@app.put("/api/assistants/{id}") +async def update_assistant(id: str,request: update_assistant_request,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + assistant.name = request.name + assistant.system_prompt = request.system_prompt + assistant.messages = request.messages + assistant.user_info = request.user_info + assistant.llm_info = request.llm_info + assistant.tts_info = request.tts_info + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + return {"code":404,'msg':"assistant not found","data":{}} + +# 获取一个assistant +@app.get("/api/assistants/{id}") +async def get_assistant(id: str,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + return {"code":200,"msg":"success","data":assistant} + else: + return {"code":404,'msg':"assistant not found","data":{}} + +# 获取所有的assistant名称和id +@app.get("/api/assistants") +async def get_all_assistants_name_id(db=Depends(get_db)): + assistants = db.query(Assistant.id, Assistant.name).all() + return {"code":200,"msg":"success","data":[{"id": assistant.id, "name": assistant.name} for assistant in assistants]} + +# 重置一个assistant的消息 +@app.post("/api/assistants/{id}/reset_msg") +async def reset_assistant_msg(id: str,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + assistant.messages = json.dumps([{"role":"system","content":assistant.system_prompt}],ensure_ascii=False) + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + return {"code":404,'msg':"assistant not found","data":{}} + +# 修改一个assistant的system_prompt +@app.put("/api/assistants/{id}/system_prompt") +async def update_assistant_system_prompt(id: str,request: update_assistant_system_prompt_request,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + assistant.system_prompt = request.system_prompt + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + return {"code":404,'msg':"assistant not found","data":{}} + +# 更新具体参数 +@app.put("/api/assistants/{id}/deatil_params") +async def update_assistant_deatil_params(id: str,request: update_assistant_deatil_params_request,db=Depends(get_db)): + assistant = db.query(Assistant).filter(Assistant.id == id).first() + if assistant: + llm_info = json.loads(assistant.llm_info) + tts_info = json.loads(assistant.tts_info) + llm_info['model'] = request.model + llm_info['temperature'] = request.temperature + tts_info['speaker_id'] = request.speaker_id + tts_info['length_scale'] = request.length_scale + assistant.llm_info = json.dumps(llm_info, ensure_ascii=False) + assistant.tts_info = json.dumps(tts_info, ensure_ascii=False) + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + return {"code":404,'msg':"assistant not found","data":{}} +# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + + + +# 用户增删改查接口 ---------------------------------------------------------------------------------------------------------------------------------------------------------------- +# 添加用户 +@app.post("/api/users") +async def create_user(request: create_user_request,db=Depends(get_db)): + id = str(uuid.uuid4()) + user = User(id=id, name=request.name, email=request.email, password=request.password) + db.add(user) + db.commit() + return {"code":200,"msg":"success","data":{"id":id}} + +# 删除用户 +@app.delete("/api/users/{id}") +async def delete_user(id: str,db=Depends(get_db)): + user = db.query(User).filter(User.id == id).first() + if user: + db.delete(user) + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + raise HTTPException(status_code=404, detail="user not found") + +# 获取用户 +@app.get("/api/users/{id}") +async def get_user(id: str,db=Depends(get_db)): + user = db.query(User).filter(User.id == id).first() + if user: + return {"code":200,"msg":"success","data":user} + else: + raise HTTPException(status_code=404, detail="user not found") + +# 更新用户 +@app.put("/api/users/{id}") +async def update_user(id: str,request: update_user_request,db=Depends(get_db)): + user = db.query(User).filter(User.id == id).first() + if user: + user.name = request.name + user.email = request.email + user.password = request.password + db.commit() + return {"code":200,"msg":"success","data":{}} + else: + raise HTTPException(status_code=404, detail="user not found") +# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +# 流式聊天websokct接口 ------------------------------------------------------------------------------------------------------------------------------------------------------------ +@app.websocket("/api/chat/streaming/temporary") +async def streaming_chat(ws: WebSocket,db=Depends(get_db)): + await ws.accept() + agent = Agent(asr_type=Config.ASR, llm_type=Config.LLM, tts_type=Config.TTS) + assistant = None + asr_results = [] + llm_text = "" + try: + while len(asr_results)==0: + chunk = json.loads(await ws.receive_text()) + if assistant is None: + assistant = db.query(Assistant).filter(Assistant.id == chunk['meta_info']['session_id']).first() + agent.init_recorder(assistant.user_id) + chunk["audio"] = agent.user_audio_process(chunk["audio"], db) + asr_results = await agent.stream_recognize(chunk, db) + except AsrResultNoneError: + await ws.send_text(json.dumps({"type":"close","code":201,"msg":""}, ensure_ascii=False)) + return + prompt = agent.prompt_process(asr_results, db) + agent.recorder.input_text = prompt + llm_frames = await agent.chat(assistant, prompt, db) + async for llm_frame in llm_frames: + resp_msgs = agent.llm_msg_process(llm_frame, db) + for resp_msg in resp_msgs: + llm_text += resp_msg + tts_audio = agent.synthetize(assistant, resp_msg, db) + agent.tts_audio_process(tts_audio, db) + await ws.send_bytes(agent.encode(resp_msg, tts_audio)) + await ws.send_text(json.dumps({"type": "close", "code": 200, "msg": ""}, ensure_ascii=False)) + assistant.messages = update_messages(assistant.messages, llm_text) + db.commit() + agent.recorder.output_text = llm_text + agent.save() + await ws.close() +# -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], # 允许所有源,也可以指定特定源 + allow_credentials=True, + allow_methods=["*"], # 允许所有方法 + allow_headers=["*"], # 允许所有头 +) + +# 启动服务 +uvicorn.run(app, host=Config.UVICORN.HOST, port=Config.UVICORN.PORT) \ No newline at end of file diff --git a/takway.db b/takway.db new file mode 100644 index 0000000000000000000000000000000000000000..05c34d860a5539e726c493de0804b77e0820e03e GIT binary patch literal 61440 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�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 hx0z`%G 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 SyXjp_D%*lTERe49?*9QRi=WK^ literal 0 HcmV?d00001 diff --git a/test/test.py b/test/test.py new file mode 100644 index 0000000..b9b17aa --- /dev/null +++ b/test/test.py @@ -0,0 +1,68 @@ +import json +import base64 +from datetime import datetime +import io +from websocket import create_connection + +data = { + "text": "", + "audio": "", + "meta_info": { + "session_id":"a36c9bb4-e813-4f0e-9c75-18e049c60f48", + "stream": True, + "voice_synthesize": True, + "is_end": False, + "encoding": "raw" + } +} + +def read_pcm_file_in_chunks(chunk_size): + with open('example_recording.wav', 'rb') as pcm_file: + while True: + data = pcm_file.read(chunk_size) + if not data: + break + yield data + +def send_audio_chunk(websocket, chunk): + # 将PCM数据进行Base64编码 + encoded_data = base64.b64encode(chunk).decode('utf-8') + # 更新data字典中的"audio"键的值为Base64编码后的音频数据 + data["audio"] = encoded_data + # 将JSON数据对象转换为JSON字符串 + message = json.dumps(data) + # 发送JSON字符串到WebSocket接口 + websocket.send(message) + + +def send_json(): + websocket = create_connection('ws://114.214.236.207:7878/api/chat/streaming/temporary') + chunks = read_pcm_file_in_chunks(1024) # 读取PCM文件并生成数据块 + for chunk in chunks: + send_audio_chunk(websocket, chunk) + # print("发送数据块:", len(chunk)) + import time; time.sleep(0.01) + # threading.Event().wait(0.01) # 等待0.01秒 + # 设置data字典中的"is_end"键为True,表示音频流结束 + data["meta_info"]["is_end"] = True + # 发送最后一个数据块和流结束信号 + send_audio_chunk(websocket, b'') # 发送空数据块表示结束 + # 等待并打印接收到的数据 + print("等待接收:", datetime.now()) + audio_bytes = b'' + while True: + data_ws = websocket.recv() + try: + message_json = json.loads(data_ws) + print(message_json) # 打印接收到的消息 + if message_json["type"] == "close": + break # 如果没有接收到消息,则退出循环 + except Exception as e: + audio_bytes += data_ws + + print(e) + print("接收完毕:", datetime.now()) + websocket.close() + +# 启动事件循环 +send_json() \ No newline at end of file diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..b6e690f --- /dev/null +++ b/utils/__init__.py @@ -0,0 +1 @@ +from . import * diff --git a/utils/vits/__init__.py b/utils/vits/__init__.py new file mode 100644 index 0000000..c96b491 --- /dev/null +++ b/utils/vits/__init__.py @@ -0,0 +1,2 @@ +from .text import * +from .monotonic_align import * \ No newline at end of file diff --git a/utils/vits/__pycache__/__init__.cpython-38.pyc b/utils/vits/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..82a34757cd03495637b4218ab8cae3ab2ee95e26 GIT binary patch literal 197 zcmWIL<>g`kf;>*6G$SDW7{oyaOhAqU5EqL8i4=wu#vFza2+atjnSvQKnO`yjr8F6D zF>3i~GTmY+Nv$Y};?K>`%P+~#%S?_>%*jm8Tggzw0#pSiep%^f2KczG$)edB7 JG01fsi~u?aFs}dr literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/__init__.cpython-39.pyc b/utils/vits/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af9d24ec3d0c1ed845c671709e1d5e0965902300 GIT binary patch literal 194 zcmYe~<>g`kf>|X=X+}W$F^GcmtT^fmzf-&n3I{Fx00cV1*i&4{4&?i$j?pH&#Fq+FGs@4C29FZx%y?9CB^#j@tJvo$B44+1{RI zb zJzLdP)z#JY`0M+>|F8Y^N~Ngb3JW)Pu5M`Be^F-ovXJ>Dgy>U5Ok;YWwbfm3>&P2{ zeqgi>oyyF>Jh0lfOk06-kZb2;+79vug?2&LzNs;Xz@B zQBq_jl$6qv3QEeXf|5#FQf2zLv{v;gdZcZ&bYX-c;^NLA?8M!E=mp5-I{kx#ei$KH zc;7qr`BtAFbm)!gi$+IR^a>(hqYT%opzGi7{8{aL6+?}w~ zXFh+bvqF#?7E`1*JaEP-OipDhJFx<+D#ciWVuNiICkD&i+G>??yuJK7nMqZYS`f$aSA+KYsK2UjM+q-WztV#~x}O zU%xMJcLOipLAS3D;%*RKkK^e2Q5O-$r8*LA93Jy3zEDAkt{~F%qV7!pj512pud1)> zb%bF(mEw)@vUE&(HN70%X@Kt_L_b877$fX{$RXX0Q+-K0F(D@g?s^RA>={zte)9x! z+%psF0?9b!?Xh_RnI2gQB#u%&JAG!aYLE33deccujK{`Y-P~;52d|93m=FS(TTf~A zpZ*`NR$deaVf0|&`$L~!M6sIwRZ1;Wv_{bdiq;Xe9R4D1LVqNjNA7_a?Tdnx6iV`! z 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 TO*csXG^iK88&Tdc7 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 E|Kv@@;Q#;t literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/commons.cpython-38.pyc b/utils/vits/__pycache__/commons.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..92e45d054892f423f0cce0cdf083f04fa66e6339 GIT binary patch literal 6092 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 xccWl~!iXdXOtNXgjP}(EWLL@!vx|BGUi> literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/commons.cpython-39.pyc b/utils/vits/__pycache__/commons.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4f8e875783376469ee4927e2dca8577bacda6d4c GIT binary patch literal 6071 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 literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/models.cpython-38.pyc b/utils/vits/__pycache__/models.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21145da3d8cc0fdf3072ab3154ce03dcadeec28d GIT binary patch literal 15256 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

8kY~&{9350 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 Pix1Vy^-{fFfBJs_EkHt` literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/transforms.cpython-38.pyc b/utils/vits/__pycache__/transforms.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c8e6ed2fec4a04247ed29b050dbbb424f739449d GIT binary patch literal 3934 zcmai1&2JmW6`z^?;BvX7NQts2Tej%$GC-sv1sb3*k~p9$om>OAZpyi*LR3U+5pu(n>RDR zdHdeHr;p2Jm*5u_-|D?_o{)bjX8PxVc@Hg-Ae?a8CvDZUJ{_>OL35eewz$!@(F$k| zH#y~2UDk=og+J1Ek=J;UyBN8cFHOyRybNgx(h9d!o2+#B9Is-=mqlkpI5h)fdV+QbAur`z2cP0f@9X*>%Kx zO2%$T#-*r|(y=QoX>IJNu5b4(R9fGny8mx z6YDA4vKh{p;Y@{J+7p_GbMcAy3ByS)PAzMC7|`yfXyVo_CeEPK1n-S8MC>R5K9x{k zN1RebjrPv|Zrs!lK+_jNGm6t@I2iVWK@h?IYc21@;K|H>&`UE*sOZn^tvF5NL1v`! z@ReX{xncz;W$s=e;-u3LcY}=H5_qgh#-d?nAduh+kA|7|(I`s8L2y%uSY);e4L=p? zd$#6I#Bp*E*TX0YdC&=Q74ZOX$iPo_+lvU`*TtfWQ$$T+a`dy}N9ilBDU@@)jh6fz zgt+qvK9{=8p%vPo4t1CZu7Ys1AyI#fnuH<3CSmzv-qU+bUV1{hDwq#{S20izm3G}P z4T9jyT~u1TBv}E+l*7V}O>rqTxOON>cT5$YV^0>PS0~)S?E9ECmAgszNOli0OS_=8 zW2=znHk`YR+)&6@HsDHivP8yZ1U=k$qESh$9Yd*DvI#aY9w&scJmc ziAGK1sZHUjA;T4*T?3v1cB~=i)ifRly~0zQ!K1ioJXL8vrQ-LgD{GQ`&iEXxIgh|~ z5!gq(tn8OKlk*3RdzfF4iS*eF*ZnOZ))Pd=;yo^0APjD#PTt3_lm^2RTdF4cei}H%Ra7Nj(IfeFUkJr%R zq{IDx9Ie92RSI3$+Xs z(XJogy94_KD8yrtXHqLyFCL3koqSyE>D2yPh?2j8km3q*sEaJ>P&8Jdb>z@_RDQ^< zw2936s>G&MNUNYqN6{5lWj4m_C1W;fMfW??oZ?@aW`&)i^Q=KVoKuCK&Fa*JcJ+JP zXz0^DoMS_t&w4ZSc`-u8BH*^lxgR^YZ+CkwiiGm>+;c5ldH7hgAZRb%xOwaP#~M~w?ysjZMkf{Pi8&((4 u&NYPMs2{weVlDXv2+YYG!$bjX7N-6~c;Q}jy&3*Za41;tm;WE}&Hn*YTfzVU literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/transforms.cpython-39.pyc b/utils/vits/__pycache__/transforms.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e60b242e801f2e13ab8b2b98d374b2ef1c58d552 GIT binary patch literal 3909 zcmai1&2JmW6`z^?Ah}#pq(oViEnD<=86Z;77Rbejlhk&jA{K(wbpav(yW*^@mB?LY zcIgjwSQJTnbm4Q6g9PN_TQB_=`Umv5rvN>tET|B7JVMT<3vWRmw;hkDWH1JN;fE;BopG&(j~0j(%a z$))Ane!(wp+tQYWKk!aT)@4aL7&(|PPtCis0%;l2s}X5dl7At_W$kP;%{13S8`{(bUDPEhz9{PQm;6us6ESwj747QEwg4n! zvn^69@q&JwI@EQyqERT@#ncYM;V6mIg;5wrYT)&QeP4DT1Txu))5eT&#}Dr9K(#p| zmA(q@dr5HLkJCaB-uG4Pr0LP z`sr2JFbd;DdEjLCM8$Sh*|3``5Fu|+B_d>GWfHN7kd2i~qyo|@<%e{)!%k%~+z9N;1oo`q4daE0%up6rTf&{(F6WCmQ(cyZgQM#Dn^y^*dR2Bfu8kqmTMtvJG3V zj}q8>{eFp&mIB#hUFkJ2l{!0-7Fg4qAQ>m2J6%=kwjtX$+Kw}mML7vI^I$)$fbkkG>)@iMA-+|sq-m2UKzBM~<}g9} z*^T~%0iwY!13UG5{9VM2cIFT{2|M7L9rCezJgOkN_?}R|PsFaF4JoAYSd5LtJh0Gg zY3foFE2K$uT-8aqZw4 zVt*9dWLq)A88e(o__aNuc|?~UyPpW0^k)w1UB~?+^SC_FrqeC&o`|_WkW7wG=%7sl62?Ni;}} zBpSXFPi;r7;H1>q_f-^k`@x={@>>e;HA_V}Obx^mT;bs`bw3`3NigtlDix{JrqJ*b zMc=bMcOs6Hut37 zEfD6+BlsNdh$64@CNJ`$aKTj(jy5FpC%BsjMYU*XuTi9@cN&SUrdRZ7n9J)!_7n95qg;Wq4{Cp4vpC zp5dua;i)6N6`)-Qo&t8PBjMFEJVo?`r#^#+xM@5!Z9d`ZcZs9xntd+h9IQEykaZB! z$Gol{l%>$~heEoTU(l5qzM<19o1fN8x=ABg;0(AXWZ$caFR-GQ@R($?4K_ZjR}NfR!;@Cm zXRzul?KnQC&&l~c>!5PTo{0F#FW6@sr(sU7l*u!z`rILJGTd=huj&Tm3plx@SMmK; z3CH+6A(}?1&u8c^=%xHTy{uRB5&Sm0Nv@%r`5s4eOSIcXoH?g20ww$bqYH;T!+A-! z^rbSRQU*6#fMpuMbXi}<9+xLL$TpXcb_1pi2ll*jBEm&|MPE2WwrowIJ>KIrv^eQ# z{~tz6SS2OTh0XmpH>k#HB~i<39Vhoz5NA*DgCN-n!WN2zmW&3dakBiX@HDXfAKwnb z05w?)3AL4#QrIMF^--YsEj*d6WC!o~Xt3q0R8BRn*O9L-&@3gFHPr-tCWvH(7A4wND*4;zmVILn=cck*1 zY31srmtrc4UzT-Q68{ZE@s}X1w1RBuAYT@dA&a8Q8_1UPsPT|Rc?&u8Rf)}Okk&v+ zhvtz7%KAX+*2)FdH6`RA?PgLxOwZnUwwF|dwXNE`###QH*Vbd zpmXX~@dr0Ie*VFoS^15dA8*`!@6N{En_0o0d3aVcWI(1$k<74Jsa(8<&>QvrcPO^v gpMt=gqG*^XmCeG`{{qjQi;g?PzbVLc^!LsG0qR7(yZ`_I literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/utils.cpython-38.pyc b/utils/vits/__pycache__/utils.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47215e880afb8b2eaeb7124d39a715b605a22a0e GIT binary patch literal 7113 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 literal 0 HcmV?d00001 diff --git a/utils/vits/__pycache__/utils.cpython-39.pyc b/utils/vits/__pycache__/utils.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9516664c5e5a6df45ea30e78f3ab10aa51468117 GIT binary patch literal 7224 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 [b, n_h, t, d_k] + b, d, t_s, t_t = (*key.size(), query.size(2)) + query = query.view(b, self.n_heads, self.k_channels, t_t).transpose(2, 3) + key = key.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3) + value = value.view(b, self.n_heads, self.k_channels, t_s).transpose(2, 3) + + scores = torch.matmul(query / math.sqrt(self.k_channels), key.transpose(-2, -1)) + if self.window_size is not None: + assert t_s == t_t, "Relative attention is only available for self-attention." + key_relative_embeddings = self._get_relative_embeddings(self.emb_rel_k, t_s) + rel_logits = self._matmul_with_relative_keys(query /math.sqrt(self.k_channels), key_relative_embeddings) + scores_local = self._relative_position_to_absolute_position(rel_logits) + scores = scores + scores_local + if self.proximal_bias: + assert t_s == t_t, "Proximal bias is only available for self-attention." + scores = scores + self._attention_bias_proximal(t_s).to(device=scores.device, dtype=scores.dtype) + if mask is not None: + scores = scores.masked_fill(mask == 0, -1e4) + if self.block_length is not None: + assert t_s == t_t, "Local attention is only available for self-attention." + block_mask = torch.ones_like(scores).triu(-self.block_length).tril(self.block_length) + scores = scores.masked_fill(block_mask == 0, -1e4) + p_attn = F.softmax(scores, dim=-1) # [b, n_h, t_t, t_s] + p_attn = self.drop(p_attn) + output = torch.matmul(p_attn, value) + if self.window_size is not None: + relative_weights = self._absolute_position_to_relative_position(p_attn) + value_relative_embeddings = self._get_relative_embeddings(self.emb_rel_v, t_s) + output = output + self._matmul_with_relative_values(relative_weights, value_relative_embeddings) + output = output.transpose(2, 3).contiguous().view(b, d, t_t) # [b, n_h, t_t, d_k] -> [b, d, t_t] + return output, p_attn + + def _matmul_with_relative_values(self, x, y): + """ + x: [b, h, l, m] + y: [h or 1, m, d] + ret: [b, h, l, d] + """ + ret = torch.matmul(x, y.unsqueeze(0)) + return ret + + def _matmul_with_relative_keys(self, x, y): + """ + x: [b, h, l, d] + y: [h or 1, m, d] + ret: [b, h, l, m] + """ + ret = torch.matmul(x, y.unsqueeze(0).transpose(-2, -1)) + return ret + + def _get_relative_embeddings(self, relative_embeddings, length): + max_relative_position = 2 * self.window_size + 1 + # Pad first before slice to avoid using cond ops. + pad_length = max(length - (self.window_size + 1), 0) + slice_start_position = max((self.window_size + 1) - length, 0) + slice_end_position = slice_start_position + 2 * length - 1 + if pad_length > 0: + padded_relative_embeddings = F.pad( + relative_embeddings, + commons.convert_pad_shape([[0, 0], [pad_length, pad_length], [0, 0]])) + else: + padded_relative_embeddings = relative_embeddings + used_relative_embeddings = padded_relative_embeddings[:,slice_start_position:slice_end_position] + return used_relative_embeddings + + def _relative_position_to_absolute_position(self, x): + """ + x: [b, h, l, 2*l-1] + ret: [b, h, l, l] + """ + batch, heads, length, _ = x.size() + # Concat columns of pad to shift from relative to absolute indexing. + x = F.pad(x, commons.convert_pad_shape([[0,0],[0,0],[0,0],[0,1]])) + + # Concat extra elements so to add up to shape (len+1, 2*len-1). + x_flat = x.view([batch, heads, length * 2 * length]) + x_flat = F.pad(x_flat, commons.convert_pad_shape([[0,0],[0,0],[0,length-1]])) + + # Reshape and slice out the padded elements. + x_final = x_flat.view([batch, heads, length+1, 2*length-1])[:, :, :length, length-1:] + return x_final + + def _absolute_position_to_relative_position(self, x): + """ + x: [b, h, l, l] + ret: [b, h, l, 2*l-1] + """ + batch, heads, length, _ = x.size() + # padd along column + x = F.pad(x, commons.convert_pad_shape([[0, 0], [0, 0], [0, 0], [0, length-1]])) + x_flat = x.view([batch, heads, length**2 + length*(length -1)]) + # add 0's in the beginning that will skew the elements after reshape + x_flat = F.pad(x_flat, commons.convert_pad_shape([[0, 0], [0, 0], [length, 0]])) + x_final = x_flat.view([batch, heads, length, 2*length])[:,:,:,1:] + return x_final + + def _attention_bias_proximal(self, length): + """Bias for self-attention to encourage attention to close positions. + Args: + length: an integer scalar. + Returns: + a Tensor with shape [1, 1, length, length] + """ + r = torch.arange(length, dtype=torch.float32) + diff = torch.unsqueeze(r, 0) - torch.unsqueeze(r, 1) + return torch.unsqueeze(torch.unsqueeze(-torch.log1p(torch.abs(diff)), 0), 0) + + +class FFN(nn.Module): + def __init__(self, in_channels, out_channels, filter_channels, kernel_size, p_dropout=0., activation=None, causal=False): + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.filter_channels = filter_channels + self.kernel_size = kernel_size + self.p_dropout = p_dropout + self.activation = activation + self.causal = causal + + if causal: + self.padding = self._causal_padding + else: + self.padding = self._same_padding + + self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size) + self.conv_2 = nn.Conv1d(filter_channels, out_channels, kernel_size) + self.drop = nn.Dropout(p_dropout) + + def forward(self, x, x_mask): + x = self.conv_1(self.padding(x * x_mask)) + if self.activation == "gelu": + x = x * torch.sigmoid(1.702 * x) + else: + x = torch.relu(x) + x = self.drop(x) + x = self.conv_2(self.padding(x * x_mask)) + return x * x_mask + + def _causal_padding(self, x): + if self.kernel_size == 1: + return x + pad_l = self.kernel_size - 1 + pad_r = 0 + padding = [[0, 0], [0, 0], [pad_l, pad_r]] + x = F.pad(x, commons.convert_pad_shape(padding)) + return x + + def _same_padding(self, x): + if self.kernel_size == 1: + return x + pad_l = (self.kernel_size - 1) // 2 + pad_r = self.kernel_size // 2 + padding = [[0, 0], [0, 0], [pad_l, pad_r]] + x = F.pad(x, commons.convert_pad_shape(padding)) + return x diff --git a/utils/vits/commons.py b/utils/vits/commons.py new file mode 100644 index 0000000..40fcc05 --- /dev/null +++ b/utils/vits/commons.py @@ -0,0 +1,172 @@ +import math +import torch +from torch.nn import functional as F +import torch.jit + + +def script_method(fn, _rcb=None): + return fn + + +def script(obj, optimize=True, _frames_up=0, _rcb=None): + return obj + + +torch.jit.script_method = script_method +torch.jit.script = script + + +def init_weights(m, mean=0.0, std=0.01): + classname = m.__class__.__name__ + if classname.find("Conv") != -1: + m.weight.data.normal_(mean, std) + + +def get_padding(kernel_size, dilation=1): + return int((kernel_size*dilation - dilation)/2) + + +def convert_pad_shape(pad_shape): + l = pad_shape[::-1] + pad_shape = [item for sublist in l for item in sublist] + return pad_shape + + +def intersperse(lst, item): + result = [item] * (len(lst) * 2 + 1) + result[1::2] = lst + return result + + +def kl_divergence(m_p, logs_p, m_q, logs_q): + """KL(P||Q)""" + kl = (logs_q - logs_p) - 0.5 + kl += 0.5 * (torch.exp(2. * logs_p) + ((m_p - m_q)**2)) * torch.exp(-2. * logs_q) + return kl + + +def rand_gumbel(shape): + """Sample from the Gumbel distribution, protect from overflows.""" + uniform_samples = torch.rand(shape) * 0.99998 + 0.00001 + return -torch.log(-torch.log(uniform_samples)) + + +def rand_gumbel_like(x): + g = rand_gumbel(x.size()).to(dtype=x.dtype, device=x.device) + return g + + +def slice_segments(x, ids_str, segment_size=4): + ret = torch.zeros_like(x[:, :, :segment_size]) + for i in range(x.size(0)): + idx_str = ids_str[i] + idx_end = idx_str + segment_size + ret[i] = x[i, :, idx_str:idx_end] + return ret + + +def rand_slice_segments(x, x_lengths=None, segment_size=4): + b, d, t = x.size() + if x_lengths is None: + x_lengths = t + ids_str_max = x_lengths - segment_size + 1 + ids_str = (torch.rand([b]).to(device=x.device) * ids_str_max).to(dtype=torch.long) + ret = slice_segments(x, ids_str, segment_size) + return ret, ids_str + + +def get_timing_signal_1d( + length, channels, min_timescale=1.0, max_timescale=1.0e4): + position = torch.arange(length, dtype=torch.float) + num_timescales = channels // 2 + log_timescale_increment = ( + math.log(float(max_timescale) / float(min_timescale)) / + (num_timescales - 1)) + inv_timescales = min_timescale * torch.exp( + torch.arange(num_timescales, dtype=torch.float) * -log_timescale_increment) + scaled_time = position.unsqueeze(0) * inv_timescales.unsqueeze(1) + signal = torch.cat([torch.sin(scaled_time), torch.cos(scaled_time)], 0) + signal = F.pad(signal, [0, 0, 0, channels % 2]) + signal = signal.view(1, channels, length) + return signal + + +def add_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4): + b, channels, length = x.size() + signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale) + return x + signal.to(dtype=x.dtype, device=x.device) + + +def cat_timing_signal_1d(x, min_timescale=1.0, max_timescale=1.0e4, axis=1): + b, channels, length = x.size() + signal = get_timing_signal_1d(length, channels, min_timescale, max_timescale) + return torch.cat([x, signal.to(dtype=x.dtype, device=x.device)], axis) + + +def subsequent_mask(length): + mask = torch.tril(torch.ones(length, length)).unsqueeze(0).unsqueeze(0) + return mask + + +@torch.jit.script +def fused_add_tanh_sigmoid_multiply(input_a, input_b, n_channels): + n_channels_int = n_channels[0] + in_act = input_a + input_b + t_act = torch.tanh(in_act[:, :n_channels_int, :]) + s_act = torch.sigmoid(in_act[:, n_channels_int:, :]) + acts = t_act * s_act + return acts + + +def convert_pad_shape(pad_shape): + l = pad_shape[::-1] + pad_shape = [item for sublist in l for item in sublist] + return pad_shape + + +def shift_1d(x): + x = F.pad(x, convert_pad_shape([[0, 0], [0, 0], [1, 0]]))[:, :, :-1] + return x + + +def sequence_mask(length, max_length=None): + if max_length is None: + max_length = length.max() + x = torch.arange(max_length, dtype=length.dtype, device=length.device) + return x.unsqueeze(0) < length.unsqueeze(1) + + +def generate_path(duration, mask): + """ + duration: [b, 1, t_x] + mask: [b, 1, t_y, t_x] + """ + device = duration.device + + b, _, t_y, t_x = mask.shape + cum_duration = torch.cumsum(duration, -1) + + cum_duration_flat = cum_duration.view(b * t_x) + path = sequence_mask(cum_duration_flat, t_y).to(mask.dtype) + path = path.view(b, t_x, t_y) + path = path - F.pad(path, convert_pad_shape([[0, 0], [1, 0], [0, 0]]))[:, :-1] + path = path.unsqueeze(1).transpose(2,3) * mask + return path + + +def clip_grad_value_(parameters, clip_value, norm_type=2): + if isinstance(parameters, torch.Tensor): + parameters = [parameters] + parameters = list(filter(lambda p: p.grad is not None, parameters)) + norm_type = float(norm_type) + if clip_value is not None: + clip_value = float(clip_value) + + total_norm = 0 + for p in parameters: + param_norm = p.grad.data.norm(norm_type) + total_norm += param_norm.item() ** norm_type + if clip_value is not None: + p.grad.data.clamp_(min=-clip_value, max=clip_value) + total_norm = total_norm ** (1. / norm_type) + return total_norm diff --git a/utils/vits/models.py b/utils/vits/models.py new file mode 100644 index 0000000..e885675 --- /dev/null +++ b/utils/vits/models.py @@ -0,0 +1,535 @@ +import math +import torch +from torch import nn +from torch.nn import functional as F + +# import commons +# import modules +# import attentions +# import monotonic_align +from utils.vits import commons, modules, attentions, monotonic_align +from utils.vits.commons import init_weights, get_padding + +from torch.nn import Conv1d, ConvTranspose1d, Conv2d +from torch.nn.utils import weight_norm, remove_weight_norm, spectral_norm +# from commons import init_weights, get_padding + + +class StochasticDurationPredictor(nn.Module): + def __init__(self, in_channels, filter_channels, kernel_size, p_dropout, n_flows=4, gin_channels=0): + super().__init__() + filter_channels = in_channels # it needs to be removed from future version. + self.in_channels = in_channels + self.filter_channels = filter_channels + self.kernel_size = kernel_size + self.p_dropout = p_dropout + self.n_flows = n_flows + self.gin_channels = gin_channels + + self.log_flow = modules.Log() + self.flows = nn.ModuleList() + self.flows.append(modules.ElementwiseAffine(2)) + for i in range(n_flows): + self.flows.append(modules.ConvFlow(2, filter_channels, kernel_size, n_layers=3)) + self.flows.append(modules.Flip()) + + self.post_pre = nn.Conv1d(1, filter_channels, 1) + self.post_proj = nn.Conv1d(filter_channels, filter_channels, 1) + self.post_convs = modules.DDSConv(filter_channels, kernel_size, n_layers=3, p_dropout=p_dropout) + self.post_flows = nn.ModuleList() + self.post_flows.append(modules.ElementwiseAffine(2)) + for i in range(4): + self.post_flows.append(modules.ConvFlow(2, filter_channels, kernel_size, n_layers=3)) + self.post_flows.append(modules.Flip()) + + self.pre = nn.Conv1d(in_channels, filter_channels, 1) + self.proj = nn.Conv1d(filter_channels, filter_channels, 1) + self.convs = modules.DDSConv(filter_channels, kernel_size, n_layers=3, p_dropout=p_dropout) + if gin_channels != 0: + self.cond = nn.Conv1d(gin_channels, filter_channels, 1) + + def forward(self, x, x_mask, w=None, g=None, reverse=False, noise_scale=1.0): + x = torch.detach(x) + x = self.pre(x) + if g is not None: + g = torch.detach(g) + x = x + self.cond(g) + x = self.convs(x, x_mask) + x = self.proj(x) * x_mask + + if not reverse: + flows = self.flows + assert w is not None + + logdet_tot_q = 0 + h_w = self.post_pre(w) + h_w = self.post_convs(h_w, x_mask) + h_w = self.post_proj(h_w) * x_mask + e_q = torch.randn(w.size(0), 2, w.size(2)).to(device=x.device, dtype=x.dtype) * x_mask + z_q = e_q + for flow in self.post_flows: + z_q, logdet_q = flow(z_q, x_mask, g=(x + h_w)) + logdet_tot_q += logdet_q + z_u, z1 = torch.split(z_q, [1, 1], 1) + u = torch.sigmoid(z_u) * x_mask + z0 = (w - u) * x_mask + logdet_tot_q += torch.sum((F.logsigmoid(z_u) + F.logsigmoid(-z_u)) * x_mask, [1,2]) + logq = torch.sum(-0.5 * (math.log(2*math.pi) + (e_q**2)) * x_mask, [1,2]) - logdet_tot_q + + logdet_tot = 0 + z0, logdet = self.log_flow(z0, x_mask) + logdet_tot += logdet + z = torch.cat([z0, z1], 1) + for flow in flows: + z, logdet = flow(z, x_mask, g=x, reverse=reverse) + logdet_tot = logdet_tot + logdet + nll = torch.sum(0.5 * (math.log(2*math.pi) + (z**2)) * x_mask, [1,2]) - logdet_tot + return nll + logq # [b] + else: + flows = list(reversed(self.flows)) + flows = flows[:-2] + [flows[-1]] # remove a useless vflow + z = torch.randn(x.size(0), 2, x.size(2)).to(device=x.device, dtype=x.dtype) * noise_scale + for flow in flows: + z = flow(z, x_mask, g=x, reverse=reverse) + z0, z1 = torch.split(z, [1, 1], 1) + logw = z0 + return logw + + +class DurationPredictor(nn.Module): + def __init__(self, in_channels, filter_channels, kernel_size, p_dropout, gin_channels=0): + super().__init__() + + self.in_channels = in_channels + self.filter_channels = filter_channels + self.kernel_size = kernel_size + self.p_dropout = p_dropout + self.gin_channels = gin_channels + + self.drop = nn.Dropout(p_dropout) + self.conv_1 = nn.Conv1d(in_channels, filter_channels, kernel_size, padding=kernel_size//2) + self.norm_1 = modules.LayerNorm(filter_channels) + self.conv_2 = nn.Conv1d(filter_channels, filter_channels, kernel_size, padding=kernel_size//2) + self.norm_2 = modules.LayerNorm(filter_channels) + self.proj = nn.Conv1d(filter_channels, 1, 1) + + if gin_channels != 0: + self.cond = nn.Conv1d(gin_channels, in_channels, 1) + + def forward(self, x, x_mask, g=None): + x = torch.detach(x) + if g is not None: + g = torch.detach(g) + x = x + self.cond(g) + x = self.conv_1(x * x_mask) + x = torch.relu(x) + x = self.norm_1(x) + x = self.drop(x) + x = self.conv_2(x * x_mask) + x = torch.relu(x) + x = self.norm_2(x) + x = self.drop(x) + x = self.proj(x * x_mask) + return x * x_mask + + +class TextEncoder(nn.Module): + def __init__(self, + n_vocab, + out_channels, + hidden_channels, + filter_channels, + n_heads, + n_layers, + kernel_size, + p_dropout): + super().__init__() + self.n_vocab = n_vocab + self.out_channels = out_channels + self.hidden_channels = hidden_channels + self.filter_channels = filter_channels + self.n_heads = n_heads + self.n_layers = n_layers + self.kernel_size = kernel_size + self.p_dropout = p_dropout + + self.emb = nn.Embedding(n_vocab, hidden_channels) + nn.init.normal_(self.emb.weight, 0.0, hidden_channels**-0.5) + + self.encoder = attentions.Encoder( + hidden_channels, + filter_channels, + n_heads, + n_layers, + kernel_size, + p_dropout) + self.proj= nn.Conv1d(hidden_channels, out_channels * 2, 1) + + def forward(self, x, x_lengths): + x = self.emb(x) * math.sqrt(self.hidden_channels) # [b, t, h] + x = torch.transpose(x, 1, -1) # [b, h, t] + x_mask = torch.unsqueeze(commons.sequence_mask(x_lengths, x.size(2)), 1).to(x.dtype) + + x = self.encoder(x * x_mask, x_mask) + stats = self.proj(x) * x_mask + + m, logs = torch.split(stats, self.out_channels, dim=1) + return x, m, logs, x_mask + + +class ResidualCouplingBlock(nn.Module): + def __init__(self, + channels, + hidden_channels, + kernel_size, + dilation_rate, + n_layers, + n_flows=4, + gin_channels=0): + super().__init__() + self.channels = channels + self.hidden_channels = hidden_channels + self.kernel_size = kernel_size + self.dilation_rate = dilation_rate + self.n_layers = n_layers + self.n_flows = n_flows + self.gin_channels = gin_channels + + self.flows = nn.ModuleList() + for i in range(n_flows): + self.flows.append(modules.ResidualCouplingLayer(channels, hidden_channels, kernel_size, dilation_rate, n_layers, gin_channels=gin_channels, mean_only=True)) + self.flows.append(modules.Flip()) + + def forward(self, x, x_mask, g=None, reverse=False): + if not reverse: + for flow in self.flows: + x, _ = flow(x, x_mask, g=g, reverse=reverse) + else: + for flow in reversed(self.flows): + x = flow(x, x_mask, g=g, reverse=reverse) + return x + + +class PosteriorEncoder(nn.Module): + def __init__(self, + in_channels, + out_channels, + hidden_channels, + kernel_size, + dilation_rate, + n_layers, + gin_channels=0): + super().__init__() + self.in_channels = in_channels + self.out_channels = out_channels + self.hidden_channels = hidden_channels + self.kernel_size = kernel_size + self.dilation_rate = dilation_rate + self.n_layers = n_layers + self.gin_channels = gin_channels + + self.pre = nn.Conv1d(in_channels, hidden_channels, 1) + self.enc = modules.WN(hidden_channels, kernel_size, dilation_rate, n_layers, gin_channels=gin_channels) + self.proj = nn.Conv1d(hidden_channels, out_channels * 2, 1) + + def forward(self, x, x_lengths, g=None): + x_mask = torch.unsqueeze(commons.sequence_mask(x_lengths, x.size(2)), 1).to(x.dtype) + x = self.pre(x) * x_mask + x = self.enc(x, x_mask, g=g) + stats = self.proj(x) * x_mask + m, logs = torch.split(stats, self.out_channels, dim=1) + z = (m + torch.randn_like(m) * torch.exp(logs)) * x_mask + return z, m, logs, x_mask + + +class Generator(torch.nn.Module): + def __init__(self, initial_channel, resblock, resblock_kernel_sizes, resblock_dilation_sizes, upsample_rates, upsample_initial_channel, upsample_kernel_sizes, gin_channels=0): + super(Generator, self).__init__() + self.num_kernels = len(resblock_kernel_sizes) + self.num_upsamples = len(upsample_rates) + self.conv_pre = Conv1d(initial_channel, upsample_initial_channel, 7, 1, padding=3) + resblock = modules.ResBlock1 if resblock == '1' else modules.ResBlock2 + + self.ups = nn.ModuleList() + for i, (u, k) in enumerate(zip(upsample_rates, upsample_kernel_sizes)): + self.ups.append(weight_norm( + ConvTranspose1d(upsample_initial_channel//(2**i), upsample_initial_channel//(2**(i+1)), + k, u, padding=(k-u)//2))) + + self.resblocks = nn.ModuleList() + for i in range(len(self.ups)): + ch = upsample_initial_channel//(2**(i+1)) + for j, (k, d) in enumerate(zip(resblock_kernel_sizes, resblock_dilation_sizes)): + self.resblocks.append(resblock(ch, k, d)) + + self.conv_post = Conv1d(ch, 1, 7, 1, padding=3, bias=False) + self.ups.apply(init_weights) + + if gin_channels != 0: + self.cond = nn.Conv1d(gin_channels, upsample_initial_channel, 1) + + def forward(self, x, g=None): + x = self.conv_pre(x) + if g is not None: + x = x + self.cond(g) + + for i in range(self.num_upsamples): + x = F.leaky_relu(x, modules.LRELU_SLOPE) + x = self.ups[i](x) + xs = None + for j in range(self.num_kernels): + if xs is None: + xs = self.resblocks[i*self.num_kernels+j](x) + else: + xs += self.resblocks[i*self.num_kernels+j](x) + x = xs / self.num_kernels + x = F.leaky_relu(x) + x = self.conv_post(x) + x = torch.tanh(x) + + return x + + def remove_weight_norm(self): + print('Removing weight norm...') + for l in self.ups: + remove_weight_norm(l) + for l in self.resblocks: + l.remove_weight_norm() + + +class DiscriminatorP(torch.nn.Module): + def __init__(self, period, kernel_size=5, stride=3, use_spectral_norm=False): + super(DiscriminatorP, self).__init__() + self.period = period + self.use_spectral_norm = use_spectral_norm + norm_f = weight_norm if use_spectral_norm == False else spectral_norm + self.convs = nn.ModuleList([ + norm_f(Conv2d(1, 32, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))), + norm_f(Conv2d(32, 128, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))), + norm_f(Conv2d(128, 512, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))), + norm_f(Conv2d(512, 1024, (kernel_size, 1), (stride, 1), padding=(get_padding(kernel_size, 1), 0))), + norm_f(Conv2d(1024, 1024, (kernel_size, 1), 1, padding=(get_padding(kernel_size, 1), 0))), + ]) + self.conv_post = norm_f(Conv2d(1024, 1, (3, 1), 1, padding=(1, 0))) + + def forward(self, x): + fmap = [] + + # 1d to 2d + b, c, t = x.shape + if t % self.period != 0: # pad first + n_pad = self.period - (t % self.period) + x = F.pad(x, (0, n_pad), "reflect") + t = t + n_pad + x = x.view(b, c, t // self.period, self.period) + + for l in self.convs: + x = l(x) + x = F.leaky_relu(x, modules.LRELU_SLOPE) + fmap.append(x) + x = self.conv_post(x) + fmap.append(x) + x = torch.flatten(x, 1, -1) + + return x, fmap + + +class DiscriminatorS(torch.nn.Module): + def __init__(self, use_spectral_norm=False): + super(DiscriminatorS, self).__init__() + norm_f = weight_norm if use_spectral_norm == False else spectral_norm + self.convs = nn.ModuleList([ + norm_f(Conv1d(1, 16, 15, 1, padding=7)), + norm_f(Conv1d(16, 64, 41, 4, groups=4, padding=20)), + norm_f(Conv1d(64, 256, 41, 4, groups=16, padding=20)), + norm_f(Conv1d(256, 1024, 41, 4, groups=64, padding=20)), + norm_f(Conv1d(1024, 1024, 41, 4, groups=256, padding=20)), + norm_f(Conv1d(1024, 1024, 5, 1, padding=2)), + ]) + self.conv_post = norm_f(Conv1d(1024, 1, 3, 1, padding=1)) + + def forward(self, x): + fmap = [] + + for l in self.convs: + x = l(x) + x = F.leaky_relu(x, modules.LRELU_SLOPE) + fmap.append(x) + x = self.conv_post(x) + fmap.append(x) + x = torch.flatten(x, 1, -1) + + return x, fmap + + +class MultiPeriodDiscriminator(torch.nn.Module): + def __init__(self, use_spectral_norm=False): + super(MultiPeriodDiscriminator, self).__init__() + periods = [2,3,5,7,11] + + discs = [DiscriminatorS(use_spectral_norm=use_spectral_norm)] + discs = discs + [DiscriminatorP(i, use_spectral_norm=use_spectral_norm) for i in periods] + self.discriminators = nn.ModuleList(discs) + + def forward(self, y, y_hat): + y_d_rs = [] + y_d_gs = [] + fmap_rs = [] + fmap_gs = [] + for i, d in enumerate(self.discriminators): + y_d_r, fmap_r = d(y) + y_d_g, fmap_g = d(y_hat) + y_d_rs.append(y_d_r) + y_d_gs.append(y_d_g) + fmap_rs.append(fmap_r) + fmap_gs.append(fmap_g) + + return y_d_rs, y_d_gs, fmap_rs, fmap_gs + + + +class SynthesizerTrn(nn.Module): + """ + Synthesizer for Training + """ + + def __init__(self, + n_vocab, + spec_channels, + segment_size, + inter_channels, + hidden_channels, + filter_channels, + n_heads, + n_layers, + kernel_size, + p_dropout, + resblock, + resblock_kernel_sizes, + resblock_dilation_sizes, + upsample_rates, + upsample_initial_channel, + upsample_kernel_sizes, + n_speakers=0, + gin_channels=0, + use_sdp=True, + **kwargs): + + super().__init__() + self.n_vocab = n_vocab + self.spec_channels = spec_channels + self.inter_channels = inter_channels + self.hidden_channels = hidden_channels + self.filter_channels = filter_channels + self.n_heads = n_heads + self.n_layers = n_layers + self.kernel_size = kernel_size + self.p_dropout = p_dropout + self.resblock = resblock + self.resblock_kernel_sizes = resblock_kernel_sizes + self.resblock_dilation_sizes = resblock_dilation_sizes + self.upsample_rates = upsample_rates + self.upsample_initial_channel = upsample_initial_channel + self.upsample_kernel_sizes = upsample_kernel_sizes + self.segment_size = segment_size + self.n_speakers = n_speakers + self.gin_channels = gin_channels + + self.use_sdp = use_sdp + + self.enc_p = TextEncoder(n_vocab, + inter_channels, + hidden_channels, + filter_channels, + n_heads, + n_layers, + kernel_size, + p_dropout) + self.dec = Generator(inter_channels, resblock, resblock_kernel_sizes, resblock_dilation_sizes, upsample_rates, upsample_initial_channel, upsample_kernel_sizes, gin_channels=gin_channels) + self.enc_q = PosteriorEncoder(spec_channels, inter_channels, hidden_channels, 5, 1, 16, gin_channels=gin_channels) + self.flow = ResidualCouplingBlock(inter_channels, hidden_channels, 5, 1, 4, gin_channels=gin_channels) + + if use_sdp: + self.dp = StochasticDurationPredictor(hidden_channels, 192, 3, 0.5, 4, gin_channels=gin_channels) + else: + self.dp = DurationPredictor(hidden_channels, 256, 3, 0.5, gin_channels=gin_channels) + + if n_speakers > 1: + self.emb_g = nn.Embedding(n_speakers, gin_channels) + + def forward(self, x, x_lengths, y, y_lengths, sid=None): + + x, m_p, logs_p, x_mask = self.enc_p(x, x_lengths) + if self.n_speakers > 0: + g = self.emb_g(sid).unsqueeze(-1) # [b, h, 1] + else: + g = None + + z, m_q, logs_q, y_mask = self.enc_q(y, y_lengths, g=g) + z_p = self.flow(z, y_mask, g=g) + + with torch.no_grad(): + # negative cross-entropy + s_p_sq_r = torch.exp(-2 * logs_p) # [b, d, t] + neg_cent1 = torch.sum(-0.5 * math.log(2 * math.pi) - logs_p, [1], keepdim=True) # [b, 1, t_s] + neg_cent2 = torch.matmul(-0.5 * (z_p ** 2).transpose(1, 2), s_p_sq_r) # [b, t_t, d] x [b, d, t_s] = [b, t_t, t_s] + neg_cent3 = torch.matmul(z_p.transpose(1, 2), (m_p * s_p_sq_r)) # [b, t_t, d] x [b, d, t_s] = [b, t_t, t_s] + neg_cent4 = torch.sum(-0.5 * (m_p ** 2) * s_p_sq_r, [1], keepdim=True) # [b, 1, t_s] + neg_cent = neg_cent1 + neg_cent2 + neg_cent3 + neg_cent4 + + attn_mask = torch.unsqueeze(x_mask, 2) * torch.unsqueeze(y_mask, -1) + attn = monotonic_align.maximum_path(neg_cent, attn_mask.squeeze(1)).unsqueeze(1).detach() + + w = attn.sum(2) + if self.use_sdp: + l_length = self.dp(x, x_mask, w, g=g) + l_length = l_length / torch.sum(x_mask) + else: + logw_ = torch.log(w + 1e-6) * x_mask + logw = self.dp(x, x_mask, g=g) + l_length = torch.sum((logw - logw_)**2, [1,2]) / torch.sum(x_mask) # for averaging + + # expand prior + m_p = torch.matmul(attn.squeeze(1), m_p.transpose(1, 2)).transpose(1, 2) + logs_p = torch.matmul(attn.squeeze(1), logs_p.transpose(1, 2)).transpose(1, 2) + + z_slice, ids_slice = commons.rand_slice_segments(z, y_lengths, self.segment_size) + o = self.dec(z_slice, g=g) + return o, l_length, attn, ids_slice, x_mask, y_mask, (z, z_p, m_p, logs_p, m_q, logs_q) + + def infer(self, x, x_lengths, sid=None, noise_scale=1, length_scale=1, noise_scale_w=1., max_len=None): + x, m_p, logs_p, x_mask = self.enc_p(x, x_lengths) + if self.n_speakers > 0: + g = self.emb_g(sid).unsqueeze(-1) # [b, h, 1] + else: + g = None + + if self.use_sdp: + logw = self.dp(x, x_mask, g=g, reverse=True, noise_scale=noise_scale_w) + else: + logw = self.dp(x, x_mask, g=g) + w = torch.exp(logw) * x_mask * length_scale + w_ceil = torch.ceil(w) + y_lengths = torch.clamp_min(torch.sum(w_ceil, [1, 2]), 1).long() + y_mask = torch.unsqueeze(commons.sequence_mask(y_lengths, None), 1).to(x_mask.dtype) + attn_mask = torch.unsqueeze(x_mask, 2) * torch.unsqueeze(y_mask, -1) + attn = commons.generate_path(w_ceil, attn_mask) + + m_p = torch.matmul(attn.squeeze(1), m_p.transpose(1, 2)).transpose(1, 2) # [b, t', t], [b, t, d] -> [b, d, t'] + logs_p = torch.matmul(attn.squeeze(1), logs_p.transpose(1, 2)).transpose(1, 2) # [b, t', t], [b, t, d] -> [b, d, t'] + + z_p = m_p + torch.randn_like(m_p) * torch.exp(logs_p) * noise_scale + z = self.flow(z_p, y_mask, g=g, reverse=True) + o = self.dec((z * y_mask)[:,:,:max_len], g=g) + return o, attn, y_mask, (z, z_p, m_p, logs_p) + + def voice_conversion(self, y, y_lengths, sid_src, sid_tgt): + assert self.n_speakers > 0, "n_speakers have to be larger than 0." + g_src = self.emb_g(sid_src).unsqueeze(-1) + g_tgt = self.emb_g(sid_tgt).unsqueeze(-1) + z, m_q, logs_q, y_mask = self.enc_q(y, y_lengths, g=g_src) + z_p = self.flow(z, y_mask, g=g_src) + z_hat = self.flow(z_p, y_mask, g=g_tgt, reverse=True) + o_hat = self.dec(z_hat * y_mask, g=g_tgt) + return o_hat, y_mask, (z, z_p, z_hat) + diff --git a/utils/vits/modules.py b/utils/vits/modules.py new file mode 100644 index 0000000..5716942 --- /dev/null +++ b/utils/vits/modules.py @@ -0,0 +1,390 @@ +import math +import numpy as np +import torch +from torch import nn +from torch.nn import functional as F + +from torch.nn import Conv1d, ConvTranspose1d, AvgPool1d, Conv2d +from torch.nn.utils import weight_norm, remove_weight_norm + +# import commons +# from commons import init_weights, get_padding +# from transforms import piecewise_rational_quadratic_transform +from utils.vits import commons +from utils.vits.commons import init_weights, get_padding +from utils.vits.transforms import piecewise_rational_quadratic_transform + +LRELU_SLOPE = 0.1 + + +class LayerNorm(nn.Module): + def __init__(self, channels, eps=1e-5): + super().__init__() + self.channels = channels + self.eps = eps + + self.gamma = nn.Parameter(torch.ones(channels)) + self.beta = nn.Parameter(torch.zeros(channels)) + + def forward(self, x): + x = x.transpose(1, -1) + x = F.layer_norm(x, (self.channels,), self.gamma, self.beta, self.eps) + return x.transpose(1, -1) + + +class ConvReluNorm(nn.Module): + def __init__(self, in_channels, hidden_channels, out_channels, kernel_size, n_layers, p_dropout): + super().__init__() + self.in_channels = in_channels + self.hidden_channels = hidden_channels + self.out_channels = out_channels + self.kernel_size = kernel_size + self.n_layers = n_layers + self.p_dropout = p_dropout + assert n_layers > 1, "Number of layers should be larger than 0." + + self.conv_layers = nn.ModuleList() + self.norm_layers = nn.ModuleList() + self.conv_layers.append(nn.Conv1d(in_channels, hidden_channels, kernel_size, padding=kernel_size//2)) + self.norm_layers.append(LayerNorm(hidden_channels)) + self.relu_drop = nn.Sequential( + nn.ReLU(), + nn.Dropout(p_dropout)) + for _ in range(n_layers-1): + self.conv_layers.append(nn.Conv1d(hidden_channels, hidden_channels, kernel_size, padding=kernel_size//2)) + self.norm_layers.append(LayerNorm(hidden_channels)) + self.proj = nn.Conv1d(hidden_channels, out_channels, 1) + self.proj.weight.data.zero_() + self.proj.bias.data.zero_() + + def forward(self, x, x_mask): + x_org = x + for i in range(self.n_layers): + x = self.conv_layers[i](x * x_mask) + x = self.norm_layers[i](x) + x = self.relu_drop(x) + x = x_org + self.proj(x) + return x * x_mask + + +class DDSConv(nn.Module): + """ + Dialted and Depth-Separable Convolution + """ + def __init__(self, channels, kernel_size, n_layers, p_dropout=0.): + super().__init__() + self.channels = channels + self.kernel_size = kernel_size + self.n_layers = n_layers + self.p_dropout = p_dropout + + self.drop = nn.Dropout(p_dropout) + self.convs_sep = nn.ModuleList() + self.convs_1x1 = nn.ModuleList() + self.norms_1 = nn.ModuleList() + self.norms_2 = nn.ModuleList() + for i in range(n_layers): + dilation = kernel_size ** i + padding = (kernel_size * dilation - dilation) // 2 + self.convs_sep.append(nn.Conv1d(channels, channels, kernel_size, + groups=channels, dilation=dilation, padding=padding + )) + self.convs_1x1.append(nn.Conv1d(channels, channels, 1)) + self.norms_1.append(LayerNorm(channels)) + self.norms_2.append(LayerNorm(channels)) + + def forward(self, x, x_mask, g=None): + if g is not None: + x = x + g + for i in range(self.n_layers): + y = self.convs_sep[i](x * x_mask) + y = self.norms_1[i](y) + y = F.gelu(y) + y = self.convs_1x1[i](y) + y = self.norms_2[i](y) + y = F.gelu(y) + y = self.drop(y) + x = x + y + return x * x_mask + + +class WN(torch.nn.Module): + def __init__(self, hidden_channels, kernel_size, dilation_rate, n_layers, gin_channels=0, p_dropout=0): + super(WN, self).__init__() + assert(kernel_size % 2 == 1) + self.hidden_channels =hidden_channels + self.kernel_size = kernel_size, + self.dilation_rate = dilation_rate + self.n_layers = n_layers + self.gin_channels = gin_channels + self.p_dropout = p_dropout + + self.in_layers = torch.nn.ModuleList() + self.res_skip_layers = torch.nn.ModuleList() + self.drop = nn.Dropout(p_dropout) + + if gin_channels != 0: + cond_layer = torch.nn.Conv1d(gin_channels, 2*hidden_channels*n_layers, 1) + self.cond_layer = torch.nn.utils.weight_norm(cond_layer, name='weight') + + for i in range(n_layers): + dilation = dilation_rate ** i + padding = int((kernel_size * dilation - dilation) / 2) + in_layer = torch.nn.Conv1d(hidden_channels, 2*hidden_channels, kernel_size, + dilation=dilation, padding=padding) + in_layer = torch.nn.utils.weight_norm(in_layer, name='weight') + self.in_layers.append(in_layer) + + # last one is not necessary + if i < n_layers - 1: + res_skip_channels = 2 * hidden_channels + else: + res_skip_channels = hidden_channels + + res_skip_layer = torch.nn.Conv1d(hidden_channels, res_skip_channels, 1) + res_skip_layer = torch.nn.utils.weight_norm(res_skip_layer, name='weight') + self.res_skip_layers.append(res_skip_layer) + + def forward(self, x, x_mask, g=None, **kwargs): + output = torch.zeros_like(x) + n_channels_tensor = torch.IntTensor([self.hidden_channels]) + + if g is not None: + g = self.cond_layer(g) + + for i in range(self.n_layers): + x_in = self.in_layers[i](x) + if g is not None: + cond_offset = i * 2 * self.hidden_channels + g_l = g[:,cond_offset:cond_offset+2*self.hidden_channels,:] + else: + g_l = torch.zeros_like(x_in) + + acts = commons.fused_add_tanh_sigmoid_multiply( + x_in, + g_l, + n_channels_tensor) + acts = self.drop(acts) + + res_skip_acts = self.res_skip_layers[i](acts) + if i < self.n_layers - 1: + res_acts = res_skip_acts[:,:self.hidden_channels,:] + x = (x + res_acts) * x_mask + output = output + res_skip_acts[:,self.hidden_channels:,:] + else: + output = output + res_skip_acts + return output * x_mask + + def remove_weight_norm(self): + if self.gin_channels != 0: + torch.nn.utils.remove_weight_norm(self.cond_layer) + for l in self.in_layers: + torch.nn.utils.remove_weight_norm(l) + for l in self.res_skip_layers: + torch.nn.utils.remove_weight_norm(l) + + +class ResBlock1(torch.nn.Module): + def __init__(self, channels, kernel_size=3, dilation=(1, 3, 5)): + super(ResBlock1, self).__init__() + self.convs1 = nn.ModuleList([ + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]))), + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]))), + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=dilation[2], + padding=get_padding(kernel_size, dilation[2]))) + ]) + self.convs1.apply(init_weights) + + self.convs2 = nn.ModuleList([ + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=1, + padding=get_padding(kernel_size, 1))), + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=1, + padding=get_padding(kernel_size, 1))), + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=1, + padding=get_padding(kernel_size, 1))) + ]) + self.convs2.apply(init_weights) + + def forward(self, x, x_mask=None): + for c1, c2 in zip(self.convs1, self.convs2): + xt = F.leaky_relu(x, LRELU_SLOPE) + if x_mask is not None: + xt = xt * x_mask + xt = c1(xt) + xt = F.leaky_relu(xt, LRELU_SLOPE) + if x_mask is not None: + xt = xt * x_mask + xt = c2(xt) + x = xt + x + if x_mask is not None: + x = x * x_mask + return x + + def remove_weight_norm(self): + for l in self.convs1: + remove_weight_norm(l) + for l in self.convs2: + remove_weight_norm(l) + + +class ResBlock2(torch.nn.Module): + def __init__(self, channels, kernel_size=3, dilation=(1, 3)): + super(ResBlock2, self).__init__() + self.convs = nn.ModuleList([ + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=dilation[0], + padding=get_padding(kernel_size, dilation[0]))), + weight_norm(Conv1d(channels, channels, kernel_size, 1, dilation=dilation[1], + padding=get_padding(kernel_size, dilation[1]))) + ]) + self.convs.apply(init_weights) + + def forward(self, x, x_mask=None): + for c in self.convs: + xt = F.leaky_relu(x, LRELU_SLOPE) + if x_mask is not None: + xt = xt * x_mask + xt = c(xt) + x = xt + x + if x_mask is not None: + x = x * x_mask + return x + + def remove_weight_norm(self): + for l in self.convs: + remove_weight_norm(l) + + +class Log(nn.Module): + def forward(self, x, x_mask, reverse=False, **kwargs): + if not reverse: + y = torch.log(torch.clamp_min(x, 1e-5)) * x_mask + logdet = torch.sum(-y, [1, 2]) + return y, logdet + else: + x = torch.exp(x) * x_mask + return x + + +class Flip(nn.Module): + def forward(self, x, *args, reverse=False, **kwargs): + x = torch.flip(x, [1]) + if not reverse: + logdet = torch.zeros(x.size(0)).to(dtype=x.dtype, device=x.device) + return x, logdet + else: + return x + + +class ElementwiseAffine(nn.Module): + def __init__(self, channels): + super().__init__() + self.channels = channels + self.m = nn.Parameter(torch.zeros(channels,1)) + self.logs = nn.Parameter(torch.zeros(channels,1)) + + def forward(self, x, x_mask, reverse=False, **kwargs): + if not reverse: + y = self.m + torch.exp(self.logs) * x + y = y * x_mask + logdet = torch.sum(self.logs * x_mask, [1,2]) + return y, logdet + else: + x = (x - self.m) * torch.exp(-self.logs) * x_mask + return x + + +class ResidualCouplingLayer(nn.Module): + def __init__(self, + channels, + hidden_channels, + kernel_size, + dilation_rate, + n_layers, + p_dropout=0, + gin_channels=0, + mean_only=False): + assert channels % 2 == 0, "channels should be divisible by 2" + super().__init__() + self.channels = channels + self.hidden_channels = hidden_channels + self.kernel_size = kernel_size + self.dilation_rate = dilation_rate + self.n_layers = n_layers + self.half_channels = channels // 2 + self.mean_only = mean_only + + self.pre = nn.Conv1d(self.half_channels, hidden_channels, 1) + self.enc = WN(hidden_channels, kernel_size, dilation_rate, n_layers, p_dropout=p_dropout, gin_channels=gin_channels) + self.post = nn.Conv1d(hidden_channels, self.half_channels * (2 - mean_only), 1) + self.post.weight.data.zero_() + self.post.bias.data.zero_() + + def forward(self, x, x_mask, g=None, reverse=False): + x0, x1 = torch.split(x, [self.half_channels]*2, 1) + h = self.pre(x0) * x_mask + h = self.enc(h, x_mask, g=g) + stats = self.post(h) * x_mask + if not self.mean_only: + m, logs = torch.split(stats, [self.half_channels]*2, 1) + else: + m = stats + logs = torch.zeros_like(m) + + if not reverse: + x1 = m + x1 * torch.exp(logs) * x_mask + x = torch.cat([x0, x1], 1) + logdet = torch.sum(logs, [1,2]) + return x, logdet + else: + x1 = (x1 - m) * torch.exp(-logs) * x_mask + x = torch.cat([x0, x1], 1) + return x + + +class ConvFlow(nn.Module): + def __init__(self, in_channels, filter_channels, kernel_size, n_layers, num_bins=10, tail_bound=5.0): + super().__init__() + self.in_channels = in_channels + self.filter_channels = filter_channels + self.kernel_size = kernel_size + self.n_layers = n_layers + self.num_bins = num_bins + self.tail_bound = tail_bound + self.half_channels = in_channels // 2 + + self.pre = nn.Conv1d(self.half_channels, filter_channels, 1) + self.convs = DDSConv(filter_channels, kernel_size, n_layers, p_dropout=0.) + self.proj = nn.Conv1d(filter_channels, self.half_channels * (num_bins * 3 - 1), 1) + self.proj.weight.data.zero_() + self.proj.bias.data.zero_() + + def forward(self, x, x_mask, g=None, reverse=False): + x0, x1 = torch.split(x, [self.half_channels]*2, 1) + h = self.pre(x0) + h = self.convs(h, x_mask, g=g) + h = self.proj(h) * x_mask + + b, c, t = x0.shape + h = h.reshape(b, c, -1, t).permute(0, 1, 3, 2) # [b, cx?, t] -> [b, c, t, ?] + + unnormalized_widths = h[..., :self.num_bins] / math.sqrt(self.filter_channels) + unnormalized_heights = h[..., self.num_bins:2*self.num_bins] / math.sqrt(self.filter_channels) + unnormalized_derivatives = h[..., 2 * self.num_bins:] + + x1, logabsdet = piecewise_rational_quadratic_transform(x1, + unnormalized_widths, + unnormalized_heights, + unnormalized_derivatives, + inverse=reverse, + tails='linear', + tail_bound=self.tail_bound + ) + + x = torch.cat([x0, x1], 1) * x_mask + logdet = torch.sum(logabsdet * x_mask, [1,2]) + if not reverse: + return x, logdet + else: + return x diff --git a/utils/vits/monotonic_align/__init__.py b/utils/vits/monotonic_align/__init__.py new file mode 100644 index 0000000..e97eecc --- /dev/null +++ b/utils/vits/monotonic_align/__init__.py @@ -0,0 +1,20 @@ +from numpy import zeros, int32, float32 +from torch import from_numpy + +from .core import maximum_path_jit + + +def maximum_path(neg_cent, mask): + """ numba optimized version. + neg_cent: [b, t_t, t_s] + mask: [b, t_t, t_s] + """ + device = neg_cent.device + dtype = neg_cent.dtype + neg_cent = neg_cent.data.cpu().numpy().astype(float32) + path = zeros(neg_cent.shape, dtype=int32) + + t_t_max = mask.sum(1)[:, 0].data.cpu().numpy().astype(int32) + t_s_max = mask.sum(2)[:, 0].data.cpu().numpy().astype(int32) + maximum_path_jit(path, neg_cent, t_t_max, t_s_max) + return from_numpy(path).to(device=device, dtype=dtype) diff --git a/utils/vits/monotonic_align/__pycache__/__init__.cpython-38.pyc b/utils/vits/monotonic_align/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d93155d13f90b1c654373d0990539b73ab45f6e GIT binary patch literal 837 zcmah{O^e$w5S3)hPSRxALt5y~rv*b&jpr@ztjF|W252MilK{Wld$yb8VFMl`;$f1|8%rgLv zIIfYzIhG_RGROn$bEFO>%_;DJhjk?5JO)mA^bO@b9=}6rZx7ul4IEupS{X-0W1pV6 zcv33{B*ktp(MlH0Le5uv>}#<*mh6j=3t7yWofb1;OFztg#6T#lSFp?vfELZrh5+JC z07$mM4sAnN)J8kJK{keL&-OXKC7ZCt+W{v#3?m2M2@faa@!vgt=%HN|{ZCb7AGBeM zTG~c8Ax3uChBtUNYDpXL=$3%|c>Oj3X_qWfb1S4+S3Fr(+6dL04ibo_x+==5vCor_ zmroK~SP$k?_f0Z${jWSYM7dqfD;;;S?QiX9%=u?9d{vTmbsvu zFC6X6b`dk(C84kJ?T(r$gIfd71GA9YTdlp)oqAXY~u9~bU zL?diboX%Hnc=&ht3C%G8q7jbp7$1=ne1ea#egwITw6907ck()2+N*WcDqT+Rl!c|z g)tyq`(#?AS4}E>_g;ab|SLfbp<6R%)AsGgL0H+hq&;S4c literal 0 HcmV?d00001 diff --git a/utils/vits/monotonic_align/__pycache__/__init__.cpython-39.pyc b/utils/vits/monotonic_align/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0b784da10e41e57f203143deacdfca6526370263 GIT binary patch literal 834 zcmah{L5mYH6izaenYOlN4^{Bi(?UUZKrbS)2nya7QBNZ>q?743-N|G~(rU{Tgw^Bz zfjzZH|5C1=`WHO;GRr~*!3Xc<%bWKe@B1=rFz6w$TRWY7BMANSmt%t*dIfHtL*R(x z5=oq5Nm3$%G{8Pb%23jj0uFdsMlw!gz?4VdQQG102Q=v%pc_pBM>mC5#!*q(XHQ)` zD-{DU!LB#cN@mqk*6RcIwb-3V_EpHG%xY%m*+SUdFLQ4(01EyZ+}uKF&;o4eprYX8J7b|Gh$xgf8X zj<#aEh?#as=xcntqh`)vYT$8TmQs7Ewb$Aat0r;UxnI|Xe!1iE{;AR!2xRbh9vBaP zB0Ylk-*1z-l0~xEm^5zdSN literal 0 HcmV?d00001 diff --git a/utils/vits/monotonic_align/__pycache__/core.cpython-38.pyc b/utils/vits/monotonic_align/__pycache__/core.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b15f7ccba170807977102879878702d9eb82953b GIT binary patch literal 988 zcmYjQ&2G~`5T5<9^WQ|MQWFjwk#fPPNN|Y|5*5b^i6Ws$#d5Pw;?zHhy$K0g_Y!(U z>VXG!9r{oxr0_+x_YVX`mK zGKC;OkP!Od!-V+om7-^Y2y#w0DCjvGvX0^K&FU>05%lfo|yvJAlJ0f_T)Wx*R9dl^iFrw&G+Igad5Tsw%>Kkx<9`U2 z*Ji(wTZ?x$T%#!XHM3^47IZ)|Ra5mfeFhAAFgu&QGu;_3zCvrwu>N6=)l>;JjUnxU zYG4(XUaN-b>4IbjcQr8Iflc(k;wc!miSowmdUjs`UWt8}n%fwmfq!}VtC*M|r3hCy zIJ%a$vavVywUv7D$k!~0rDl=0LIVx`*BTedUak$af|m2afbk zKX@zWsBo`CPY#nba^^A!Ge^qISp*1C5+^c=gMsUX!6J#KTEJEKacnZ4~QrFG|Eb^q-r1$jr}LX733Fdc)~I*zNPe literal 0 HcmV?d00001 diff --git a/utils/vits/monotonic_align/__pycache__/core.cpython-39.pyc b/utils/vits/monotonic_align/__pycache__/core.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9137b9824807332da15ece5dee4d9219f780c626 GIT binary patch literal 983 zcmYjPJ8u&~5T1S9`5jv*keGrJ$qhz9g2qBfNgW}P0$B>Di}!4wa}WD&ZEUoc=17T@ zf{F@C{s0vXKOhqIwp95G6bZ8z5qnqj&Cbp@JKx=|+h|k)#}|1rJmUa=Ot3jj_7z&H z5CjMkKp#Aq5D&gm^h^*z&gmKjJ!eDKHXOd*y=83ViaHY)%#G+97Yrx=#Dpd6kC2nT zCCD4-l&(+#99|K`qYl;OD4wq5IF9;O6p#F1fb#D~3s)7ieYErlOB75{d>b+@Xl6+w zsp2`w$pKuDs; zZS8=n>_Sc@H<92wxXvlEf~={UYU`9H7s|@&QA?Fgeiu}8NU?8SH3h-!Puw;BhhSN4 z_8YmiXnV~y6$QU$_Drn>ZIDdWR6VCJfI$ytXS26Po#Emyv~q_14>RnhN?6kv(jKS= zc45i2Y8XuyBt5w6f%!J9qyHUG!LUt~HD=edhXU|Q?8C&|#t03(%gbNI!UPFLxVpj7 zv9y(r-KnRo#EnLtW_~0!3*9AxA9Y&Vn!0kFYJ1@Zb1&_4>8uJ|rkb4eYshpWZ{%QF z6JK+~)>c8*47moDeS6_d6K~PC7S3RvXv>d;x71{%$?`iS_fgH?{q8spz3$}0pexPZjoP^zlFVk)qN3o0}f8e-*KZ?48IPsoLSGt9A{BRyRMus!- zrFnGeQv_gD!pS{SzMT|3t&_(X*|b&c+0>@n0G7sg^9crVQ*q-BIMdq?;Ur~d$`H1X~L literal 0 HcmV?d00001 diff --git a/utils/vits/monotonic_align/core.py b/utils/vits/monotonic_align/core.py new file mode 100644 index 0000000..1f94060 --- /dev/null +++ b/utils/vits/monotonic_align/core.py @@ -0,0 +1,36 @@ +import numba + + +@numba.jit(numba.void(numba.int32[:, :, ::1], numba.float32[:, :, ::1], numba.int32[::1], numba.int32[::1]), + nopython=True, nogil=True) +def maximum_path_jit(paths, values, t_ys, t_xs): + b = paths.shape[0] + max_neg_val = -1e9 + for i in range(int(b)): + path = paths[i] + value = values[i] + t_y = t_ys[i] + t_x = t_xs[i] + + v_prev = v_cur = 0.0 + index = t_x - 1 + + for y in range(t_y): + for x in range(max(0, t_x + y - t_y), min(t_x, y + 1)): + if x == y: + v_cur = max_neg_val + else: + v_cur = value[y - 1, x] + if x == 0: + if y == 0: + v_prev = 0. + else: + v_prev = max_neg_val + else: + v_prev = value[y - 1, x - 1] + value[y, x] += max(v_prev, v_cur) + + for y in range(t_y - 1, -1, -1): + path[y, index] = 1 + if index != 0 and (index == y or value[y - 1, index] < value[y - 1, index - 1]): + index = index - 1 diff --git a/utils/vits/text/LICENSE b/utils/vits/text/LICENSE new file mode 100644 index 0000000..4ad4ed1 --- /dev/null +++ b/utils/vits/text/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 Keith Ito + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/utils/vits/text/__init__.py b/utils/vits/text/__init__.py new file mode 100644 index 0000000..edc98aa --- /dev/null +++ b/utils/vits/text/__init__.py @@ -0,0 +1,57 @@ +""" from https://github.com/keithito/tacotron """ +from . import cleaners +from .symbols import symbols + + +# Mappings from symbol to numeric ID and vice versa: +_symbol_to_id = {s: i for i, s in enumerate(symbols)} +_id_to_symbol = {i: s for i, s in enumerate(symbols)} + + +def text_to_sequence(text, symbols, cleaner_names): + '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + Args: + text: string to convert to a sequence + cleaner_names: names of the cleaner functions to run the text through + Returns: + List of integers corresponding to the symbols in the text + ''' + _symbol_to_id = {s: i for i, s in enumerate(symbols)} + sequence = [] + + clean_text = _clean_text(text, cleaner_names) + for symbol in clean_text: + if symbol not in _symbol_to_id.keys(): + continue + symbol_id = _symbol_to_id[symbol] + sequence += [symbol_id] + return sequence, clean_text + + +def cleaned_text_to_sequence(cleaned_text): + '''Converts a string of text to a sequence of IDs corresponding to the symbols in the text. + Args: + text: string to convert to a sequence + Returns: + List of integers corresponding to the symbols in the text + ''' + sequence = [_symbol_to_id[symbol] for symbol in cleaned_text if symbol in _symbol_to_id.keys()] + return sequence + + +def sequence_to_text(sequence): + '''Converts a sequence of IDs back to a string''' + result = '' + for symbol_id in sequence: + s = _id_to_symbol[symbol_id] + result += s + return result + + +def _clean_text(text, cleaner_names): + for name in cleaner_names: + cleaner = getattr(cleaners, name) + if not cleaner: + raise Exception('Unknown cleaner: %s' % name) + text = cleaner(text) + return text diff --git a/utils/vits/text/__pycache__/__init__.cpython-38.pyc b/utils/vits/text/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8e24a93799f32623da73c109436ea1c7350d7266 GIT binary patch literal 2308 zcmd5;O>Y}T7@nD3d)JPghBTB!99UJMl3V1hKmsX>0x02tgeug~i$%2B?2PTj>)m8# z+&0$uLh=U?f1n)uNB9wY;KGT&z=`)A+sVdi5gd>hYrfw3c)y-`*3a7QCV`SSKJNco zC**gWREq3b~0z|^c)zwymm!|E1XMuL@sHs#_KDRI`_DL zMS31@@Fw&=U*j$48@$cep>Og#$E33{eH8R%F%E`WpQ*ht9He?UIqfFJI2;KWr@9Dr zoD^CXdGH4XyE?S=lT5_9kP610x)`4pnM!bNSLFBh51N!1a#6AiAM9e8L6gq+mj$B4u{{0obzVRMUb%#$^^qB3pZ z6tDH6R#YVzi)F#J>$p6H2`2c8XkzF*kuzsNX0E1&7xgmvm)oX6}IT12o{+Q(%eq*bhjBm`BDzlo*f1D&b_4$IGD^8-&V8O zyMRrU$77-P0^3=;K-pp~=uh%Qr$w&t206J=4K~PPG8o#so(esY`Lz+>q)OvOX|BZp zaQTn@fy>?qgJa0e-vGCg_qV~|F5Ym1xals2FVaP{41IS$E0Q=<2i+T(cAT;y^2u1p zSc`HkvO$UPWa*B?h3fdFi!+I!D%-c>S+=8j!ca-dOMj`TY*wzR&-av##om-xd_fGC z8>@z{p(mTr5Py@ptVw;^qRh7PU69@iAOiu`L#X!99N~r_P0gsGh|uY8|3i5GSCGPJ zAV@5v0vHUC3%4;An!KX$rt8v02G}7#Syr?O=`gtgdu1CM7$cA*LTWWz&HW6pZ#nJ( zEH4npNQ+EAn!|%z{JaHu*M}EMd#&mr`OX_OZdZ3yul)e^BfAlAoyzy1zl983LD*Vk z+=l^2JOD0Ewq^|cXTWHVp~e9|qvyUw3Y$KvB4vfNPUB>>;2BGCC4QUQfPHI~{Va7{ z>qA)wcAI2cZh>BjEW8@Wjpb{>v-koY!X{-u*USa1`?N{r`yfj&pUZ+iUGw>4m>BpR zpFBW+fWwi&9pk9`nsJ!jgBS24_-F7XkaO1nBs%QL^zO5Klov1ZB?ayUA1WXMZyL;YjQ{`u literal 0 HcmV?d00001 diff --git a/utils/vits/text/__pycache__/__init__.cpython-39.pyc b/utils/vits/text/__pycache__/__init__.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9bc556a3c475e8cb4e0bd5a0658fecfee8796bd GIT binary patch literal 2281 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 literal 0 HcmV?d00001 diff --git a/utils/vits/text/__pycache__/cleaners.cpython-39.pyc b/utils/vits/text/__pycache__/cleaners.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c0111f52628d701ec524c3a30e2f3c2f2b88fd0 GIT binary patch literal 12600 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 F_yyJ9hVcLZ literal 0 HcmV?d00001 diff --git a/utils/vits/text/cleaners.py b/utils/vits/text/cleaners.py new file mode 100644 index 0000000..347ca36 --- /dev/null +++ b/utils/vits/text/cleaners.py @@ -0,0 +1,475 @@ +""" from https://github.com/keithito/tacotron """ + +''' +Cleaners are transformations that run over the input text at both training and eval time. + +Cleaners can be selected by passing a comma-delimited list of cleaner names as the "cleaners" +hyperparameter. Some cleaners are English-specific. You'll typically want to use: + 1. "english_cleaners" for English text + 2. "transliteration_cleaners" for non-English text that can be transliterated to ASCII using + the Unidecode library (https://pypi.python.org/pypi/Unidecode) + 3. "basic_cleaners" if you do not want to transliterate (in this case, you should also update + the symbols in symbols.py to match your data). +''' + +import re +from unidecode import unidecode +# import pyopenjtalk +from jamo import h2j, j2hcj +from pypinyin import lazy_pinyin, BOPOMOFO +import jieba, cn2an + + +# This is a list of Korean classifiers preceded by pure Korean numerals. +_korean_classifiers = '군데 권 개 그루 닢 대 두 마리 모 모금 뭇 발 발짝 방 번 벌 보루 살 수 술 시 쌈 움큼 정 짝 채 척 첩 축 켤레 톨 통' + +# Regular expression matching whitespace: +_whitespace_re = re.compile(r'\s+') + +# Regular expression matching Japanese without punctuation marks: +_japanese_characters = re.compile(r'[A-Za-z\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d]') + +# Regular expression matching non-Japanese characters or punctuation marks: +_japanese_marks = re.compile(r'[^A-Za-z\d\u3005\u3040-\u30ff\u4e00-\u9fff\uff11-\uff19\uff21-\uff3a\uff41-\uff5a\uff66-\uff9d]') + +# List of (regular expression, replacement) pairs for abbreviations: +_abbreviations = [(re.compile('\\b%s\\.' % x[0], re.IGNORECASE), x[1]) for x in [ + ('mrs', 'misess'), + ('mr', 'mister'), + ('dr', 'doctor'), + ('st', 'saint'), + ('co', 'company'), + ('jr', 'junior'), + ('maj', 'major'), + ('gen', 'general'), + ('drs', 'doctors'), + ('rev', 'reverend'), + ('lt', 'lieutenant'), + ('hon', 'honorable'), + ('sgt', 'sergeant'), + ('capt', 'captain'), + ('esq', 'esquire'), + ('ltd', 'limited'), + ('col', 'colonel'), + ('ft', 'fort'), +]] + +# List of (hangul, hangul divided) pairs: +_hangul_divided = [(re.compile('%s' % x[0]), x[1]) for x in [ + ('ㄳ', 'ㄱㅅ'), + ('ㄵ', 'ㄴㅈ'), + ('ㄶ', 'ㄴㅎ'), + ('ㄺ', 'ㄹㄱ'), + ('ㄻ', 'ㄹㅁ'), + ('ㄼ', 'ㄹㅂ'), + ('ㄽ', 'ㄹㅅ'), + ('ㄾ', 'ㄹㅌ'), + ('ㄿ', 'ㄹㅍ'), + ('ㅀ', 'ㄹㅎ'), + ('ㅄ', 'ㅂㅅ'), + ('ㅘ', 'ㅗㅏ'), + ('ㅙ', 'ㅗㅐ'), + ('ㅚ', 'ㅗㅣ'), + ('ㅝ', 'ㅜㅓ'), + ('ㅞ', 'ㅜㅔ'), + ('ㅟ', 'ㅜㅣ'), + ('ㅢ', 'ㅡㅣ'), + ('ㅑ', 'ㅣㅏ'), + ('ㅒ', 'ㅣㅐ'), + ('ㅕ', 'ㅣㅓ'), + ('ㅖ', 'ㅣㅔ'), + ('ㅛ', 'ㅣㅗ'), + ('ㅠ', 'ㅣㅜ') +]] + +# List of (Latin alphabet, hangul) pairs: +_latin_to_hangul = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [ + ('a', '에이'), + ('b', '비'), + ('c', '시'), + ('d', '디'), + ('e', '이'), + ('f', '에프'), + ('g', '지'), + ('h', '에이치'), + ('i', '아이'), + ('j', '제이'), + ('k', '케이'), + ('l', '엘'), + ('m', '엠'), + ('n', '엔'), + ('o', '오'), + ('p', '피'), + ('q', '큐'), + ('r', '아르'), + ('s', '에스'), + ('t', '티'), + ('u', '유'), + ('v', '브이'), + ('w', '더블유'), + ('x', '엑스'), + ('y', '와이'), + ('z', '제트') +]] + +# List of (Latin alphabet, bopomofo) pairs: +_latin_to_bopomofo = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [ + ('a', 'ㄟˉ'), + ('b', 'ㄅㄧˋ'), + ('c', 'ㄙㄧˉ'), + ('d', 'ㄉㄧˋ'), + ('e', 'ㄧˋ'), + ('f', 'ㄝˊㄈㄨˋ'), + ('g', 'ㄐㄧˋ'), + ('h', 'ㄝˇㄑㄩˋ'), + ('i', 'ㄞˋ'), + ('j', 'ㄐㄟˋ'), + ('k', 'ㄎㄟˋ'), + ('l', 'ㄝˊㄛˋ'), + ('m', 'ㄝˊㄇㄨˋ'), + ('n', 'ㄣˉ'), + ('o', 'ㄡˉ'), + ('p', 'ㄆㄧˉ'), + ('q', 'ㄎㄧㄡˉ'), + ('r', 'ㄚˋ'), + ('s', 'ㄝˊㄙˋ'), + ('t', 'ㄊㄧˋ'), + ('u', 'ㄧㄡˉ'), + ('v', 'ㄨㄧˉ'), + ('w', 'ㄉㄚˋㄅㄨˋㄌㄧㄡˋ'), + ('x', 'ㄝˉㄎㄨˋㄙˋ'), + ('y', 'ㄨㄞˋ'), + ('z', 'ㄗㄟˋ') +]] + + +# List of (bopomofo, romaji) pairs: +_bopomofo_to_romaji = [(re.compile('%s' % x[0], re.IGNORECASE), x[1]) for x in [ + ('ㄅㄛ', 'p⁼wo'), + ('ㄆㄛ', 'pʰwo'), + ('ㄇㄛ', 'mwo'), + ('ㄈㄛ', 'fwo'), + ('ㄅ', 'p⁼'), + ('ㄆ', 'pʰ'), + ('ㄇ', 'm'), + ('ㄈ', 'f'), + ('ㄉ', 't⁼'), + ('ㄊ', 'tʰ'), + ('ㄋ', 'n'), + ('ㄌ', 'l'), + ('ㄍ', 'k⁼'), + ('ㄎ', 'kʰ'), + ('ㄏ', 'h'), + ('ㄐ', 'ʧ⁼'), + ('ㄑ', 'ʧʰ'), + ('ㄒ', 'ʃ'), + ('ㄓ', 'ʦ`⁼'), + ('ㄔ', 'ʦ`ʰ'), + ('ㄕ', 's`'), + ('ㄖ', 'ɹ`'), + ('ㄗ', 'ʦ⁼'), + ('ㄘ', 'ʦʰ'), + ('ㄙ', 's'), + ('ㄚ', 'a'), + ('ㄛ', 'o'), + ('ㄜ', 'ə'), + ('ㄝ', 'e'), + ('ㄞ', 'ai'), + ('ㄟ', 'ei'), + ('ㄠ', 'au'), + ('ㄡ', 'ou'), + ('ㄧㄢ', 'yeNN'), + ('ㄢ', 'aNN'), + ('ㄧㄣ', 'iNN'), + ('ㄣ', 'əNN'), + ('ㄤ', 'aNg'), + ('ㄧㄥ', 'iNg'), + ('ㄨㄥ', 'uNg'), + ('ㄩㄥ', 'yuNg'), + ('ㄥ', 'əNg'), + ('ㄦ', 'əɻ'), + ('ㄧ', 'i'), + ('ㄨ', 'u'), + ('ㄩ', 'ɥ'), + ('ˉ', '→'), + ('ˊ', '↑'), + ('ˇ', '↓↑'), + ('ˋ', '↓'), + ('˙', ''), + (',', ','), + ('。', '.'), + ('!', '!'), + ('?', '?'), + ('—', '-') +]] + + +def expand_abbreviations(text): + for regex, replacement in _abbreviations: + text = re.sub(regex, replacement, text) + return text + + +def lowercase(text): + return text.lower() + + +def collapse_whitespace(text): + return re.sub(_whitespace_re, ' ', text) + + +def convert_to_ascii(text): + return unidecode(text) + + +def japanese_to_romaji_with_accent(text): + '''Reference https://r9y9.github.io/ttslearn/latest/notebooks/ch10_Recipe-Tacotron.html''' + sentences = re.split(_japanese_marks, text) + marks = re.findall(_japanese_marks, text) + text = '' + for i, sentence in enumerate(sentences): + if re.match(_japanese_characters, sentence): + if text!='': + text+=' ' + labels = pyopenjtalk.extract_fullcontext(sentence) + for n, label in enumerate(labels): + phoneme = re.search(r'\-([^\+]*)\+', label).group(1) + if phoneme not in ['sil','pau']: + text += phoneme.replace('ch','ʧ').replace('sh','ʃ').replace('cl','Q') + else: + continue + n_moras = int(re.search(r'/F:(\d+)_', label).group(1)) + a1 = int(re.search(r"/A:(\-?[0-9]+)\+", label).group(1)) + a2 = int(re.search(r"\+(\d+)\+", label).group(1)) + a3 = int(re.search(r"\+(\d+)/", label).group(1)) + if re.search(r'\-([^\+]*)\+', labels[n + 1]).group(1) in ['sil','pau']: + a2_next=-1 + else: + a2_next = int(re.search(r"\+(\d+)\+", labels[n + 1]).group(1)) + # Accent phrase boundary + if a3 == 1 and a2_next == 1: + text += ' ' + # Falling + elif a1 == 0 and a2_next == a2 + 1 and a2 != n_moras: + text += '↓' + # Rising + elif a2 == 1 and a2_next == 2: + text += '↑' + if i= bin_locations, + dim=-1 + ) - 1 + + +def unconstrained_rational_quadratic_spline(inputs, + unnormalized_widths, + unnormalized_heights, + unnormalized_derivatives, + inverse=False, + tails='linear', + tail_bound=1., + min_bin_width=DEFAULT_MIN_BIN_WIDTH, + min_bin_height=DEFAULT_MIN_BIN_HEIGHT, + min_derivative=DEFAULT_MIN_DERIVATIVE): + inside_interval_mask = (inputs >= -tail_bound) & (inputs <= tail_bound) + outside_interval_mask = ~inside_interval_mask + + outputs = torch.zeros_like(inputs) + logabsdet = torch.zeros_like(inputs) + + if tails == 'linear': + unnormalized_derivatives = F.pad(unnormalized_derivatives, pad=(1, 1)) + constant = np.log(np.exp(1 - min_derivative) - 1) + unnormalized_derivatives[..., 0] = constant + unnormalized_derivatives[..., -1] = constant + + outputs[outside_interval_mask] = inputs[outside_interval_mask] + logabsdet[outside_interval_mask] = 0 + else: + raise RuntimeError('{} tails are not implemented.'.format(tails)) + + outputs[inside_interval_mask], logabsdet[inside_interval_mask] = rational_quadratic_spline( + inputs=inputs[inside_interval_mask], + unnormalized_widths=unnormalized_widths[inside_interval_mask, :], + unnormalized_heights=unnormalized_heights[inside_interval_mask, :], + unnormalized_derivatives=unnormalized_derivatives[inside_interval_mask, :], + inverse=inverse, + left=-tail_bound, right=tail_bound, bottom=-tail_bound, top=tail_bound, + min_bin_width=min_bin_width, + min_bin_height=min_bin_height, + min_derivative=min_derivative + ) + + return outputs, logabsdet + +def rational_quadratic_spline(inputs, + unnormalized_widths, + unnormalized_heights, + unnormalized_derivatives, + inverse=False, + left=0., right=1., bottom=0., top=1., + min_bin_width=DEFAULT_MIN_BIN_WIDTH, + min_bin_height=DEFAULT_MIN_BIN_HEIGHT, + min_derivative=DEFAULT_MIN_DERIVATIVE): + if torch.min(inputs) < left or torch.max(inputs) > right: + raise ValueError('Input to a transform is not within its domain') + + num_bins = unnormalized_widths.shape[-1] + + if min_bin_width * num_bins > 1.0: + raise ValueError('Minimal bin width too large for the number of bins') + if min_bin_height * num_bins > 1.0: + raise ValueError('Minimal bin height too large for the number of bins') + + widths = F.softmax(unnormalized_widths, dim=-1) + widths = min_bin_width + (1 - min_bin_width * num_bins) * widths + cumwidths = torch.cumsum(widths, dim=-1) + cumwidths = F.pad(cumwidths, pad=(1, 0), mode='constant', value=0.0) + cumwidths = (right - left) * cumwidths + left + cumwidths[..., 0] = left + cumwidths[..., -1] = right + widths = cumwidths[..., 1:] - cumwidths[..., :-1] + + derivatives = min_derivative + F.softplus(unnormalized_derivatives) + + heights = F.softmax(unnormalized_heights, dim=-1) + heights = min_bin_height + (1 - min_bin_height * num_bins) * heights + cumheights = torch.cumsum(heights, dim=-1) + cumheights = F.pad(cumheights, pad=(1, 0), mode='constant', value=0.0) + cumheights = (top - bottom) * cumheights + bottom + cumheights[..., 0] = bottom + cumheights[..., -1] = top + heights = cumheights[..., 1:] - cumheights[..., :-1] + + if inverse: + bin_idx = searchsorted(cumheights, inputs)[..., None] + else: + bin_idx = searchsorted(cumwidths, inputs)[..., None] + + input_cumwidths = cumwidths.gather(-1, bin_idx)[..., 0] + input_bin_widths = widths.gather(-1, bin_idx)[..., 0] + + input_cumheights = cumheights.gather(-1, bin_idx)[..., 0] + delta = heights / widths + input_delta = delta.gather(-1, bin_idx)[..., 0] + + input_derivatives = derivatives.gather(-1, bin_idx)[..., 0] + input_derivatives_plus_one = derivatives[..., 1:].gather(-1, bin_idx)[..., 0] + + input_heights = heights.gather(-1, bin_idx)[..., 0] + + if inverse: + a = (((inputs - input_cumheights) * (input_derivatives + + input_derivatives_plus_one + - 2 * input_delta) + + input_heights * (input_delta - input_derivatives))) + b = (input_heights * input_derivatives + - (inputs - input_cumheights) * (input_derivatives + + input_derivatives_plus_one + - 2 * input_delta)) + c = - input_delta * (inputs - input_cumheights) + + discriminant = b.pow(2) - 4 * a * c + assert (discriminant >= 0).all() + + root = (2 * c) / (-b - torch.sqrt(discriminant)) + outputs = root * input_bin_widths + input_cumwidths + + theta_one_minus_theta = root * (1 - root) + denominator = input_delta + ((input_derivatives + input_derivatives_plus_one - 2 * input_delta) + * theta_one_minus_theta) + derivative_numerator = input_delta.pow(2) * (input_derivatives_plus_one * root.pow(2) + + 2 * input_delta * theta_one_minus_theta + + input_derivatives * (1 - root).pow(2)) + logabsdet = torch.log(derivative_numerator) - 2 * torch.log(denominator) + + return outputs, -logabsdet + else: + theta = (inputs - input_cumwidths) / input_bin_widths + theta_one_minus_theta = theta * (1 - theta) + + numerator = input_heights * (input_delta * theta.pow(2) + + input_derivatives * theta_one_minus_theta) + denominator = input_delta + ((input_derivatives + input_derivatives_plus_one - 2 * input_delta) + * theta_one_minus_theta) + outputs = input_cumheights + numerator / denominator + + derivative_numerator = input_delta.pow(2) * (input_derivatives_plus_one * theta.pow(2) + + 2 * input_delta * theta_one_minus_theta + + input_derivatives * (1 - theta).pow(2)) + logabsdet = torch.log(derivative_numerator) - 2 * torch.log(denominator) + + return outputs, logabsdet diff --git a/utils/vits/utils.py b/utils/vits/utils.py new file mode 100644 index 0000000..ee4b01d --- /dev/null +++ b/utils/vits/utils.py @@ -0,0 +1,225 @@ +import os +import sys +import argparse +import logging +import json +import subprocess +import numpy as np +import librosa +import torch + +MATPLOTLIB_FLAG = False + +logging.basicConfig(stream=sys.stdout, level=logging.DEBUG) +logger = logging + + +def load_checkpoint(checkpoint_path, model, optimizer=None): + assert os.path.isfile(checkpoint_path) + checkpoint_dict = torch.load(checkpoint_path, map_location='cpu') + iteration = checkpoint_dict['iteration'] + learning_rate = checkpoint_dict['learning_rate'] + if optimizer is not None: + optimizer.load_state_dict(checkpoint_dict['optimizer']) + saved_state_dict = checkpoint_dict['model'] + if hasattr(model, 'module'): + state_dict = model.module.state_dict() + else: + state_dict = model.state_dict() + new_state_dict= {} + for k, v in state_dict.items(): + try: + new_state_dict[k] = saved_state_dict[k] + except: + logger.info("%s is not in the checkpoint" % k) + new_state_dict[k] = v + if hasattr(model, 'module'): + model.module.load_state_dict(new_state_dict) + else: + model.load_state_dict(new_state_dict) + logger.info("Loaded checkpoint '{}' (iteration {})" .format( + checkpoint_path, iteration)) + return model, optimizer, learning_rate, iteration + + +def plot_spectrogram_to_numpy(spectrogram): + global MATPLOTLIB_FLAG + if not MATPLOTLIB_FLAG: + import matplotlib + matplotlib.use("Agg") + MATPLOTLIB_FLAG = True + mpl_logger = logging.getLogger('matplotlib') + mpl_logger.setLevel(logging.WARNING) + import matplotlib.pylab as plt + import numpy as np + + fig, ax = plt.subplots(figsize=(10,2)) + im = ax.imshow(spectrogram, aspect="auto", origin="lower", + interpolation='none') + plt.colorbar(im, ax=ax) + plt.xlabel("Frames") + plt.ylabel("Channels") + plt.tight_layout() + + fig.canvas.draw() + data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='') + data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close() + return data + + +def plot_alignment_to_numpy(alignment, info=None): + global MATPLOTLIB_FLAG + if not MATPLOTLIB_FLAG: + import matplotlib + matplotlib.use("Agg") + MATPLOTLIB_FLAG = True + mpl_logger = logging.getLogger('matplotlib') + mpl_logger.setLevel(logging.WARNING) + import matplotlib.pylab as plt + import numpy as np + + fig, ax = plt.subplots(figsize=(6, 4)) + im = ax.imshow(alignment.transpose(), aspect='auto', origin='lower', + interpolation='none') + fig.colorbar(im, ax=ax) + xlabel = 'Decoder timestep' + if info is not None: + xlabel += '\n\n' + info + plt.xlabel(xlabel) + plt.ylabel('Encoder timestep') + plt.tight_layout() + + fig.canvas.draw() + data = np.fromstring(fig.canvas.tostring_rgb(), dtype=np.uint8, sep='') + data = data.reshape(fig.canvas.get_width_height()[::-1] + (3,)) + plt.close() + return data + + +def load_audio_to_torch(full_path, target_sampling_rate): + audio, sampling_rate = librosa.load(full_path, sr=target_sampling_rate, mono=True) + return torch.FloatTensor(audio.astype(np.float32)) + + +def load_filepaths_and_text(filename, split="|"): + with open(filename, encoding='utf-8') as f: + filepaths_and_text = [line.strip().split(split) for line in f] + return filepaths_and_text + + +def get_hparams(init=True): + parser = argparse.ArgumentParser() + parser.add_argument('-c', '--config', type=str, default="./configs/base.json", + help='JSON file for configuration') + parser.add_argument('-m', '--model', type=str, required=True, + help='Model name') + + args = parser.parse_args() + model_dir = os.path.join("./logs", args.model) + + if not os.path.exists(model_dir): + os.makedirs(model_dir) + + config_path = args.config + config_save_path = os.path.join(model_dir, "config.json") + if init: + with open(config_path, "r") as f: + data = f.read() + with open(config_save_path, "w") as f: + f.write(data) + else: + with open(config_save_path, "r") as f: + data = f.read() + config = json.loads(data) + + hparams = HParams(**config) + hparams.model_dir = model_dir + return hparams + + +def get_hparams_from_dir(model_dir): + config_save_path = os.path.join(model_dir, "config.json") + with open(config_save_path, "r") as f: + data = f.read() + config = json.loads(data) + + hparams =HParams(**config) + hparams.model_dir = model_dir + return hparams + + +def get_hparams_from_file(config_path): + with open(config_path, "r") as f: + data = f.read() + config = json.loads(data) + + hparams =HParams(**config) + return hparams + + +def check_git_hash(model_dir): + source_dir = os.path.dirname(os.path.realpath(__file__)) + if not os.path.exists(os.path.join(source_dir, ".git")): + logger.warn("{} is not a git repository, therefore hash value comparison will be ignored.".format( + source_dir + )) + return + + cur_hash = subprocess.getoutput("git rev-parse HEAD") + + path = os.path.join(model_dir, "githash") + if os.path.exists(path): + saved_hash = open(path).read() + if saved_hash != cur_hash: + logger.warn("git hash values are different. {}(saved) != {}(current)".format( + saved_hash[:8], cur_hash[:8])) + else: + open(path, "w").write(cur_hash) + + +def get_logger(model_dir, filename="train.log"): + global logger + logger = logging.getLogger(os.path.basename(model_dir)) + logger.setLevel(logging.DEBUG) + + formatter = logging.Formatter("%(asctime)s\t%(name)s\t%(levelname)s\t%(message)s") + if not os.path.exists(model_dir): + os.makedirs(model_dir) + h = logging.FileHandler(os.path.join(model_dir, filename)) + h.setLevel(logging.DEBUG) + h.setFormatter(formatter) + logger.addHandler(h) + return logger + + +class HParams(): + def __init__(self, **kwargs): + for k, v in kwargs.items(): + if type(v) == dict: + v = HParams(**v) + self[k] = v + + def keys(self): + return self.__dict__.keys() + + def items(self): + return self.__dict__.items() + + def values(self): + return self.__dict__.values() + + def __len__(self): + return len(self.__dict__) + + def __getitem__(self, key): + return getattr(self, key) + + def __setitem__(self, key, value): + return setattr(self, key, value) + + def __contains__(self, key): + return key in self.__dict__ + + def __repr__(self): + return self.__dict__.__repr__() diff --git a/utils/vits_utils.py b/utils/vits_utils.py new file mode 100644 index 0000000..1ff919c --- /dev/null +++ b/utils/vits_utils.py @@ -0,0 +1,114 @@ +import os +import numpy as np +import torch +from torch import LongTensor +from typing import Optional +import soundfile as sf +# vits +from .vits import utils, commons +from .vits.models import SynthesizerTrn +from .vits.text import text_to_sequence + +def tts_model_init(model_path='./vits_model', device='cuda'): + hps_ms = utils.get_hparams_from_file(os.path.join(model_path, 'config.json')) + # hps_ms = utils.get_hparams_from_file('vits_model/config.json') + net_g_ms = SynthesizerTrn( + len(hps_ms.symbols), + hps_ms.data.filter_length // 2 + 1, + hps_ms.train.segment_size // hps_ms.data.hop_length, + n_speakers=hps_ms.data.n_speakers, + **hps_ms.model) + net_g_ms = net_g_ms.eval().to(device) + speakers = hps_ms.speakers + utils.load_checkpoint(os.path.join(model_path, 'G_953000.pth'), net_g_ms, None) + # utils.load_checkpoint('vits_model/G_953000.pth', net_g_ms, None) + return hps_ms, net_g_ms, speakers + +class TextToSpeech: + def __init__(self, + model_path="./utils/vits_model", + device='cuda', + RATE=22050, + debug=False, + ): + self.debug = debug + self.RATE = RATE + self.device = torch.device(device) + self.limitation = os.getenv("SYSTEM") == "spaces" # 在huggingface spaces中限制文本和音频长度 + self.hps_ms, self.net_g_ms, self.speakers = self._tts_model_init(model_path) + + def _tts_model_init(self, model_path): + hps_ms = utils.get_hparams_from_file(os.path.join(model_path, 'config.json')) + net_g_ms = SynthesizerTrn( + len(hps_ms.symbols), + hps_ms.data.filter_length // 2 + 1, + hps_ms.train.segment_size // hps_ms.data.hop_length, + n_speakers=hps_ms.data.n_speakers, + **hps_ms.model) + net_g_ms = net_g_ms.eval().to(self.device) + speakers = hps_ms.speakers + utils.load_checkpoint(os.path.join(model_path, 'G_953000.pth'), net_g_ms, None) + if self.debug: + print("Model loaded.") + return hps_ms, net_g_ms, speakers + + def _get_text(self, text): + text_norm, clean_text = text_to_sequence(text, self.hps_ms.symbols, self.hps_ms.data.text_cleaners) + if self.hps_ms.data.add_blank: + text_norm = commons.intersperse(text_norm, 0) + text_norm = LongTensor(text_norm) + return text_norm, clean_text + + def _preprocess_text(self, text, language): + if language == 0: + return f"[ZH]{text}[ZH]" + elif language == 1: + return f"[JA]{text}[JA]" + return text + + def _generate_audio(self, text, speaker_id, noise_scale, noise_scale_w, length_scale): + import time + start_time = time.time() + stn_tst, clean_text = self._get_text(text) + with torch.no_grad(): + x_tst = stn_tst.unsqueeze(0).to(self.device) + x_tst_lengths = LongTensor([stn_tst.size(0)]).to(self.device) + speaker_id = LongTensor([speaker_id]).to(self.device) + audio = self.net_g_ms.infer(x_tst, x_tst_lengths, sid=speaker_id, noise_scale=noise_scale, noise_scale_w=noise_scale_w, + length_scale=length_scale)[0][0, 0].data.cpu().float().numpy() + if self.debug: + print(f"Synthesis time: {time.time() - start_time} s") + return audio + + def synthesize(self, text, tts_info,target_se: Optional[np.ndarray]=None, save_audio=False, return_bytes=True): + if not len(text): + return b'' + text = text.replace('\n', ' ').replace('\r', '').replace(" ", "") + if len(text) > 100 and self.limitation: + return f"输入文字过长!{len(text)}>100", None + text = self._preprocess_text(text, tts_info['language']) + audio = self._generate_audio(text, tts_info['speaker_id'], tts_info['noise_scale'], tts_info['noise_scale_w'], tts_info['length_scale']) + if return_bytes: + audio = self.convert_numpy_to_bytes(audio) + return audio + + def convert_numpy_to_bytes(self, audio_data): + if isinstance(audio_data, np.ndarray): + if audio_data.dtype == np.dtype('float32'): + audio_data = np.int16(audio_data * np.iinfo(np.int16).max) + audio_data = audio_data.tobytes() + return audio_data + else: + raise TypeError("audio_data must be a numpy array") + + def save_audio(self, audio, sample_rate, file_name='output_file.wav'): + sf.write(file_name, audio, samplerate=sample_rate) + print(f"VITS Audio saved to {file_name}") + + + + + + + + diff --git a/utils/xf_asr_utils.py b/utils/xf_asr_utils.py new file mode 100644 index 0000000..3b1b071 --- /dev/null +++ b/utils/xf_asr_utils.py @@ -0,0 +1,67 @@ +import websockets +import datetime +import hashlib +import base64 +import hmac +import json +from urllib.parse import urlencode +from wsgiref.handlers import format_date_time +from datetime import datetime +from time import mktime +from config import Config + +def generate_xf_asr_url(): + #设置讯飞流式听写API相关参数 + APIKey = Config.XF_ASR.API_KEY + APISecret = Config.XF_ASR.API_SECRET + + #鉴权并创建websocket_url + url = 'wss://ws-api.xfyun.cn/v2/iat' + now = datetime.now() + date = format_date_time(mktime(now.timetuple())) + signature_origin = "host: " + "ws-api.xfyun.cn" + "\n" + signature_origin += "date: " + date + "\n" + signature_origin += "GET " + "/v2/iat " + "HTTP/1.1" + signature_sha = hmac.new(APISecret.encode('utf-8'), signature_origin.encode('utf-8'), + digestmod=hashlib.sha256).digest() + signature_sha = base64.b64encode(signature_sha).decode(encoding='utf-8') + authorization_origin = "api_key=\"%s\", algorithm=\"%s\", headers=\"%s\", signature=\"%s\"" % ( + APIKey, "hmac-sha256", "host date request-line", signature_sha) + authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode(encoding='utf-8') + v = { + "authorization": authorization, + "date": date, + "host": "ws-api.xfyun.cn" + } + url = url + '?' + urlencode(v) + return url + + +def make_first_frame(buf): + first_frame = {"common" : {"app_id":Config.XF_ASR.APP_ID},"business" : {"domain":"iat","language":"zh_cn","accent":"mandarin","vad_eos":10000}, + "data":{"status":0,"format":"audio/L16;rate=16000","audio":buf,"encoding":"raw"}} + return json.dumps(first_frame) + +def make_continue_frame(buf): + continue_frame = {"data":{"status":1,"format":"audio/L16;rate=16000","audio":buf,"encoding":"raw"}} + return json.dumps(continue_frame) + +def make_last_frame(buf): + last_frame = {"data":{"status":2,"format":"audio/L16;rate=16000","audio":buf,"encoding":"raw"}} + return json.dumps(last_frame) + +def parse_xfasr_recv(message): + code = message['code'] + if code!=0: + raise Exception("讯飞ASR错误码:"+str(code)) + else: + data = message['data']['result']['ws'] + result = "" + for i in data: + for w in i['cw']: + result += w['w'] + return result + +async def xf_asr_websocket_factory(): + url = generate_xf_asr_url() + return await websockets.connect(url) \ No newline at end of file