codemo/fish-speech-1
0
1import argparse2import base643import wave4 5import ormsgpack6import pyaudio7import requests8from pydub import AudioSegment9from pydub.playback import play10 11from tools.commons import ServeReferenceAudio, ServeTTSRequest12from tools.file import audio_to_bytes, read_ref_text13 14 15def parse_args():16 17 parser = argparse.ArgumentParser(18 description="Send a WAV file and text to a server and receive synthesized audio."19 )20 21 parser.add_argument(22 "--url",23 "-u",24 type=str,25 default="http://127.0.0.1:8080/v1/tts",26 help="URL of the server",27 )28 parser.add_argument(29 "--text", "-t", type=str, required=True, help="Text to be synthesized"30 )31 parser.add_argument(32 "--reference_id",33 "-id",34 type=str,35 default=None,36 help="ID of the reference model o be used for the speech",37 )38 parser.add_argument(39 "--reference_audio",40 "-ra",41 type=str,42 nargs="+",43 default=None,44 help="Path to the WAV file",45 )46 parser.add_argument(47 "--reference_text",48 "-rt",49 type=str,50 nargs="+",51 default=None,52 help="Reference text for voice synthesis",53 )54 parser.add_argument(55 "--output",56 "-o",57 type=str,58 default="generated_audio",59 help="Output audio file name",60 )61 parser.add_argument(62 "--play",63 type=bool,64 default=True,65 help="Whether to play audio after receiving data",66 )67 parser.add_argument("--normalize", type=bool, default=True)68 parser.add_argument(69 "--format", type=str, choices=["wav", "mp3", "flac"], default="wav"70 )71 parser.add_argument("--mp3_bitrate", type=int, default=64)72 parser.add_argument("--opus_bitrate", type=int, default=-1000)73 parser.add_argument("--latency", type=str, default="normal", help="延迟选项")74 parser.add_argument(75 "--max_new_tokens",76 type=int,77 default=1024,78 help="Maximum new tokens to generate",79 )80 parser.add_argument(81 "--chunk_length", type=int, default=100, help="Chunk length for synthesis"82 )83 parser.add_argument(84 "--top_p", type=float, default=0.7, help="Top-p sampling for synthesis"85 )86 parser.add_argument(87 "--repetition_penalty",88 type=float,89 default=1.2,90 help="Repetition penalty for synthesis",91 )92 parser.add_argument(93 "--temperature", type=float, default=0.7, help="Temperature for sampling"94 )95 parser.add_argument(96 "--speaker", type=str, default=None, help="Speaker ID for voice synthesis"97 )98 parser.add_argument("--emotion", type=str, default=None, help="Speaker's Emotion")99 parser.add_argument(100 "--streaming", type=bool, default=False, help="Enable streaming response"101 )102 parser.add_argument(103 "--channels", type=int, default=1, help="Number of audio channels"104 )105 parser.add_argument("--rate", type=int, default=44100, help="Sample rate for audio")106 107 return parser.parse_args()108 109 110if __name__ == "__main__":111 112 args = parse_args()113 114 idstr: str | None = args.reference_id115 # priority: ref_id > [{text, audio},...]116 if idstr is None:117 ref_audios = args.reference_audio118 ref_texts = args.reference_text119 if ref_audios is None:120 byte_audios = []121 else:122 byte_audios = [audio_to_bytes(ref_audio) for ref_audio in ref_audios]123 if ref_texts is None:124 ref_texts = []125 else:126 ref_texts = [read_ref_text(ref_text) for ref_text in ref_texts]127 else:128 byte_audios = []129 ref_texts = []130 pass # in api.py131 132 data = {133 "text": args.text,134 "references": [135 ServeReferenceAudio(audio=ref_audio, text=ref_text)136 for ref_text, ref_audio in zip(ref_texts, byte_audios)137 ],138 "reference_id": idstr,139 "normalize": args.normalize,140 "format": args.format,141 "mp3_bitrate": args.mp3_bitrate,142 "opus_bitrate": args.opus_bitrate,143 "max_new_tokens": args.max_new_tokens,144 "chunk_length": args.chunk_length,145 "top_p": args.top_p,146 "repetition_penalty": args.repetition_penalty,147 "temperature": args.temperature,148 "speaker": args.speaker,149 "emotion": args.emotion,150 "streaming": args.streaming,151 }152 153 pydantic_data = ServeTTSRequest(**data)154 155 response = requests.post(156 args.url,157 data=ormsgpack.packb(pydantic_data, option=ormsgpack.OPT_SERIALIZE_PYDANTIC),158 stream=args.streaming,159 headers={160 "authorization": "Bearer YOUR_API_KEY",161 "content-type": "application/msgpack",162 },163 )164 165 if response.status_code == 200:166 if args.streaming:167 p = pyaudio.PyAudio()168 audio_format = pyaudio.paInt16 # Assuming 16-bit PCM format169 stream = p.open(170 format=audio_format, channels=args.channels, rate=args.rate, output=True171 )172 173 wf = wave.open(f"{args.output}.wav", "wb")174 wf.setnchannels(args.channels)175 wf.setsampwidth(p.get_sample_size(audio_format))176 wf.setframerate(args.rate)177 178 stream_stopped_flag = False179 180 try:181 for chunk in response.iter_content(chunk_size=1024):182 if chunk:183 stream.write(chunk)184 wf.writeframesraw(chunk)185 else:186 if not stream_stopped_flag:187 stream.stop_stream()188 stream_stopped_flag = True189 finally:190 stream.close()191 p.terminate()192 wf.close()193 else:194 audio_content = response.content195 audio_path = f"{args.output}.{args.format}"196 with open(audio_path, "wb") as audio_file:197 audio_file.write(audio_content)198 199 audio = AudioSegment.from_file(audio_path, format=args.format)200 if args.play:201 play(audio)202 print(f"Audio has been saved to '{audio_path}'.")203 else:204 print(f"Request failed with status code {response.status_code}")205 print(response.json())206 