refactor: Remove cache and metrics endpoints, and clean up voice design CRUD operations

This commit is contained in:
2026-02-04 19:41:08 +08:00
parent dc5fd643e7
commit 4f535b20e5
10 changed files with 4 additions and 275 deletions

View File

@@ -1,156 +0,0 @@
import logging
import json
from pathlib import Path
from typing import Optional
from fastapi import APIRouter, Depends, HTTPException, Request
from sqlalchemy.orm import Session
from slowapi import Limiter
from slowapi.util import get_remote_address
from core.config import settings
from core.database import get_db
from core.cache_manager import VoiceCacheManager
from api.auth import get_current_user
from db.crud import list_cache_entries, delete_cache_entry
from db.models import VoiceCache, User
from utils.metrics import cache_metrics
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/cache", tags=["cache"])
limiter = Limiter(key_func=get_remote_address)
@router.get("/voices")
@limiter.limit("30/minute")
async def list_user_caches(
request: Request,
skip: int = 0,
limit: int = 100,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
caches = list_cache_entries(db, current_user.id, skip=skip, limit=limit)
result = []
for cache in caches:
meta_data = json.loads(cache.meta_data) if cache.meta_data else {}
cache_file = Path(cache.cache_path)
file_size_mb = cache_file.stat().st_size / (1024 * 1024) if cache_file.exists() else 0
result.append({
'id': cache.id,
'ref_audio_hash': cache.ref_audio_hash,
'created_at': cache.created_at.isoformat(),
'last_accessed': cache.last_accessed.isoformat(),
'access_count': cache.access_count,
'metadata': meta_data,
'size_mb': round(file_size_mb, 2)
})
return {
'caches': result,
'total': len(result)
}
@router.delete("/voices/{cache_id}")
@limiter.limit("30/minute")
async def delete_user_cache(
request: Request,
cache_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
cache = db.query(VoiceCache).filter(
VoiceCache.id == cache_id,
VoiceCache.user_id == current_user.id
).first()
if not cache:
raise HTTPException(status_code=404, detail="Cache not found")
cache_file = Path(cache.cache_path)
if cache_file.exists():
cache_file.unlink()
success = delete_cache_entry(db, cache_id, current_user.id)
if not success:
raise HTTPException(status_code=500, detail="Failed to delete cache")
logger.info(f"Cache deleted: id={cache_id}, user={current_user.id}")
return {
'message': 'Cache deleted successfully',
'cache_id': cache_id
}
@router.delete("/voices")
@limiter.limit("10/minute")
async def cleanup_expired_caches(
request: Request,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
cache_manager = await VoiceCacheManager.get_instance()
deleted_count = await cache_manager.cleanup_expired(db)
logger.info(f"Expired cache cleanup: user={current_user.id}, deleted={deleted_count}")
return {
'message': 'Expired caches cleaned up',
'deleted_count': deleted_count
}
@router.post("/voices/prune")
@limiter.limit("10/minute")
async def prune_caches(
request: Request,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
cache_manager = await VoiceCacheManager.get_instance()
deleted_count = await cache_manager.enforce_max_entries(current_user.id, db)
logger.info(f"LRU prune: user={current_user.id}, deleted={deleted_count}")
return {
'message': 'LRU pruning completed',
'deleted_count': deleted_count
}
@router.get("/stats")
@limiter.limit("30/minute")
async def get_cache_stats(
request: Request,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
stats = cache_metrics.get_stats(db, settings.CACHE_DIR)
user_stats = None
for user_stat in stats['users']:
if user_stat['user_id'] == current_user.id:
user_stats = user_stat
break
if user_stats is None:
user_cache_count = db.query(VoiceCache).filter(
VoiceCache.user_id == current_user.id
).count()
user_stats = {
'user_id': current_user.id,
'hits': 0,
'misses': 0,
'hit_rate': 0.0,
'cache_entries': user_cache_count
}
return {
'global': stats['global'],
'user': user_stats
}

View File

@@ -1,21 +0,0 @@
import logging
from fastapi import APIRouter
from core.metrics import MetricsCollector
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/metrics", tags=["metrics"])
@router.get("")
async def get_metrics():
metrics = await MetricsCollector.get_instance()
data = await metrics.get_metrics()
return data
@router.post("/reset")
async def reset_metrics():
metrics = await MetricsCollector.get_instance()
await metrics.reset()
return {"message": "Metrics reset successfully"}

View File

@@ -665,13 +665,6 @@ async def create_voice_clone_job(
}
@router.get("/models")
@limiter.limit("30/minute")
async def list_models(request: Request):
model_manager = await ModelManager.get_instance()
return model_manager.get_model_info()
@router.get("/speakers")
@limiter.limit("30/minute")
async def list_speakers(request: Request, backend: Optional[str] = "local"):

View File

@@ -13,7 +13,6 @@ from db import crud
from schemas.voice_design import (
VoiceDesignCreate,
VoiceDesignResponse,
VoiceDesignUpdate,
VoiceDesignListResponse
)
@@ -58,45 +57,6 @@ async def list_voice_designs(
designs = crud.list_voice_designs(db, current_user.id, backend_type, skip, limit)
return VoiceDesignListResponse(designs=[VoiceDesignResponse.from_orm(d) for d in designs], total=len(designs))
@router.get("/{design_id}", response_model=VoiceDesignResponse)
@limiter.limit("30/minute")
async def get_voice_design(
request: Request,
design_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
design = crud.get_voice_design(db, design_id, current_user.id)
if not design:
raise HTTPException(status_code=404, detail="Voice design not found")
return VoiceDesignResponse.from_orm(design)
@router.patch("/{design_id}", response_model=VoiceDesignResponse)
@limiter.limit("30/minute")
async def update_voice_design(
request: Request,
design_id: int,
data: VoiceDesignUpdate,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
design = crud.update_voice_design(db, design_id, current_user.id, data.name)
if not design:
raise HTTPException(status_code=404, detail="Voice design not found")
return VoiceDesignResponse.from_orm(design)
@router.delete("/{design_id}", status_code=status.HTTP_204_NO_CONTENT)
@limiter.limit("30/minute")
async def delete_voice_design(
request: Request,
design_id: int,
current_user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
success = crud.delete_voice_design(db, design_id, current_user.id)
if not success:
raise HTTPException(status_code=404, detail="Voice design not found")
@router.post("/{design_id}/prepare-clone")
@limiter.limit("10/minute")
async def prepare_voice_clone_prompt(

View File

@@ -329,25 +329,3 @@ def update_voice_design_usage(db: Session, design_id: int, user_id: int) -> Opti
db.refresh(design)
return design
def update_voice_design(
db: Session,
design_id: int,
user_id: int,
name: Optional[str] = None
) -> Optional[VoiceDesign]:
design = get_voice_design(db, design_id, user_id)
if not design:
return None
if name is not None:
design.name = name
db.commit()
db.refresh(design)
return design
def delete_voice_design(db: Session, design_id: int, user_id: int) -> bool:
design = get_voice_design(db, design_id, user_id)
if not design:
return False
design.is_active = False
db.commit()
return True

View File

@@ -15,7 +15,7 @@ from core.config import settings
from core.database import init_db
from core.model_manager import ModelManager
from core.cleanup import run_scheduled_cleanup
from api import auth, jobs, tts, cache, metrics, users, voice_designs
from api import auth, jobs, tts, users, voice_designs
from apscheduler.schedulers.asyncio import AsyncIOScheduler
logging.basicConfig(
@@ -130,8 +130,6 @@ if settings.LOG_LEVEL == "debug":
app.include_router(auth.router)
app.include_router(jobs.router)
app.include_router(tts.router)
app.include_router(cache.router)
app.include_router(metrics.router)
app.include_router(users.router)
app.include_router(voice_designs.router)

View File

@@ -10,9 +10,6 @@ class VoiceDesignCreate(BaseModel):
meta_data: Optional[Dict[str, Any]] = None
preview_text: Optional[str] = None
class VoiceDesignUpdate(BaseModel):
name: Optional[str] = Field(None, min_length=1, max_length=100)
class VoiceDesignResponse(BaseModel):
id: int
user_id: int