Percy3822 commited on
Commit
84df2c7
·
verified ·
1 Parent(s): 0bbd045

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -47
app.py CHANGED
@@ -1,73 +1,92 @@
1
- import os
2
- import time
3
- import json
4
  from pathlib import Path
5
  from fastapi import FastAPI, Request
6
  from fastapi.responses import JSONResponse, StreamingResponse
7
 
8
- # ------------------
9
- # Setup paths
10
- # ------------------
11
- BASE_DIR = Path(__file__).parent
12
- FILES_DIR = BASE_DIR / "files"
13
- LOG_DIR = FILES_DIR / "logs"
14
 
15
- FILES_DIR.mkdir(parents=True, exist_ok=True)
16
- LOG_DIR.mkdir(parents=True, exist_ok=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # ------------------
19
- # Safe logger
20
- # ------------------
21
- def _safe_append_jsonl(path: Path, event: dict):
22
- """Safely append JSON event to a file without crashing."""
 
 
23
  try:
24
  path.parent.mkdir(parents=True, exist_ok=True)
25
- with open(path, "a", encoding="utf-8") as f:
26
- f.write(json.dumps(event, ensure_ascii=False) + "\n")
27
  except Exception as e:
28
- print(f"[WARN] Could not log event: {e}")
29
-
30
- # ------------------
31
- # FastAPI app
32
- # ------------------
33
- app = FastAPI(title="Brain", version="0.1")
34
 
 
 
 
35
  @app.get("/health")
36
- async def health():
37
  return {
38
  "ok": True,
39
  "service": "brain",
40
  "time": time.time(),
 
41
  "files_dir": str(FILES_DIR),
42
- "logs": str(LOG_DIR),
 
43
  }
44
 
45
  @app.post("/process")
46
- async def process(request: Request):
47
- payload = await request.json()
48
-
49
- event = {
50
- "ts": time.time(),
51
- "type": "process",
52
- "data": payload,
53
- }
54
- _safe_append_jsonl(LOG_DIR / "events.jsonl", event)
55
-
56
- # Echo back
57
- return JSONResponse({"ok": True, "received": payload})
58
 
59
- @app.get("/stream/logs")
60
- async def stream_logs():
61
- """Stream logs line-by-line to client (SSE style)."""
 
 
 
 
62
 
63
- async def event_stream():
64
- path = LOG_DIR / "events.jsonl"
 
65
  if not path.exists():
66
  yield "data: {}\n\n"
67
  return
68
-
69
- with open(path, "r", encoding="utf-8") as f:
70
  for line in f:
71
- yield f"data: {line.strip()}\n\n"
 
 
 
 
 
72
 
73
- return StreamingResponse(event_stream(), media_type="text/event-stream")
 
 
 
1
+ # app.py
2
+ import json, time, os
 
3
  from pathlib import Path
4
  from fastapi import FastAPI, Request
5
  from fastapi.responses import JSONResponse, StreamingResponse
6
 
7
+ app = FastAPI(title="Brain", version="0.1.0")
 
 
 
 
 
8
 
9
+ # -----------------------------
10
+ # Writable paths (with fallback)
11
+ # -----------------------------
12
+ def _mk_dir(path: Path) -> Path:
13
+ try:
14
+ path.mkdir(parents=True, exist_ok=True)
15
+ return path
16
+ except Exception as e:
17
+ # fallback to /tmp which is always writable on HF Spaces
18
+ fallback = Path("/tmp/brain_app/files") if "files" in str(path) else Path("/tmp/brain_app")
19
+ try:
20
+ fallback.mkdir(parents=True, exist_ok=True)
21
+ except Exception:
22
+ pass
23
+ print(f"[WARN] Could not create {path} ({e}); using {fallback}")
24
+ return fallback
25
+
26
+ # Allow overrides via env, else use /tmp
27
+ BASE_DIR = Path(os.getenv("BRAIN_BASE_DIR", "/tmp/brain_app"))
28
+ FILES_DIR = _mk_dir(Path(os.getenv("FILES_DIR", str(BASE_DIR / "files"))))
29
+ LOG_DIR = _mk_dir(Path(os.getenv("LOG_DIR", str(FILES_DIR / "logs"))))
30
 
31
+ EVENTS_FILE = LOG_DIR / "events.jsonl"
32
+ ERRORS_FILE = LOG_DIR / "errors.jsonl"
33
+
34
+ # -----------------------------
35
+ # Safe file append
36
+ # -----------------------------
37
+ def _append_jsonl(path: Path, obj: dict):
38
  try:
39
  path.parent.mkdir(parents=True, exist_ok=True)
40
+ with path.open("a", encoding="utf-8") as f:
41
+ f.write(json.dumps(obj, ensure_ascii=False) + "\n")
42
  except Exception as e:
43
+ print(f"[WARN] log write failed: {e}")
 
 
 
 
 
44
 
45
+ # -----------------------------
46
+ # Endpoints
47
+ # -----------------------------
48
  @app.get("/health")
49
+ def health():
50
  return {
51
  "ok": True,
52
  "service": "brain",
53
  "time": time.time(),
54
+ "base_dir": str(BASE_DIR),
55
  "files_dir": str(FILES_DIR),
56
+ "logs_dir": str(LOG_DIR),
57
+ "events_file": str(EVENTS_FILE),
58
  }
59
 
60
  @app.post("/process")
61
+ async def process(req: Request):
62
+ payload = await req.json()
63
+ evt = {"ts": time.time(), "type": "process", "data": payload}
64
+ _append_jsonl(EVENTS_FILE, evt)
65
+ return {"ok": True, "received": payload}
 
 
 
 
 
 
 
66
 
67
+ @app.post("/log_error")
68
+ async def log_error(req: Request):
69
+ payload = await req.json()
70
+ err = {"ts": time.time(), "type": "error", "data": payload}
71
+ _append_jsonl(ERRORS_FILE, err)
72
+ _append_jsonl(EVENTS_FILE, {"ts": err["ts"], "type": "error_ref"})
73
+ return {"ok": True}
74
 
75
+ def _sse_from_file(path: Path):
76
+ # generator for SSE streaming of an existing file (no tailing daemon)
77
+ def gen():
78
  if not path.exists():
79
  yield "data: {}\n\n"
80
  return
81
+ with path.open("r", encoding="utf-8") as f:
 
82
  for line in f:
83
+ yield f"data: " + line.strip() + "\n\n"
84
+ return gen
85
+
86
+ @app.get("/stream/logs")
87
+ def stream_logs():
88
+ return StreamingResponse(_sse_from_file(EVENTS_FILE)(), media_type="text/event-stream")
89
 
90
+ @app.get("/stream/errors")
91
+ def stream_errors():
92
+ return StreamingResponse(_sse_from_file(ERRORS_FILE)(), media_type="text/event-stream")