CoolFace
Apppublic

lenML/ChatTTS-Forge

sourceHugging Faceagpl-3.0updated 2y agoView on Hugging Face
301likes
google_api.py183 linesDownload Raw Back to impl
1from typing import Union2 3from fastapi import HTTPException4from pydantic import BaseModel5 6from modules.api import utils as api_utils7from modules.api.Api import APIManager8from modules.api.impl.handler.SSMLHandler import SSMLHandler9from modules.api.impl.handler.TTSHandler import TTSHandler10from modules.api.impl.model.audio_model import AdjustConfig, AudioFormat11from modules.api.impl.model.chattts_model import ChatTTSConfig, InferConfig12from modules.api.impl.model.enhancer_model import EnhancerConfig13from modules.speaker import Speaker, speaker_mgr14 15 16class SynthesisInput(BaseModel):17    text: Union[str, None] = None18    ssml: Union[str, None] = None19 20 21class VoiceSelectionParams(BaseModel):22    languageCode: str = "ZH-CN"23 24    name: str = "female2"25    style: str = ""26    temperature: float = 0.327    topP: float = 0.728    topK: int = 2029    seed: int = 4230 31    # end_of_sentence32    eos: str = "[uv_break]"33 34 35class AudioConfig(BaseModel):36    audioEncoding: AudioFormat = AudioFormat.mp337    speakingRate: float = 138    pitch: float = 039    volumeGainDb: float = 040    sampleRateHertz: int = 2400041    batchSize: int = 442    spliterThreshold: int = 10043 44 45class GoogleTextSynthesizeRequest(BaseModel):46    input: SynthesisInput47    voice: VoiceSelectionParams48    audioConfig: AudioConfig49    enhancerConfig: EnhancerConfig = None50 51 52class GoogleTextSynthesizeResponse(BaseModel):53    audioContent: str54 55 56async def google_text_synthesize(request: GoogleTextSynthesizeRequest):57    input = request.input58    voice = request.voice59    audioConfig = request.audioConfig60    enhancerConfig = request.enhancerConfig61 62    # 提取参数63 64    # TODO 这个也许应该传给 normalizer65    language_code = voice.languageCode66    voice_name = voice.name67    infer_seed = voice.seed or 4268    eos = voice.eos or "[uv_break]"69    audio_format = audioConfig.audioEncoding70 71    if not isinstance(audio_format, AudioFormat) and isinstance(audio_format, str):72        audio_format = AudioFormat(audio_format)73 74    speaking_rate = audioConfig.speakingRate or 175    pitch = audioConfig.pitch or 076    volume_gain_db = audioConfig.volumeGainDb or 077 78    batch_size = audioConfig.batchSize or 179 80    spliter_threshold = audioConfig.spliterThreshold or 10081 82    # TODO83    sample_rate = audioConfig.sampleRateHertz or 2400084 85    params = api_utils.calc_spk_style(spk=voice.name, style=voice.style)86 87    # 虽然 calc_spk_style 可以解析 seed 形式,但是这个接口只准备支持 speakers list 中存在的 speaker88    if speaker_mgr.get_speaker(voice_name) is None:89        raise HTTPException(90            status_code=422, detail="The specified voice name is not supported."91        )92 93    if not isinstance(params.get("spk"), Speaker):94        raise HTTPException(95            status_code=422, detail="The specified voice name is not supported."96        )97 98    speaker = params.get("spk")99    tts_config = ChatTTSConfig(100        style=params.get("style", ""),101        temperature=voice.temperature,102        top_k=voice.topK,103        top_p=voice.topP,104    )105    infer_config = InferConfig(106        batch_size=batch_size,107        spliter_threshold=spliter_threshold,108        eos=eos,109        seed=infer_seed,110    )111    adjust_config = AdjustConfig(112        speaking_rate=speaking_rate,113        pitch=pitch,114        volume_gain_db=volume_gain_db,115    )116    enhancer_config = enhancerConfig117 118    mime_type = f"audio/{audio_format.value}"119    if audio_format == AudioFormat.mp3:120        mime_type = "audio/mpeg"121    try:122        if input.text:123            text_content = input.text124 125            handler = TTSHandler(126                text_content=text_content,127                spk=speaker,128                tts_config=tts_config,129                infer_config=infer_config,130                adjust_config=adjust_config,131                enhancer_config=enhancer_config,132            )133 134            base64_string = handler.enqueue_to_base64(format=audio_format)135            return {"audioContent": f"data:{mime_type};base64,{base64_string}"}136 137        elif input.ssml:138            ssml_content = input.ssml139 140            handler = SSMLHandler(141                ssml_content=ssml_content,142                infer_config=infer_config,143                adjust_config=adjust_config,144                enhancer_config=enhancer_config,145            )146 147            base64_string = handler.enqueue_to_base64(format=audio_format)148 149            return {"audioContent": f"data:{mime_type};base64,{base64_string}"}150 151        else:152            raise HTTPException(153                status_code=422, detail="Invalid input text or ssml specified."154            )155 156    except Exception as e:157        import logging158 159        logging.exception(e)160 161        if isinstance(e, HTTPException):162            raise e163        else:164            raise HTTPException(status_code=500, detail=str(e))165 166 167def setup(app: APIManager):168    app.post(169        "/v1/text:synthesize",170        response_model=GoogleTextSynthesizeResponse,171        description="""172google api document: <br/>173[https://cloud.google.com/text-to-speech/docs/reference/rest/v1/text/synthesize](https://cloud.google.com/text-to-speech/docs/reference/rest/v1/text/synthesize)174 175- 多个属性在本系统中无用仅仅是为了兼容google api176- voice 中的 topP, topK, temperature 为本系统中的参数177- voice.name 即 speaker name (或者speaker seed)178- voice.seed 为 infer seed (可在webui中测试具体作用)179 180- 编码格式影响的是 audioContent 的二进制格式,所以所有format都是返回带有base64数据的json181        """,182    )(google_text_synthesize)183