arcshukla commited on
Commit
9f57991
·
1 Parent(s): 0a3ca97

fixing bucket issue

Browse files
Files changed (4) hide show
  1. Dockerfile +2 -1
  2. README.md +5 -0
  3. main.py +16 -1
  4. test_data/hf_logs.py +127 -0
Dockerfile CHANGED
@@ -28,7 +28,8 @@ COPY . .
28
 
29
  # Pre-create /data so local Docker runs work; on HF Spaces the volume is mounted
30
  # here at runtime (owned by root, container also runs as root — no permission issue)
31
- RUN mkdir -p /data
 
32
 
33
  # Add venv to PATH
34
  ENV PATH="/home/app/.venv/bin:$PATH" \
 
28
 
29
  # Pre-create /data so local Docker runs work; on HF Spaces the volume is mounted
30
  # here at runtime (owned by root, container also runs as root — no permission issue)
31
+ #RUN mkdir -p /data
32
+ RUN mkdir -p /data && chmod 777 /data
33
 
34
  # Add venv to PATH
35
  ENV PATH="/home/app/.venv/bin:$PATH" \
README.md CHANGED
@@ -7,6 +7,11 @@ sdk: docker
7
  app_port: 7860
8
  pinned: false
9
  short_description: Conflict-free batch scheduling engine for GeeksforGeeks
 
 
 
 
 
10
  ---
11
 
12
  # GFG SmartSched
 
7
  app_port: 7860
8
  pinned: false
9
  short_description: Conflict-free batch scheduling engine for GeeksforGeeks
10
+ volumes:
11
+ type: "bucket"
12
+ source: "arcshukla/ai-scheduling-platform-storage"
13
+ mount_path: "/app/data"
14
+
15
  ---
16
 
17
  # GFG SmartSched
main.py CHANGED
@@ -6,19 +6,33 @@ setup_logging(settings.log_level)
6
  logger = get_logger(__name__)
7
 
8
  # ── Now safe to import everything else (logs visible from here on) ────────────
 
9
  from contextlib import asynccontextmanager
10
 
11
- from fastapi import FastAPI
12
  from fastapi.staticfiles import StaticFiles
 
13
 
14
  from app.constants import APP_NAME, APP_VERSION
15
  from app.db.database import init_db
 
16
 
17
  logger.info("Importing routers...")
18
  from app.routers import router
19
  logger.info("Routers loaded")
20
 
21
 
 
 
 
 
 
 
 
 
 
 
 
22
  @asynccontextmanager
23
  async def lifespan(app: FastAPI):
24
  logger.info("Starting %s v%s (log_level=%s)", APP_NAME, APP_VERSION, settings.log_level)
@@ -31,6 +45,7 @@ async def lifespan(app: FastAPI):
31
 
32
  app = FastAPI(title=APP_NAME, version=APP_VERSION, lifespan=lifespan)
33
 
 
34
  app.mount("/static", StaticFiles(directory="app/static"), name="static")
35
 
36
  app.include_router(router)
 
6
  logger = get_logger(__name__)
7
 
8
  # ── Now safe to import everything else (logs visible from here on) ────────────
9
+ import uuid
10
  from contextlib import asynccontextmanager
11
 
12
+ from fastapi import FastAPI, Request
13
  from fastapi.staticfiles import StaticFiles
14
+ from starlette.middleware.base import BaseHTTPMiddleware
15
 
16
  from app.constants import APP_NAME, APP_VERSION
17
  from app.db.database import init_db
18
+ from app.logging_config import set_request_id, clear_request_id
19
 
20
  logger.info("Importing routers...")
21
  from app.routers import router
22
  logger.info("Routers loaded")
23
 
24
 
25
+ class RequestIdMiddleware(BaseHTTPMiddleware):
26
+ """Injects a short request ID into the logging context for every request."""
27
+ async def dispatch(self, request: Request, call_next):
28
+ req_id = request.headers.get("X-Request-ID") or uuid.uuid4().hex[:8]
29
+ set_request_id(req_id)
30
+ response = await call_next(request)
31
+ response.headers["X-Request-ID"] = req_id
32
+ clear_request_id()
33
+ return response
34
+
35
+
36
  @asynccontextmanager
37
  async def lifespan(app: FastAPI):
38
  logger.info("Starting %s v%s (log_level=%s)", APP_NAME, APP_VERSION, settings.log_level)
 
45
 
46
  app = FastAPI(title=APP_NAME, version=APP_VERSION, lifespan=lifespan)
47
 
48
+ app.add_middleware(RequestIdMiddleware)
49
  app.mount("/static", StaticFiles(directory="app/static"), name="static")
50
 
51
  app.include_router(router)
test_data/hf_logs.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """
3
+ hf_logs.py — Stream Hugging Face Spaces logs to the terminal.
4
+
5
+ Usage
6
+ -----
7
+ uv run python test_data/hf_logs.py # build + run logs (default)
8
+ uv run python test_data/hf_logs.py --kind run # runtime logs only
9
+ uv run python test_data/hf_logs.py --kind build # build logs only
10
+ uv run python test_data/hf_logs.py --status # space status + last error
11
+ uv run python test_data/hf_logs.py --restart # restart the space, then stream run logs
12
+
13
+ Reads HF_TOKEN and HF_SPACE_NAME from .env (falls back to env vars).
14
+ """
15
+ import argparse
16
+ import json
17
+ import os
18
+ import sys
19
+ import urllib.request
20
+ from dotenv import load_dotenv
21
+
22
+ load_dotenv()
23
+
24
+ # ── Helpers ────────────────────────────────────────────────────────────────────
25
+
26
+ def _token() -> str:
27
+ t = os.environ.get("HF_TOKEN", "")
28
+ if not t:
29
+ sys.exit("HF_TOKEN not set — add it to .env")
30
+ return t
31
+
32
+ def _space() -> str:
33
+ s = os.environ.get("HF_SPACE_NAME", "")
34
+ if not s:
35
+ sys.exit("HF_SPACE_NAME not set — add it to .env")
36
+ return s
37
+
38
+ def _req(url: str, method: str = "GET") -> urllib.request.Request:
39
+ return urllib.request.Request(
40
+ url, method=method,
41
+ headers={
42
+ "Authorization": f"Bearer {_token()}",
43
+ "Content-Length": "0",
44
+ },
45
+ )
46
+
47
+ def _api(path: str) -> str:
48
+ return f"https://huggingface.co/api/spaces/{_space()}/{path}"
49
+
50
+
51
+ # ── Commands ───────────────────────────────────────────────────────────────────
52
+
53
+ def cmd_status():
54
+ with urllib.request.urlopen(_req(_api("")), timeout=10) as r:
55
+ d = json.loads(r.read())
56
+ rt = d.get("runtime", {})
57
+ hw = rt.get("hardware", {})
58
+ print(f"Space : {_space()}")
59
+ print(f"SHA : {d.get('sha','')[:12]}")
60
+ print(f"Stage : {rt.get('stage')}")
61
+ print(f"HW : {hw.get('requested')} (current: {hw.get('current')})")
62
+ err = rt.get("errorMessage")
63
+ if err:
64
+ print(f"Error : {err}")
65
+
66
+
67
+ def cmd_restart():
68
+ with urllib.request.urlopen(_req(_api("restart"), method="POST"), timeout=10) as r:
69
+ d = json.loads(r.read())
70
+ print(f"Restarted → stage: {d.get('stage')}")
71
+
72
+
73
+ def cmd_stream(kind: str):
74
+ """Stream SSE log lines for the given kind ('build' or 'run')."""
75
+ url = _api(f"logs/{kind}")
76
+ print(f"=== {_space()} / {kind} logs ===")
77
+ try:
78
+ with urllib.request.urlopen(_req(url), timeout=120) as r:
79
+ while True:
80
+ raw = r.readline()
81
+ if not raw:
82
+ break
83
+ line = raw.decode("utf-8", errors="replace").strip()
84
+ if not line:
85
+ continue
86
+ if line.startswith("data:"):
87
+ payload = line[5:].strip()
88
+ try:
89
+ msg = json.loads(payload).get("data", "")
90
+ if msg:
91
+ print(msg)
92
+ except json.JSONDecodeError:
93
+ if payload:
94
+ print(payload)
95
+ except KeyboardInterrupt:
96
+ print("\n[interrupted]")
97
+ except Exception as e:
98
+ print(f"[stream ended: {e}]")
99
+
100
+
101
+ # ── Main ───────────────────────────────────────────────────────────────────────
102
+
103
+ def main():
104
+ parser = argparse.ArgumentParser(description="HF Spaces log viewer")
105
+ parser.add_argument("--kind", choices=["build", "run", "both"], default="both",
106
+ help="Which log stream to show (default: both)")
107
+ parser.add_argument("--status", action="store_true", help="Show space status and exit")
108
+ parser.add_argument("--restart", action="store_true", help="Restart the space then stream run logs")
109
+ args = parser.parse_args()
110
+
111
+ if args.status:
112
+ cmd_status()
113
+ return
114
+
115
+ if args.restart:
116
+ cmd_restart()
117
+ args.kind = "run" # fall through to stream
118
+
119
+ if args.kind == "both":
120
+ cmd_stream("build")
121
+ cmd_stream("run")
122
+ else:
123
+ cmd_stream(args.kind)
124
+
125
+
126
+ if __name__ == "__main__":
127
+ main()