File size: 4,889 Bytes
c50a873
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Direct HF Spaces deploy script — creates space, uploads all files.
"""
import os
import json
import shutil
import tempfile
from pathlib import Path
from huggingface_hub import HfApi, upload_folder

api = HfApi()
SPACE_ID = "Raunak211006/hale-api"
PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))

print("=" * 60)
print("HALE API -> Hugging Face Spaces Deploy")
print("=" * 60)

# 1. Create Space
print("\n[1/4] Creating Space...")
try:
    api.create_repo(
        repo_id=SPACE_ID,
        repo_type="space",
        space_sdk="docker",
        private=False,
        exist_ok=True,
    )
    print(f"  > Space ready: https://huggingface.co/spaces/{SPACE_ID}")
except Exception as e:
    print(f"  Space: {e}")

# 2. Prepare deploy directory
print("\n[2/4] Preparing deploy files...")
deploy_dir = os.path.join(tempfile.gettempdir(), "hale-deploy")
if os.path.exists(deploy_dir):
    shutil.rmtree(deploy_dir)
os.makedirs(deploy_dir)

# Files/dirs to SKIP
SKIP = {
    '.git', '__pycache__', '.pytest_cache', 'hale-frontend',
    'node_modules', '.env', 'data', 'logs', '.planning',
    'Dockerfile.spaces', 'deploy_hf.py', 'deploy_spaces.py',
    '.github', '.gitattributes', '.dockerignore',
    'docker-compose.yml', 'alembic', 'alembic.ini',
    'debug_hale_db.py', 'migrate_db.py', 'seed_test_data.py',
    'simulate_e2e.py', '.antigravityignore',
}

for item in os.listdir(PROJECT_DIR):
    if item in SKIP:
        continue
    src = os.path.join(PROJECT_DIR, item)
    dst = os.path.join(deploy_dir, item)
    try:
        if os.path.isdir(src):
            shutil.copytree(src, dst, dirs_exist_ok=True,
                          ignore=shutil.ignore_patterns('__pycache__', '*.pyc', '.pytest_cache'))
        else:
            shutil.copy2(src, dst)
    except Exception as e:
        print(f"  Skip {item}: {e}")

# Copy Dockerfile.spaces as Dockerfile
spaces_dockerfile = os.path.join(PROJECT_DIR, "Dockerfile.spaces")
if os.path.exists(spaces_dockerfile):
    shutil.copy2(spaces_dockerfile, os.path.join(deploy_dir, "Dockerfile"))
    print("  > Dockerfile.spaces -> Dockerfile")

# Create .env for spaces
env_content = f"""APP_ENV=production
DATABASE_URL=sqlite:///./data/hale.db
CORS_ORIGINS=*
LOG_LEVEL=INFO
GEMINI_API_KEYS={os.environ.get('GEMINI_API_KEYS', '')}
SECRET_KEY=hale-production-key-change-me-to-random-64-chars-in-settings
"""

# Read GEMINI keys from local .env
local_env = os.path.join(PROJECT_DIR, ".env")
if os.path.exists(local_env):
    with open(local_env) as f:
        for line in f:
            line = line.strip()
            if line.startswith("GEMINI_API_KEYS="):
                gemini_keys = line.split("=", 1)[1]
                env_content = env_content.replace(
                    f"GEMINI_API_KEYS=",
                    f"GEMINI_API_KEYS={gemini_keys}"
                )
                break

with open(os.path.join(deploy_dir, ".env"), "w", encoding="utf-8") as f:
    f.write(env_content)
print("  > .env created")

# Create README.md with HF Spaces metadata
readme = "---\ntitle: HALE - Adaptive Learning Engine API\nemoji: \U0001F9E0\ncolorFrom: purple\ncolorTo: blue\nsdk: docker\napp_port: 7860\npinned: true\n---\n\n# HALE - Adaptive Learning Engine\n\nAI-powered adaptive learning API with Reinforcement Learning behavioral engine.\n\n**API Docs**: [Open Swagger UI](/docs)\n\n## Quick Start\n1. POST /api/auth/register - Register user\n2. POST /api/auth/login - Get JWT token\n3. POST /api/goals/ - Create a learning goal\n4. GET /api/plan - Get todays adaptive plan\n5. POST /api/complete-task - Mark task done\n6. GET /api/stats - View analytics\n\n## Features\n- Contextual Multi-Armed Bandit RL engine (Thompson Sampling)\n- AI-generated curriculum via Gemini\n- Behavioral adaptation (mood, fatigue, stress, sleep)\n- Multi-goal support with priority-weighted scheduling\n- Streak tracking, XP, and leveling system\n- Auto-close at 2 AM IST with next-day preparation\n"

with open(os.path.join(deploy_dir, "README.md"), "w", encoding="utf-8") as f:
    f.write(readme)
print("  > README.md created")

# Count files
file_count = sum(len(files) for _, _, files in os.walk(deploy_dir))
print(f"  > {file_count} files ready")

# 3. Upload
print(f"\n[3/4] Uploading to HF Spaces ({SPACE_ID})...")
try:
    api.upload_folder(
        folder_path=deploy_dir,
        repo_id=SPACE_ID,
        repo_type="space",
        commit_message="Deploy HALE API v3.1",
    )
    print("  > Upload complete!")
except Exception as e:
    print(f"  Upload failed: {e}")
    raise

# 4. Done
print("")
print("=" * 60)
print("DEPLOYMENT COMPLETE!")
print("")
print("API:   https://raunak211006-hale-api.hf.space")
print("Docs:  https://raunak211006-hale-api.hf.space/docs")
print(f"Space: https://huggingface.co/spaces/{SPACE_ID}")
print("")
print("Building may take 2-3 minutes. Check the Space page for status.")
print("=" * 60)