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

289 lines
12 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
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": (
"Это за рамками наших текущих сервисов. "
"Мы специализируемся на: **отслеживание судов**, **расчёт маршрутов**, "
"**подбор судов под груз** и **контакты владельцев/операторов**. "
"Чем могу помочь в этих направлениях?"
),
}