Files
xAdmin 41e08611c9 Implement optional single-image intake, Signal ingestion, and multimodal vision analysis
- Add image intake service with format validation (JPEG, PNG, WebP) and EXIF/GPS stripping
- Enforce strict single-image rule across Web and Signal attachment channels
- Implement token-optimized vision downscaling and JPEG compression
- Add IMAGE_CONTEXT pipeline stage with OmniRoute vision routing and resilient failover
- Seed and manage versioned idea-image-interpreter prompt in catalog
- Update Web UI with responsive image picker, preview chip, and Visual Context tab
- Add comprehensive automated test suite in test_image_intake.py
- Update README and Labyricorn devlog
2026-08-23 01:40:22 -07:00

107 lines
4.4 KiB
Python

"""
ThinkStorm Configuration Module
Manages application settings, service URLs, secret keys, and default policies.
"""
import os
import socket
from pathlib import Path
from dataclasses import dataclass, field
from typing import Dict, Any, List
try:
import urllib3.util.connection as urllib3_cn
urllib3_cn.allowed_gai_family = lambda: socket.AF_INET
except Exception:
pass
BASE_DIR = Path(__file__).resolve().parent.parent
DATA_DIR = BASE_DIR / "data"
DATA_DIR.mkdir(parents=True, exist_ok=True)
DB_PATH = DATA_DIR / "thinkstorm.db"
# Automatic .env File Loader
def _load_env_file(path: Path):
if not path.is_file():
return
try:
with open(path, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
k = k.strip()
v = v.strip().strip("'\"")
if v:
os.environ[k] = v
except Exception as e:
print(f"[ThinkStorm Config] Notice loading .env from {path}: {e}")
_load_env_file(Path("/root/.env"))
_load_env_file(BASE_DIR / ".env")
_load_env_file(BASE_DIR / "thinkstorm" / ".env")
@dataclass
class ServiceEndpoints:
opengist_url: str = os.getenv("OPENGIST_URL", "https://gist.labyricorn.com")
opengist_api_token: str = os.getenv("OPENGIST_API_TOKEN", "")
gitea_url: str = os.getenv("GITEA_URL", "https://git.labyricorn.com")
gitea_api_token: str = os.getenv("GITEA_API_TOKEN", "")
gitea_client_id: str = os.getenv("GITEA_CLIENT_ID", "")
gitea_client_secret: str = os.getenv("GITEA_CLIENT_SECRET", "")
searxng_url: str = os.getenv("SEARXNG_URL", "https://sx.godno.de")
perplexica_url: str = os.getenv("PERPLEXICA_URL", "https://px.godno.de")
omniroute_url: str = os.getenv("OMNIROUTE_URL", "https://omni.godno.de/v1")
omniroute_api_key: str = os.getenv("OMNIROUTE_API_KEY", "sk-6008fe4dfd069465-236c4f-28414ca2")
omniroute_manage_api_key: str = os.getenv("OMNIROUTE_MANAGE_API_KEY", "")
omniroute_model_reasoning: str = os.getenv("OMNIROUTE_MODEL_REASONING", "auto/best-reasoning")
omniroute_model_coding: str = os.getenv("OMNIROUTE_MODEL_CODING", "auto/best-coding")
omniroute_model_fast: str = os.getenv("OMNIROUTE_MODEL_FAST", "auto/best-fast")
virustotal_api_key: str = os.getenv("VIRUSTOTAL_API_KEY", "")
# Signal Gateway Integration
signal_gateway_base_url: str = os.getenv("SIGNAL_GATEWAY_BASE_URL", "http://10.138.4.46:8000")
signal_gateway_application_id: str = os.getenv("SIGNAL_GATEWAY_APPLICATION_ID", "thinkstorm")
signal_gateway_api_key: str = os.getenv("SIGNAL_GATEWAY_API_KEY", "")
signal_gateway_callback_secret: str = os.getenv("SIGNAL_GATEWAY_CALLBACK_SECRET", "")
signal_gateway_timeout_seconds: float = float(os.getenv("SIGNAL_GATEWAY_TIMEOUT_SECONDS", "5.0"))
@dataclass
class AppConfig:
app_name: str = "ThinkStorm"
version: str = "0.1.0-mvp"
base_url: str = os.getenv("BASE_URL", "https://ts.labyricorn.com")
host: str = os.getenv("HOST", "0.0.0.0")
port: int = int(os.getenv("PORT", "8000"))
secret_key: str = os.getenv("SECRET_KEY", "thinkstorm-secret-key-development-2026")
admin_bootstrap_key: str = os.getenv("ADMIN_BOOTSTRAP_KEY", "admin-thinkstorm-pass-2026")
admin_usernames: List[str] = field(default_factory=lambda: ["admin", "root", "labyricorn"])
# Abuse & Rate Limiting Controls
max_submission_chars: int = 10000
max_extracted_urls: int = 10
rate_limit_window_seconds: int = 60
rate_limit_max_submissions: int = int(os.getenv("RATE_LIMIT_MAX_SUBMISSIONS", "100"))
# Image Intake & Vision Optimization Controls
max_image_upload_bytes: int = int(os.getenv("MAX_IMAGE_UPLOAD_BYTES", str(10 * 1024 * 1024))) # 10 MB
allowed_image_mime_types: List[str] = field(default_factory=lambda: ["image/jpeg", "image/png", "image/webp"])
vision_max_dimension: int = int(os.getenv("VISION_MAX_DIMENSION", "1536")) # Token bounding for LLM
vision_jpeg_quality: int = int(os.getenv("VISION_JPEG_QUALITY", "85"))
omniroute_model_vision: str = os.getenv("OMNIROUTE_MODEL_VISION", "auto/best-vision")
# Queue Limits
max_concurrent_background_jobs: int = 2
max_processor_retries: int = 3
processor_timeout_seconds: int = 45
services: ServiceEndpoints = field(default_factory=ServiceEndpoints)
config = AppConfig()