14
14
from pydantic import BaseModel
15
15
import threading
16
16
import uvicorn
17
+ import logging
17
18
18
- from tools .torchgate import TorchGate
19
- import tools .rvc_for_realtime as rvc_for_realtime
20
- from configs .config import Config
21
-
22
- load_dotenv ()
23
- os .environ ["OMP_NUM_THREADS" ] = "4"
24
- if sys .platform == "darwin" :
25
- os .environ ["PYTORCH_ENABLE_MPS_FALLBACK" ] = "1"
26
-
27
- now_dir = os .getcwd ()
28
- sys .path .append (now_dir )
29
-
30
- stream_latency = - 1
19
+ # Initialize the logger
20
+ logging .basicConfig (level = logging .INFO )
21
+ logger = logging .getLogger (__name__ )
31
22
23
+ # Define FastAPI app
32
24
app = FastAPI ()
33
25
34
26
class GUIConfig :
@@ -69,23 +61,25 @@ class ConfigData(BaseModel):
69
61
class AudioAPI :
70
62
def __init__ (self ) -> None :
71
63
self .gui_config = GUIConfig ()
72
- self .config = Config ()
64
+ self .config = None # Initialize Config object as None
73
65
self .flag_vc = False
74
66
self .function = "vc"
75
67
self .delay_time = 0
68
+ self .rvc = None # Initialize RVC object as None
76
69
77
70
def load (self ):
78
71
input_devices , output_devices , _ , _ = self .get_devices ()
79
72
try :
80
- with open ("configs/config.json" , "r" ) as j :
73
+ with open ("configs/config.json" , "r" , encoding = 'utf-8' ) as j :
81
74
data = json .load (j )
82
75
data ["rmvpe" ] = True # Ensure rmvpe is the only f0method
83
76
if data ["sg_input_device" ] not in input_devices :
84
77
data ["sg_input_device" ] = input_devices [sd .default .device [0 ]]
85
78
if data ["sg_output_device" ] not in output_devices :
86
79
data ["sg_output_device" ] = output_devices [sd .default .device [1 ]]
87
- except :
88
- with open ("configs/config.json" , "w" ) as j :
80
+ except Exception as e :
81
+ logger .error (f"Failed to load configuration: { e } " )
82
+ with open ("configs/config.json" , "w" , encoding = 'utf-8' ) as j :
89
83
data = {
90
84
"pth_path" : " " ,
91
85
"index_path" : " " ,
@@ -102,18 +96,15 @@ def load(self):
102
96
"use_jit" : False ,
103
97
}
104
98
data ["rmvpe" ] = True # Ensure rmvpe is the only f0method
99
+ json .dump (data , j , ensure_ascii = False )
105
100
return data
106
101
107
102
def set_values (self , values ):
108
- if len (values .pth_path .strip ()) == 0 :
103
+ logger .info (f"Setting values: { values } " )
104
+ if not values .pth_path .strip ():
109
105
raise HTTPException (status_code = 400 , detail = "Please select a .pth file" )
110
- if len ( values .index_path .strip ()) == 0 :
106
+ if not values .index_path .strip ():
111
107
raise HTTPException (status_code = 400 , detail = "Please select an index file" )
112
- pattern = re .compile ("[^\x00 -\x7F ]+" )
113
- if pattern .findall (values .pth_path ):
114
- raise HTTPException (status_code = 400 , detail = ".pth file path should not contain non-ASCII characters" )
115
- if pattern .findall (values .index_path ):
116
- raise HTTPException (status_code = 400 , detail = "Index file path should not contain non-ASCII characters" )
117
108
self .set_devices (values .sg_input_device , values .sg_output_device )
118
109
self .config .use_jit = False
119
110
self .gui_config .pth_path = values .pth_path
@@ -143,10 +134,8 @@ def start_vc(self):
143
134
0 ,
144
135
0 ,
145
136
self .config ,
146
- self .rvc if hasattr ( self , " rvc" ) else None ,
137
+ self .rvc if self . rvc else None ,
147
138
)
148
- if not hasattr (self .rvc , 'tgt_sr' ):
149
- self .rvc .tgt_sr = 44100
150
139
self .gui_config .samplerate = self .rvc .tgt_sr
151
140
self .zc = self .rvc .tgt_sr // 100
152
141
self .block_frame = (
@@ -226,8 +215,8 @@ def soundinput(self):
226
215
stream_latency = stream .latency [- 1 ]
227
216
while self .flag_vc :
228
217
time .sleep (self .gui_config .block_time )
229
- print ("Audio block passed." )
230
- print ( "ENDing VC" )
218
+ logger . info ("Audio block passed." )
219
+ logger . info ( "Ending VC" )
231
220
232
221
def audio_callback (self , indata : np .ndarray , outdata : np .ndarray , frames , times , status ):
233
222
start_time = time .perf_counter ()
@@ -289,7 +278,7 @@ def audio_callback(self, indata: np.ndarray, outdata: np.ndarray, frames, times,
289
278
sola_offset = sola_offset .item ()
290
279
else :
291
280
sola_offset = torch .argmax (cor_nom [0 , 0 ] / cor_den [0 , 0 ])
292
- print ( "sola_offset = %d" % int ( sola_offset ) )
281
+ logger . info ( f "sola_offset = { sola_offset } " )
293
282
infer_wav = infer_wav [sola_offset : sola_offset + self .block_frame + self .crossfade_frame ]
294
283
infer_wav [: self .crossfade_frame ] *= self .fade_in_window
295
284
infer_wav [: self .crossfade_frame ] += self .sola_buffer * self .fade_out_window
@@ -299,7 +288,7 @@ def audio_callback(self, indata: np.ndarray, outdata: np.ndarray, frames, times,
299
288
else :
300
289
outdata [:] = infer_wav [: - self .crossfade_frame ].repeat (2 , 1 ).t ().cpu ().numpy ()
301
290
total_time = time .perf_counter () - start_time
302
- print ( "Infer time: % .2f" % total_time )
291
+ logger . info ( f "Infer time: { total_time : .2f} " )
303
292
304
293
def get_devices (self , update : bool = True ):
305
294
if update :
@@ -344,34 +333,61 @@ def set_devices(self, input_device, output_device):
344
333
input_device_indices ,
345
334
output_device_indices ,
346
335
) = self .get_devices ()
336
+ logger .debug (f"Available input devices: { input_devices } " )
337
+ logger .debug (f"Available output devices: { output_devices } " )
338
+ logger .debug (f"Selected input device: { input_device } " )
339
+ logger .debug (f"Selected output device: { output_device } " )
340
+
341
+ if input_device not in input_devices :
342
+ logger .error (f"Input device '{ input_device } ' is not in the list of available devices" )
343
+ raise HTTPException (status_code = 400 , detail = f"Input device '{ input_device } ' is not available" )
344
+
345
+ if output_device not in output_devices :
346
+ logger .error (f"Output device '{ output_device } ' is not in the list of available devices" )
347
+ raise HTTPException (status_code = 400 , detail = f"Output device '{ output_device } ' is not available" )
348
+
347
349
sd .default .device [0 ] = input_device_indices [input_devices .index (input_device )]
348
350
sd .default .device [1 ] = output_device_indices [output_devices .index (output_device )]
349
- print ( "Input device: %s:%s" % ( str ( sd .default .device [0 ]), input_device ) )
350
- print ( "Output device: %s:%s" % ( str ( sd .default .device [1 ]), output_device ) )
351
+ logger . info ( f "Input device set to { sd .default .device [0 ]} : { input_device } " )
352
+ logger . info ( f "Output device set to { sd .default .device [1 ]} : { output_device } " )
351
353
352
354
audio_api = AudioAPI ()
353
355
354
- @app .get ("/inputDevices" )
356
+ @app .get ("/inputDevices" , response_model = list )
355
357
def get_input_devices ():
356
- input_devices , _ , _ , _ = audio_api .get_devices ()
357
- return input_devices
358
+ try :
359
+ input_devices , _ , _ , _ = audio_api .get_devices ()
360
+ return input_devices
361
+ except Exception as e :
362
+ logger .error (f"Failed to get input devices: { e } " )
363
+ raise HTTPException (status_code = 500 , detail = "Failed to get input devices" )
358
364
359
- @app .get ("/outputDevices" )
365
+ @app .get ("/outputDevices" , response_model = list )
360
366
def get_output_devices ():
361
- _ , output_devices , _ , _ = audio_api .get_devices ()
362
- return output_devices
367
+ try :
368
+ _ , output_devices , _ , _ = audio_api .get_devices ()
369
+ return output_devices
370
+ except Exception as e :
371
+ logger .error (f"Failed to get output devices: { e } " )
372
+ raise HTTPException (status_code = 500 , detail = "Failed to get output devices" )
363
373
364
374
@app .post ("/config" )
365
375
def configure_audio (config_data : ConfigData ):
366
376
try :
377
+ logger .info (f"Configuring audio with data: { config_data } " )
367
378
if audio_api .set_values (config_data ):
368
379
settings = config_data .dict ()
369
380
settings ["use_jit" ] = False
370
381
settings ["f0method" ] = "rmvpe"
371
- with open ("configs/config.json" , "w" ) as j :
372
- json .dump (settings , j )
382
+ with open ("configs/config.json" , "w" , encoding = 'utf-8' ) as j :
383
+ json .dump (settings , j , ensure_ascii = False )
384
+ logger .info ("Configuration set successfully" )
373
385
return {"message" : "Configuration set successfully" }
386
+ except HTTPException as e :
387
+ logger .error (f"Configuration error: { e .detail } " )
388
+ raise
374
389
except Exception as e :
390
+ logger .error (f"Configuration failed: { e } " )
375
391
raise HTTPException (status_code = 400 , detail = f"Configuration failed: { e } " )
376
392
377
393
@app .post ("/start" )
@@ -381,8 +397,13 @@ def start_conversion():
381
397
audio_api .start_vc ()
382
398
return {"message" : "Audio conversion started" }
383
399
else :
400
+ logger .warning ("Audio conversion already running" )
384
401
raise HTTPException (status_code = 400 , detail = "Audio conversion already running" )
402
+ except HTTPException as e :
403
+ logger .error (f"Start conversion error: { e .detail } " )
404
+ raise
385
405
except Exception as e :
406
+ logger .error (f"Failed to start conversion: { e } " )
386
407
raise HTTPException (status_code = 500 , detail = f"Failed to start conversion: { e } " )
387
408
388
409
@app .post ("/stop" )
@@ -394,9 +415,25 @@ def stop_conversion():
394
415
stream_latency = - 1
395
416
return {"message" : "Audio conversion stopped" }
396
417
else :
418
+ logger .warning ("Audio conversion not running" )
397
419
raise HTTPException (status_code = 400 , detail = "Audio conversion not running" )
420
+ except HTTPException as e :
421
+ logger .error (f"Stop conversion error: { e .detail } " )
422
+ raise
398
423
except Exception as e :
424
+ logger .error (f"Failed to stop conversion: { e } " )
399
425
raise HTTPException (status_code = 500 , detail = f"Failed to stop conversion: { e } " )
400
426
401
427
if __name__ == "__main__" :
402
- uvicorn .run (app , host = "0.0.0.0" , port = 8043 )
428
+ if sys .platform == "win32" :
429
+ from multiprocessing import freeze_support
430
+ freeze_support ()
431
+ load_dotenv ()
432
+ os .environ ["OMP_NUM_THREADS" ] = "4"
433
+ if sys .platform == "darwin" :
434
+ os .environ ["PYTORCH_ENABLE_MPS_FALLBACK" ] = "1"
435
+ from tools .torchgate import TorchGate
436
+ import tools .rvc_for_realtime as rvc_for_realtime
437
+ from configs .config import Config
438
+ audio_api .config = Config ()
439
+ uvicorn .run (app , host = "0.0.0.0" , port = 6242 )
0 commit comments