KU_SW_Academy / main.py
heybaeheef's picture
Fix model loading with subfolder parameter
5c6cdde
raw
history blame
7.77 kB
"""
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 ์—”๋“œํฌ์ธํŠธ
# ============================================
@app.get("/")
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": "์„œ๋ฒ„ ์ƒํƒœ ํ™•์ธ"
}
}
@app.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
}
@app.post("/predict")
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))
@app.post("/process")
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))
@app.post("/process_with_params")
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)