Spaces:
Sleeping
Sleeping
File size: 7,201 Bytes
ed65aea | 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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | #!/usr/bin/env python3
"""
Deploy script for DR MURPHY ODE Dashboard to HuggingFace Spaces.
Run this from any directory:
python3 /path/to/hf_ode_space/deploy.py
Steps:
1. Copy source files from the project tree into this flat directory
2. Patch sys.path imports for flat structure
3. Fix run_sweep_unified argument mismatch
4. Test import chain
5. Deploy to HuggingFace
"""
import shutil
import os
import sys
import re
HERE = os.path.dirname(os.path.abspath(__file__))
SRC_BASE = os.path.dirname(os.path.dirname(HERE)) # cycle2mdot_acceleration/
def step1_copy_files():
"""Copy all source files into the flat deployment directory."""
print("Step 1: Copying source files...")
# Dashboard files
dash = os.path.join(SRC_BASE, 'ode_reformulation/dashboard')
for f in ['scenario_gui.py', 'scenario_analyzer.py', 'sweep_cache.py', 'pump_animation.js']:
src = os.path.join(dash, f)
dst = os.path.join(HERE, f)
shutil.copy2(src, dst)
print(f" Copied dashboard/{f}")
# ODE engine files
ode = os.path.join(SRC_BASE, 'ode_reformulation')
for f in ['cycle2mdot_ode_v2.py', 'cycle2mdot_10var_njit.py']:
shutil.copy2(os.path.join(ode, f), os.path.join(HERE, f))
print(f" Copied ode_reformulation/{f}")
# Project root files
for f in ['cycle2mdot_fast.py', 'cycle2mdot_cached.py', 'h2_ps_lut.npz']:
shutil.copy2(os.path.join(SRC_BASE, f), os.path.join(HERE, f))
print(f" Copied {f}")
# break_coolprop directory
bc_src = os.path.join(SRC_BASE, 'break_coolprop')
bc_dst = os.path.join(HERE, 'break_coolprop')
os.makedirs(bc_dst, exist_ok=True)
for f in ['__init__.py', 'helmholtz_h2.py', 'lut_ps.py', 'h2_props.py', 'cycle2mdot_break.py']:
shutil.copy2(os.path.join(bc_src, f), os.path.join(bc_dst, f))
print(f" Copied break_coolprop/{f}")
# sweep_analysis.py is already created by the Write tool
# engine_bridge.py, app.py, README.md, requirements.txt are already present
print(" Done.")
def step2_patch_imports():
"""Patch sys.path hacks in copied engine files for flat structure."""
print("\nStep 2: Patching imports for flat structure...")
# cycle2mdot_ode_v2.py: change sys.path.insert to use current dir
_patch_sys_path(os.path.join(HERE, 'cycle2mdot_ode_v2.py'))
# cycle2mdot_10var_njit.py: same
_patch_sys_path(os.path.join(HERE, 'cycle2mdot_10var_njit.py'))
print(" Done.")
def _patch_sys_path(filepath):
"""Replace sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))
with sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))"""
with open(filepath, 'r') as f:
content = f.read()
# Replace grandparent path with current directory path
old_pattern = "sys.path.insert(0, os.path.dirname(os.path.dirname(__file__)))"
new_pattern = "sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))"
if old_pattern in content:
content = content.replace(old_pattern, new_pattern)
with open(filepath, 'w') as f:
f.write(content)
print(f" Patched {os.path.basename(filepath)}: sys.path -> current dir")
else:
print(f" {os.path.basename(filepath)}: no sys.path patch needed")
def step3_fix_sweep_args():
"""Fix run_sweep_unified to accept the engine argument from sr_all_inputs."""
print("\nStep 3: Fixing run_sweep_unified argument mismatch...")
gui_path = os.path.join(HERE, 'scenario_gui.py')
with open(gui_path, 'r') as f:
content = f.read()
# Find the function signature and add engine parameter
old_sig = " fill_type, vsnubber, vchss, aov140f, rodia,\n num_cycles=1):"
new_sig = " fill_type, vsnubber, vchss, aov140f, rodia,\n num_cycles=1, engine='njit_10var'):"
if old_sig in content and "def run_sweep_unified" in content:
content = content.replace(old_sig, new_sig, 1)
with open(gui_path, 'w') as f:
f.write(content)
print(" Added 'engine' parameter to run_sweep_unified()")
else:
print(" run_sweep_unified already has engine param or signature changed")
print(" Done.")
def step4_test_imports():
"""Test that the import chain works in the flat structure."""
print("\nStep 4: Testing import chain...")
# Add this directory to path
if HERE not in sys.path:
sys.path.insert(0, HERE)
try:
import engine_bridge
print(f" engine_bridge: OK (engines: {engine_bridge.ENGINES})")
except Exception as e:
print(f" engine_bridge: FAILED - {e}")
return False
try:
import scenario_analyzer
print(" scenario_analyzer: OK")
except Exception as e:
print(f" scenario_analyzer: FAILED - {e}")
return False
try:
import sweep_analysis
print(" sweep_analysis: OK")
except Exception as e:
print(f" sweep_analysis: FAILED - {e}")
return False
try:
import sweep_cache
print(" sweep_cache: OK")
except Exception as e:
print(f" sweep_cache: FAILED - {e}")
return False
print(" All imports OK!")
return True
def step5_deploy():
"""Deploy to HuggingFace Spaces."""
print("\nStep 5: Deploying to HuggingFace...")
try:
from huggingface_hub import HfApi
except ImportError:
print(" huggingface_hub not installed. Installing...")
os.system(f"{sys.executable} -m pip install huggingface_hub")
from huggingface_hub import HfApi
api = HfApi()
# Create the repo (or verify it exists)
try:
api.create_repo("csh2/ode-pump-dashboard", repo_type="space",
space_sdk="gradio", exist_ok=True)
print(" Repository csh2/ode-pump-dashboard created/verified.")
except Exception as e:
print(f" Error creating repo: {e}")
print(" You may need to run: huggingface-cli login")
return False
# Upload the folder (exclude deploy.py, __pycache__, .db files)
try:
api.upload_folder(
folder_path=HERE,
repo_id="csh2/ode-pump-dashboard",
repo_type="space",
ignore_patterns=["deploy.py", "__pycache__", "*.db", "*.db-shm", "*.db-wal",
".DS_Store", "*.pyc"],
)
print(" Upload complete!")
print(" Space URL: https://huggingface.co/spaces/csh2/ode-pump-dashboard")
except Exception as e:
print(f" Upload failed: {e}")
print(" You may need to run: huggingface-cli login")
return False
return True
def main():
print("=" * 60)
print("DR MURPHY ODE -- HuggingFace Space Deployment")
print("=" * 60)
step1_copy_files()
step2_patch_imports()
step3_fix_sweep_args()
ok = step4_test_imports()
if not ok:
print("\nImport test failed. Fix errors before deploying.")
sys.exit(1)
step5_deploy()
print("\n" + "=" * 60)
print("Deployment complete!")
print("=" * 60)
if __name__ == "__main__":
main()
|