- 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
107 lines
4.4 KiB
Python
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()
|