diff --git a/.env.example b/.env.example new file mode 100644 index 00000000..51323464 --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# AI Station - Environment Variables Template +# Copy this file to .env and fill in your values +# IMPORTANT: Never commit .env to version control! + +# === GOOGLE OAUTH === +OAUTH_GOOGLE_CLIENT_ID=your_client_id_here +OAUTH_GOOGLE_CLIENT_SECRET=your_client_secret_here + +# === CHAINLIT CONFIGURATION === +CHAINLIT_URL=https://ai.dffm.it +CHAINLIT_AUTH_SECRET=generate_a_secure_random_string_here + +# === DATABASE === +# Format: postgresql+asyncpg://username:password@hostname:port/database_name +DATABASE_URL=postgresql+asyncpg://ai_user:your_secure_password@postgres:5432/ai_station + +# === AI SERVICES === +OLLAMA_URL=http://192.168.1.243:11434 +QDRANT_URL=http://qdrant:6333 +BGE_API_URL=http://192.168.1.243:8001/embed + +# === OPTIONAL === +# GEMINI_API_KEY=your_gemini_api_key_here diff --git a/.gitignore b/.gitignore index 637505aa..adf133d3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ workspaces/* qdrant_storage/.files/ __pycache__/ .env -.files/ \ No newline at end of file +.files/ +config/user_profiles.json \ No newline at end of file diff --git a/app.py b/app.py index 4d76c44c..067d0c74 100644 --- a/app.py +++ b/app.py @@ -1,5 +1,6 @@ import os import re +import json import uuid import shutil import requests @@ -37,10 +38,15 @@ except ImportError: # ========================= # CONFIG # ========================= -DATABASE_URL = os.getenv( - "DATABASE_URL", - "postgresql+asyncpg://ai_user:secure_password_here@postgres:5432/ai_station", -) +# SECURITY: Fail fast if DATABASE_URL is not set +DATABASE_URL = os.getenv("DATABASE_URL") +if not DATABASE_URL: + raise EnvironmentError( + "DATABASE_URL environment variable is required. " + "Set it via: export DATABASE_URL='postgresql+asyncpg://user:pass@host:5432/db'" + ) + +# Service URLs - can be overridden via environment OLLAMA_URL = os.getenv("OLLAMA_URL", "http://192.168.1.243:11434") QDRANT_URL = os.getenv("QDRANT_URL", "http://qdrant:6333") BGE_API_URL = os.getenv("BGE_API_URL", "http://192.168.1.243:8001/embed") @@ -64,50 +70,24 @@ os.makedirs(STORAGE_DIR, exist_ok=True) os.makedirs(WORKSPACES_DIR, exist_ok=True) # ========================= -# USER PROFILES +# USER PROFILES (loaded from JSON for security) # ========================= -USER_PROFILES = { - "giuseppe@defranceschi.pro": { - "role": "admin", - "name": "Giuseppe", - "workspace": "admin_workspace", - "rag_collection": "admin_docs", - "capabilities": ["debug", "all"], - "show_code": True, - }, - "federica.tecchio@gmail.com": { - "role": "business", - "name": "Federica", - "workspace": "business_workspace", - "rag_collection": "contabilita", - "capabilities": ["basic_chat"], - "show_code": False, - }, - "riccardob545@gmail.com": { - "role": "engineering", - "name": "Riccardo", - "workspace": "engineering_workspace", - "rag_collection": "engineering_docs", - "capabilities": ["code"], - "show_code": True, - }, - "giuliadefranceschi05@gmail.com": { - "role": "architecture", - "name": "Giulia", - "workspace": "architecture_workspace", - "rag_collection": "architecture_manuals", - "capabilities": ["visual"], - "show_code": False, - }, - "giuseppe.defranceschi@gmail.com": { - "role": "architecture", - "name": "Giuseppe", - "workspace": "architecture_workspace", - "rag_collection": "architecture_manuals", - "capabilities": ["visual"], - "show_code": False, - }, -} +def load_user_profiles() -> Dict[str, Dict]: + """Load user profiles from JSON config file.""" + config_path = os.getenv("USER_PROFILES_PATH", "config/user_profiles.json") + try: + with open(config_path, "r", encoding="utf-8") as f: + config = json.load(f) + return config.get("user_profiles", {}) + except FileNotFoundError: + print(f"WARNING: User profiles config not found at {config_path}") + return {} + except json.JSONDecodeError as e: + print(f"WARNING: Invalid JSON in user profiles config: {e}") + return {} + +# Load profiles at startup +USER_PROFILES = load_user_profiles() GUEST_PROFILE = { "role": "guest", diff --git a/config/user_profiles.json.example b/config/user_profiles.json.example new file mode 100644 index 00000000..d2ed5e12 --- /dev/null +++ b/config/user_profiles.json.example @@ -0,0 +1,52 @@ +{ + "user_profiles": { + "giuseppe@defranceschi.pro": { + "role": "admin", + "name": "Giuseppe", + "workspace": "admin_workspace", + "rag_collection": "admin_docs", + "capabilities": ["debug", "all"], + "show_code": true + }, + "federica.tecchio@gmail.com": { + "role": "business", + "name": "Federica", + "workspace": "business_workspace", + "rag_collection": "contabilita", + "capabilities": ["basic_chat"], + "show_code": false + }, + "riccardob545@gmail.com": { + "role": "engineering", + "name": "Riccardo", + "workspace": "engineering_workspace", + "rag_collection": "engineering_docs", + "capabilities": ["code"], + "show_code": true + }, + "giuliadefranceschi05@gmail.com": { + "role": "architecture", + "name": "Giulia", + "workspace": "architecture_workspace", + "rag_collection": "architecture_manuals", + "capabilities": ["visual"], + "show_code": false + }, + "giuseppe.defranceschi@gmail.com": { + "role": "architecture", + "name": "Giuseppe", + "workspace": "architecture_workspace", + "rag_collection": "architecture_manuals", + "capabilities": ["visual"], + "show_code": false + } + }, + "guest_profile": { + "role": "guest", + "name": "Guest", + "workspace": "guest", + "rag_collection": "public", + "capabilities": ["basic_chat"], + "show_code": false + } +}