orakzai-io commited on
Commit
59466ba
·
1 Parent(s): 8b922e3
backend/core/config.py CHANGED
@@ -1,19 +1,19 @@
1
- # pydantic-settings: env vars, constants (TOP_K, etc.)
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 = "http://localhost:5173,http://localhost:80"
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
- base_url, db_name = settings.DATABASE_URL.rsplit("/", 1)
15
- admin_engine = create_async_engine(
16
- f"{base_url}/postgres",
17
- isolation_level="AUTOCOMMIT",
18
- )
19
  try:
20
- async with admin_engine.connect() as conn:
21
- exists = await conn.scalar(
22
- text("SELECT 1 FROM pg_database WHERE datname = :name"),
23
- {"name": db_name},
24
- )
25
- if not exists:
26
- await conn.execute(text(f'CREATE DATABASE "{db_name}"'))
27
- logger.info("Created database '%s'.", db_name)
28
- finally:
29
- await admin_engine.dispose()
 
 
 
 
 
 
 
 
 
 
 
30
 
31
 
32
  async def init_database() -> None:
 
 
 
33
  await ensure_database_exists()
34
- async with engine.begin() as conn:
35
- await conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
36
- await conn.run_sync(Base.metadata.create_all)
37
- logger.info("Database schema is ready.")
 
 
 
 
 
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
- settings.DATABASE_URL,
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