merge: chore/cleanup-remove-bloat-and-secrets into main
This commit is contained in:
commit
bde2f3a97d
1173 changed files with 437609 additions and 0 deletions
276
app/routers/intelligence_panel.py
Normal file
276
app/routers/intelligence_panel.py
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
"""
|
||||
Intelligence Panel Router
|
||||
=========================
|
||||
Endpoints for the intelligence feed panel on rugmunch.io/intelligence
|
||||
|
||||
Data sources:
|
||||
- News service (200+ crypto news sources, 15 tiers)
|
||||
- Security alerts (rug detection, whale tracking)
|
||||
- Prediction market signals (Polymarket, Kalshi, Limitless, Manifold)
|
||||
- Crypto Fear Index (aggregated risk from prediction markets)
|
||||
- Bulletin posts (community intelligence)
|
||||
"""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from fastapi import APIRouter, Query
|
||||
from pydantic import BaseModel
|
||||
|
||||
from app.core.logging import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
router = APIRouter(prefix="/api/v1/intelligence", tags=["intelligence-panel"])
|
||||
|
||||
# Import prediction market intelligence (LAZY — deferred to first request)
|
||||
pm_intel = None
|
||||
_pm_intel_loaded = False
|
||||
|
||||
|
||||
def _get_pm_intel():
|
||||
global pm_intel, _pm_intel_loaded
|
||||
if _pm_intel_loaded:
|
||||
return pm_intel
|
||||
_pm_intel_loaded = True
|
||||
try:
|
||||
from app.services.prediction_market_intel import (
|
||||
get_prediction_market_intel,
|
||||
)
|
||||
|
||||
pm_intel = get_prediction_market_intel()
|
||||
except ImportError:
|
||||
pm_intel = None
|
||||
return pm_intel
|
||||
|
||||
|
||||
class IntelSignalResponse(BaseModel):
|
||||
signal_type: str
|
||||
severity: str
|
||||
headline: str
|
||||
insight: str
|
||||
action: str
|
||||
confidence: float
|
||||
generated_at: str
|
||||
|
||||
|
||||
class FearIndexResponse(BaseModel):
|
||||
overall_risk: float
|
||||
exploit_risk: float
|
||||
regulatory_risk: float
|
||||
stablecoin_risk: float
|
||||
exchange_risk: float
|
||||
generated_at: str
|
||||
|
||||
|
||||
class IntelligenceItem(BaseModel):
|
||||
id: str
|
||||
title: str
|
||||
content: str | None = None
|
||||
url: str | None = None
|
||||
source: str
|
||||
published_at: str
|
||||
category: str
|
||||
kind: str
|
||||
highlight: bool | None = False
|
||||
severity: str | None = None
|
||||
|
||||
|
||||
class IntelligenceFeedResponse(BaseModel):
|
||||
items: list[IntelligenceItem]
|
||||
count: int
|
||||
timestamp: str
|
||||
|
||||
|
||||
# ── Prediction Market Intelligence ─────────────────────────
|
||||
|
||||
|
||||
@router.get("/prediction-signals", response_model=list[IntelSignalResponse])
|
||||
async def get_prediction_signals(limit: int = Query(10, ge=1, le=20)):
|
||||
"""Get actionable intelligence signals from prediction markets.
|
||||
|
||||
Signal types:
|
||||
- HIGH_CONSENSUS_THREAT: Markets strongly expect an adverse event
|
||||
- LOW_CONSENSUS_RISK: Markets dismiss a feared risk
|
||||
- TOKEN_RISK_SIGNAL: Specific token flagged by prediction markets
|
||||
- ECOSYSTEM_RISK: Broad ecosystem-level threat indicator
|
||||
|
||||
Each signal includes: severity, plain-English insight, recommended action.
|
||||
"""
|
||||
_get_pm_intel()
|
||||
if not pm_intel:
|
||||
return []
|
||||
|
||||
signals = await pm_intel.generate_signals(max_signals=limit)
|
||||
return [
|
||||
IntelSignalResponse(
|
||||
signal_type=s.signal_type,
|
||||
severity=s.severity,
|
||||
headline=s.headline,
|
||||
insight=s.insight,
|
||||
action=s.action,
|
||||
confidence=round(s.confidence, 2),
|
||||
generated_at=s.generated_at,
|
||||
)
|
||||
for s in signals
|
||||
]
|
||||
|
||||
|
||||
@router.get("/crypto-fear-index", response_model=FearIndexResponse)
|
||||
async def get_crypto_fear_index():
|
||||
"""Get the Crypto Fear Index — risk aggregated from prediction markets.
|
||||
|
||||
Components:
|
||||
- overall_risk: Weighted aggregate of all categories
|
||||
- exploit_risk: DeFi hack/exploit/vulnerability probability
|
||||
- regulatory_risk: SEC/CFTC/enforcement action probability
|
||||
- stablecoin_risk: Depeg/collapse probability
|
||||
- exchange_risk: Insolvency/breach probability
|
||||
|
||||
Derived from live prediction market data across Polymarket, Kalshi, Limitless, Manifold.
|
||||
Higher = more risk priced in by traders with real money at stake.
|
||||
"""
|
||||
_get_pm_intel()
|
||||
if not pm_intel:
|
||||
return FearIndexResponse(
|
||||
overall_risk=0,
|
||||
exploit_risk=0,
|
||||
regulatory_risk=0,
|
||||
stablecoin_risk=0,
|
||||
exchange_risk=0,
|
||||
generated_at=datetime.now(UTC).isoformat(),
|
||||
)
|
||||
|
||||
fear = await pm_intel.generate_crypto_fear_index()
|
||||
return FearIndexResponse(
|
||||
overall_risk=fear.overall_risk,
|
||||
exploit_risk=fear.exploit_risk,
|
||||
regulatory_risk=fear.regulatory_risk,
|
||||
stablecoin_risk=fear.stablecoin_risk,
|
||||
exchange_risk=fear.exchange_risk,
|
||||
generated_at=fear.generated_at,
|
||||
)
|
||||
|
||||
|
||||
# ── Aggregated Feed ────────────────────────────────────────
|
||||
|
||||
|
||||
@router.get("/feed", response_model=IntelligenceFeedResponse)
|
||||
async def get_intelligence_feed(limit: int = Query(20, ge=1, le=50)):
|
||||
"""Get aggregated intelligence feed combining all sources."""
|
||||
_get_pm_intel()
|
||||
items = []
|
||||
now_ts = datetime.now(UTC).isoformat()
|
||||
|
||||
# 1. Prediction market signals (highest priority — forward-looking)
|
||||
if pm_intel:
|
||||
try:
|
||||
signals = await pm_intel.generate_signals(max_signals=5)
|
||||
for s in signals:
|
||||
severity = s.severity
|
||||
items.append(
|
||||
IntelligenceItem(
|
||||
id=f"pm-{s.signal_type}-{now_ts}",
|
||||
title=s.headline,
|
||||
content=s.insight,
|
||||
url="/intelligence",
|
||||
source=f"Prediction Markets ({s.signal_type.replace('_', ' ').title()})",
|
||||
published_at=now_ts,
|
||||
category="prediction-market",
|
||||
kind="signal",
|
||||
highlight=(severity in ("critical", "high")),
|
||||
severity=severity,
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.info(f"Prediction market signals unavailable: {e}")
|
||||
# 2. Crypto Fear Index summary
|
||||
if pm_intel:
|
||||
try:
|
||||
fear = await pm_intel.generate_crypto_fear_index()
|
||||
risk_label = (
|
||||
"EXTREME FEAR"
|
||||
if fear.overall_risk >= 75
|
||||
else "FEAR"
|
||||
if fear.overall_risk >= 50
|
||||
else "NEUTRAL"
|
||||
if fear.overall_risk >= 25
|
||||
else "GREED"
|
||||
if fear.overall_risk >= 10
|
||||
else "EXTREME GREED"
|
||||
)
|
||||
items.append(
|
||||
IntelligenceItem(
|
||||
id=f"fear-index-{now_ts}",
|
||||
title=f"Crypto Fear Index: {fear.overall_risk:.0f}/100 — {risk_label}",
|
||||
content=(
|
||||
f"Exploit risk: {fear.exploit_risk:.0f}/100 | "
|
||||
f"Regulatory: {fear.regulatory_risk:.0f}/100 | "
|
||||
f"Stablecoin: {fear.stablecoin_risk:.0f}/100 | "
|
||||
f"Exchange: {fear.exchange_risk:.0f}/100. "
|
||||
f"Derived from live Polymarket + Kalshi + Manifold prediction markets."
|
||||
),
|
||||
url="/intelligence",
|
||||
source="Crypto Fear Index",
|
||||
published_at=now_ts,
|
||||
category="risk-index",
|
||||
kind="index",
|
||||
highlight=(fear.overall_risk >= 50),
|
||||
severity="high" if fear.overall_risk >= 50 else "medium",
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
logger.info(f"Crypto Fear Index unavailable: {e}")
|
||||
# 3. Prediction market data sources status
|
||||
items.append(
|
||||
IntelligenceItem(
|
||||
id=f"sources-{now_ts}",
|
||||
title="Prediction Market Intelligence Active — 4 Sources Live",
|
||||
content="RMI now monitors Polymarket, Kalshi, Limitless, and Manifold for crypto security signals. Live risk indicators, token threat detection, and ecosystem monitoring are online.",
|
||||
url="/intelligence",
|
||||
source="RMI System",
|
||||
published_at=now_ts,
|
||||
category="system",
|
||||
kind="status",
|
||||
highlight=False,
|
||||
)
|
||||
)
|
||||
|
||||
return IntelligenceFeedResponse(
|
||||
items=items[:limit],
|
||||
count=min(len(items), limit),
|
||||
timestamp=now_ts,
|
||||
)
|
||||
|
||||
|
||||
@router.get("/latest")
|
||||
async def get_latest_intelligence():
|
||||
"""Get latest intelligence snapshot for quick updates."""
|
||||
_get_pm_intel()
|
||||
latest = {
|
||||
"timestamp": datetime.now(UTC).isoformat(),
|
||||
}
|
||||
|
||||
if pm_intel:
|
||||
try:
|
||||
signals = await pm_intel.generate_signals(max_signals=3)
|
||||
if signals:
|
||||
top = signals[0]
|
||||
latest["top_signal"] = {
|
||||
"headline": top.headline,
|
||||
"severity": top.severity,
|
||||
"insight": top.insight,
|
||||
"action": top.action,
|
||||
}
|
||||
|
||||
fear = await pm_intel.generate_crypto_fear_index()
|
||||
latest["fear_index"] = {
|
||||
"overall": fear.overall_risk,
|
||||
"exploit": fear.exploit_risk,
|
||||
"regulatory": fear.regulatory_risk,
|
||||
"stablecoin": fear.stablecoin_risk,
|
||||
"exchange": fear.exchange_risk,
|
||||
}
|
||||
except Exception as e:
|
||||
latest["error"] = str(e)
|
||||
|
||||
return latest
|
||||
Loading…
Add table
Add a link
Reference in a new issue