avinash-rai's picture
Shorter realistic responses: mood-based length, max 80 tokens like real SMS/chat
3fb98b1
# app/config.py - Application configuration (Production Hardened)
from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import Optional
from functools import lru_cache
from dotenv import load_dotenv
import os
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# FIX 1: HF-SAFE DOTENV LOADING
# On HuggingFace, secrets are injected at runtime. Don't override them.
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
if os.getenv("HF_SPACE_ID") is None:
load_dotenv(override=True) # Local dev โ†’ .env
else:
load_dotenv(override=False) # HF prod โ†’ Secrets only
class Settings(BaseSettings):
"""Application settings loaded from environment variables."""
# Application
APP_NAME: str = "Scam Honeypot API"
VERSION: str = "2.5.0"
DEBUG: bool = False
GUVI_API_KEY: str = "" # Must be set via Environment Variable (HF Secrets)
GUVI_CALLBACK_URL: str = "https://hackathon.guvi.in/api/updateHoneyPotFinalResult"
# SOC Hardening (SIEM Integration)
SYSLOG_ENABLED: bool = False
SYSLOG_HOST: str = "localhost"
SYSLOG_PORT: int = 514
# LLM Configuration
LLM_PROVIDER: str = "groq"
OPENAI_API_KEY: Optional[str] = None
ANTHROPIC_API_KEY: Optional[str] = None
GROQ_API_KEY: Optional[str] = None
OPENROUTER_API_KEY: Optional[str] = None
# Local HF (Offline / Free-Tier) Inference
# FIX: Enable by default as crash-proof fallback when Groq fails
USE_LOCAL_HF_MODEL: bool = True # Auto-fallback when API fails
HF_LOCAL_MODEL_NAME: str = "facebook/opt-125m" # Tiny model, runs on CPU
HF_LOCAL_MAX_TOKENS: int = 80 # Short responses like real SMS/chat
HF_LOCAL_DEVICE: str = "cpu" # Explicit so HF Spaces & local dev behave consistently
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# FIX 2: EXPLICIT MODEL DEFAULTS (No None = No Surprises)
# Aligned with Groq limits and capability-aware fallback chains
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
GPT_MODEL: str = "gpt-4-turbo-preview"
CLAUDE_MODEL: str = "claude-3-sonnet-20240229"
GROQ_MODEL: str = "llama-3.3-70b-versatile"
# Per-task model routing (Production Grade)
MAX_RETRIES: int = 2
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# FIX: HARD LLM CALL LIMITS (Prevent rate limit exhaustion)
# OPTIMIZED for GUVI's 30s timeout & Groq free tier rate limits
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
MAX_LLM_CALLS_PER_REQUEST: int = 6 # Reduced from 10 - fits within 20s timeout
MAX_LLM_CALLS_PER_SESSION: int = 20 # Reduced from 30 - prevents key exhaustion
# Per-task model routing (Production Grade)
# FIX: llama-3.3-70b fails JSON_SCHEMA mode with 400. Use qwen3-32b for structured.
GROQ_FAST_MODEL: str = "llama-3.1-8b-instant" # Blazing fast (~300 tokens/sec)
GROQ_SMART_MODEL: str = "qwen/qwen3-32b" # Native reasoning, 60 RPM
GROQ_NATURAL_MODEL: str = "moonshotai/kimi-k2-instruct-0905"
GROQ_STRUCTURED_MODEL: str = "qwen/qwen3-32b" # FIX: Supports JSON_SCHEMA properly
GROQ_SAFETY_MODEL: str = "meta-llama/llama-guard-4-12b"
GROQ_SAFEGUARD_MODEL: str = "openai/gpt-oss-safeguard-20b"
OPENROUTER_MODEL: str = "meta-llama/llama-3.1-70b-instruct"
# LLM parameters
LLM_TEMPERATURE: float = 0.7
LLM_MAX_TOKENS: int = 500
# Conversation
MAX_CONVERSATION_LENGTH: int = 50
CONVERSATION_TTL_HOURS: int = 24
# Rate Limiting
RATE_LIMIT_PER_MINUTE: int = 60
# Feature Flags
ENABLE_LLM_DETECTION: bool = True
ENABLE_LLM_RESPONSES: bool = True
ENABLE_THREAT_INTELLIGENCE: bool = True
ENABLE_LAW_ENFORCEMENT_API: bool = False # Disabled for hackathon
ENABLE_ENGAGEMENT_DELAY: bool = False
# Forensic Clinic (Compound Systems)
ENABLE_MATH_FORENSICS: bool = False # ๐Ÿงฎ Claim Verifier (Compound-Mini)
ENABLE_VISUAL_EVIDENCE: bool = False # ๐Ÿ“Š Chart Lab (Compound)
# Database (SQLite default, PostgreSQL/Supabase via env)
DATABASE_URL: str = "sqlite+aiosqlite:///./data/honeypot.db"
# Compliance
SANDBOX_MODE: bool = False
ANONYMIZE_LOGS: bool = True
SYNTHETIC_DATA_ONLY: bool = False
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=True,
extra="allow"
)
@lru_cache()
def get_settings() -> Settings:
return Settings()
settings = get_settings()
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
# FIX 3 & 4: STARTUP VALIDATION (Fail Fast)
# โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•
def validate_production_config():
"""Validates critical config at startup. Raises RuntimeError if invalid."""
errors = []
# FIX 3: GUVI_API_KEY must be set for scoring
if not settings.GUVI_API_KEY:
errors.append("GUVI_API_KEY missing โ€” scoring impossible")
# FIX 4: Exactly ONE *external* LLM provider key must be set
# EXCEPTION: When USE_LOCAL_HF_MODEL=True we allow zero external keys
active_keys = [
("GROQ_API_KEY", settings.GROQ_API_KEY),
("OPENAI_API_KEY", settings.OPENAI_API_KEY),
("ANTHROPIC_API_KEY", settings.ANTHROPIC_API_KEY),
("OPENROUTER_API_KEY", settings.OPENROUTER_API_KEY),
]
set_keys = [(name, key) for name, key in active_keys if key]
if len(set_keys) == 0 and not settings.USE_LOCAL_HF_MODEL:
errors.append("No LLM API key set โ€” system cannot function (set USE_LOCAL_HF_MODEL=True to enable offline mode)")
elif len(set_keys) > 1:
key_names = [name for name, _ in set_keys]
errors.append(f"Multiple LLM API keys set ({', '.join(key_names)}) โ€” please use exactly one")
# In production, fail hard
if errors and not settings.DEBUG:
raise RuntimeError("๐Ÿšจ CONFIG VALIDATION FAILED:\n - " + "\n - ".join(errors))
elif errors:
# In debug mode, just warn
import warnings
for err in errors:
warnings.warn(f"โš ๏ธ CONFIG WARNING: {err}")
# Run validation at import time (fail fast)
validate_production_config()