# File: ai-service/core/utils.py import os import cv2 import numpy as np from sklearn.cluster import KMeans import urllib.request import ssl from supabase import create_client, Client from dotenv import load_dotenv # Load environment variables from the root .env file ROOT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) load_dotenv(dotenv_path=os.path.join(ROOT_DIR, '.env')) def get_supabase_client() -> Client: """ Creates and returns a Supabase client. Raises ValueError if credentials are not set in the environment. """ try: url = os.environ.get("SUPABASE_URL") key = os.environ.get("SUPABASE_SERVICE_KEY") # We use service key for backend tasks if not url or not key: raise ValueError("Supabase credentials (URL or Service Key) are not set.") return create_client(url, key) except Exception as e: print(f"🔴 FATAL: Could not create Supabase client: {e}") raise # Re-raise the exception to stop the app if this fails. def extract_colors_from_url(image_url: str, num_colors=4) -> list: """ Downloads an image from a URL and returns the top N dominant colors in Hex format. Requires: opencv-python-headless, scikit-learn, numpy """ try: print(f"🎨 Extracting colors from: {image_url}") # 1. Handle SSL Context (Dev environments often fail strict SSL) context = ssl._create_unverified_context() # 2. Download Image directly to memory with urllib.request.urlopen(image_url, context=context) as req: arr = np.asarray(bytearray(req.read()), dtype=np.uint8) img = cv2.imdecode(arr, -1) if img is None: return [] # 3. Setup Image (Convert BGR to RGB, Resize for speed) # If image has alpha channel (Transparency), remove it if img.shape[2] == 4: img = cv2.cvtColor(img, cv2.COLOR_BGRA2BGR) img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img = cv2.resize(img, (100, 100), interpolation=cv2.INTER_AREA) # Reshape to list of pixels img = img.reshape((img.shape[0] * img.shape[1], 3)) # 4. Use KMeans clustering to find dominant colors kmeans = KMeans(n_clusters=num_colors, n_init='auto') kmeans.fit(img) colors = kmeans.cluster_centers_ # 5. Convert to Hex hex_colors = [] for color in colors: hex_code = '#{:02x}{:02x}{:02x}'.format(int(color[0]), int(color[1]), int(color[2])) hex_colors.append(hex_code) return hex_colors except Exception as e: print(f"⚠️ Error extracting colors: {str(e)}") # Return fallback gray/black if extraction fails return ["#000000", "#808080"]