File size: 6,380 Bytes
4a39063
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4450892
4a39063
 
 
4450892
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a39063
4450892
 
 
 
 
 
 
 
 
 
 
21a5c88
4450892
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4a39063
4450892
 
 
 
 
4a39063
 
 
 
 
 
 
 
c711f10
 
 
 
 
 
 
 
 
 
4a39063
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34dbefa
4a39063
 
 
 
 
 
 
 
 
34dbefa
4a39063
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#!/usr/bin/env python3
"""Deploy NBA Quant AI to lbjlincoln/nomos-nba-quant HF Space.

Uploads all files from hf-space/ dir, configures secrets, restarts.

Usage:
    source .env.local
    python3 hf-space/deploy.py
"""

import os, sys
from pathlib import Path
from huggingface_hub import HfApi, CommitOperationAdd

SPACE_ID = "lbjlincoln/nomos-nba-quant"
HF_TOKEN = os.environ.get("HF_TOKEN") or os.environ.get("HF_TOKEN_2")
LOCAL_DIR = Path(__file__).parent

SECRETS = {
    # ── Core DB ──
    "DATABASE_URL": os.environ.get("DATABASE_URL", ""),
    "SUPABASE_URL": os.environ.get("SUPABASE_URL", ""),
    "SUPABASE_API_KEY": os.environ.get("SUPABASE_API_KEY", ""),
    "SUPABASE_PASSWORD": os.environ.get("SUPABASE_PASSWORD", ""),
    "SUPABASE_URL_2": os.environ.get("SUPABASE_URL_2", ""),
    "SUPABASE_ANON_KEY_2": os.environ.get("SUPABASE_ANON_KEY_2", ""),
    "SUPABASE_PASSWORD_2": os.environ.get("SUPABASE_PASSWORD_2", ""),
    "SUPABASE_POOLER_2": os.environ.get("SUPABASE_POOLER_2", ""),
    # ── Neo4j ──
    "NEO4J_URI": os.environ.get("NEO4J_URI", ""),
    "NEO4J_USER": os.environ.get("NEO4J_USER", ""),
    "NEO4J_PASSWORD": os.environ.get("NEO4J_PASSWORD", ""),
    "NEO4J_URI_2": os.environ.get("NEO4J_URI_2", ""),
    "NEO4J_USER_2": os.environ.get("NEO4J_USER_2", ""),
    "NEO4J_PASSWORD_2": os.environ.get("NEO4J_PASSWORD_2", ""),
    # ── Pinecone ──
    "PINECONE_API_KEY": os.environ.get("PINECONE_API_KEY", ""),
    "PINECONE_API_KEY_2": os.environ.get("PINECONE_API_KEY_2", ""),
    "PINECONE_HOST": os.environ.get("PINECONE_HOST", ""),
    # ── Sports / Odds ──
    "ODDS_API_KEY": os.environ.get("ODDS_API_KEY", ""),
    # ── LLM Keys (for CrewAI, agents, research) ──
    "OPENROUTER_API_KEY": os.environ.get("OPENROUTER_API_KEY", ""),
    "OPENROUTER_KEY_QUANTITATIVE": os.environ.get("OPENROUTER_KEY_QUANTITATIVE", ""),
    "OPENROUTER_KEY_SPARE": os.environ.get("OPENROUTER_KEY_SPARE", ""),
    "OPENAI_API_KEY": os.environ.get("OPENAI_API_KEY", ""),
    "GROQ_API_KEY": os.environ.get("GROQ_API_KEY", ""),
    "GROQ_API_KEY_2": os.environ.get("GROQ_API_KEY_2", ""),
    "GROQ_API_KEY_3": os.environ.get("GROQ_API_KEY_3", ""),
    "XAI_API_KEY": os.environ.get("XAI_API_KEY", ""),
    "COHERE_API_KEY": os.environ.get("COHERE_API_KEY", ""),
    "KIMI_API_KEY": os.environ.get("KIMI_API_KEY", ""),
    # LiteLLM removed β€” direct provider calls only
    # ── Telegram ──
    "TELEGRAM_BOT_TOKEN": os.environ.get("TELEGRAM_BOT_TOKEN", ""),
    "ADMIN_TELEGRAM_ID": os.environ.get("ADMIN_TELEGRAM_ID", ""),
    "TELEGRAM_CHANNEL_ID": os.environ.get("TELEGRAM_CHANNEL_ID", ""),
    # ── Search / Research ──
    "BRAVE_API_KEY": os.environ.get("BRAVE_API_KEY", ""),
    "TAVILY_API_KEY": os.environ.get("TAVILY_API_KEY", ""),
    "EXA_API_KEY": os.environ.get("EXA_API_KEY", ""),
    "JINA_API_KEY": os.environ.get("JINA_API_KEY", ""),
    # ── GitHub ──
    "GH_TOKEN": os.environ.get("GH_TOKEN", ""),
    "GITHUB_TOKEN": os.environ.get("GITHUB_TOKEN", ""),
    # ── HuggingFace ──
    "HF_TOKEN": os.environ.get("HF_TOKEN", ""),
    "HF_TOKEN_2": os.environ.get("HF_TOKEN_2", ""),
    "HF_TOKEN_3": os.environ.get("HF_TOKEN_3", ""),
    # ── Infrastructure ──
    "VM_CALLBACK_URL": os.environ.get("VM_CALLBACK_URL", "http://34.136.180.66:8080"),
    "VM_HOST": os.environ.get("VM_HOST", ""),
    "REDIS_URL": os.environ.get("REDIS_URL", ""),
    "REMOTE_CONTROL_KEY": os.environ.get("REMOTE_CONTROL_KEY", ""),
    # ── Google ──
    "GOOGLE_API_KEY": os.environ.get("GOOGLE_API_KEY", ""),
}


def main():
    if not HF_TOKEN:
        print("ERROR: HF_TOKEN not set. Run: source .env.local")
        sys.exit(1)

    # ── Engine parity check ──
    root_engine = (LOCAL_DIR.parent / "features" / "engine.py").read_bytes()
    hf_engine = (LOCAL_DIR / "features" / "engine.py").read_bytes()
    if root_engine != hf_engine:
        print("ERROR: features/engine.py and hf-space/features/engine.py have diverged!")
        print("Fix: cp hf-space/features/engine.py features/engine.py")
        print("Or:  cp features/engine.py hf-space/features/engine.py")
        sys.exit(1)
    print("Engine parity check: OK")

    api = HfApi(token=HF_TOKEN)
    print(f"Deploying NBA Quant AI to {SPACE_ID}...")

    operations = []
    skip = {"__pycache__", ".pyc", "node_modules", ".git", "deploy.py"}

    for fp in LOCAL_DIR.rglob("*"):
        if fp.is_dir():
            continue
        if any(s in str(fp) for s in skip):
            continue
        rel = fp.relative_to(LOCAL_DIR)
        print(f"  + {rel}")
        operations.append(CommitOperationAdd(path_in_repo=str(rel), path_or_fileobj=str(fp)))

    if not operations:
        print("ERROR: No files found")
        sys.exit(1)

    print(f"\nUploading {len(operations)} files...")
    try:
        api.create_commit(
            repo_id=SPACE_ID, repo_type="space", operations=operations,
            commit_message="feat: real box scores + skip_placeholder + checkpoint/rollback + Brier-dominant fitness",
        )
        print("Upload OK!")
    except Exception as e:
        if "404" in str(e) or "not found" in str(e).lower():
            print(f"Space not found, creating {SPACE_ID}...")
            api.create_repo(repo_id=SPACE_ID, repo_type="space", space_sdk="docker",
                           space_hardware="cpu-basic", private=False)
            api.create_commit(
                repo_id=SPACE_ID, repo_type="space", operations=operations,
                commit_message="feat: real box scores + skip_placeholder + checkpoint/rollback + Brier-dominant fitness",
            )
        else:
            raise

    print("\nConfiguring secrets...")
    for key, value in SECRETS.items():
        if value:
            try:
                api.add_space_secret(SPACE_ID, key, value)
                print(f"  Set {key}")
            except Exception as e:
                print(f"  WARN: {key}: {e}")
        else:
            print(f"  SKIP {key} (empty)")

    print("\nRestarting Space...")
    try:
        api.restart_space(SPACE_ID)
    except Exception as e:
        print(f"  Restart: {e}")

    print(f"\nDone! Space: https://lbjlincoln-nomos-nba-quant.hf.space")
    print(f"Monitor: https://huggingface.co/spaces/{SPACE_ID}")


if __name__ == "__main__":
    main()