Dashm commited on
Commit
435cf23
·
1 Parent(s): 0c0cc35

Fix: read env vars at runtime not import time for HF Space secrets

Browse files
backend/config.py CHANGED
@@ -8,13 +8,18 @@ from dotenv import load_dotenv
8
 
9
  load_dotenv(override=False) # Don't override existing env vars (e.g. HF Space secrets)
10
 
11
- # Supabase
12
- SUPABASE_URL = os.getenv("SUPABASE_URL", "")
13
- SUPABASE_KEY = os.getenv("SUPABASE_KEY", "")
14
- SUPABASE_SERVICE_KEY = os.getenv("SUPABASE_SERVICE_KEY", "")
15
-
16
- # Database (direct connection for pgvector queries)
17
- DATABASE_URL = os.getenv("DATABASE_URL", "")
 
 
 
 
 
18
 
19
  # JWT Auth
20
  JWT_SECRET = os.getenv("JWT_SECRET", "change-this-in-production")
 
8
 
9
  load_dotenv(override=False) # Don't override existing env vars (e.g. HF Space secrets)
10
 
11
+ # Supabase — read lazily at runtime so HF Space secrets are available
12
+ def get_supabase_url(): return os.environ.get("SUPABASE_URL", "")
13
+ def get_supabase_key(): return os.environ.get("SUPABASE_KEY", "")
14
+ def get_supabase_service_key(): return os.environ.get("SUPABASE_SERVICE_KEY", "")
15
+ def get_database_url(): return os.environ.get("DATABASE_URL", "")
16
+ def get_jwt_secret(): return os.environ.get("JWT_SECRET", "change-this-in-production")
17
+
18
+ # Keep these as constants too for backwards compatibility
19
+ SUPABASE_URL = os.environ.get("SUPABASE_URL", "")
20
+ SUPABASE_KEY = os.environ.get("SUPABASE_KEY", "")
21
+ SUPABASE_SERVICE_KEY = os.environ.get("SUPABASE_SERVICE_KEY", "")
22
+ DATABASE_URL = os.environ.get("DATABASE_URL", "")
23
 
24
  # JWT Auth
25
  JWT_SECRET = os.getenv("JWT_SECRET", "change-this-in-production")
backend/database.py CHANGED
@@ -4,11 +4,11 @@ Uses psycopg (v3) for direct PostgreSQL/pgvector queries (search),
4
  and supabase-py for standard CRUD operations.
5
  """
6
 
 
7
  import psycopg
8
  from psycopg.rows import dict_row
9
  import numpy as np
10
  from supabase import create_client, Client
11
- from config import SUPABASE_URL, SUPABASE_KEY, DATABASE_URL
12
 
13
  # --- Supabase Client (for CRUD operations) ---
14
 
@@ -19,7 +19,10 @@ def get_supabase() -> Client:
19
  """Get or create the Supabase client for standard CRUD operations."""
20
  global _supabase_client
21
  if _supabase_client is None:
22
- _supabase_client = create_client(SUPABASE_URL, SUPABASE_KEY)
 
 
 
23
  return _supabase_client
24
 
25
 
@@ -27,7 +30,7 @@ def get_supabase() -> Client:
27
 
28
  def get_db_connection():
29
  """Create a new psycopg3 connection for pgvector queries."""
30
- conn = psycopg.connect(DATABASE_URL, row_factory=dict_row)
31
  return conn
32
 
33
 
 
4
  and supabase-py for standard CRUD operations.
5
  """
6
 
7
+ import os
8
  import psycopg
9
  from psycopg.rows import dict_row
10
  import numpy as np
11
  from supabase import create_client, Client
 
12
 
13
  # --- Supabase Client (for CRUD operations) ---
14
 
 
19
  """Get or create the Supabase client for standard CRUD operations."""
20
  global _supabase_client
21
  if _supabase_client is None:
22
+ _supabase_client = create_client(
23
+ os.environ["SUPABASE_URL"],
24
+ os.environ["SUPABASE_KEY"],
25
+ )
26
  return _supabase_client
27
 
28
 
 
30
 
31
  def get_db_connection():
32
  """Create a new psycopg3 connection for pgvector queries."""
33
+ conn = psycopg.connect(os.environ["DATABASE_URL"], row_factory=dict_row)
34
  return conn
35
 
36
 
backend/routes/auth.py CHANGED
@@ -10,8 +10,9 @@ from pydantic import BaseModel
10
  from datetime import datetime, timedelta, timezone
11
  import bcrypt
12
  import jwt
 
13
  from database import get_supabase
14
- from config import JWT_SECRET, JWT_ALGORITHM, JWT_EXPIRATION_HOURS
15
 
16
  router = APIRouter(prefix="/auth", tags=["Authentication"])
17
  security = HTTPBearer()
@@ -58,13 +59,13 @@ def create_token(user_id: str, email: str, role: str = "buyer") -> str:
58
  "exp": datetime.now(timezone.utc) + timedelta(hours=JWT_EXPIRATION_HOURS),
59
  "iat": datetime.now(timezone.utc),
60
  }
61
- return jwt.encode(payload, JWT_SECRET, algorithm=JWT_ALGORITHM)
62
 
63
 
64
  def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
65
  """Dependency that verifies JWT token and returns the payload."""
66
  try:
67
- payload = jwt.decode(credentials.credentials, JWT_SECRET, algorithms=[JWT_ALGORITHM])
68
  return payload
69
  except jwt.ExpiredSignatureError:
70
  raise HTTPException(status_code=401, detail="Token expired")
 
10
  from datetime import datetime, timedelta, timezone
11
  import bcrypt
12
  import jwt
13
+ import os
14
  from database import get_supabase
15
+ from config import JWT_ALGORITHM, JWT_EXPIRATION_HOURS
16
 
17
  router = APIRouter(prefix="/auth", tags=["Authentication"])
18
  security = HTTPBearer()
 
59
  "exp": datetime.now(timezone.utc) + timedelta(hours=JWT_EXPIRATION_HOURS),
60
  "iat": datetime.now(timezone.utc),
61
  }
62
+ return jwt.encode(payload, os.environ.get("JWT_SECRET", "change-this-in-production"), algorithm=JWT_ALGORITHM)
63
 
64
 
65
  def verify_token(credentials: HTTPAuthorizationCredentials = Depends(security)) -> dict:
66
  """Dependency that verifies JWT token and returns the payload."""
67
  try:
68
+ payload = jwt.decode(credentials.credentials, os.environ.get("JWT_SECRET", "change-this-in-production"), algorithms=[JWT_ALGORITHM])
69
  return payload
70
  except jwt.ExpiredSignatureError:
71
  raise HTTPException(status_code=401, detail="Token expired")
backend/routes/products.py CHANGED
@@ -9,10 +9,10 @@ from typing import Optional
9
  import uuid
10
  import base64
11
 
 
12
  from database import get_supabase, store_product_embedding
13
  from models.bert_service import bert_service
14
  from routes.auth import get_current_user
15
- from config import SUPABASE_URL
16
 
17
  router = APIRouter(prefix="/products", tags=["Products"])
18
 
@@ -106,7 +106,7 @@ async def upload_image(
106
  raise HTTPException(status_code=500, detail=f"Failed to upload image: {str(e)}")
107
 
108
  # Get public URL
109
- public_url = f"{SUPABASE_URL}/storage/v1/object/public/product-images/{filename}"
110
 
111
  return {"url": public_url, "filename": filename}
112
 
 
9
  import uuid
10
  import base64
11
 
12
+ import os
13
  from database import get_supabase, store_product_embedding
14
  from models.bert_service import bert_service
15
  from routes.auth import get_current_user
 
16
 
17
  router = APIRouter(prefix="/products", tags=["Products"])
18
 
 
106
  raise HTTPException(status_code=500, detail=f"Failed to upload image: {str(e)}")
107
 
108
  # Get public URL
109
+ public_url = f"{os.environ.get('SUPABASE_URL', '')}/storage/v1/object/public/product-images/{filename}"
110
 
111
  return {"url": public_url, "filename": filename}
112