@@ -1154,7 +1154,22 @@ def _on_progress(pct, msg):
11541154
11551155 effective_dir = output_dir or tempfile .gettempdir ()
11561156
1157- if engine == "kokoro" :
1157+ if engine == "chatterbox" :
1158+ from opencut .core .voice_gen import chatterbox_generate
1159+ voice_ref = data .get ("voice_ref" , "" )
1160+ if voice_ref :
1161+ try :
1162+ voice_ref = validate_filepath (voice_ref )
1163+ except ValueError :
1164+ voice_ref = None
1165+ else :
1166+ voice_ref = None
1167+ exaggeration = safe_float (data .get ("exaggeration" , 0.5 ), 0.5 , min_val = 0.0 , max_val = 1.0 )
1168+ out = chatterbox_generate (
1169+ text , voice_ref = voice_ref , output_dir = effective_dir ,
1170+ exaggeration = exaggeration , on_progress = _on_progress ,
1171+ )
1172+ elif engine == "kokoro" :
11581173 from opencut .core .voice_gen import kokoro_generate
11591174 out = kokoro_generate (
11601175 text , voice = voice , output_dir = effective_dir ,
@@ -1697,6 +1712,53 @@ def _p(pct, msg):
16971712 return jsonify ({"job_id" : job_id , "status" : "running" })
16981713
16991714
1715+ @audio_bp .route ("/audio/music-ai/ace-step" , methods = ["POST" ])
1716+ @require_csrf
1717+ def music_ai_ace_step ():
1718+ """Generate music with vocals + lyrics using ACE-Step 1.5."""
1719+ data = request .get_json (force = True )
1720+ prompt = data .get ("prompt" , "" ).strip ()
1721+ lyrics = data .get ("lyrics" , "" ).strip ()
1722+ if not prompt :
1723+ return jsonify ({"error" : "No prompt" }), 400
1724+ if len (lyrics ) > 10000 :
1725+ return jsonify ({"error" : "Lyrics too long (max 10000 chars)" }), 400
1726+
1727+ job_id = _new_job ("ace-step" , prompt [:40 ])
1728+
1729+ def _process ():
1730+ try :
1731+ from opencut .core .music_ai import generate_music_ace_step
1732+
1733+ def _p (pct , msg ):
1734+ _update_job (job_id , progress = pct , message = msg )
1735+
1736+ d = data .get ("output_dir" , "" )
1737+ if d :
1738+ try :
1739+ d = validate_path (d )
1740+ except ValueError as e :
1741+ _update_job (job_id , status = "error" , message = str (e ))
1742+ return
1743+ else :
1744+ d = tempfile .gettempdir ()
1745+ out = generate_music_ace_step (
1746+ prompt , lyrics = lyrics , output_dir = d ,
1747+ duration = safe_float (data .get ("duration" , 30 ), 30.0 , min_val = 10.0 , max_val = 600.0 ),
1748+ on_progress = _p ,
1749+ )
1750+ _update_job (job_id , status = "complete" , progress = 100 , result = {"output_path" : out })
1751+ except Exception as e :
1752+ _update_job (job_id , status = "error" , error = str (e ), message = f"Error: { e } " )
1753+
1754+ thread = threading .Thread (target = _process , daemon = True )
1755+ thread .start ()
1756+ with job_lock :
1757+ if job_id in jobs :
1758+ jobs [job_id ]["_thread" ] = thread
1759+ return jsonify ({"job_id" : job_id , "status" : "running" })
1760+
1761+
17001762@audio_bp .route ("/audio/music-ai/melody" , methods = ["POST" ])
17011763@require_csrf
17021764def music_ai_melody ():
0 commit comments