move CRUD and service modules into services/, platform_detect into utils/

Move 9 business-logic modules from the backend root into services/:
channels, effects, history, profiles, stories, versions, export_import,
transcribe, tts. Move platform_detect.py into utils/.

Backend root now contains only infrastructure (app, main, config, server,
models, build_binary) and docs. All 94 routes verified.
This commit is contained in:
James Pine
2026-03-16 02:15:20 -07:00
parent 88536d27f7
commit b3012ed10c
24 changed files with 82 additions and 71 deletions
+3 -2
View File
@@ -6,7 +6,8 @@ from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from .. import history, models
from .. import models
from ..services import history
from ..database import get_db
router = APIRouter()
@@ -15,7 +16,7 @@ router = APIRouter()
@router.get("/audio/version/{version_id}")
async def get_version_audio(version_id: str, db: Session = Depends(get_db)):
"""Serve audio for a specific version."""
from .. import versions as versions_mod
from ..services import versions as versions_mod
version = versions_mod.get_version(version_id, db)
if not version:
+2 -1
View File
@@ -3,7 +3,8 @@
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from .. import channels, models
from .. import models
from ..services import channels
from ..database import get_db
router = APIRouter()
+12 -11
View File
@@ -9,7 +9,8 @@ from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from .. import config, history, models
from .. import config, models
from ..services import history
from ..database import Generation as DBGeneration, get_db
router = APIRouter()
@@ -28,7 +29,7 @@ async def preview_effects(
if (gen.status or "completed") != "completed":
raise HTTPException(status_code=400, detail="Generation is not completed")
from .. import versions as versions_mod
from ..services import versions as versions_mod
from ..utils.effects import apply_effects, validate_effects_chain
from ..utils.audio import load_audio
@@ -73,7 +74,7 @@ async def get_available_effects():
@router.get("/effects/presets", response_model=list[models.EffectPresetResponse])
async def list_effect_presets(db: Session = Depends(get_db)):
"""List all effect presets (built-in + user-created)."""
from .. import effects as effects_mod
from ..services import effects as effects_mod
return effects_mod.list_presets(db)
@@ -81,7 +82,7 @@ async def list_effect_presets(db: Session = Depends(get_db)):
@router.get("/effects/presets/{preset_id}", response_model=models.EffectPresetResponse)
async def get_effect_preset(preset_id: str, db: Session = Depends(get_db)):
"""Get a specific effect preset."""
from .. import effects as effects_mod
from ..services import effects as effects_mod
preset = effects_mod.get_preset(preset_id, db)
if not preset:
@@ -95,7 +96,7 @@ async def create_effect_preset(
db: Session = Depends(get_db),
):
"""Create a new effect preset."""
from .. import effects as effects_mod
from ..services import effects as effects_mod
try:
return effects_mod.create_preset(data, db)
@@ -110,7 +111,7 @@ async def update_effect_preset(
db: Session = Depends(get_db),
):
"""Update an effect preset."""
from .. import effects as effects_mod
from ..services import effects as effects_mod
try:
result = effects_mod.update_preset(preset_id, data, db)
@@ -124,7 +125,7 @@ async def update_effect_preset(
@router.delete("/effects/presets/{preset_id}")
async def delete_effect_preset(preset_id: str, db: Session = Depends(get_db)):
"""Delete a user effect preset."""
from .. import effects as effects_mod
from ..services import effects as effects_mod
try:
if not effects_mod.delete_preset(preset_id, db):
@@ -147,7 +148,7 @@ async def list_generation_versions(
if not gen:
raise HTTPException(status_code=404, detail="Generation not found")
from .. import versions as versions_mod
from ..services import versions as versions_mod
return versions_mod.list_versions(generation_id, db)
@@ -168,7 +169,7 @@ async def apply_effects_to_generation(
if (gen.status or "completed") != "completed":
raise HTTPException(status_code=400, detail="Generation is not completed")
from .. import versions as versions_mod
from ..services import versions as versions_mod
from ..utils.effects import apply_effects, validate_effects_chain
from ..utils.audio import load_audio, save_audio
@@ -227,7 +228,7 @@ async def set_default_version(
db: Session = Depends(get_db),
):
"""Set a specific version as the default for a generation."""
from .. import versions as versions_mod
from ..services import versions as versions_mod
version = versions_mod.get_version(version_id, db)
if not version or version.generation_id != generation_id:
@@ -246,7 +247,7 @@ async def delete_generation_version(
db: Session = Depends(get_db),
):
"""Delete a version. Cannot delete the last remaining version."""
from .. import versions as versions_mod
from ..services import versions as versions_mod
version = versions_mod.get_version(version_id, db)
if not version or version.generation_id != generation_id:
+2 -1
View File
@@ -7,7 +7,8 @@ from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from .. import history, models, profiles, tts
from .. import models
from ..services import history, profiles, tts
from ..database import Generation as DBGeneration, VoiceProfile as DBVoiceProfile, get_db
from ..services.generation import run_generation
from ..services.task_queue import enqueue_generation
+3 -2
View File
@@ -8,9 +8,10 @@ import torch
from fastapi import APIRouter, Depends
from sqlalchemy.orm import Session
from .. import config, models, tts
from .. import config, models
from ..services import tts
from ..database import get_db
from ..platform_detect import get_backend_type
from ..utils.platform_detect import get_backend_type
router = APIRouter()
+2 -1
View File
@@ -7,7 +7,8 @@ from fastapi import APIRouter, Depends, File, HTTPException, UploadFile
from fastapi.responses import FileResponse, StreamingResponse
from sqlalchemy.orm import Session
from .. import export_import, history, models
from .. import models
from ..services import export_import, history
from ..app import safe_content_disposition
from ..database import Generation as DBGeneration, VoiceProfile as DBVoiceProfile, get_db
+3 -3
View File
@@ -9,7 +9,7 @@ from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from .. import models
from ..platform_detect import get_backend_type
from ..utils.platform_detect import get_backend_type
from ..services.task_queue import create_background_task
from ..utils.progress import get_progress_manager
from ..utils.tasks import get_task_manager
@@ -50,7 +50,7 @@ def _copy_with_progress(src: Path, dst: Path, progress_manager, copied_so_far: i
@router.post("/models/load")
async def load_model(model_size: str = "1.7B"):
"""Manually load TTS model."""
from .. import tts
from ..services import tts
try:
tts_model = tts.get_tts_model()
@@ -63,7 +63,7 @@ async def load_model(model_size: str = "1.7B"):
@router.post("/models/unload")
async def unload_model():
"""Unload the default Qwen TTS model to free memory."""
from .. import tts
from ..services import tts
try:
tts.unload_tts_model()
+3 -2
View File
@@ -9,10 +9,11 @@ from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from fastapi.responses import FileResponse, StreamingResponse
from sqlalchemy.orm import Session
from .. import channels, config, export_import, models, profiles
from .. import config, models
from ..app import safe_content_disposition
from ..database import VoiceProfile as DBVoiceProfile, get_db
from ..profiles import _profile_to_response
from ..services import channels, export_import, profiles
from ..services.profiles import _profile_to_response
router = APIRouter()
+2 -1
View File
@@ -6,7 +6,8 @@ from fastapi import APIRouter, Depends, HTTPException
from fastapi.responses import StreamingResponse
from sqlalchemy.orm import Session
from .. import database, models, stories
from .. import database, models
from ..services import stories
from ..app import safe_content_disposition
from ..database import get_db
+2 -1
View File
@@ -6,7 +6,8 @@ from pathlib import Path
from fastapi import APIRouter, File, Form, HTTPException, UploadFile
from .. import models, transcribe
from .. import models
from ..services import transcribe
from ..services.task_queue import create_background_task
from ..utils.tasks import get_task_manager