This commit is contained in:
yumoqing 2024-12-19 16:50:53 +08:00
parent 0bc047429f
commit a737d25670
14 changed files with 3865 additions and 112 deletions

BIN
app/.f5tts.py.swp Normal file

Binary file not shown.

View File

@ -1,5 +1,4 @@
import sys import sys
sys.path.append('./F5TTS')
import argparse import argparse
import codecs import codecs
import re import re
@ -7,11 +6,11 @@ from pathlib import Path
import numpy as np import numpy as np
import soundfile as sf import soundfile as sf
import tomli # import tomli
from cached_path import cached_path from cached_path import cached_path
from model import DiT, UNetT from f5_tts.model import DiT, UNetT
from model.utils_infer import ( from f5_tts.model.utils_infer import (
load_vocoder, load_vocoder,
load_model, load_model,
preprocess_ref_audio_text, preprocess_ref_audio_text,
@ -23,9 +22,11 @@ import os
import json import json
from time import time from time import time
from appPublic.dictObject import DictObject from appPublic.dictObject import DictObject
from appPublic.zmq_reqrep import ZmqReplier
from appPublic.folderUtils import temp_file from appPublic.folderUtils import temp_file
from appPublic.jsonConfig import getConfig from appPublic.jsonConfig import getConfig
from appPublic.worker import awaitify
from ahserver.webapp import webapp
from ahserver.serverEnv import ServerEnv
n_mel_channels = 100 n_mel_channels = 100
hop_length = 256 hop_length = 256
@ -39,17 +40,10 @@ speed = 1.0
class F5TTS: class F5TTS:
def __init__(self): def __init__(self):
self.config = getConfig() self.config = getConfig()
self.zmq_url = self.config.zmq_url
self.replier = ZmqReplier(self.config.zmq_url, self.generate)
# self.vocos = load_vocoder(is_local=True, local_path="../checkpoints/charactr/vocos-mel-24khz") # self.vocos = load_vocoder(is_local=True, local_path="../checkpoints/charactr/vocos-mel-24khz")
self.load_model() self.load_model()
self.setup_voice() self.setup_voice()
def run(self):
print(f'running {self.zmq_url}')
self.replier._run()
print('ended ...')
def load_model(self): def load_model(self):
# load models # load models
ckpt_file = '' ckpt_file = ''
@ -75,37 +69,6 @@ class F5TTS:
self.config.vocab_file) self.config.vocab_file)
self.model = self.model.to(self.config.device) self.model = self.model.to(self.config.device)
def generate(self, d):
msg= d.decode('utf-8')
data = DictObject(**json.loads(msg))
print(data)
t1 = time()
if data.stream:
for wav in self.inference_stream(data.prompt, stream=data.stream):
d = {
"reqid":data.reqid,
"b64wave":b64str(wav),
"finish":False
}
self.replier.send(json.dumps(d))
t2 = time()
d = {
"reqid":data.reqid,
"time_cost":t2 - t1,
"finish":True
}
return json.dumps(d)
else:
audio_fn = self.inference(data.prompt)
t2 = time()
d = {
"reqid":data.reqid,
"audio_file":audio_fn,
"time_cost":t2 - t1
}
print(f'{d}')
return json.dumps(d)
def setup_voice(self): def setup_voice(self):
main_voice = {"ref_audio": self.config.ref_audio_fn, main_voice = {"ref_audio": self.config.ref_audio_fn,
"ref_text": self.config.ref_text} "ref_text": self.config.ref_text}
@ -123,7 +86,7 @@ class F5TTS:
print("Ref_text:", voices[voice]["ref_text"]) print("Ref_text:", voices[voice]["ref_text"])
self.voices = voices self.voices = voices
def inference_stream(self, prompt): def _inference_stream(self, prompt):
text_gen = prompt text_gen = prompt
remove_silence = False remove_silence = False
generated_audio_segments = [] generated_audio_segments = []
@ -157,11 +120,11 @@ class F5TTS:
'finish':True 'finish':True
} }
def inference(self, prompt): def _inference(self, prompt):
generated_audio_segments = [] generated_audio_segments = []
remove_silence = self.config.remove_silence or False remove_silence = self.config.remove_silence or False
final_sample_rate = 24000 final_sample_rate = 24000
for d in self.inference_stream(prompt): for d in self._inference_stream(prompt):
if not d['finish']: if not d['finish']:
audio = d['audio'] audio = d['audio']
final_sample_rate = d['sample_rate'] final_sample_rate = d['sample_rate']
@ -177,20 +140,11 @@ class F5TTS:
remove_silence_for_generated_wav(f.name) remove_silence_for_generated_wav(f.name)
return fn return fn
def init():
g = ServerEnv()
f5 = F5TTS()
g.infer_stream = awaitify(f5._inference_stream)
g.infer = awaitify(f5._inference)
if __name__ == '__main__': if __name__ == '__main__':
workdir = os.getcwd() webapp(init)
config = getConfig(workdir, {'workdir':workdir})
print(config.ref_audio_fn)
tts = F5TTS()
print('here')
tts.run()
"""
while True:
print('prompt:')
p = input()
if p != '':
t1 = time()
f = tts.inference(p)
t2 = time()
print(f'{f}, cost {t2-t1} seconds')
"""

14
app/w4a2wav.py Normal file
View File

@ -0,0 +1,14 @@
import os
import sys
from pydub import AudioSegment
if len(sys.argv) < 2:
exit(1)
m4afn = sys.argv[1]
wavfn = m4afn[:-3] + 'wav'
# Load the m4a file
audio = AudioSegment.from_file(m4afn, format="m4a")
# Export the audio as a wav file
audio.export(wavfn, format="wav")

View File

@ -1,5 +1,4 @@
{ {
"zmq_url" : "tcp://127.0.0.1:10003",
"sample_rate":16000, "sample_rate":16000,
"vocab_file":"", "vocab_file":"",
"remove_silence":false, "remove_silence":false,
@ -7,6 +6,61 @@
"device":"cuda:0", "device":"cuda:0",
"ref_audio_fn":"$[workdir]$/samples/ttt.wav", "ref_audio_fn":"$[workdir]$/samples/ttt.wav",
"ref_text":"快点吃饭,上课要迟到了。", "ref_text":"快点吃饭,上课要迟到了。",
"cross_fade_duration":0 "cross_fade_duration":0,
"website":{
"paths":[
["$[workdir]$/wwwroot",""]
],
"client_max_size":10000,
"host":"0.0.0.0",
"port":10099,
"coding":"utf-8",
"ssl_gg":{
"crtfile":"$[workdir]$/conf/www.bsppo.com.pem",
"keyfile":"$[workdir]$/conf/www.bsppo.com.key"
},
"indexes":[
"index.html",
"index.tmpl",
"index.ui",
"index.dspy",
"index.md"
],
"startswiths":[
{
"leading":"/idfile",
"registerfunction":"idFileDownload"
}
],
"processors":[
[".ws","ws"],
[".xterm","xterm"],
[".proxy","proxy"],
[".llm", "llm"],
[".llms", "llms"],
[".llma", "llma"],
[".xlsxds","xlsxds"],
[".sqlds","sqlds"],
[".tmpl.js","tmpl"],
[".tmpl.css","tmpl"],
[".html.tmpl","tmpl"],
[".bcrud", "bricks_crud"],
[".tmpl","tmpl"],
[".app","app"],
[".bui","bui"],
[".ui","bui"],
[".dspy","dspy"],
[".md","md"]
],
"rsakey":{
"privatekey":"$[workdir]$/conf/rsa_private_key.pem",
"publickey":"$[workdir]$/conf/rsa_public_key.pem"
},
"session_max_time":3000,
"session_issue_time":2500,
"session_redis_notuse":{
"url":"redis://127.0.0.1:6379"
}
}
} }

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

79
install Executable file
View File

@ -0,0 +1,79 @@
#!/usr/bin/python3
import os
import sys
import codecs
if len(sys.argv) < 3:
print(f'Usage:\n{sys.argv[0]} venvname')
sys.exit(1)
user = os.getlogin()
home = os.environ.get('HOME')
try:
os.mkdir(f'{home}/ve')
except:
pass
venv = sys.argv[1]
port = int(sys.argv[2])
if not os.path.exists(f'{home}/{venv}'):
os.system(f'python3 -m venv ~/{venv}')
pwd = os.getcwd()
name = os.path.basename(pwd)
if os.path.exists(f'./app/{name}.py'):
print('env exists')
sys.exit(1)
dirs = f'./app ./conf ./files ./wwwroot ./script ./logs'.split(' ')
for d in dirs:
try:
os.mkdir(d)
except:
pass
files=f'app/{name}.py conf/config.json files/README.md wwwroot/index.dspy'.split(' ')
for f in files:
os.system(f'touch {f}')
service = f"""[Unit]
Description={name} service
Wants=systemd-networkd.service
Requires=nginx.service
[Service]
Type=forking
ExecStart=su - {user} -c "{pwd}/script/{name}.sh"
ExecStop=su - ymq "{home}/bin/killname {name}.py"
[Install]
WantedBy=multi-user.target
"""
with codecs.open(f'./script/{name}.service', 'w', 'utf-8') as f:
f.write(service)
with codecs.open(f'./script/{name}.sh', 'w', 'utf-8') as f:
f.write(f"""#!/usr/bin/bash
killname {pwd}/app/{name}.py
{home}/{venv}/bin/python {pwd}/app/{name}.py -w {pwd} > {pwd}/logs/stderr.log 2>&1 &
exit 0
""")
with codecs.open(f'./script/install.sh', 'w', 'utf-8') as f:
f.write(f"""#!/usr/bin/bash
sudo cp {name}.service /etc/systemd/system
sudo systemctl enable {name}.service
sudo systemctl start {name}
""")
if not os.path.exists(f'{home}/bin'):
os.mkdir(f'{home}/bin')
if not os.path.exists(f'{home}/bin/killname'):
with codecs.open(f'{home}/bin/killname', 'w', 'utf-8') as f:
f.write("""#!/usr/bin/bash
ps -ef|grep "$1"|grep -v grep|awk '{print("kill -9", $2)}'|sh
""")
os.system(f'chmod +x {pwd}/bin/*')
os.system(f'{pwd}/script/install.sh')

4
run.sh
View File

@ -1,4 +0,0 @@
#!/bin/sh
r=$HOME/ve/f5tts/bin/python
$r $*

13
script/f5tts.service Normal file
View File

@ -0,0 +1,13 @@
[Unit]
Description=f5tts service
Documention=f5tts service to control f5tts service start or stoop
Wants=systemd-networkd.service
Requires=nginx.service
[Service]
Type=forking
ExecStart=su - ymq -c "/d/ymq/py/f5tts/run.sh f5tts.py"
ExecStop=su - ymq "/d/ymq/bin/killname f5tts.py"
[Install]
WantedBy=multi-user.target

BIN
tests/out.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,15 @@
async def g():
async for d in infer_stream(params_kw.prompt):
nd = d.get('audio')
if nd:
yield nd
try:
resp = await stream_response(request, g, content_type='audio/mpeg')
return resp
except Exception as e:
exc = format_exc()
exception(f'{e=}\n{exc}')
return {
"status":"error",
"message":str(e)
}

View File

@ -1,44 +0,0 @@
import sys
import json
import os
from appPublic.dictObject import DictObject
from appPublic.zmq_reqrep import ZmqRequester
from appPublic.jsonConfig import getConfig
from appPublic.uniqueID import getID
zmq_url = "tcp://127.0.0.1:9999"
from time import time
class F5TTSClient:
def __init__(self, zmq_url):
self.zmq_url = zmq_url
self.requester = ZmqRequester(self.zmq_url)
def generate(self, prompt):
d = {
"prompt":prompt,
"reqid":getID()
}
msg = json.dumps(d)
resp = self.requester.send(msg)
if resp != None:
ret = json.loads(resp)
print(f'response={ret}')
else:
print(f'response is None')
def run(self):
print(f'running {self.zmq_url}')
while True:
print('input audio_file:')
af = input()
if len(af) > 0:
self.generate(af)
print('ended ...')
if __name__ == '__main__':
workdir = os.getcwd()
config = getConfig(workdir)
asr = ASRClient(config.zmq_url or zmq_url)
asr.run()