Spaces:
Sleeping
Sleeping
orakzai-io commited on
Commit ·
59466ba
1
Parent(s): 8b922e3
db bug
Browse files- backend/core/config.py +9 -10
- backend/db/init.py +35 -19
- backend/db/session.py +3 -3
backend/core/config.py
CHANGED
|
@@ -1,19 +1,19 @@
|
|
| 1 |
-
|
| 2 |
from pydantic_settings import BaseSettings, SettingsConfigDict
|
| 3 |
|
| 4 |
|
| 5 |
class Settings(BaseSettings):
|
| 6 |
-
DATABASE_URL: str
|
| 7 |
-
GROQ_API_KEY: str
|
| 8 |
-
UPLOAD_DIR: str = "./uploads"
|
| 9 |
-
FASTEMBED_CACHE_PATH: str = "../fastembed_cache"
|
| 10 |
-
SECRET_KEY: str
|
| 11 |
TOP_K: int = 5
|
| 12 |
CHUNK_SIZE: int = 500
|
| 13 |
CHUNK_OVERLAP: int = 50
|
| 14 |
MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 10MB
|
| 15 |
# Comma-separated list of allowed CORS origins (e.g., "http://localhost:5173,https://example.com")
|
| 16 |
-
ALLOWED_ORIGINS: str = "
|
| 17 |
# Number of uvicorn workers for production
|
| 18 |
UVICORN_WORKERS: int = 4
|
| 19 |
# Database connection pool settings
|
|
@@ -25,11 +25,10 @@ class Settings(BaseSettings):
|
|
| 25 |
@property
|
| 26 |
def allowed_origins_list(self) -> list[str]:
|
| 27 |
"""Parse ALLOWED_ORIGINS comma-separated string into a list."""
|
|
|
|
|
|
|
| 28 |
return [origin.strip() for origin in self.ALLOWED_ORIGINS.split(",") if origin.strip()]
|
| 29 |
|
| 30 |
-
def model_post_init(self, __context: object) -> None:
|
| 31 |
-
if not self.SECRET_KEY:
|
| 32 |
-
raise ValueError("SECRET_KEY environment variable must be set when auth is enabled")
|
| 33 |
|
| 34 |
|
| 35 |
settings = Settings(_env_file=".env", _env_file_encoding="utf-8") # type: ignore[call-arg]
|
|
|
|
| 1 |
+
import os
|
| 2 |
from pydantic_settings import BaseSettings, SettingsConfigDict
|
| 3 |
|
| 4 |
|
| 5 |
class Settings(BaseSettings):
|
| 6 |
+
DATABASE_URL: str = ""
|
| 7 |
+
GROQ_API_KEY: str = ""
|
| 8 |
+
UPLOAD_DIR: str = "/tmp/uploads" if os.environ.get("VERCEL") else "./uploads"
|
| 9 |
+
FASTEMBED_CACHE_PATH: str = "/tmp/fastembed_cache" if os.environ.get("VERCEL") else "../fastembed_cache"
|
| 10 |
+
SECRET_KEY: str = "default_secret_key_change_in_production_32bytes"
|
| 11 |
TOP_K: int = 5
|
| 12 |
CHUNK_SIZE: int = 500
|
| 13 |
CHUNK_OVERLAP: int = 50
|
| 14 |
MAX_FILE_SIZE: int = 10 * 1024 * 1024 # 10MB
|
| 15 |
# Comma-separated list of allowed CORS origins (e.g., "http://localhost:5173,https://example.com")
|
| 16 |
+
ALLOWED_ORIGINS: str = "*"
|
| 17 |
# Number of uvicorn workers for production
|
| 18 |
UVICORN_WORKERS: int = 4
|
| 19 |
# Database connection pool settings
|
|
|
|
| 25 |
@property
|
| 26 |
def allowed_origins_list(self) -> list[str]:
|
| 27 |
"""Parse ALLOWED_ORIGINS comma-separated string into a list."""
|
| 28 |
+
if self.ALLOWED_ORIGINS == "*":
|
| 29 |
+
return ["*"]
|
| 30 |
return [origin.strip() for origin in self.ALLOWED_ORIGINS.split(",") if origin.strip()]
|
| 31 |
|
|
|
|
|
|
|
|
|
|
| 32 |
|
| 33 |
|
| 34 |
settings = Settings(_env_file=".env", _env_file_encoding="utf-8") # type: ignore[call-arg]
|
backend/db/init.py
CHANGED
|
@@ -11,27 +11,43 @@ logger = logging.getLogger(__name__)
|
|
| 11 |
|
| 12 |
|
| 13 |
async def ensure_database_exists() -> None:
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
isolation_level="AUTOCOMMIT",
|
| 18 |
-
)
|
| 19 |
try:
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
|
| 31 |
|
| 32 |
async def init_database() -> None:
|
|
|
|
|
|
|
|
|
|
| 33 |
await ensure_database_exists()
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
|
| 13 |
async def ensure_database_exists() -> None:
|
| 14 |
+
if not settings.DATABASE_URL or "/" not in settings.DATABASE_URL:
|
| 15 |
+
logger.warning("DATABASE_URL is not set or invalid.")
|
| 16 |
+
return
|
|
|
|
|
|
|
| 17 |
try:
|
| 18 |
+
base_url, db_name = settings.DATABASE_URL.rsplit("/", 1)
|
| 19 |
+
# Strip query parameters if present (e.g. ?sslmode=require)
|
| 20 |
+
if "?" in db_name:
|
| 21 |
+
db_name = db_name.split("?")[0]
|
| 22 |
+
admin_engine = create_async_engine(
|
| 23 |
+
f"{base_url}/postgres",
|
| 24 |
+
isolation_level="AUTOCOMMIT",
|
| 25 |
+
)
|
| 26 |
+
try:
|
| 27 |
+
async with admin_engine.connect() as conn:
|
| 28 |
+
exists = await conn.scalar(
|
| 29 |
+
text("SELECT 1 FROM pg_database WHERE datname = :name"),
|
| 30 |
+
{"name": db_name},
|
| 31 |
+
)
|
| 32 |
+
if not exists:
|
| 33 |
+
await conn.execute(text(f'CREATE DATABASE "{db_name}"'))
|
| 34 |
+
logger.info("Created database '%s'.", db_name)
|
| 35 |
+
finally:
|
| 36 |
+
await admin_engine.dispose()
|
| 37 |
+
except Exception as e:
|
| 38 |
+
logger.warning("Could not auto-create database (managed cloud DBs usually pre-create databases): %s", e)
|
| 39 |
|
| 40 |
|
| 41 |
async def init_database() -> None:
|
| 42 |
+
if not settings.DATABASE_URL:
|
| 43 |
+
logger.warning("DATABASE_URL is not configured.")
|
| 44 |
+
return
|
| 45 |
await ensure_database_exists()
|
| 46 |
+
try:
|
| 47 |
+
async with engine.begin() as conn:
|
| 48 |
+
await conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
|
| 49 |
+
await conn.run_sync(Base.metadata.create_all)
|
| 50 |
+
logger.info("Database schema is ready.")
|
| 51 |
+
except Exception as e:
|
| 52 |
+
logger.error("Database initialization failed: %s", e)
|
| 53 |
+
|
backend/db/session.py
CHANGED
|
@@ -2,11 +2,11 @@ from typing import AsyncGenerator
|
|
| 2 |
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
|
| 3 |
from core.config import settings
|
| 4 |
|
|
|
|
|
|
|
| 5 |
engine = create_async_engine(
|
| 6 |
-
|
| 7 |
echo=False, # Disable SQL echo in production
|
| 8 |
-
pool_size=settings.DB_POOL_SIZE,
|
| 9 |
-
max_overflow=settings.DB_MAX_OVERFLOW,
|
| 10 |
pool_pre_ping=True,
|
| 11 |
)
|
| 12 |
|
|
|
|
| 2 |
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
|
| 3 |
from core.config import settings
|
| 4 |
|
| 5 |
+
db_url = settings.DATABASE_URL if settings.DATABASE_URL else "sqlite+aiosqlite:///:memory:"
|
| 6 |
+
|
| 7 |
engine = create_async_engine(
|
| 8 |
+
db_url,
|
| 9 |
echo=False, # Disable SQL echo in production
|
|
|
|
|
|
|
| 10 |
pool_pre_ping=True,
|
| 11 |
)
|
| 12 |
|