Download backend/intelligence.py from AIBRUH/big-proppa: direct link, hf CLI and curl.
- Browser
- Download file 19.3 kB
-
https://huggingface.co/AIBRUH/big-proppa/resolve/main/backend/intelligence.py
- Command line
-
hf download hf://AIBRUH/big-proppa/backend/intelligence.py
-
curl -L -o intelligence.py https://huggingface.co/AIBRUH/big-proppa/resolve/main/backend/intelligence.py
19.3 kB
| """ | |
| Intelligence layer: Claude + JEV + NVIDIA NIM working as a team. | |
| Architecture: | |
| Claude (Anthropic) — strategist: reads the lake snapshot, identifies | |
| overhyped lines, hidden correlations, best spots. | |
| Returns natural language analysis + specific testable | |
| hypotheses. | |
| JEV (TypeSafe) — probability engine: given each Claude hypothesis, | |
| scores it as a structured Noul probability (0-1). | |
| NVIDIA NIM — validator: independent second LLM pass on the top | |
| consensus findings for cross-verification. | |
| All three degrade gracefully when their key is absent. The result always | |
| reports which providers contributed so the UI can show connection state. | |
| Daily cached (same as jimmy_hunt). Force refresh with invalidate_cache(). | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import textwrap | |
| from datetime import datetime, timezone | |
| from functools import lru_cache | |
| from typing import Any | |
| import data | |
| import jimmy | |
| import jimmy_hunt | |
| import jev | |
| # --------------------------------------------------------------------------- | |
| # Provider availability | |
| # --------------------------------------------------------------------------- | |
| def _anthropic_client(): | |
| try: | |
| import anthropic | |
| key = os.environ.get("ANTHROPIC_API_KEY") | |
| if not key: | |
| return None | |
| return anthropic.Anthropic(api_key=key) | |
| except ImportError: | |
| return None | |
| def claude_available() -> bool: | |
| return _anthropic_client() is not None | |
| def nvidia_available() -> bool: | |
| return bool(os.environ.get("NVIDIA_API_KEY")) | |
| _GEMMA_LOCAL_URL = "http://127.0.0.1:8765" | |
| def gemma_available() -> bool: | |
| """Gemma runs locally via Ollama on port 8765.""" | |
| try: | |
| import httpx | |
| r = httpx.get(f"{_GEMMA_LOCAL_URL}/health", timeout=3.0) | |
| return r.status_code == 200 | |
| except Exception: | |
| return False | |
| def ai_status() -> dict: | |
| jev_diag = jev.diagnose() | |
| return { | |
| "claude": { | |
| "connected": claude_available(), | |
| "model": "claude-opus-5-5", | |
| "keyVar": "ANTHROPIC_API_KEY", | |
| }, | |
| "jev": { | |
| "connected": jev.available(), | |
| "model": "jev-latest", | |
| "keyVar": jev_diag.get("activeKeyVar"), | |
| "callTest": jev_diag.get("callTest"), | |
| }, | |
| "nvidia": { | |
| "connected": nvidia_available(), | |
| "model": "meta/llama-3.2-11b-vision-instruct", | |
| "keyVar": "NVIDIA_API_KEY", | |
| }, | |
| "gemma": { | |
| "connected": gemma_available(), | |
| "model": "gemma3:4b Q4 (local)", | |
| "keyVar": "Ollama :8765", | |
| }, | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Lake snapshot — compact context for the LLMs | |
| # --------------------------------------------------------------------------- | |
| def _lake_snapshot() -> str: | |
| """ | |
| A compact but complete picture of this week's lake: matchup edges, | |
| top-usage players, hunt picks, and recent hit-rate vs lines. | |
| Kept under ~6K tokens so Claude can reason over it efficiently. | |
| """ | |
| lines: list[str] = [] | |
| # Matchup edges for this week | |
| try: | |
| from matchup import slate | |
| games = slate() | |
| lines.append("=== WEEK 3 MATCHUP EDGES (z-score, + favors offense) ===") | |
| for g in games[:8]: | |
| h, a = g["home"], g["away"] | |
| edge_str = " | ".join(f"{u}:{h['edges'].get(u,0):+.2f}" for u in ["SCORING","AIR","GROUND"]) | |
| lines.append(f"{h['team']} vs {a['team']} — HOME: {edge_str}") | |
| except Exception as e: | |
| lines.append(f"[matchup snapshot error: {e}]") | |
| # Top-usage players by position | |
| try: | |
| usage_rows = sorted( | |
| [r for r in data.load("player_usage") if r.get("usage_index_score")], | |
| key=lambda r: float(r.get("usage_index_score", 0)), reverse=True | |
| ) | |
| lines.append("\n=== TOP USAGE PLAYERS (coach trust score) ===") | |
| pos_seen: dict[str, int] = {} | |
| for r in usage_rows: | |
| pos = (r.get("position") or "").upper() | |
| if pos not in ("QB","RB","WR","TE"): | |
| continue | |
| if pos_seen.get(pos, 0) >= 3: | |
| continue | |
| pos_seen[pos] = pos_seen.get(pos, 0) + 1 | |
| lines.append(f"{pos} {r['player_name']} ({r['team']}) usage={r['usage_index_score']}") | |
| except Exception as e: | |
| lines.append(f"[usage snapshot error: {e}]") | |
| # Hunt picks — Jimmy's best per question | |
| try: | |
| hunt = jimmy_hunt.hunt() | |
| lines.append("\n=== JIMMY'S TOP PICKS THIS WEEK ===") | |
| for q in hunt["questions"][:12]: | |
| if q["players"]: | |
| best = q["players"][0] | |
| lines.append( | |
| f"{q['question']}: {best['name']} ({best['team']}) " | |
| f"jimmy={best['jimmyScore']} jev={best.get('jevScore','?')} " | |
| f"defWeakness={best.get('defWeakness','?')}" | |
| ) | |
| except Exception as e: | |
| lines.append(f"[hunt snapshot error: {e}]") | |
| # Recent performance vs lines (L2, since we only have 2 weeks) | |
| try: | |
| lines.append("\n=== L2 PERFORMANCE VS FANDUEL LINE (sample players) ===") | |
| from jimmy_hunt import _hit_rate | |
| sample = [("00-0036963","A.St. Brown","WR","recyds",80.5), | |
| ("00-0033280","C.McCaffrey","RB","rushyds",75.5), | |
| ("00-0035228","J.Jefferson","WR","recyds",80.5)] | |
| for pid, name, pos, mkt, line_ in sample: | |
| hr = _hit_rate(pid, mkt, line_, "over") | |
| lines.append(f"{pos} {name}: L2 hit rate {mkt}>{line_} = {hr}") | |
| except Exception as e: | |
| lines.append(f"[L2 snapshot error: {e}]") | |
| return "\n".join(lines) | |
| # --------------------------------------------------------------------------- | |
| # Claude analysis | |
| # --------------------------------------------------------------------------- | |
| _CLAUDE_SYSTEM = textwrap.dedent(""" | |
| You are Jimmy the Greek's analytical brain — a sharp, concise NFL prop analyst | |
| with deep knowledge of how betting markets misprice player props in early-season | |
| games when sample sizes are small and books rely on reputation rather than data. | |
| You receive a lake snapshot: matchup unit edges, usage/coach-trust scores, and | |
| prop-pick recommendations. Your job: | |
| 1. IDENTIFY OVERHYPED PROPS — lines the market has set inflated vs actual lake | |
| signals (e.g., a WR the offense clearly trusts less than their line implies). | |
| 2. FIND CORRELATIONS — pairs of props that tend to move together (e.g., if a | |
| team is weak AIR unit, the QB's yards AND the WR's yards both get a boost). | |
| 3. SPOT VALUE — props where the lake says yes but the market is undervaluing | |
| (defWeakness high, usage score high, matchup edge positive). | |
| Output exactly 5–8 "nuggets" as a JSON array (nothing else — no prose wrapper): | |
| [ | |
| { | |
| "rank": 1, | |
| "claim": "one specific, actionable claim about a player/prop", | |
| "category": "overhyped" | "correlation" | "value", | |
| "action": "BET OVER / BET UNDER / PARLAY WITH [X]", | |
| "reasoning": "2-3 sentences max", | |
| "testable": "a yes/no question JEV can score" | |
| } | |
| ] | |
| """).strip() | |
| def _ask_claude(lake_ctx: str, query: str | None = None) -> list[dict]: | |
| client = _anthropic_client() | |
| if not client: | |
| return [] | |
| try: | |
| import anthropic | |
| prompt = lake_ctx | |
| if query: | |
| prompt += f"\n\n=== USER QUERY ===\n{query}\n\nAnswer the query using the lake data above. Still output 5-8 nuggets as JSON." | |
| msg = client.messages.create( | |
| model="claude-opus-5-5", | |
| max_tokens=1500, | |
| system=_CLAUDE_SYSTEM, | |
| messages=[{"role": "user", "content": prompt}], | |
| ) | |
| raw = msg.content[0].text.strip() | |
| # Strip markdown code fences if present | |
| if raw.startswith("```"): | |
| raw = raw.split("```")[1] | |
| if raw.startswith("json"): | |
| raw = raw[4:] | |
| return json.loads(raw) | |
| except Exception as e: | |
| return [{"error": str(e), "rank": 0}] | |
| # --------------------------------------------------------------------------- | |
| # NVIDIA NIM — primary generation (when Claude absent) + validation | |
| # --------------------------------------------------------------------------- | |
| _NVIDIA_BASE = "https://integrate.api.nvidia.com/v1" | |
| _NVIDIA_MODEL = "meta/llama-3.2-11b-vision-instruct" | |
| def _nvidia_generate(lake_ctx: str) -> list[dict]: | |
| """Use NVIDIA as primary nugget generator when Claude is unavailable.""" | |
| key = os.environ.get("NVIDIA_API_KEY") | |
| if not key: | |
| return [] | |
| try: | |
| import httpx | |
| resp = httpx.post( | |
| f"{_NVIDIA_BASE}/chat/completions", | |
| headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, | |
| json={ | |
| "model": _NVIDIA_MODEL, | |
| "messages": [ | |
| {"role": "system", "content": _CLAUDE_SYSTEM}, | |
| {"role": "user", "content": lake_ctx}, | |
| ], | |
| "max_tokens": 1500, | |
| "temperature": 0.4, | |
| }, | |
| timeout=90.0, | |
| ) | |
| resp.raise_for_status() | |
| raw = resp.json()["choices"][0]["message"]["content"].strip() | |
| if raw.startswith("```"): | |
| raw = raw.split("```")[1] | |
| if raw.startswith("json"): | |
| raw = raw[4:] | |
| return json.loads(raw) | |
| except Exception as e: | |
| return [{"error": str(e), "rank": 0}] | |
| def _ask_nvidia(nuggets: list[dict], lake_ctx: str) -> dict[int, str]: | |
| """Returns {rank: validation_comment} for the top nuggets.""" | |
| key = os.environ.get("NVIDIA_API_KEY") | |
| if not key or not nuggets: | |
| return {} | |
| try: | |
| import httpx | |
| top = [n for n in nuggets if "rank" in n and "testable" in n][:4] | |
| if not top: | |
| return {} | |
| questions = "\n".join(f"{n['rank']}. {n['testable']}" for n in top) | |
| prompt = ( | |
| f"You are an independent NFL analytics validator. Given this week's data " | |
| f"context and a set of betting prop claims, assess each claim's validity.\n\n" | |
| f"DATA CONTEXT:\n{lake_ctx[:2000]}\n\n" | |
| f"CLAIMS TO VALIDATE (answer each in 1 sentence — agree/disagree + why):\n{questions}" | |
| ) | |
| resp = httpx.post( | |
| f"{_NVIDIA_BASE}/chat/completions", | |
| headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, | |
| json={ | |
| "model": _NVIDIA_MODEL, | |
| "messages": [{"role": "user", "content": prompt}], | |
| "max_tokens": 600, | |
| "temperature": 0.3, | |
| }, | |
| timeout=60.0, | |
| ) | |
| resp.raise_for_status() | |
| text = resp.json()["choices"][0]["message"]["content"] | |
| # Parse line-by-line, map back to rank | |
| out = {} | |
| for line in text.strip().split("\n"): | |
| for n in top: | |
| if str(n["rank"]) in line[:5]: | |
| out[n["rank"]] = line.strip().lstrip("0123456789. ") | |
| break | |
| return out | |
| except Exception as e: | |
| return {0: f"NVIDIA error: {str(e)[:120]}"} | |
| # --------------------------------------------------------------------------- | |
| # Gemma 3 ZeroGPU analysis (HF Space) | |
| # --------------------------------------------------------------------------- | |
| def _ask_gemma(lake_ctx: str) -> list[dict]: | |
| """Call local Gemma 3 server (Ollama Q4, port 8765).""" | |
| try: | |
| import httpx | |
| resp = httpx.post( | |
| f"{_GEMMA_LOCAL_URL}/predict", | |
| json={"data": [lake_ctx[:4000]]}, | |
| headers={"Content-Type": "application/json"}, | |
| timeout=120.0, # CPU inference on 4B Q4 can take 60-90s | |
| ) | |
| resp.raise_for_status() | |
| raw = resp.json().get("data", ["[]"])[0] | |
| if isinstance(raw, str): | |
| if raw.startswith("```"): | |
| raw = raw.split("```")[1] | |
| if raw.startswith("json"): | |
| raw = raw[4:] | |
| return json.loads(raw) | |
| return raw if isinstance(raw, list) else [] | |
| except Exception as e: | |
| return [{"error": f"Gemma: {str(e)[:120]}", "rank": 0}] | |
| # --------------------------------------------------------------------------- | |
| # JEV scoring of Claude's hypotheses | |
| # --------------------------------------------------------------------------- | |
| def _score_nuggets_with_jev(nuggets: list[dict]) -> list[dict]: | |
| """Ask JEV to score each nugget's 'testable' question as a Noul probability.""" | |
| if not jev.available() or not nuggets: | |
| return nuggets | |
| enriched = [] | |
| for n in nuggets: | |
| if "error" in n or not n.get("testable"): | |
| enriched.append(n) | |
| continue | |
| try: | |
| prob = jev.leg_probability( | |
| player_id=n.get("claim", "unknown")[:20], | |
| name=n.get("claim", "")[:40], | |
| team="", | |
| market_slug="nugget", | |
| direction="over", | |
| line=0.5, | |
| hit_rate=None, | |
| usage_score=None, | |
| matchup_edge=None, | |
| opponent=None, | |
| ) | |
| enriched.append({**n, "jevProbability": prob}) | |
| except Exception: | |
| enriched.append(n) | |
| return enriched | |
| # --------------------------------------------------------------------------- | |
| # Daily cache | |
| # --------------------------------------------------------------------------- | |
| _cache: dict | None = None | |
| _cache_date: str = "" | |
| def invalidate_cache() -> None: | |
| global _cache, _cache_date | |
| _cache = None | |
| _cache_date = "" | |
| def nuggets(force: bool = False) -> dict: | |
| global _cache, _cache_date | |
| today = datetime.now(timezone.utc).strftime("%Y-%m-%d") | |
| if not force and _cache and _cache_date == today: | |
| return _cache | |
| result = _build_nuggets(today) | |
| _cache = result | |
| _cache_date = today | |
| return result | |
| def _build_nuggets(today: str) -> dict: | |
| lake_ctx = _lake_snapshot() | |
| # Primary nugget generation — Claude preferred, NVIDIA fallback | |
| claude_nuggets = _ask_claude(lake_ctx) | |
| claude_ok = bool(claude_nuggets and not any("error" in n for n in claude_nuggets)) | |
| if not claude_ok: | |
| # Claude unavailable — NVIDIA generates the nuggets | |
| nvidia_primary = _nvidia_generate(lake_ctx) | |
| primary_nuggets = nvidia_primary if nvidia_primary and not any("error" in n for n in nvidia_primary) else [] | |
| primary_source = "nvidia" | |
| else: | |
| primary_nuggets = claude_nuggets | |
| primary_source = "claude" | |
| # Gemma: independent open-weight perspective | |
| gemma_nuggets = _ask_gemma(lake_ctx) | |
| gemma_ok = bool(gemma_nuggets and not any("error" in n for n in gemma_nuggets)) | |
| # Merge primary + Gemma before JEV scoring — tag source | |
| combined: list[dict] = [] | |
| for n in primary_nuggets: | |
| combined.append({**n, "source": primary_source}) | |
| for n in (gemma_nuggets if gemma_ok else []): | |
| combined.append({**n, "rank": n.get("rank", 0) + 100, "source": "gemma"}) | |
| # JEV: probability scores on each claim | |
| if combined and not any("error" in n for n in combined): | |
| scored = _score_nuggets_with_jev(combined) | |
| else: | |
| scored = combined | |
| # NVIDIA: independent validation | |
| nvidia_comments = _ask_nvidia(scored, lake_ctx) | |
| # Merge and rank by consensus | |
| final = [] | |
| for n in scored: | |
| rank = n.get("rank", 99) | |
| jev_p = n.get("jevProbability") | |
| nvidia_note = nvidia_comments.get(rank) | |
| # Consensus score: average of what we have | |
| signals = [] | |
| if jev_p is not None: | |
| signals.append(jev_p) | |
| if nvidia_note and any(word in nvidia_note.lower() for word in ("agree", "correct", "strong", "confirm", "yes")): | |
| signals.append(0.75) | |
| elif nvidia_note and any(word in nvidia_note.lower() for word in ("disagree", "weak", "unlikely", "no")): | |
| signals.append(0.35) | |
| consensus = round(sum(signals) / len(signals), 3) if signals else None | |
| final.append({ | |
| **n, | |
| "jevProbability": jev_p, | |
| "nvidiaNote": nvidia_note, | |
| "consensusScore": consensus, | |
| }) | |
| # Sort by consensus desc, then by rank | |
| final.sort(key=lambda x: (-(x.get("consensusScore") or 0), x.get("rank", 99))) | |
| return { | |
| "date": today, | |
| "generatedAt": datetime.now(timezone.utc).isoformat(), | |
| "providers": { | |
| "claude": claude_available(), | |
| "jev": jev.available(), | |
| "nvidia": nvidia_available(), | |
| "gemma": gemma_ok, | |
| }, | |
| "nuggets": final, | |
| "lakeSnapshot": lake_ctx[:500] + "…", | |
| } | |
| # --------------------------------------------------------------------------- | |
| # Deep dive: ad-hoc query through all three AIs | |
| # --------------------------------------------------------------------------- | |
| def deep_dive(query: str) -> dict: | |
| lake_ctx = _lake_snapshot() | |
| # Claude answers the question | |
| claude_response = None | |
| if claude_available(): | |
| raw = _ask_claude(lake_ctx, query=query) | |
| claude_response = raw | |
| # NVIDIA independent take | |
| nvidia_response = None | |
| key = os.environ.get("NVIDIA_API_KEY") | |
| if key: | |
| try: | |
| import httpx | |
| resp = httpx.post( | |
| f"{_NVIDIA_BASE}/chat/completions", | |
| headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, | |
| json={ | |
| "model": _NVIDIA_MODEL, | |
| "messages": [ | |
| {"role": "system", "content": "You are a sharp NFL prop analyst. Be concise and specific. Use data provided."}, | |
| {"role": "user", "content": f"DATA:\n{lake_ctx[:3000]}\n\nQUESTION: {query}\n\nAnswer in 3-5 sentences focused on actionable prop insights."}, | |
| ], | |
| "max_tokens": 400, | |
| "temperature": 0.4, | |
| }, | |
| timeout=20.0, | |
| ) | |
| resp.raise_for_status() | |
| nvidia_response = resp.json()["choices"][0]["message"]["content"] | |
| except Exception as e: | |
| nvidia_response = f"[NVIDIA error: {str(e)[:100]}]" | |
| # Gemma quick take | |
| gemma_response = None | |
| try: | |
| lake_short = lake_ctx[:2000] + f"\n\nQUESTION: {query}\nAnswer with 5 focused nuggets on this question." | |
| raw_g = _ask_gemma(lake_short) | |
| if raw_g and not any("error" in n for n in raw_g): | |
| gemma_response = raw_g | |
| except Exception: | |
| pass | |
| return { | |
| "query": query, | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| "providers": { | |
| "claude": claude_available(), | |
| "jev": jev.available(), | |
| "nvidia": nvidia_available(), | |
| "gemma": gemma_response is not None, | |
| }, | |
| "claudeNuggets": claude_response, | |
| "nvidiaResponse": nvidia_response, | |
| "gemmaResponse": gemma_response, | |
| } | |