amarck commited on
Commit
28ea021
·
1 Parent(s): 8b98d83

Fix demo mode: writable /data check, path resolution, load order

Browse files

- config.py: verify /data is writable before using it (HF Spaces
without persistent storage has /data but read-only)
- demo.py: use CONFIG_PATH/DB_PATH from config, load DB before
copying config to avoid early-exit race
- entrypoint.sh: always set DEMO_MODE when no API key, simpler logic

Files changed (3) hide show
  1. entrypoint.sh +6 -11
  2. src/config.py +8 -1
  3. src/demo.py +13 -30
entrypoint.sh CHANGED
@@ -5,18 +5,13 @@ PORT="${PORT:-8888}"
5
 
6
  echo "=== Research Intelligence ==="
7
 
8
- # Bootstrap demo data if no config exists and no API key set
9
- if [ -n "$SPACE_ID" ]; then
10
- CONFIG_PATH="/data/config.yaml"
11
- else
12
- CONFIG_PATH="config.yaml"
13
- fi
14
-
15
- if [ ! -f "$CONFIG_PATH" ] && [ -f "data/demo-data.json" ] && [ -z "$ANTHROPIC_API_KEY" ]; then
16
- echo "No config found and no API key set — loading demo data..."
17
- python -c "from src.demo import load_demo; load_demo()"
18
  export DEMO_MODE=1
19
- echo "Demo mode active. Deploy locally with an API key for full functionality."
20
  fi
21
 
22
  echo "Starting web server + scheduler on port ${PORT} ..."
 
5
 
6
  echo "=== Research Intelligence ==="
7
 
8
+ # No API key demo mode (load bundled data if needed)
9
+ if [ -z "$ANTHROPIC_API_KEY" ]; then
10
+ if [ -f "data/demo-data.json" ]; then
11
+ python -c "from src.demo import load_demo; load_demo()" || true
12
+ fi
 
 
 
 
 
13
  export DEMO_MODE=1
14
+ echo "Demo mode no API key set. Deploy locally for full functionality."
15
  fi
16
 
17
  echo "Starting web server + scheduler on port ${PORT} ..."
src/config.py CHANGED
@@ -37,7 +37,14 @@ DEMO_MODE = bool(os.environ.get("DEMO_MODE"))
37
  def _spaces_data_dir() -> Path:
38
  """Return /data on HF Spaces (persistent storage), otherwise local data/."""
39
  if IS_HF_SPACE and Path("/data").exists():
40
- return Path("/data")
 
 
 
 
 
 
 
41
  return Path("data")
42
 
43
 
 
37
  def _spaces_data_dir() -> Path:
38
  """Return /data on HF Spaces (persistent storage), otherwise local data/."""
39
  if IS_HF_SPACE and Path("/data").exists():
40
+ # Verify /data is actually writable (persistent storage enabled)
41
+ try:
42
+ test_file = Path("/data/.write_test")
43
+ test_file.touch()
44
+ test_file.unlink()
45
+ return Path("/data")
46
+ except OSError:
47
+ pass # /data exists but not writable — no persistent storage
48
  return Path("data")
49
 
50
 
src/demo.py CHANGED
@@ -10,7 +10,7 @@ log = logging.getLogger(__name__)
10
 
11
  def load_demo():
12
  """Load demo data into a fresh database and copy demo config."""
13
- from src.config import IS_HF_SPACE, SPACES_DATA_DIR
14
 
15
  json_path = Path("data/demo-data.json")
16
  config_src = Path("data/demo-config.yaml")
@@ -19,44 +19,23 @@ def load_demo():
19
  log.warning("Demo data not found at %s", json_path)
20
  return
21
 
22
- # Determine target paths
23
- if IS_HF_SPACE:
24
- config_dst = SPACES_DATA_DIR / "config.yaml"
25
- db_path = SPACES_DATA_DIR / "researcher.db"
26
- else:
27
- config_dst = Path("config.yaml")
28
- db_path = Path("data/researcher.db")
29
 
30
- # Copy config
31
- if config_src.exists() and not config_dst.exists():
32
- config_dst.parent.mkdir(parents=True, exist_ok=True)
33
- shutil.copy2(config_src, config_dst)
34
- log.info("Demo config copied to %s", config_dst)
35
-
36
- # Skip if DB already has data
37
- if db_path.exists():
38
- log.info("DB already exists at %s — skipping demo load", db_path)
39
  return
40
 
41
- # Initialize DB with current schema
42
- import os
43
- os.environ["DB_PATH"] = str(db_path)
44
-
45
- # Re-import to pick up new path
46
- import importlib
47
- import src.config
48
- importlib.reload(src.config)
49
-
50
  from src.db import init_db, get_conn
51
  init_db()
52
 
53
- # Load JSON
54
  data = json.loads(json_path.read_text())
55
  runs = data.get("runs", [])
56
  papers = data.get("papers", [])
57
 
58
  with get_conn() as conn:
59
- # Insert runs
60
  for r in runs:
61
  conn.execute(
62
  """INSERT OR IGNORE INTO runs (id, domain, started_at, finished_at,
@@ -66,7 +45,6 @@ def load_demo():
66
  r["date_start"], r["date_end"], r["paper_count"], r["status"]),
67
  )
68
 
69
- # Insert papers
70
  for p in papers:
71
  conn.execute(
72
  """INSERT INTO papers (run_id, domain, arxiv_id, entry_id, title,
@@ -87,7 +65,12 @@ def load_demo():
87
  p.get("s2_tldr"), p.get("s2_paper_id"), p.get("topics")),
88
  )
89
 
90
- # Rebuild FTS index
91
  conn.execute("INSERT INTO papers_fts(papers_fts) VALUES('rebuild')")
92
 
93
  log.info("Demo data loaded: %d runs, %d papers into %s", len(runs), len(papers), db_path)
 
 
 
 
 
 
 
10
 
11
  def load_demo():
12
  """Load demo data into a fresh database and copy demo config."""
13
+ from src.config import CONFIG_PATH, DB_PATH
14
 
15
  json_path = Path("data/demo-data.json")
16
  config_src = Path("data/demo-config.yaml")
 
19
  log.warning("Demo data not found at %s", json_path)
20
  return
21
 
22
+ config_dst = CONFIG_PATH
23
+ db_path = DB_PATH
 
 
 
 
 
24
 
25
+ # Skip if already set up
26
+ if config_dst.exists() or db_path.exists():
27
+ log.info("Config or DB already exists — skipping demo load")
 
 
 
 
 
 
28
  return
29
 
30
+ # Load DB first, then copy config
 
 
 
 
 
 
 
 
31
  from src.db import init_db, get_conn
32
  init_db()
33
 
 
34
  data = json.loads(json_path.read_text())
35
  runs = data.get("runs", [])
36
  papers = data.get("papers", [])
37
 
38
  with get_conn() as conn:
 
39
  for r in runs:
40
  conn.execute(
41
  """INSERT OR IGNORE INTO runs (id, domain, started_at, finished_at,
 
45
  r["date_start"], r["date_end"], r["paper_count"], r["status"]),
46
  )
47
 
 
48
  for p in papers:
49
  conn.execute(
50
  """INSERT INTO papers (run_id, domain, arxiv_id, entry_id, title,
 
65
  p.get("s2_tldr"), p.get("s2_paper_id"), p.get("topics")),
66
  )
67
 
 
68
  conn.execute("INSERT INTO papers_fts(papers_fts) VALUES('rebuild')")
69
 
70
  log.info("Demo data loaded: %d runs, %d papers into %s", len(runs), len(papers), db_path)
71
+
72
+ # Copy config last (entrypoint checks config existence to set DEMO_MODE)
73
+ if config_src.exists():
74
+ config_dst.parent.mkdir(parents=True, exist_ok=True)
75
+ shutil.copy2(config_src, config_dst)
76
+ log.info("Demo config written to %s", config_dst)