fariedalfarizi's picture
Set all analysis default TRUE and cleanup unused files
1e0d7f9
"""
API Routes
"""
from fastapi import APIRouter, UploadFile, File, Form, HTTPException
from typing import Optional, List
import uuid
import os
import json
from app.models import TaskResponse, TaskStatusResponse, TaskStatus, AnalysisRequest
from app.core.redis_client import get_queue
from app.core.storage import save_uploaded_file
from app.config import settings
from app.tasks import process_audio_task
router = APIRouter()
@router.post("/analyze", response_model=TaskResponse)
async def analyze_audio(
audio: UploadFile = File(...),
reference_text: Optional[str] = Form(None),
topic_id: Optional[str] = Form(None),
custom_topic: Optional[str] = Form(None),
custom_keywords: Optional[str] = Form(None), # JSON string dari frontend
analyze_tempo: bool = Form(True),
analyze_articulation: bool = Form(True),
analyze_structure: bool = Form(True),
analyze_keywords: bool = Form(True), # Default TRUE
analyze_profanity: bool = Form(True) # Default TRUE
):
"""
Submit audio file untuk analisis
Parameters:
- audio: File audio (.wav, .mp3, .m4a, .flac, .ogg)
- reference_text: Teks referensi untuk artikulasi (optional)
- topic_id: ID topik dari database untuk Level 1-2 (optional)
- custom_topic: Topik custom untuk Level 3 (optional)
- custom_keywords: JSON array kata kunci dari GPT, contoh: ["inovasi", "kreativitas", "perubahan"] (optional)
- analyze_tempo: Analisis tempo (default: true)
- analyze_articulation: Analisis artikulasi (default: true)
- analyze_structure: Analisis struktur (default: true)
- analyze_keywords: Analisis kata kunci (default: true) - otomatis skip jika tidak ada topic_id/custom_keywords
- analyze_profanity: Deteksi kata tidak senonoh (default: true)
Returns task_id yang bisa digunakan untuk check status
"""
# Validate file extension
file_ext = os.path.splitext(audio.filename)[1].lower()
if file_ext not in settings.ALLOWED_EXTENSIONS:
raise HTTPException(
status_code=400,
detail=f"File type {file_ext} not allowed. Allowed: {settings.ALLOWED_EXTENSIONS}"
)
# Validate file size
content = await audio.read()
if len(content) > settings.MAX_UPLOAD_SIZE:
raise HTTPException(
status_code=400,
detail=f"File too large. Max size: {settings.MAX_UPLOAD_SIZE / 1024 / 1024}MB"
)
# Parse custom_keywords dari JSON string
parsed_custom_keywords = None
if custom_keywords:
try:
parsed_custom_keywords = json.loads(custom_keywords)
if not isinstance(parsed_custom_keywords, list):
raise ValueError("custom_keywords harus berupa array")
except json.JSONDecodeError:
raise HTTPException(
status_code=400,
detail="custom_keywords harus berupa JSON array valid, contoh: [\"kata1\", \"kata2\"]"
)
# Save file
task_id = str(uuid.uuid4())
filename = f"{task_id}{file_ext}"
file_path = save_uploaded_file(content, filename)
# Submit task to queue
queue = get_queue()
job = queue.enqueue(
process_audio_task,
audio_path=file_path,
reference_text=reference_text,
topic_id=topic_id,
custom_topic=custom_topic,
custom_keywords=parsed_custom_keywords,
analyze_tempo=analyze_tempo,
analyze_articulation=analyze_articulation,
analyze_structure=analyze_structure,
analyze_keywords=analyze_keywords,
analyze_profanity=analyze_profanity,
job_id=task_id,
job_timeout=settings.JOB_TIMEOUT,
result_ttl=settings.RESULT_TTL
)
return TaskResponse(
task_id=task_id,
status=TaskStatus.QUEUED,
message="Task submitted successfully"
)
@router.get("/status/{task_id}", response_model=TaskStatusResponse)
async def get_task_status(task_id: str):
"""
Check status dari task
Returns status dan result jika sudah selesai
"""
from rq.job import Job
from app.core.redis_client import get_redis_connection
try:
redis_conn = get_redis_connection()
job = Job.fetch(task_id, connection=redis_conn)
# Map job status to our TaskStatus
if job.is_queued:
status = TaskStatus.QUEUED
elif job.is_started:
status = TaskStatus.PROCESSING
elif job.is_finished:
status = TaskStatus.COMPLETED
elif job.is_failed:
status = TaskStatus.FAILED
else:
status = TaskStatus.QUEUED
# Get result if completed
result = None
error = None
if job.is_finished:
job_result = job.result
if isinstance(job_result, dict):
if job_result.get('status') == 'completed':
result = job_result.get('result')
elif job_result.get('status') == 'failed':
error = job_result.get('error')
status = TaskStatus.FAILED
if job.is_failed:
error = str(job.exc_info)
return TaskStatusResponse(
task_id=task_id,
status=status,
result=result,
error=error,
created_at=job.created_at.isoformat() if job.created_at else None,
updated_at=job.ended_at.isoformat() if job.ended_at else None
)
except Exception as e:
raise HTTPException(
status_code=404,
detail=f"Task not found: {str(e)}"
)
@router.get("/health")
async def health_check():
"""Health check endpoint"""
from app.core.redis_client import check_redis_connection
from app.core.device import get_device_info
is_connected, error_msg = check_redis_connection()
if is_connected:
redis_status = "healthy"
else:
redis_status = f"unhealthy: {error_msg}"
# Get device information
device_info = get_device_info()
return {
"status": "healthy" if is_connected else "degraded",
"redis": redis_status,
"version": settings.VERSION,
"device": device_info
}