Spaces:
Runtime error
Runtime error
fix: make external services optional
Browse files- app/database.py +29 -9
- app/main.py +17 -11
- app/services/storage_adapter.py +14 -8
- app/services/vector_db_adapter.py +14 -5
app/database.py
CHANGED
|
@@ -3,26 +3,46 @@ from sqlalchemy import create_engine
|
|
| 3 |
from sqlalchemy.orm import sessionmaker, Session
|
| 4 |
from app.config import get_settings
|
| 5 |
from app.models import Base
|
|
|
|
| 6 |
|
|
|
|
| 7 |
settings = get_settings()
|
| 8 |
|
| 9 |
-
engine
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
|
| 19 |
def init_db():
|
| 20 |
"""Initialize database tables."""
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
|
| 24 |
def get_db() -> Session:
|
| 25 |
"""Dependency for getting database session."""
|
|
|
|
|
|
|
|
|
|
| 26 |
db = SessionLocal()
|
| 27 |
try:
|
| 28 |
yield db
|
|
|
|
| 3 |
from sqlalchemy.orm import sessionmaker, Session
|
| 4 |
from app.config import get_settings
|
| 5 |
from app.models import Base
|
| 6 |
+
import logging
|
| 7 |
|
| 8 |
+
logger = logging.getLogger(__name__)
|
| 9 |
settings = get_settings()
|
| 10 |
|
| 11 |
+
# Create engine with connection pooling
|
| 12 |
+
try:
|
| 13 |
+
engine = create_engine(
|
| 14 |
+
settings.DATABASE_URL,
|
| 15 |
+
pool_pre_ping=True,
|
| 16 |
+
pool_size=10,
|
| 17 |
+
max_overflow=20
|
| 18 |
+
)
|
| 19 |
+
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
|
| 20 |
+
logger.info("Database engine created successfully")
|
| 21 |
+
except Exception as e:
|
| 22 |
+
logger.warning(f"Failed to create database engine: {e}")
|
| 23 |
+
engine = None
|
| 24 |
+
SessionLocal = None
|
| 25 |
|
| 26 |
|
| 27 |
def init_db():
|
| 28 |
"""Initialize database tables."""
|
| 29 |
+
if engine is None:
|
| 30 |
+
logger.warning("Database not configured - skipping initialization")
|
| 31 |
+
return
|
| 32 |
+
|
| 33 |
+
try:
|
| 34 |
+
Base.metadata.create_all(bind=engine)
|
| 35 |
+
logger.info("Database tables created successfully")
|
| 36 |
+
except Exception as e:
|
| 37 |
+
logger.error(f"Failed to initialize database: {e}")
|
| 38 |
+
raise
|
| 39 |
|
| 40 |
|
| 41 |
def get_db() -> Session:
|
| 42 |
"""Dependency for getting database session."""
|
| 43 |
+
if SessionLocal is None:
|
| 44 |
+
raise RuntimeError("Database not configured")
|
| 45 |
+
|
| 46 |
db = SessionLocal()
|
| 47 |
try:
|
| 48 |
yield db
|
app/main.py
CHANGED
|
@@ -42,18 +42,24 @@ async def startup_event():
|
|
| 42 |
"""Initialize on startup."""
|
| 43 |
logger.info("Starting Ragora API...")
|
| 44 |
|
| 45 |
-
# Initialize database
|
| 46 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
-
# Initialize vector DB collection
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
|
|
|
|
|
|
|
|
|
| 57 |
|
| 58 |
|
| 59 |
@app.get("/health")
|
|
|
|
| 42 |
"""Initialize on startup."""
|
| 43 |
logger.info("Starting Ragora API...")
|
| 44 |
|
| 45 |
+
# Initialize database (optional)
|
| 46 |
+
try:
|
| 47 |
+
init_db()
|
| 48 |
+
logger.info("Database initialized")
|
| 49 |
+
except Exception as e:
|
| 50 |
+
logger.warning(f"Database initialization skipped: {e}")
|
| 51 |
|
| 52 |
+
# Initialize vector DB collection (optional)
|
| 53 |
+
try:
|
| 54 |
+
embedder = get_embedder_port()
|
| 55 |
+
vector_db = get_vector_db_port()
|
| 56 |
+
await vector_db.initialize_collection(
|
| 57 |
+
settings.QDRANT_COLLECTION,
|
| 58 |
+
embedder.get_dimension()
|
| 59 |
+
)
|
| 60 |
+
logger.info("Vector DB initialized")
|
| 61 |
+
except Exception as e:
|
| 62 |
+
logger.warning(f"Vector DB initialization skipped: {e}")
|
| 63 |
|
| 64 |
|
| 65 |
@app.get("/health")
|
app/services/storage_adapter.py
CHANGED
|
@@ -14,14 +14,20 @@ class MinIOStorageAdapter(StoragePort):
|
|
| 14 |
"""MinIO implementation of StoragePort."""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
|
| 26 |
def _ensure_bucket(self):
|
| 27 |
"""Ensure bucket exists."""
|
|
|
|
| 14 |
"""MinIO implementation of StoragePort."""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
+
try:
|
| 18 |
+
self.client = Minio(
|
| 19 |
+
settings.MINIO_ENDPOINT,
|
| 20 |
+
access_key=settings.MINIO_ACCESS_KEY,
|
| 21 |
+
secret_key=settings.MINIO_SECRET_KEY,
|
| 22 |
+
secure=settings.MINIO_SECURE
|
| 23 |
+
)
|
| 24 |
+
self.bucket = settings.MINIO_BUCKET
|
| 25 |
+
self._ensure_bucket()
|
| 26 |
+
logger.info(f"Connected to MinIO at {settings.MINIO_ENDPOINT}")
|
| 27 |
+
except Exception as e:
|
| 28 |
+
logger.warning(f"Failed to connect to MinIO: {e}")
|
| 29 |
+
self.client = None
|
| 30 |
+
self.bucket = None
|
| 31 |
|
| 32 |
def _ensure_bucket(self):
|
| 33 |
"""Ensure bucket exists."""
|
app/services/vector_db_adapter.py
CHANGED
|
@@ -14,14 +14,23 @@ class QdrantAdapter(VectorDBPort):
|
|
| 14 |
"""Qdrant implementation of VectorDBPort."""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
async def initialize_collection(self, collection_name: str, dimension: int) -> None:
|
| 24 |
"""Initialize vector collection."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 25 |
try:
|
| 26 |
collections = self.client.get_collections().collections
|
| 27 |
exists = any(c.name == collection_name for c in collections)
|
|
|
|
| 14 |
"""Qdrant implementation of VectorDBPort."""
|
| 15 |
|
| 16 |
def __init__(self):
|
| 17 |
+
try:
|
| 18 |
+
self.client = QdrantClient(
|
| 19 |
+
host=settings.QDRANT_HOST,
|
| 20 |
+
port=settings.QDRANT_PORT,
|
| 21 |
+
timeout=5.0
|
| 22 |
+
)
|
| 23 |
+
logger.info(f"Connected to Qdrant at {settings.QDRANT_HOST}:{settings.QDRANT_PORT}")
|
| 24 |
+
except Exception as e:
|
| 25 |
+
logger.warning(f"Failed to connect to Qdrant: {e}")
|
| 26 |
+
self.client = None
|
| 27 |
|
| 28 |
async def initialize_collection(self, collection_name: str, dimension: int) -> None:
|
| 29 |
"""Initialize vector collection."""
|
| 30 |
+
if self.client is None:
|
| 31 |
+
logger.warning("Qdrant client not available - skipping collection initialization")
|
| 32 |
+
return
|
| 33 |
+
|
| 34 |
try:
|
| 35 |
collections = self.client.get_collections().collections
|
| 36 |
exists = any(c.name == collection_name for c in collections)
|