krishnadhulipalla commited on
Commit
deb575f
·
1 Parent(s): d51358c

Updated docker for /data issue

Browse files
Files changed (3) hide show
  1. .dockerignore +0 -1
  2. Dockerfile +4 -0
  3. backend/app/config/settings.py +41 -12
.dockerignore CHANGED
@@ -6,4 +6,3 @@ __pycache__/
6
  node_modules/
7
  web/node_modules/
8
  web/.vite/
9
- data/
 
6
  node_modules/
7
  web/node_modules/
8
  web/.vite/
 
Dockerfile CHANGED
@@ -14,6 +14,10 @@ ENV PYTHONUNBUFFERED=1 \
14
  DATA_DIR=/data
15
  WORKDIR /app
16
 
 
 
 
 
17
  # (optional) if you hit build issues with some libs
18
  RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/*
19
 
 
14
  DATA_DIR=/data
15
  WORKDIR /app
16
 
17
+ ENV PORT=7860 DATA_DIR=/data
18
+
19
+ RUN mkdir -p /data/uploads
20
+
21
  # (optional) if you hit build issues with some libs
22
  RUN apt-get update && apt-get install -y --no-install-recommends build-essential && rm -rf /var/lib/apt/lists/*
23
 
backend/app/config/settings.py CHANGED
@@ -1,15 +1,34 @@
1
  from pathlib import Path
2
  from pydantic import Field
3
  from pydantic_settings import BaseSettings, SettingsConfigDict
 
4
 
5
- # Resolve repo root no matter where uvicorn is launched from
6
  REPO_ROOT = Path(__file__).resolve().parents[3]
7
 
8
- def _default_data_dir() -> Path:
9
- return (REPO_ROOT / "data").resolve()
 
 
 
 
 
 
 
 
 
10
 
11
- def _default_uploads_dir() -> Path:
12
- return (_default_data_dir() / "uploads").resolve()
 
 
 
 
 
 
 
 
 
13
 
14
  def _default_frontend_dist() -> Path:
15
  return (REPO_ROOT / "web" / "dist").resolve()
@@ -22,16 +41,16 @@ class Settings(BaseSettings):
22
  populate_by_name=True,
23
  )
24
 
25
- # Models / API keys
26
  OPENAI_API_KEY: str | None = None
27
  OPENAI_MODEL_AGENT: str = "gpt-4o"
28
  OPENAI_MODEL_CLASSIFIER: str = "gpt-4o-mini"
29
 
30
- # Paths (env may override with absolute or relative; we resolve below)
31
  DATA_DIR: Path = Field(default_factory=_default_data_dir)
32
- REPORTS_DB: Path = Field(default_factory=lambda: _default_data_dir() / "pulsemaps_reports.db")
33
- SESSIONS_DB: Path = Field(default_factory=lambda: _default_data_dir() / "pulsemap_sessions.db")
34
- UPLOADS_DIR: Path = Field(default_factory=_default_uploads_dir)
35
  FRONTEND_DIST: Path = Field(default_factory=_default_frontend_dist)
36
 
37
  # Defaults
@@ -45,10 +64,20 @@ class Settings(BaseSettings):
45
  nvidia_api_key: str | None = None
46
 
47
  def ensure_dirs(self) -> None:
48
- # Resolve in case env provided relative strings
 
 
 
 
 
 
 
 
49
  self.DATA_DIR = self.DATA_DIR.resolve()
 
 
50
  self.UPLOADS_DIR = self.UPLOADS_DIR.resolve()
51
- # Create everything robustly
52
  self.DATA_DIR.mkdir(parents=True, exist_ok=True)
53
  self.UPLOADS_DIR.mkdir(parents=True, exist_ok=True)
54
 
 
1
  from pathlib import Path
2
  from pydantic import Field
3
  from pydantic_settings import BaseSettings, SettingsConfigDict
4
+ import os, tempfile
5
 
6
+ # Resolve the repo root when running outside Docker
7
  REPO_ROOT = Path(__file__).resolve().parents[3]
8
 
9
+ def _writable_dir(candidates: list[Path]) -> Path:
10
+ for p in candidates:
11
+ try:
12
+ p.mkdir(parents=True, exist_ok=True)
13
+ t = p / ".write_test"
14
+ t.write_text("ok", encoding="utf-8")
15
+ t.unlink(missing_ok=True)
16
+ return p
17
+ except Exception:
18
+ continue
19
+ raise RuntimeError(f"No writable data dir from: {candidates!r}")
20
 
21
+ def _default_data_dir() -> Path:
22
+ # 1) Respect env if provided
23
+ if os.getenv("DATA_DIR"):
24
+ return Path(os.getenv("DATA_DIR")).resolve()
25
+ # 2) Prefer /data inside containers (Docker/HF Spaces)
26
+ candidates = [Path("/data")]
27
+ # 3) Repo local ./data for local dev
28
+ candidates.append((REPO_ROOT / "data").resolve())
29
+ # 4) Last resort: /tmp
30
+ candidates.append(Path(tempfile.gettempdir()) / "pulsemaps" / "data")
31
+ return _writable_dir(candidates)
32
 
33
  def _default_frontend_dist() -> Path:
34
  return (REPO_ROOT / "web" / "dist").resolve()
 
41
  populate_by_name=True,
42
  )
43
 
44
+ # API / Models
45
  OPENAI_API_KEY: str | None = None
46
  OPENAI_MODEL_AGENT: str = "gpt-4o"
47
  OPENAI_MODEL_CLASSIFIER: str = "gpt-4o-mini"
48
 
49
+ # Paths
50
  DATA_DIR: Path = Field(default_factory=_default_data_dir)
51
+ REPORTS_DB: Path | None = None
52
+ SESSIONS_DB: Path | None = None
53
+ UPLOADS_DIR: Path | None = None
54
  FRONTEND_DIST: Path = Field(default_factory=_default_frontend_dist)
55
 
56
  # Defaults
 
64
  nvidia_api_key: str | None = None
65
 
66
  def ensure_dirs(self) -> None:
67
+ # Fill path fields if not set, then ensure they exist
68
+ if self.REPORTS_DB is None:
69
+ self.REPORTS_DB = (self.DATA_DIR / "pulsemaps_reports.db")
70
+ if self.SESSIONS_DB is None:
71
+ self.SESSIONS_DB = (self.DATA_DIR / "pulsemap_sessions.db")
72
+ if self.UPLOADS_DIR is None:
73
+ self.UPLOADS_DIR = (self.DATA_DIR / "uploads")
74
+
75
+ # Absolute, existing
76
  self.DATA_DIR = self.DATA_DIR.resolve()
77
+ self.REPORTS_DB = self.REPORTS_DB.resolve()
78
+ self.SESSIONS_DB = self.SESSIONS_DB.resolve()
79
  self.UPLOADS_DIR = self.UPLOADS_DIR.resolve()
80
+
81
  self.DATA_DIR.mkdir(parents=True, exist_ok=True)
82
  self.UPLOADS_DIR.mkdir(parents=True, exist_ok=True)
83