From 284a0e87ff06d8c59f356e6d9b53072e14a455ff Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:20:34 +0800 Subject: [PATCH 1/8] Update server.py , add API respose --- server.py | 134 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 75 insertions(+), 59 deletions(-) diff --git a/server.py b/server.py index d458775..d167ffe 100644 --- a/server.py +++ b/server.py @@ -23,7 +23,13 @@ format="%(asctime)s - %(levelname)-7s: %(message)s", datefmt="%Y-%m-%d %H:%M:%S") +''' +GET /version HTTP/1.1 +HTTP/1.1 200 OK +Content-Type:application/json +{"version": "1.0.1", "date": "2023-01-08"} +''' def version(request: BaseHTTPRequestHandler): v = { 'version': VERSION, @@ -34,7 +40,13 @@ def version(request: BaseHTTPRequestHandler): request.end_headers() request.wfile.write(json.dumps(v).encode('utf8')) +''' +GET /models HTTP/1.1 +HTTP/1.1 200 OK +Content-Type:application/json +{"models": ["1215_opencpop_ds1000_fix_label_nomidi"]} +''' def models(request: BaseHTTPRequestHandler): res = { 'models': [os.path.basename(file)[:-5] for file in glob.glob(os.path.join(ACOUSTIC_ROOT, '*.onnx'))] @@ -44,37 +56,25 @@ def models(request: BaseHTTPRequestHandler): request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) +""" +POST /rhythm HTTP/1.1 +Content-Type:application/json +{ + "notes":[ + {"key": 0,"duration": 0.5,"slur": false,"phonemes": ["SP"]}, + {"key": 69,"duration": 0.5,"slur": false,"phonemes": ["sh","a"]}, + {"key": 71,"duration": 1.0,"slur": true} + ] +} +HTTP/1.1 200 OK +Content-Type:application/json +{"phonemes":[ + {"name": "SP", "duration": 0.235995352268219}, + {"name": "sh", "duration": 0.264004647731781}, {"name": "a", "duration": 1.5} +]} +""" def rhythm(request: BaseHTTPRequestHandler): - """ - Example: - { - "notes": [ - { - "key": 0, - "duration": 0.5, - "slur": false, - "phonemes": [ - "SP" - ] - }, - { - "key": 69, - "duration": 0.5, - "slur": false, - "phonemes": [ - "sh", - "a" - ] - }, - { - "key": 71, - "duration": 1.0, - "slur": true - } - ] - } - """ request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) ph_seq, ph_dur = synthesis.predict_rhythm(request_body['notes'], phoneme_list, vowels, config) res = { @@ -90,36 +90,32 @@ def rhythm(request: BaseHTTPRequestHandler): request.send_header('Content-Type', 'application/json') request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) + +""" +POST /submit HTTP/1.1 +Content-Type:application/json +{ + "model": "1215_opencpop_ds1000_fix_label_nomidi", + "phonemes": [ + {"name": "SP","duration": 0.5}, + {"name": "SP","duration": 0.5} + ], + "f0":{ + "timestep": 0.01, + "values": [440.0,440.0,440.0,440.0,440.0] + }, + "speedup": 50 +} - +HTTP/1.1 200 OK +Content-Type:application/json +{ + "token": "afbc3057747f0cd98b67f01038855380", + "status": "SUBMITTED", + "code": "ae67" +} +""" def submit(request: BaseHTTPRequestHandler): - """ - Example: - { - "model": "1215_opencpop_ds1000_fix_label_nomidi", - "phonemes": [ - { - "name": "SP", - "duration": 0.5 - }, - { - "name": "SP", - "duration": 0.5 - } - ], - "f0": { - "timestep": 0.01, - "values": [ - 440.0, - 440.0, - 440.0, - 440.0, - 440.0 - ] - }, - "speedup": 50 - } - """ request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) if 'speedup' not in request_body: request_body['speedup'] = config['acoustic']['speedup'] @@ -151,8 +147,17 @@ def submit(request: BaseHTTPRequestHandler): request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) +''' +POST /submit HTTP/1.1 +Content-Type:application/json +{"token": "afbc3057747f0cd98b67f01038855380"} +HTTP/1.1 200 OK +Content-Type:application/json +{"status": "HIT_CACHE"} +''' def query(request: BaseHTTPRequestHandler): + request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) token = request_body['token'] cache_file = os.path.join(cache, f'{token}.wav') @@ -198,8 +203,14 @@ def query(request: BaseHTTPRequestHandler): request.send_error(404) mutex.release() - +''' +POST /cancel HTTP/1.1 +Content-Type:application/json +{"token": "afbc3057747f0cd98b67f01038855380","code":"ae67"} +{"succeeded": false,"message": "Task result already in cache."} +''' def cancel(request: BaseHTTPRequestHandler): + request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) token = request_body['token'] code = request_body['code'] @@ -229,7 +240,12 @@ def cancel(request: BaseHTTPRequestHandler): request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) +''' +GET /download?token=afbc3057747f0cd98b67f01038855380 HTTP/1.1 +HTTP/1.1 200 ok +content-type: audio/wav +''' def download(request: BaseHTTPRequestHandler): params = dict(urllib.parse.parse_qsl(urllib.parse.urlsplit(request.path).query)) token = params['token'] @@ -289,7 +305,7 @@ def _execute(request: dict, cache_file: str, token: str): '/download': (download, ['GET']) } mutex = threading.Lock() - + class Request(BaseHTTPRequestHandler): def do_GET(self): From 2c8df095d6d84da3059e5095617e2ea37c5370c8 Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Tue, 11 Jul 2023 14:27:43 +0800 Subject: [PATCH 2/8] Update server.py /query --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index d167ffe..3ff087b 100644 --- a/server.py +++ b/server.py @@ -148,7 +148,7 @@ def submit(request: BaseHTTPRequestHandler): request.wfile.write(json.dumps(res).encode('utf8')) ''' -POST /submit HTTP/1.1 +POST /query HTTP/1.1 Content-Type:application/json {"token": "afbc3057747f0cd98b67f01038855380"} From 249c271a58bd1e4e58754db5d5097ec4911b4bdd Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Tue, 11 Jul 2023 15:18:23 +0800 Subject: [PATCH 3/8] =?UTF-8?q?Update=20server.py=20=E6=9C=89error?= =?UTF-8?q?=E4=B8=80=E5=BE=8B400?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- server.py | 94 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 70 insertions(+), 24 deletions(-) diff --git a/server.py b/server.py index 3ff087b..e642bf6 100644 --- a/server.py +++ b/server.py @@ -75,30 +75,40 @@ def models(request: BaseHTTPRequestHandler): ]} """ def rhythm(request: BaseHTTPRequestHandler): - request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) - ph_seq, ph_dur = synthesis.predict_rhythm(request_body['notes'], phoneme_list, vowels, config) - res = { - 'phonemes': [ - { - 'name': name, - 'duration': duration - } - for name, duration in zip(ph_seq, ph_dur) - ] - } - request.send_response(200) - request.send_header('Content-Type', 'application/json') - request.end_headers() - request.wfile.write(json.dumps(res).encode('utf8')) + try: + request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) + ph_seq, ph_dur = synthesis.predict_rhythm(request_body['notes'], phoneme_list, vowels, config) + res = { + 'phonemes': [ + { + 'name': name, + 'duration': duration + } + for name, duration in zip(ph_seq, ph_dur) + ] + } + request.send_response(200) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + except Exception as e: + res = { + 'error': str(repr(e)) + } + request.send_response(400) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + raise e """ POST /submit HTTP/1.1 Content-Type:application/json { "model": "1215_opencpop_ds1000_fix_label_nomidi", - "phonemes": [ - {"name": "SP","duration": 0.5}, - {"name": "SP","duration": 0.5} + "phonemes":[ + {"name": "SP", "duration": 0.235995352268219}, + {"name": "sh", "duration": 0.264004647731781}, {"name": "a", "duration": 1.5} ], "f0":{ "timestep": 0.01, @@ -116,6 +126,7 @@ def rhythm(request: BaseHTTPRequestHandler): } """ def submit(request: BaseHTTPRequestHandler): + try: request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) if 'speedup' not in request_body: request_body['speedup'] = config['acoustic']['speedup'] @@ -146,9 +157,18 @@ def submit(request: BaseHTTPRequestHandler): request.send_header('Content-Type', 'application/json') request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) + except Exception as e: + res = { + 'error': str(repr(e)) + } + request.send_response(400) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + raise e ''' -POST /query HTTP/1.1 +POST /queryHTTP/1.1 Content-Type:application/json {"token": "afbc3057747f0cd98b67f01038855380"} @@ -157,9 +177,10 @@ def submit(request: BaseHTTPRequestHandler): {"status": "HIT_CACHE"} ''' def query(request: BaseHTTPRequestHandler): - + try: request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) token = request_body['token'] + cache_file = os.path.join(cache, f'{token}.wav') if os.path.exists(cache_file): res = { @@ -202,7 +223,15 @@ def query(request: BaseHTTPRequestHandler): else: request.send_error(404) mutex.release() - + except Exception as e: + res = { + 'error': str(repr(e)) + } + request.send_response(400) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + raise e ''' POST /cancel HTTP/1.1 Content-Type:application/json @@ -210,7 +239,7 @@ def query(request: BaseHTTPRequestHandler): {"succeeded": false,"message": "Task result already in cache."} ''' def cancel(request: BaseHTTPRequestHandler): - + try: request_body = json.loads(request.rfile.read(int(request.headers['Content-Length']))) token = request_body['token'] code = request_body['code'] @@ -239,7 +268,15 @@ def cancel(request: BaseHTTPRequestHandler): request.send_header('Content-Type', 'application/json') request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) - + except Exception as e: + res = { + 'error': str(repr(e)) + } + request.send_response(400) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + raise e ''' GET /download?token=afbc3057747f0cd98b67f01038855380 HTTP/1.1 @@ -247,6 +284,7 @@ def cancel(request: BaseHTTPRequestHandler): content-type: audio/wav ''' def download(request: BaseHTTPRequestHandler): + try: params = dict(urllib.parse.parse_qsl(urllib.parse.urlsplit(request.path).query)) token = params['token'] cache_file = os.path.join(cache, f'{token}.wav') @@ -258,7 +296,15 @@ def download(request: BaseHTTPRequestHandler): request.wfile.write(f.read()) else: request.send_response(404) - + except Exception as e: + res = { + 'error': str(repr(e)) + } + request.send_response(400) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + raise e def _execute(request: dict, cache_file: str, token: str): logging.info(f'Task \'{token}\' begins') From 3d0f95d6308043c701ad0b10ab2bde7e7d854abd Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:16:03 +0800 Subject: [PATCH 4/8] Update README.md API --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 89 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 73c630e..41262dd 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ A minimum inference engine for DiffSinger MIDI-less mode. ## Getting Started -1. Install `onnxruntime` following the [official guidance](https://onnxruntime.ai/). +1. Install `onnxruntime` following the [official guidance](https://onnxruntime.ai/). `pip install onnxruntime-gpu` 2. Install other dependencies with `pip install PyYAML soundfile`. 3. Download ONNX version of the NSF-HiFiGAN vocoder from [here](https://github.com/openvpi/vocoders/releases/tag/nsf-hifigan-v1) and unzip it into `assets/vocoder` directory. 4. Download an ONNX rhythm predictor from [here](https://github.com/openvpi/DiffSinger/releases/tag/v1.4.1) and put it into `assets/rhythmizer` directory. @@ -12,8 +12,95 @@ A minimum inference engine for DiffSinger MIDI-less mode. 7. Run server with `python server.py` or `python server.py --config `. ## API Specification +* 版本信息 -TBD +``` +GET /version HTTP/1.1 + +HTTP/1.1 200 OK +{"version": "1.0.1", "date": "2023-01-08"} +``` + +* 模型列表 +``` +GET /models HTTP/1.1 + +HTTP/1.1 200 OK +Content-Type:application/json +{"models": ["1215_opencpop_ds1000_fix_label_nomidi"]} +``` +* 生成节奏 +``` +POST /rhythm HTTP/1.1 +Content-Type:application/json +{ + "notes":[ + {"key": 0,"duration": 0.5,"slur": false,"phonemes": ["SP"]}, + {"key": 69,"duration": 0.5,"slur": false,"phonemes": ["sh","a"]}, + {"key": 71,"duration": 1.0,"slur": true} + ] +} + +HTTP/1.1 200 OK +Content-Type:application/json +{"phonemes":[ + {"name": "SP", "duration": 0.235995352268219}, + {"name": "sh", "duration": 0.264004647731781}, + {"name": "a", "duration": 1.5} +]} +``` + +* 提交 +``` +POST /submit HTTP/1.1 +Content-Type:application/json +{ + "model": "1215_opencpop_ds1000_fix_label_nomidi", + "phonemes":[ + {"name": "SP", "duration": 0.235995352268219}, + {"name": "sh", "duration": 0.264004647731781}, + {"name": "a", "duration": 1.5} + ], + "f0":{ + "timestep": 0.01, + "values": [440.0,440.0,440.0,440.0,440.0] + }, + "speedup": 50 +} + +HTTP/1.1 200 OK +Content-Type:application/json +{ + "token": "afbc3057747f0cd98b67f01038855380", + "status": "SUBMITTED", + "code": "ae67" +} +``` +* 查询 +``` +POST /query HTTP/1.1 +Content-Type:application/json +{"token": "afbc3057747f0cd98b67f01038855380"} + +HTTP/1.1 200 OK +Content-Type:application/json +{"status": "HIT_CACHE"} +``` + +* 取消任务 +``` +POST /cancel HTTP/1.1 +Content-Type:application/json +{"token": "afbc3057747f0cd98b67f01038855380","code":"ae67"} +{"succeeded": false,"message": "Task result already in cache."} +``` +* 下载文件 +``` +GET /download?token=afbc3057747f0cd98b67f01038855380 HTTP/1.1 + +HTTP/1.1 200 ok +content-type: audio/wav +``` ## How to Obtain Acoustic Models From ad43415ce4cb731f681d445ed0c59ccfddabac71 Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Tue, 11 Jul 2023 18:16:31 +0800 Subject: [PATCH 5/8] Update server.py --- server.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server.py b/server.py index e642bf6..2aa8e0b 100644 --- a/server.py +++ b/server.py @@ -168,7 +168,7 @@ def submit(request: BaseHTTPRequestHandler): raise e ''' -POST /queryHTTP/1.1 +POST /query HTTP/1.1 Content-Type:application/json {"token": "afbc3057747f0cd98b67f01038855380"} From 478df2ca077ff946a9936745237e2cabda134b11 Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Sun, 31 Mar 2024 22:19:09 +0800 Subject: [PATCH 6/8] add getdict --- requirements.txt | 5 +++++ server.py | 13 ++++++++++++- synthesis.py | 4 ++++ utils.py | 1 - 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..f73d389 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,5 @@ +onnxruntime-gpu +PyYAML +soundfile +librosa +httpx diff --git a/server.py b/server.py index 2aa8e0b..8dbbda8 100644 --- a/server.py +++ b/server.py @@ -56,6 +56,14 @@ def models(request: BaseHTTPRequestHandler): request.end_headers() request.wfile.write(json.dumps(res).encode('utf8')) + +def getdict(request: BaseHTTPRequestHandler): + res = dictionary + request.send_response(200) + request.send_header('Content-Type', 'application/json') + request.end_headers() + request.wfile.write(json.dumps(res).encode('utf8')) + """ POST /rhythm HTTP/1.1 Content-Type:application/json @@ -71,7 +79,8 @@ def models(request: BaseHTTPRequestHandler): Content-Type:application/json {"phonemes":[ {"name": "SP", "duration": 0.235995352268219}, - {"name": "sh", "duration": 0.264004647731781}, {"name": "a", "duration": 1.5} + {"name": "sh", "duration": 0.264004647731781}, + {"name": "a", "duration": 1.5} ]} """ def rhythm(request: BaseHTTPRequestHandler): @@ -101,6 +110,7 @@ def rhythm(request: BaseHTTPRequestHandler): request.wfile.write(json.dumps(res).encode('utf8')) raise e + """ POST /submit HTTP/1.1 Content-Type:application/json @@ -344,6 +354,7 @@ def _execute(request: dict, cache_file: str, token: str): apis = { '/version': (version, ['GET']), '/models': (models, ['GET']), + '/getdict': (getdict, ['GET']), '/rhythm': (rhythm, ['POST']), '/submit': (submit, ['POST']), '/query': (query, ['POST']), diff --git a/synthesis.py b/synthesis.py index 938adcf..f52c059 100644 --- a/synthesis.py +++ b/synthesis.py @@ -118,12 +118,16 @@ def acoustic_preprocess(name2token: list, def acoustic_infer(model: str, providers: list, tokens, durations, f0, speedup): session = utils.create_session(model, providers) mel = session.run(['mel'], {'tokens': tokens, 'durations': durations, 'f0': f0, 'speedup': speedup})[0] + session.end_profiling() + del(session) return mel def vocoder_infer(model: str, providers: list, mel, f0, force_on_cpu=True): session = utils.create_session(model, providers, force_on_cpu=force_on_cpu) waveform = session.run(['waveform'], {'mel': mel, 'f0': f0})[0] + session.end_profiling() + del(session) return waveform diff --git a/utils.py b/utils.py index 65b1c6b..62befb1 100644 --- a/utils.py +++ b/utils.py @@ -62,7 +62,6 @@ def create_session(model_path: str, providers: list, force_on_cpu: bool = False) # Create inference session session = ort.InferenceSession(path_or_bytes=model_path, sess_options=options, providers=providers) - return session From 3df1503d4ed85838e58f1fa25c86ad4bfefb89b3 Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:14:12 +0800 Subject: [PATCH 7/8] Update README.md --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 41262dd..f446a57 100644 --- a/README.md +++ b/README.md @@ -106,3 +106,8 @@ content-type: audio/wav 1. [Train with your own dataset](https://github.com/openvpi/DiffSinger/blob/refactor/pipelines/no_midi_preparation.ipynb) or download pretrained checkpoints from [here](https://github.com/openvpi/DiffSinger/releases/tag/v1.4.0). 2. Export PyTorch checkpoints to ONNX format. See instructions [here](https://github.com/openvpi/DiffSinger/blob/refactor/docs/README-SVS-onnx.md). + +## 声明: + 请确保你制作数据集的数据来源合法合规,且数据提供者明确你在制作什么以及可能造成的后果 + 该项目为歌声合成项目,无法进行其他用途,请知晓 + From 6fce28b4259f522ce6c3cb291d491f997cd6da9a Mon Sep 17 00:00:00 2001 From: zhzhongshi <39423408+zhzhongshi@users.noreply.github.com> Date: Fri, 5 Apr 2024 09:18:37 +0800 Subject: [PATCH 8/8] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f446a57..5830b5b 100644 --- a/README.md +++ b/README.md @@ -110,4 +110,5 @@ content-type: audio/wav ## 声明: 请确保你制作数据集的数据来源合法合规,且数据提供者明确你在制作什么以及可能造成的后果 该项目为歌声合成项目,无法进行其他用途,请知晓 + 本项目数据集来源:[Opencpop](https://wenet.org.cn/opencpop/liscense/)