k-l-lambda commited on
Commit
465d818
·
1 Parent(s): e1e6e90

app.py: add long-lived Cache-Control for large web/ assets via Starlette middleware

Browse files
Files changed (1) hide show
  1. app.py +35 -0
app.py CHANGED
@@ -24,6 +24,8 @@ from collections import deque
24
 
25
  import gradio as gr
26
 
 
 
27
  from lilyscript.generator import StreamingLilyletGenerator
28
  from lilyscript.postprocess import postprocess
29
  from lilyscript.mask_monitor import MaskMonitor, load_blacklist
@@ -45,6 +47,35 @@ EXAMPLES_DIR = os.path.join(HERE, 'examples')
45
  OUTPUT_DIR = os.path.join(HERE, 'outputs')
46
  WEB_DIR = os.path.join(HERE, 'web') # vendored browser libs + score player (gitignored bundles)
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  EXAMPLE_PREFIX = '\U0001F4C4 ' # 📄 examples
49
  OUTPUT_PREFIX = '✨ ' # ✨ session outputs
50
 
@@ -989,9 +1020,13 @@ def build_ui ():
989
 
990
  if __name__ == '__main__':
991
  demo = build_ui()
 
992
  demo.queue().launch(
993
  theme=gr.themes.Soft(),
994
  css=CUSTOM_CSS,
995
  head=build_head(),
996
  allowed_paths=[WEB_DIR],
 
 
 
997
  )
 
24
 
25
  import gradio as gr
26
 
27
+ from starlette.middleware.base import BaseHTTPMiddleware
28
+
29
  from lilyscript.generator import StreamingLilyletGenerator
30
  from lilyscript.postprocess import postprocess
31
  from lilyscript.mask_monitor import MaskMonitor, load_blacklist
 
47
  OUTPUT_DIR = os.path.join(HERE, 'outputs')
48
  WEB_DIR = os.path.join(HERE, 'web') # vendored browser libs + score player (gitignored bundles)
49
 
50
+
51
+ # Gradio serves our vendored web/ assets (soundfont gm.sf3 ~38 MB, verovio.bundle.js ~8 MB,
52
+ # libfluidsynth ~2 MB, …) via `/gradio_api/file=<abs-path>` with NO Cache-Control header, so the
53
+ # browser re-validates (or refetches) them on every load. These are large, static, and effectively
54
+ # immutable per deploy — bundles carry a `?v=<mtime>` cache-buster (see _file_url), and the soundfont
55
+ # rarely changes. This middleware adds a long-lived Cache-Control to responses for web/ assets so
56
+ # returning visitors reuse them from the browser cache instead of re-downloading. It runs inside our
57
+ # own app.py, so it applies on Hugging Face and ModelScope Spaces (where we are the server), unlike a
58
+ # static-host CDN we couldn't configure.
59
+ _WEB_ASSET_MARKER = '/web/'
60
+ _CACHEABLE_EXTS = ('.sf3', '.sf2', '.js', '.wasm', '.css', '.mp3', '.ogg')
61
+
62
+
63
+ class AssetCacheHeaderMiddleware(BaseHTTPMiddleware):
64
+ async def dispatch (self, request, call_next):
65
+ response = await call_next(request)
66
+ # Only touch Gradio's static-file route for our vendored web/ assets, and only if a
67
+ # Cache-Control wasn't already set. request.url.path holds the decoded `/gradio_api/file=...`.
68
+ path = request.url.path
69
+ if (
70
+ '/file=' in path
71
+ and _WEB_ASSET_MARKER in path
72
+ and path.endswith(_CACHEABLE_EXTS)
73
+ and 'cache-control' not in {k.lower() for k in response.headers.keys()}
74
+ ):
75
+ # 30 days. Safe: bundle URLs change via ?v=<mtime> on redeploy; soundfont is stable.
76
+ response.headers['Cache-Control'] = 'public, max-age=2592000'
77
+ return response
78
+
79
  EXAMPLE_PREFIX = '\U0001F4C4 ' # 📄 examples
80
  OUTPUT_PREFIX = '✨ ' # ✨ session outputs
81
 
 
1020
 
1021
  if __name__ == '__main__':
1022
  demo = build_ui()
1023
+ from starlette.middleware import Middleware
1024
  demo.queue().launch(
1025
  theme=gr.themes.Soft(),
1026
  css=CUSTOM_CSS,
1027
  head=build_head(),
1028
  allowed_paths=[WEB_DIR],
1029
+ # Inject a long-lived Cache-Control on our large static web/ assets (see
1030
+ # AssetCacheHeaderMiddleware). app_kwargs flows into the FastAPI/Starlette constructor.
1031
+ app_kwargs={'middleware': [Middleware(AssetCacheHeaderMiddleware)]},
1032
  )