Spaces:
Sleeping
Sleeping
Commit
·
df50c8c
1
Parent(s):
1f33b89
Refactor application structure: rename 'models' directory to 'db_models', update import paths across multiple files, and enhance Dockerfile to create and populate the new directory, improving organization and clarity in the codebase.
Browse files- Dockerfile +6 -6
- alembic/env.py +1 -1
- app/api/audiobook_routes.py +1 -1
- app/db.py +1 -1
- app/db_models/.gitkeep +2 -0
- app/db_models/__init__.py +61 -0
- app/db_models/database.py +47 -0
- app/main.py +1 -1
- scripts/migrate.py +1 -1
Dockerfile
CHANGED
@@ -23,7 +23,7 @@ RUN useradd -m -u 1000 app
|
|
23 |
RUN mkdir -p /app/storage/audio \
|
24 |
/app/storage/text \
|
25 |
/app/storage/temp \
|
26 |
-
/app/app/
|
27 |
&& chown -R app:app /app
|
28 |
|
29 |
# Copy requirements first to leverage Docker cache
|
@@ -33,11 +33,11 @@ RUN pip install --no-cache-dir -r requirements.txt
|
|
33 |
# Copy the entire application code
|
34 |
COPY --chown=app:app . .
|
35 |
|
36 |
-
# Create and populate the
|
37 |
-
RUN mkdir -p /app/app/
|
38 |
-
echo '"""Database models and configuration."""\nfrom sqlalchemy.ext.declarative import declarative_base\nBase = declarative_base()' > /app/app/
|
39 |
-
echo '"""Database models."""\nfrom datetime import datetime\nfrom sqlalchemy import Column, Integer, String, DateTime, Float, Text, JSON, Boolean\nfrom sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n\nclass Audiobook(Base):\n """Model for storing audiobook information."""\n __tablename__ = "audiobooks"\n\n id = Column(String(36), primary_key=True)\n title = Column(String(255), nullable=False)\n author = Column(String(255))\n voice_id = Column(String(50), nullable=False)\n status = Column(String(20), nullable=False, default="pending")\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)\n duration = Column(Float)\n file_path = Column(String(255))\n error = Column(Text)\n metadata = Column(JSON)\n\nclass Voice(Base):\n """Model for storing voice information."""\n __tablename__ = "voices"\n\n id = Column(String(36), primary_key=True)\n name = Column(String(255), nullable=False)\n type = Column(String(50), nullable=False)\n speaker_id = Column(Integer)\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n is_active = Column(Boolean, default=True)\n metadata = Column(JSON)\n\nclass AudioCache(Base):\n """Model for caching generated audio."""\n __tablename__ = "audio_cache"\n\n id = Column(String(36), primary_key=True)\n hash = Column(String(64), nullable=False, unique=True)\n format = Column(String(10), nullable=False)\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n file_path = Column(String(255), nullable=False)\n metadata = Column(JSON)' > /app/app/
|
40 |
-
chown -R app:app /app/app/
|
41 |
|
42 |
# Make scripts executable
|
43 |
RUN chmod +x /app/scripts/*.sh
|
|
|
23 |
RUN mkdir -p /app/storage/audio \
|
24 |
/app/storage/text \
|
25 |
/app/storage/temp \
|
26 |
+
/app/app/db_models \
|
27 |
&& chown -R app:app /app
|
28 |
|
29 |
# Copy requirements first to leverage Docker cache
|
|
|
33 |
# Copy the entire application code
|
34 |
COPY --chown=app:app . .
|
35 |
|
36 |
+
# Create and populate the db_models directory
|
37 |
+
RUN mkdir -p /app/app/db_models && \
|
38 |
+
echo '"""Database models and configuration."""\nfrom sqlalchemy.ext.declarative import declarative_base\nBase = declarative_base()' > /app/app/db_models/__init__.py && \
|
39 |
+
echo '"""Database models."""\nfrom datetime import datetime\nfrom sqlalchemy import Column, Integer, String, DateTime, Float, Text, JSON, Boolean\nfrom sqlalchemy.ext.declarative import declarative_base\n\nBase = declarative_base()\n\nclass Audiobook(Base):\n """Model for storing audiobook information."""\n __tablename__ = "audiobooks"\n\n id = Column(String(36), primary_key=True)\n title = Column(String(255), nullable=False)\n author = Column(String(255))\n voice_id = Column(String(50), nullable=False)\n status = Column(String(20), nullable=False, default="pending")\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)\n duration = Column(Float)\n file_path = Column(String(255))\n error = Column(Text)\n metadata = Column(JSON)\n\nclass Voice(Base):\n """Model for storing voice information."""\n __tablename__ = "voices"\n\n id = Column(String(36), primary_key=True)\n name = Column(String(255), nullable=False)\n type = Column(String(50), nullable=False)\n speaker_id = Column(Integer)\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n is_active = Column(Boolean, default=True)\n metadata = Column(JSON)\n\nclass AudioCache(Base):\n """Model for caching generated audio."""\n __tablename__ = "audio_cache"\n\n id = Column(String(36), primary_key=True)\n hash = Column(String(64), nullable=False, unique=True)\n format = Column(String(10), nullable=False)\n created_at = Column(DateTime, nullable=False, default=datetime.utcnow)\n file_path = Column(String(255), nullable=False)\n metadata = Column(JSON)' > /app/app/db_models/database.py && \
|
40 |
+
chown -R app:app /app/app/db_models
|
41 |
|
42 |
# Make scripts executable
|
43 |
RUN chmod +x /app/scripts/*.sh
|
alembic/env.py
CHANGED
@@ -5,7 +5,7 @@ from sqlalchemy import pool
|
|
5 |
|
6 |
from alembic import context
|
7 |
|
8 |
-
from app.
|
9 |
from app.config import get_settings
|
10 |
|
11 |
# this is the Alembic Config object, which provides
|
|
|
5 |
|
6 |
from alembic import context
|
7 |
|
8 |
+
from app.db_models.database import Base
|
9 |
from app.config import get_settings
|
10 |
|
11 |
# this is the Alembic Config object, which provides
|
app/api/audiobook_routes.py
CHANGED
@@ -11,7 +11,7 @@ from typing import Optional, List
|
|
11 |
from fastapi import APIRouter, Request, HTTPException, BackgroundTasks, UploadFile, File, Form, Depends
|
12 |
from fastapi.responses import FileResponse, JSONResponse
|
13 |
from sqlalchemy.orm import Session
|
14 |
-
from app.
|
15 |
from app.services.storage import storage
|
16 |
from app.db import get_db
|
17 |
import torchaudio
|
|
|
11 |
from fastapi import APIRouter, Request, HTTPException, BackgroundTasks, UploadFile, File, Form, Depends
|
12 |
from fastapi.responses import FileResponse, JSONResponse
|
13 |
from sqlalchemy.orm import Session
|
14 |
+
from app.db_models.database import Audiobook, AudiobookStatus, AudiobookChunk, TextChunk
|
15 |
from app.services.storage import storage
|
16 |
from app.db import get_db
|
17 |
import torchaudio
|
app/db.py
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
import os
|
3 |
from sqlalchemy import create_engine
|
4 |
from sqlalchemy.orm import sessionmaker
|
5 |
-
from app.
|
6 |
|
7 |
# Get database URL from environment or use SQLite as default
|
8 |
DATABASE_URL = os.getenv(
|
|
|
2 |
import os
|
3 |
from sqlalchemy import create_engine
|
4 |
from sqlalchemy.orm import sessionmaker
|
5 |
+
from app.db_models.database import Base
|
6 |
|
7 |
# Get database URL from environment or use SQLite as default
|
8 |
DATABASE_URL = os.getenv(
|
app/db_models/.gitkeep
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
# This file ensures the models directory is tracked by Git
|
2 |
+
# Even if it's empty
|
app/db_models/__init__.py
ADDED
@@ -0,0 +1,61 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Models package initialization."""
|
2 |
+
from app.db_models.database import Base, Audiobook, AudiobookChunk, TextChunk, AudiobookStatus
|
3 |
+
|
4 |
+
__all__ = [
|
5 |
+
'Base',
|
6 |
+
'Audiobook',
|
7 |
+
'AudiobookChunk',
|
8 |
+
'TextChunk',
|
9 |
+
'AudiobookStatus'
|
10 |
+
]
|
11 |
+
|
12 |
+
"""
|
13 |
+
Database configuration and session management.
|
14 |
+
"""
|
15 |
+
import os
|
16 |
+
from sqlalchemy import create_engine
|
17 |
+
from sqlalchemy.orm import sessionmaker
|
18 |
+
from sqlalchemy.ext.declarative import declarative_base
|
19 |
+
|
20 |
+
# Get database URL from environment or use SQLite as default
|
21 |
+
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///app/storage/audiobooks.db")
|
22 |
+
|
23 |
+
# Create engine with connection pool settings
|
24 |
+
engine = create_engine(
|
25 |
+
DATABASE_URL,
|
26 |
+
pool_size=5,
|
27 |
+
max_overflow=10,
|
28 |
+
pool_timeout=30,
|
29 |
+
pool_recycle=1800,
|
30 |
+
echo=False # Set to True for SQL query logging
|
31 |
+
)
|
32 |
+
|
33 |
+
# Create session factory
|
34 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
35 |
+
|
36 |
+
def get_db():
|
37 |
+
"""Get database session."""
|
38 |
+
db = SessionLocal()
|
39 |
+
try:
|
40 |
+
yield db
|
41 |
+
finally:
|
42 |
+
db.close()
|
43 |
+
|
44 |
+
# Import models to ensure they are registered with SQLAlchemy
|
45 |
+
from .database import Base, Audiobook, Voice, AudioCache
|
46 |
+
|
47 |
+
# Create all tables
|
48 |
+
def init_db():
|
49 |
+
"""Initialize database tables."""
|
50 |
+
Base.metadata.create_all(bind=engine)
|
51 |
+
|
52 |
+
__all__ = [
|
53 |
+
'Base',
|
54 |
+
'Audiobook',
|
55 |
+
'Voice',
|
56 |
+
'AudioCache',
|
57 |
+
'get_db',
|
58 |
+
'init_db',
|
59 |
+
'engine',
|
60 |
+
'SessionLocal'
|
61 |
+
]
|
app/db_models/database.py
ADDED
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
Database models for the TTS API.
|
3 |
+
"""
|
4 |
+
from datetime import datetime
|
5 |
+
from sqlalchemy import Column, Integer, String, DateTime, Float, Text, JSON, Boolean
|
6 |
+
from sqlalchemy.ext.declarative import declarative_base
|
7 |
+
|
8 |
+
Base = declarative_base()
|
9 |
+
|
10 |
+
class Audiobook(Base):
|
11 |
+
"""Model for storing audiobook information."""
|
12 |
+
__tablename__ = 'audiobooks'
|
13 |
+
|
14 |
+
id = Column(String(36), primary_key=True)
|
15 |
+
title = Column(String(255), nullable=False)
|
16 |
+
author = Column(String(255))
|
17 |
+
voice_id = Column(String(50), nullable=False)
|
18 |
+
status = Column(String(20), nullable=False, default='pending') # pending, processing, completed, failed
|
19 |
+
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
20 |
+
updated_at = Column(DateTime, nullable=False, default=datetime.utcnow, onupdate=datetime.utcnow)
|
21 |
+
duration = Column(Float) # Duration in seconds
|
22 |
+
file_path = Column(String(255)) # Path to the audio file
|
23 |
+
error = Column(Text) # Error message if status is 'failed'
|
24 |
+
metadata = Column(JSON) # Additional metadata
|
25 |
+
|
26 |
+
class Voice(Base):
|
27 |
+
"""Model for storing voice information."""
|
28 |
+
__tablename__ = 'voices'
|
29 |
+
|
30 |
+
id = Column(String(36), primary_key=True)
|
31 |
+
name = Column(String(255), nullable=False)
|
32 |
+
type = Column(String(50), nullable=False) # standard, cloned
|
33 |
+
speaker_id = Column(Integer)
|
34 |
+
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
35 |
+
is_active = Column(Boolean, default=True)
|
36 |
+
metadata = Column(JSON) # Store voice-specific settings and data
|
37 |
+
|
38 |
+
class AudioCache(Base):
|
39 |
+
"""Model for caching generated audio."""
|
40 |
+
__tablename__ = 'audio_cache'
|
41 |
+
|
42 |
+
id = Column(String(36), primary_key=True)
|
43 |
+
hash = Column(String(64), nullable=False, unique=True) # Hash of input parameters
|
44 |
+
format = Column(String(10), nullable=False) # Audio format (mp3, wav, etc.)
|
45 |
+
created_at = Column(DateTime, nullable=False, default=datetime.utcnow)
|
46 |
+
file_path = Column(String(255), nullable=False)
|
47 |
+
metadata = Column(JSON) # Store generation parameters
|
app/main.py
CHANGED
@@ -18,7 +18,7 @@ from fastapi.middleware.cors import CORSMiddleware
|
|
18 |
from fastapi.responses import RedirectResponse, FileResponse
|
19 |
from fastapi.staticfiles import StaticFiles
|
20 |
from app.api.routes import router as api_router
|
21 |
-
from app.
|
22 |
|
23 |
# Setup logging
|
24 |
os.makedirs("logs", exist_ok=True)
|
|
|
18 |
from fastapi.responses import RedirectResponse, FileResponse
|
19 |
from fastapi.staticfiles import StaticFiles
|
20 |
from app.api.routes import router as api_router
|
21 |
+
from app.db_models.database import Base, get_db
|
22 |
|
23 |
# Setup logging
|
24 |
os.makedirs("logs", exist_ok=True)
|
scripts/migrate.py
CHANGED
@@ -22,7 +22,7 @@ def run_migrations():
|
|
22 |
logger.info(f"Python Path (sys.path): {sys.path}")
|
23 |
|
24 |
# Import the database configuration
|
25 |
-
from app.
|
26 |
|
27 |
# Initialize database tables
|
28 |
init_db()
|
|
|
22 |
logger.info(f"Python Path (sys.path): {sys.path}")
|
23 |
|
24 |
# Import the database configuration
|
25 |
+
from app.db_models import init_db
|
26 |
|
27 |
# Initialize database tables
|
28 |
init_db()
|