montana/Русский/Логистика/config.py

289 lines
12 KiB
Python
Raw Permalink Normal View History

"""
SeaFare Montana Centralized Configuration
All hardcoded constants in one place.
"""
# =============================================================================
# APPLICATION
# =============================================================================
APP_VERSION = '3.44.0'
DEFAULT_PORT = 5050
ALLOWED_ORIGINS = [
"https://seafare.efir.org",
"https://seafare-montana.duckdns.org", # legacy
]
# Dev origins added dynamically if FLASK_DEBUG is set (see seafare_api.py)
# =============================================================================
# AI PROVIDERS — priority: mistral → cerebras → groq → openrouter (no claude)
# =============================================================================
# Provider selection: 'mistral', 'cerebras', 'groq', 'openrouter', 'auto' (tries in order)
AI_PROVIDER = 'auto'
# Groq (free, fast — Llama 3.3 70B)
GROQ_MODEL = "llama-3.3-70b-versatile"
GROQ_MODEL_LIGHT = "llama-3.1-8b-instant" # for casual chat
GROQ_MAX_TOKENS = 2048
GROQ_TIMEOUT = 15.0
ENV_GROQ_API_KEY = "GROQ_API_KEY"
# Mistral (cheap fallback)
MISTRAL_MODEL = "mistral-large-latest"
MISTRAL_MODEL_LIGHT = "mistral-small-latest"
MISTRAL_MAX_TOKENS = 2048
MISTRAL_TIMEOUT = 15.0
ENV_MISTRAL_API_KEY = "MISTRAL_API_KEY"
# OpenRouter (free tier — DeepSeek, Gemini Flash, etc.)
OPENROUTER_MODEL = 'meta-llama/llama-3.3-70b-instruct:free'
OPENROUTER_MODEL_LIGHT = 'meta-llama/llama-3.3-70b-instruct:free'
OPENROUTER_MAX_TOKENS = 2048
OPENROUTER_TIMEOUT = 45.0
OPENROUTER_BASE_URL = 'https://openrouter.ai/api/v1'
ENV_OPENROUTER_API_KEY = 'OPENROUTER_API_KEY'
# Cerebras (free — 1M tokens/day, OpenAI-compatible)
CEREBRAS_MODEL = 'qwen-3-235b-a22b-instruct-2507'
CEREBRAS_MODEL_LIGHT = 'llama3.1-8b'
CEREBRAS_MAX_TOKENS = 2048
CEREBRAS_TIMEOUT = 45.0
CEREBRAS_BASE_URL = 'https://api.cerebras.ai/v1'
ENV_CEREBRAS_API_KEY = 'CEREBRAS_API_KEY'
# Claude (kept for agent tools only — NOT in auto chain)
CLAUDE_MODEL = "claude-sonnet-4-5-20250929"
CLAUDE_MAX_TOKENS = 2048
CLAUDE_TIMEOUT = 45.0
AGENT_MAX_TOOL_ITERATIONS = 4
# Per-session budget control (input tokens)
AGENT_BUDGET_SOFT_INPUT = 5000 # inject "be concise" hint after this
AGENT_BUDGET_HARD_INPUT = 12000 # force stop loop after this
# Claude pricing ($/1M tokens, Sonnet 4.5)
CLAUDE_PRICE_INPUT = 3.0
CLAUDE_PRICE_OUTPUT = 15.0
CLAUDE_PRICE_CACHE_WRITE = 3.75
CLAUDE_PRICE_CACHE_READ = 0.30
# Moltbook integration
MOLTBOOK_BASE_URL = "https://www.moltbook.com/api/v1"
# Contact unlock price (currently free)
CONTACT_UNLOCK_PRICE = 0.0
# =============================================================================
# AUTH
# =============================================================================
TOKEN_MAX_AGE = 30 * 24 * 3600 # 30 days in seconds
# =============================================================================
# RATE LIMITS
# =============================================================================
RATE_LIMIT_DEFAULT_MAX_CALLS = 30
RATE_LIMIT_DEFAULT_PERIOD = 60 # seconds
RATE_LIMIT_CHAT_AUTH_MAX = 30 # authenticated user chat
RATE_LIMIT_CHAT_AUTH_PERIOD = 60
RATE_LIMIT_CHAT_ANON_MAX = 5 # anonymous user chat
RATE_LIMIT_CHAT_ANON_PERIOD = 3600
RATE_LIMIT_CLEANUP_INTERVAL = 300 # bucket cleanup every 5 min
# =============================================================================
# CACHING
# =============================================================================
POSITION_CACHE_MINUTES = 5
VESSEL_CACHE_HOURS = 24
PORT_CACHE_MINUTES = 15
# =============================================================================
# DATABASE
# =============================================================================
PG_POOL_MIN_CONN = 1
PG_POOL_MAX_CONN = 5
# Position cleanup
POSITION_CLEANUP_INTERVAL_HOURS = 6
POSITION_KEEP_HOURS = 48
# =============================================================================
# EQUASIS
# =============================================================================
EQUASIS_DAILY_LIMIT = 400 # conservative (actual ~500)
EQUASIS_CACHE_HOURS = {
'search': 24, # search results: 24h
'details': 168, # vessel details: 7 days
'contacts': 168, # company contacts: 7 days
}
# =============================================================================
# WALLET / PAYMENTS (USDT TRC20)
# =============================================================================
USDT_TRC20_CONTRACT = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t'
DEPOSIT_FEE_PERCENT = 2.0
DEPOSIT_FEE_MIN = 0.10
WITHDRAW_FEE = 1.0
WITHDRAW_MIN = 2.0
# =============================================================================
# AGENT MEMORY
# =============================================================================
MEMORY_MAX_FACTS = 50 # max memories per user
MEMORY_INJECT_LIMIT = 10 # memories injected into prompt
MEMORY_SUMMARY_INTERVAL = 20 # summarize every N messages
MEMORY_DECAY_HALFLIFE_DAYS = 30 # half-life for relevance decay
# =============================================================================
# SECURITY
# =============================================================================
CHAT_MESSAGE_MAX_LENGTH = 2000 # max user message length (chars)
MEMORY_CONTENT_MAX_LENGTH = 200 # max single memory entry length
# =============================================================================
# SMART PARSE (Layer 2 — local entity extraction, 0 tokens)
# =============================================================================
SMART_PARSE_MAX_LENGTH = 200 # skip smart parse for messages longer than this
SMART_PARSE_FUZZY_THRESHOLD = 0.65 # minimum difflib score for fuzzy vessel match
PROFILE_CACHE_TTL = 60 # seconds — profile cache for fast path layers
# =============================================================================
# LIGHTWEIGHT AI EXTRACTION (Layer 3 — ~230 tokens per query)
# =============================================================================
LAYER3_EXTRACT_MAX_TOKENS = 150 # max tokens for AI extraction response
LAYER3_MAX_MESSAGE_LENGTH = 300 # skip Layer 3 for messages longer than this
# =============================================================================
# VESSEL COLLECTOR (background Med/Baltic/Caspian enrichment)
# =============================================================================
COLLECTOR_CYCLE_HOURS = 6 # run every 6 hours
COLLECTOR_MAX_PER_CYCLE = 40 # max vessels to enrich per cycle
COLLECTOR_EQUASIS_RESERVE = 50 # stop if equasis remaining < this
COLLECTOR_ENRICHMENT_TTL_DAYS = 7 # re-enrich after 7 days
COLLECTOR_MIN_TYPE_CODE = 70 # only cargo (70+) and tanker (80+)
# Freight-only filter (temporary — set False to show all vessel types)
FREIGHT_VESSELS_ONLY = True
FREIGHT_MIN_TYPE_CODE = 70 # cargo (70-79) + tanker (80-89)
# Vessel type category codes (for compact bulk API response)
TYPE_CAT_CODES = {
'tanker': 0, 'bulk': 1, 'container': 2, 'cargo': 3,
'passenger': 4, 'roro': 5, 'fishing': 6, 'tug': 7,
'offshore': 8, 'other': 9
}
TYPE_CAT_NAMES = {v: k for k, v in TYPE_CAT_CODES.items()}
# =============================================================================
# ENVIRONMENT VARIABLE NAMES
# =============================================================================
ENV_ANTHROPIC_API_KEY = 'ANTHROPIC_API_KEY'
ENV_SECRET_KEY = 'SECRET_KEY'
ENV_GOOGLE_CLIENT_ID = 'GOOGLE_CLIENT_ID'
ENV_ADMIN_EMAILS = 'ADMIN_EMAILS'
ENV_DATABASE_URL = 'DATABASE_URL'
ENV_MOLTBOOK_API_KEY = 'MOLTBOOK_API_KEY'
ENV_AISSTREAM_API_KEY = 'AISSTREAM_API_KEY'
ENV_AISHUB_USERNAME = 'AISHUB_USERNAME'
ENV_DIGITRAFFIC_ENABLED = 'DIGITRAFFIC_ENABLED'
ENV_RENDER_EXTERNAL_URL = 'RENDER_EXTERNAL_URL'
ENV_SEAFARE_PORT = 'SEAFARE_PORT'
ENV_FLASK_DEBUG = 'FLASK_DEBUG'
# ==================================================================
# ROLE-BASED SYSTEM (v3.39.0)
# ==================================================================
ROLE_GROUPS = {
"fleet": ["shipowner", "operator"],
"cargo": ["charterer", "freight_forwarder"],
"market": ["broker", "port_agent", "surveyor"],
}
ROLE_PROMPT_ADDONS = {
"fleet": (
"User is a SHIPOWNER/OPERATOR. They likely ask about THEIR OWN vessels. "
"Check vessels_of_interest first for disambiguation. "
"Focus on: fleet tracking, cargo matching for their vessels, contacts of charterers, route optimization. "
"Style: technical maritime terminology, concise operational data."
),
"cargo": (
"User is a CARGO OWNER/CHARTERER. They need to SHIP cargo. "
"Focus on: finding available vessels, freight estimates, route/time, vessel vetting, owner contacts. "
"Style: business-oriented, cost comparisons, delivery timelines."
),
"market": (
"User is a BROKER/AGENT. They match cargo to vessels. "
"Focus on: market intelligence, vessel availability by region, owner/operator contacts, tonnage specs. "
"Style: professional, data-dense, comparative tables."
),
}
OUT_OF_SCOPE_KEYWORDS = {
"demurrage": ["демередж", "demurrage", "demora", "простой судна", "штраф за простой", "laytime"],
"bunker": ["бункер", "bunker", "vlsfo", "hsfo", "mgo", "fuel price", "цена топлив"],
"sanctions": ["санкци", "санкции", "sanctions", "sanciones", "ofac", "screening", "скрининг"],
"charter_party": ["чартер-парти", "charter party", "carta de fletamento", "тайм-чартер"],
"bill_of_lading": ["коносамент", "bill of lading", "conocimiento de embarque"],
"fixture_recap": ["fixture recap", "фикстура", "рекап"],
"insurance": ["страхов", "insurance", "seguro", "p&i club", "hull insurance"],
"port_costs": ["портовые расход", "port cost", "costos portuarios", "лоцман", "pilotage", "remolcador"],
"congestion": ["загруженност", "congestion", "пробка в порту"],
"weather": ["погод", "weather", "clima", "шторм", "forecast", "pronostico", "tiempo"],
"crew": ["экипаж", "crew change", "manning", "смена экипажа"],
"performance": ["cii рейтинг", "cii rating", "vessel performance", "производительн", "расход топлив"],
"dark_fleet": ["dark fleet", "теневой флот", "тёмн", "flota oscura", "shadow fleet"],
"ais_anomaly": ["ais аномали", "ais anomal", "spoofing", "спуфинг"],
"freight_rate": ["ставка фрахт", "freight rate", "tasa de flete", "bdi", "baltic dry", "baltic index", "стоит фрахт", "цена фрахт", "фрахтовая ставка", "cost of freight"],
"laycan": ["laycan", "лейкан", "lay can", "lay/can"],
"laytime": ["laytime", "лейтайм", "lay time", "loading rate", "норма погрузки", "discharge rate", "норма выгрузки"],
"tce": ["tce", "time charter equivalent", "тайм-чартерный эквивалент"],
"port_dues": ["port dues", "портовые сбор", "terminal handling", "thc", "причальный сбор"],
}
OUT_OF_SCOPE_RESPONSE = {
"en": (
"This is outside our current service scope. "
"We specialize in: **vessel tracking & search**, **route calculation**, "
"**cargo-to-vessel matching**, and **owner/operator contacts**. "
"How can I help you with these?"
),
"zh": (
"这超出了我们当前的服务范围。"
"我们专注于:**船舶追踪与搜索**、**航线计算**、"
"**货物匹配船舶** 和 **船主/运营商联系人**。"
"我能在这些方面为您提供帮助吗?"
),
"es": (
"Esto está fuera de nuestros servicios actuales. "
"Nos especializamos en: **rastreo de buques**, **cálculo de rutas**, "
"**selección de buques para carga** y **contactos de armadores/operadores**. "
"¿Cómo puedo ayudarle con estos servicios?"
),
"ru": (
"Это за рамками наших текущих сервисов. "
"Мы специализируемся на: **отслеживание судов**, **расчёт маршрутов**, "
"**подбор судов под груз** и **контакты владельцев/операторов**. "
"Чем могу помочь в этих направлениях?"
),
}