jameszokah commited on
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 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/models \
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 models directory
37
- RUN mkdir -p /app/app/models && \
38
- echo '"""Database models and configuration."""\nfrom sqlalchemy.ext.declarative import declarative_base\nBase = declarative_base()' > /app/app/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/models/database.py && \
40
- chown -R app:app /app/app/models
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.models.database import Base
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.models.database import Audiobook, AudiobookStatus, AudiobookChunk, TextChunk
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.models.database import Base
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.models.database import Base, get_db
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.models import init_db
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()