Spaces:
Running
on
A10G
Running
on
A10G
| """ | |
| MagicPath AI Vocal Effects Server - DiffVox LLM ํตํฉ ๋ฒ์ | |
| ========================================================= | |
| """ | |
| from fastapi import FastAPI, UploadFile, File, Form, HTTPException | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from pathlib import Path | |
| import tempfile | |
| import os | |
| import uuid | |
| import base64 | |
| import logging | |
| from datetime import datetime | |
| # ๋ก๊น ์ค์ | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| print(f"\n===== Application Startup at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} =====\n") | |
| # ๋ด๋ถ ๋ชจ๋ | |
| from models.ai_effector import AIEffector | |
| from audio_processing.effect_chain import EffectChain | |
| # ============================================ | |
| # ์ค์ | |
| # ============================================ | |
| # ํ์ต๋ ๋ชจ๋ธ ๊ฒฝ๋ก - repo_id์ subfolder ๋ถ๋ฆฌ! | |
| MODEL_REPO_ID = os.environ.get("DIFFVOX_MODEL_REPO", "heybaeheef/KU_SW_Academy") | |
| MODEL_SUBFOLDER = os.environ.get("DIFFVOX_MODEL_SUBFOLDER", "checkpoints") | |
| BASE_MODEL_NAME = os.environ.get("BASE_MODEL_NAME", "Qwen/Qwen3-8B") | |
| AUDIO_FEATURE_DIM = int(os.environ.get("AUDIO_FEATURE_DIM", "64")) | |
| USE_HUGGINGFACE = os.environ.get("USE_HUGGINGFACE", "true").lower() == "true" | |
| # ์์ ํ์ผ ์ ์ฅ ๊ฒฝ๋ก | |
| TEMP_DIR = Path(tempfile.gettempdir()) / "magicpath" | |
| TEMP_DIR.mkdir(exist_ok=True) | |
| # ============================================ | |
| # FastAPI ์ฑ ์ด๊ธฐํ | |
| # ============================================ | |
| app = FastAPI( | |
| title="MagicPath AI Vocal Effects", | |
| description="AI-powered vocal effect processing server (DiffVox LLM ํตํฉ)", | |
| version="2.0.0" | |
| ) | |
| # CORS ์ค์ | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| # ์ ์ญ ๊ฐ์ฒด ์ด๊ธฐํ | |
| print("=" * 60) | |
| print("MagicPath AI Vocal Effects Server v2.0") | |
| print("=" * 60) | |
| print(f"Model Repo: {MODEL_REPO_ID}") | |
| print(f"Model Subfolder: {MODEL_SUBFOLDER}") | |
| print(f"Base Model: {BASE_MODEL_NAME}") | |
| print(f"Audio Feature Dim: {AUDIO_FEATURE_DIM}") | |
| print(f"Use Hugging Face: {USE_HUGGINGFACE}") | |
| print("=" * 60) | |
| ai_effector = AIEffector( | |
| model_repo_id=MODEL_REPO_ID, | |
| model_subfolder=MODEL_SUBFOLDER, | |
| base_model_name=BASE_MODEL_NAME, | |
| audio_feature_dim=AUDIO_FEATURE_DIM, | |
| use_huggingface=USE_HUGGINGFACE | |
| ) | |
| effect_chain = EffectChain() | |
| # ============================================ | |
| # API ์๋ํฌ์ธํธ | |
| # ============================================ | |
| async def root(): | |
| """์๋ฒ ์ ๋ณด""" | |
| return { | |
| "status": "running", | |
| "message": "MagicPath AI Vocal Effects Server v2.0 (DiffVox LLM)", | |
| "ai_model_loaded": ai_effector.is_loaded(), | |
| "model_repo": MODEL_REPO_ID, | |
| "model_subfolder": MODEL_SUBFOLDER, | |
| "endpoints": { | |
| "POST /process": "์ค๋์ค ํ์ผ ์ฒ๋ฆฌ ํ ๋ฐํ", | |
| "POST /predict": "ํ๋ผ๋ฏธํฐ๋ง ์์ธก (JSON)", | |
| "POST /process_with_params": "์ค๋์ค ์ฒ๋ฆฌ + ํ๋ผ๋ฏธํฐ ๋ฐํ", | |
| "GET /health": "์๋ฒ ์ํ ํ์ธ" | |
| } | |
| } | |
| async def health_check(): | |
| """์๋ฒ ๋ฐ ๋ชจ๋ธ ์ํ ํ์ธ""" | |
| return { | |
| "status": "healthy", | |
| "ai_model_loaded": ai_effector.is_loaded(), | |
| "supported_effects": effect_chain.get_available_effects(), | |
| "model_repo": MODEL_REPO_ID, | |
| "base_model": BASE_MODEL_NAME | |
| } | |
| async def predict_parameters( | |
| audio: UploadFile = File(..., description="Dry ๋ณด์ปฌ ์ค๋์ค ํ์ผ"), | |
| prompt: str = Form("", description="ํ ์คํธ ๋ช ๋ น (์: 'warm', 'bright')") | |
| ): | |
| """AI ๋ชจ๋ธ๋ก ์ดํํฐ ํ๋ผ๋ฏธํฐ ์์ธก""" | |
| try: | |
| input_path = TEMP_DIR / f"{uuid.uuid4()}_{audio.filename}" | |
| with open(input_path, "wb") as f: | |
| content = await audio.read() | |
| f.write(content) | |
| parameters = ai_effector.predict( | |
| audio_path=str(input_path), | |
| text_prompt=prompt | |
| ) | |
| os.remove(input_path) | |
| return JSONResponse(content={ | |
| "status": "success", | |
| "prompt": prompt, | |
| "ai_model_used": ai_effector.is_loaded(), | |
| "parameters": parameters | |
| }) | |
| except Exception as e: | |
| logger.error(f"Predict error: {e}") | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def process_audio( | |
| audio: UploadFile = File(..., description="Dry ๋ณด์ปฌ ์ค๋์ค ํ์ผ"), | |
| prompt: str = Form("", description="ํ ์คํธ ๋ช ๋ น (์: 'warm', 'bright')") | |
| ): | |
| """AI๊ฐ ์์ธกํ ํ๋ผ๋ฏธํฐ๋ก ์ค์ ์ค๋์ค ์ฒ๋ฆฌ""" | |
| input_path = None | |
| output_path = None | |
| try: | |
| file_id = str(uuid.uuid4()) | |
| input_path = TEMP_DIR / f"{file_id}_input_{audio.filename}" | |
| output_path = TEMP_DIR / f"{file_id}_output.wav" | |
| with open(input_path, "wb") as f: | |
| content = await audio.read() | |
| f.write(content) | |
| parameters = ai_effector.predict( | |
| audio_path=str(input_path), | |
| text_prompt=prompt | |
| ) | |
| effect_chain.process( | |
| input_path=str(input_path), | |
| output_path=str(output_path), | |
| parameters=parameters | |
| ) | |
| os.remove(input_path) | |
| return FileResponse( | |
| path=str(output_path), | |
| media_type="audio/wav", | |
| filename=f"processed_{audio.filename.rsplit('.', 1)[0]}.wav", | |
| background=None | |
| ) | |
| except Exception as e: | |
| logger.error(f"Process error: {e}") | |
| if input_path and Path(input_path).exists(): | |
| os.remove(input_path) | |
| if output_path and Path(output_path).exists(): | |
| os.remove(output_path) | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| async def process_audio_with_params( | |
| audio: UploadFile = File(..., description="Dry ๋ณด์ปฌ ์ค๋์ค ํ์ผ"), | |
| prompt: str = Form("", description="ํ ์คํธ ๋ช ๋ น") | |
| ): | |
| """์ค๋์ค ์ฒ๋ฆฌ + ์ฌ์ฉ๋ ํ๋ผ๋ฏธํฐ๋ ํจ๊ป ๋ฐํ""" | |
| input_path = None | |
| output_path = None | |
| try: | |
| file_id = str(uuid.uuid4()) | |
| input_path = TEMP_DIR / f"{file_id}_input_{audio.filename}" | |
| output_path = TEMP_DIR / f"{file_id}_output.wav" | |
| with open(input_path, "wb") as f: | |
| content = await audio.read() | |
| f.write(content) | |
| parameters = ai_effector.predict( | |
| audio_path=str(input_path), | |
| text_prompt=prompt | |
| ) | |
| effect_chain.process( | |
| input_path=str(input_path), | |
| output_path=str(output_path), | |
| parameters=parameters | |
| ) | |
| os.remove(input_path) | |
| with open(output_path, "rb") as f: | |
| audio_base64 = base64.b64encode(f.read()).decode('utf-8') | |
| os.remove(output_path) | |
| return JSONResponse(content={ | |
| "status": "success", | |
| "prompt": prompt, | |
| "ai_model_used": ai_effector.is_loaded(), | |
| "parameters": parameters, | |
| "audio_base64": audio_base64, | |
| "audio_format": "wav" | |
| }) | |
| except Exception as e: | |
| logger.error(f"Process with params error: {e}") | |
| if input_path and Path(input_path).exists(): | |
| os.remove(input_path) | |
| if output_path and Path(output_path).exists(): | |
| os.remove(output_path) | |
| raise HTTPException(status_code=500, detail=str(e)) | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |