Bobby commited on
Commit
3aac0a4
Β·
1 Parent(s): 2fa74f6

Restart Crowd Counter hourly

Browse files
Files changed (2) hide show
  1. AGENTS.md +1 -0
  2. app.py +22 -0
AGENTS.md CHANGED
@@ -7,6 +7,7 @@ Type: code
7
  - Structure: `app.py` (UI + ZeroGPU handler), `count.py` (model build/inference/tiling/overlay), `PET/` (patched model code), `weights/` (git-lfs).
8
  - Rules: this Space is Gradio 6 β€” `theme`/`css`/`js`/`head` go on `demo.launch()`, NOT `gr.Blocks()` (Gradio 6 moved them). UI must mirror the sibling Spaces' design language (interior-ai-designer is the reference): Markdown hero "# πŸ‘₯ ... by [SkyeBrowse]", sponsor banner, inter-app nav cluster, forceLight JS, link-rewrite JS, JSON-LD + canonical head, SEO footer.
9
  - `@spaces.GPU(duration=7)` β€” Bobby raised the cap from 5s (2026-07-03) so the two-grid ensemble completes on large drone stills; ZeroGPU quota charges actual seconds used, not the reservation, so typical 2-3s runs cost the same.
 
10
  - Always LIGHT mode on every host (Bobby 2026-07-02): enforced by the `_force_light_theme` FastAPI middleware (307 `/` β†’ `/?__theme=light` for Accept: text/html; relative Location; probes get 200). Gradio 6's CSR frontend does NOT execute `launch(js=...)`/`head=` scripts, so the sibling-style client-side redirect never runs β€” do not rely on custom_js for anything load-bearing in this repo.
11
  - Embedding is restricted through the `Content-Security-Policy: frame-ancestors` response header in `_force_light_theme`: `https://skyebrowse.com`, `https://*.skyebrowse.com`, plus `http://localhost:8080` for local webapp development.
12
  - Successful user uploads save the original and first counted overlay to the configured Google Drive folder through `drive_storage.py`; threshold recounts and bundled examples do not create duplicate Drive files. Drive saving is asynchronous and best-effort so storage failures never break inference.
 
7
  - Structure: `app.py` (UI + ZeroGPU handler), `count.py` (model build/inference/tiling/overlay), `PET/` (patched model code), `weights/` (git-lfs).
8
  - Rules: this Space is Gradio 6 β€” `theme`/`css`/`js`/`head` go on `demo.launch()`, NOT `gr.Blocks()` (Gradio 6 moved them). UI must mirror the sibling Spaces' design language (interior-ai-designer is the reference): Markdown hero "# πŸ‘₯ ... by [SkyeBrowse]", sponsor banner, inter-app nav cluster, forceLight JS, link-rewrite JS, JSON-LD + canonical head, SEO footer.
9
  - `@spaces.GPU(duration=7)` β€” Bobby raised the cap from 5s (2026-07-03) so the two-grid ensemble completes on large drone stills; ZeroGPU quota charges actual seconds used, not the reservation, so typical 2-3s runs cost the same.
10
+ - The Space self-restarts after one hour of container uptime, matching 3D AI and Anime AI; the external five-minute watchdog still handles `RUNTIME_ERROR` when the container cannot run its own restart thread.
11
  - Always LIGHT mode on every host (Bobby 2026-07-02): enforced by the `_force_light_theme` FastAPI middleware (307 `/` β†’ `/?__theme=light` for Accept: text/html; relative Location; probes get 200). Gradio 6's CSR frontend does NOT execute `launch(js=...)`/`head=` scripts, so the sibling-style client-side redirect never runs β€” do not rely on custom_js for anything load-bearing in this repo.
12
  - Embedding is restricted through the `Content-Security-Policy: frame-ancestors` response header in `_force_light_theme`: `https://skyebrowse.com`, `https://*.skyebrowse.com`, plus `http://localhost:8080` for local webapp development.
13
  - Successful user uploads save the original and first counted overlay to the configured Google Drive folder through `drive_storage.py`; threshold recounts and bundled examples do not create duplicate Drive files. Drive saving is asynchronous and best-effort so storage failures never break inference.
app.py CHANGED
@@ -1,5 +1,7 @@
1
  import json
2
  import os
 
 
3
 
4
  os.environ.setdefault("PYTORCH_ENABLE_MPS_FALLBACK", "1")
5
 
@@ -10,6 +12,7 @@ import gradio as gr
10
  import gradio.route_utils
11
  import spaces
12
  import torch
 
13
  from PIL import Image
14
  from pillow_heif import register_heif_opener
15
  from starlette.middleware import Middleware
@@ -69,6 +72,25 @@ async def _force_light_theme(request, call_next):
69
 
70
  force_light_middleware = Middleware(BaseHTTPMiddleware, dispatch=_force_light_theme)
71
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  TILE = 768
73
  OVERLAP = 192
74
  UPSCALE = 1.0
 
1
  import json
2
  import os
3
+ import threading
4
+ import time
5
 
6
  os.environ.setdefault("PYTORCH_ENABLE_MPS_FALLBACK", "1")
7
 
 
12
  import gradio.route_utils
13
  import spaces
14
  import torch
15
+ from huggingface_hub import HfApi
16
  from PIL import Image
17
  from pillow_heif import register_heif_opener
18
  from starlette.middleware import Middleware
 
72
 
73
  force_light_middleware = Middleware(BaseHTTPMiddleware, dispatch=_force_light_theme)
74
 
75
+ RESTART_INTERVAL_SECONDS = 3600
76
+
77
+
78
+ def _restart_space_after_interval(space_id):
79
+ time.sleep(RESTART_INTERVAL_SECONDS)
80
+ try:
81
+ HfApi().restart_space(space_id)
82
+ except Exception as exc:
83
+ print(f"Auto-restart failed: {exc}", flush=True)
84
+
85
+
86
+ space_id = os.getenv("SPACE_ID")
87
+ if space_id:
88
+ threading.Thread(
89
+ target=_restart_space_after_interval,
90
+ args=(space_id,),
91
+ daemon=True,
92
+ ).start()
93
+
94
  TILE = 768
95
  OVERLAP = 192
96
  UPSCALE = 1.0