Download data/docs/deployment.html from SuckSome/artifex: direct link, hf CLI and curl.
- Browser
- Download file 12.1 kB
-
https://huggingface.co/spaces/SuckSome/artifex/resolve/main/data/docs/deployment.html
- Command line
-
hf download hf://spaces/SuckSome/artifex/data/docs/deployment.html
-
curl -L -o deployment.html https://huggingface.co/spaces/SuckSome/artifex/resolve/main/data/docs/deployment.html
12.1 kB
| <h2>Local (supported)</h2> | |
| <p>Artifex is designed to run locally. After the pipeline has been run (see README.md):</p> | |
| <pre><code class="language-bash">streamlit run app/main.py | |
| </code></pre> | |
| <p>The app listens on <a href="http://localhost:8501">http://localhost:8501</a>. Settings in <code>.streamlit/config.toml</code>:</p> | |
| <ul> | |
| <li><code>browser.gatherUsageStats = false</code> β Streamlit's usage telemetry is disabled.</li> | |
| <li><code>server.maxUploadSize = 20</code> β upload limit in MB (the analyser also enforces <code>configs/preprocessing.yaml</code>).</li> | |
| <li><code>client.showErrorDetails = false</code> β tracebacks (which can contain local paths) are not shown to visitors.</li> | |
| </ul> | |
| <h3>Resource requirements</h3> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Resource</th> | |
| <th>Requirement</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Python</td> | |
| <td>3.10β3.12 (developed on 3.12)</td> | |
| </tr> | |
| <tr> | |
| <td>RAM</td> | |
| <td>β1.1 GB resident for the analyser on CPU (DINOv2-B + reference index), measured on the development machine with an earlier 5,000-record index; the 10,084-record index adds β 60 MB of embeddings; allow 2 GB for the app as a whole</td> | |
| </tr> | |
| <tr> | |
| <td>GPU</td> | |
| <td>optional; CUDA is used automatically if available. Measured on the development machine (AMD Ryzen 7 5800HS, CPU only): β0.2 s per analysis after a β10 s one-time model load. Embedding extraction for the whole collection: β25β40 s on an RTX 3050 Laptop GPU (4 GB).</td> | |
| </tr> | |
| <tr> | |
| <td>Disk</td> | |
| <td>~0.4 GB model cache (<code>models/hf</code>), plus downloaded images and thumbnails (see the dataset card for the current size)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <h3>Upload handling</h3> | |
| <p>Streamlit keeps uploaded files in memory (its upload manager does not write them to disk). Artifex decodes the bytes | |
| in memory, never saves them, and holds at most the current analysis result in the user's session; closing the tab or | |
| pressing <em>Remove image</em> discards it. No cached uploads exist, so there is nothing to purge. If a future version caches | |
| uploads, it must provide a purge command and document it here.</p> | |
| <h2>In-browser edition (static website)</h2> | |
| <p><strong>Deployed:</strong> <a href="https://sucksome-artifex.static.hf.space">https://sucksome-artifex.static.hf.space</a> (Hugging Face Space | |
| <a href="https://huggingface.co/spaces/SuckSome/artifex"><code>SuckSome/artifex</code></a>, static SDK, public), 22 October 2026, model | |
| <code>artifex-0.1-e94d93bf34</code>, dataset <code>0.1+5cc3c8d20c19</code> (redeployed the same day after the grouping correction). Verified after each upload: the isolation headers are served, the large | |
| files (redirected to Hugging Face's CDN) arrive with CORS headers, every page loads without script errors at 1440 px and | |
| 390 px in headless Chromium, and a held-out test image analysed on the live site gave the same region, period, tradition | |
| and abstention results as the Python application.</p> | |
| <p><em>Content blockers.</em> The first upload named the analysis page module <code>analyse.js</code>; EasyPrivacy (used by Opera's built-in | |
| blocker, uBlock Origin and others) blocks any file of that name, so the Analyse page failed in those browsers while | |
| passing in a plain headless browser. The module is now <code>workspace.js</code>, a test keeps site file names clear of common | |
| blocklist names, and the deployed site was re-checked in headless Chromium with all EasyList and EasyPrivacy rules that | |
| apply to first-party resources enforced (nothing blocked; analysis completed).</p> | |
| <p>The hosted edition is a static website that runs the deployed model <strong>in the visitor's browser</strong>. There is no Artifex | |
| server: uploads are decoded and analysed on the visitor's device and never transmitted. It can be hosted anywhere that | |
| serves static files, including free static Hugging Face Spaces. (Hugging Face requires a paid plan for Docker Spaces; see | |
| the next section for the server-side alternative.)</p> | |
| <pre><code class="language-bash">python scripts/export_browser_model.py # ONNX export of the encoder + comparison of weight formats (build/browser_model/) | |
| python scripts/build_static_site.py # site in build/static/ (web/ + exported data + vendored libraries + thumbnails) | |
| python scripts/validate_browser.py # end-to-end comparison with the Python application (headless Chromium) | |
| python scripts/build_static_site.py --no-thumbnails # include the comparison result in the site | |
| python scripts/serve_static.py # local preview at http://localhost:8600 | |
| </code></pre> | |
| <p>What the site contains (β 490 MB):</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Part</th> | |
| <th>Source</th> | |
| <th>Notes</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>model/dinov2b_fp16w.onnx</code> (β 174 MB)</td> | |
| <td><code>export_browser_model.py</code></td> | |
| <td>DINOv2-B at the pinned commit, CLS + mean-patch pooling and L2 normalisation inside the graph; weights stored in float16, cast to float32 when the session is created. Downloaded on the first analysis and kept in the browser's Cache Storage.</td> | |
| </tr> | |
| <tr> | |
| <td><code>data/embeddings.f16</code> (β 31 MB)</td> | |
| <td>deployed embeddings</td> | |
| <td>Reference embeddings in float16.</td> | |
| </tr> | |
| <tr> | |
| <td><code>data/model.json</code></td> | |
| <td><code>heads.pkl</code>, <code>model_card.json</code></td> | |
| <td>Scaler means/scales, logistic-regression coefficients, temperatures, abstention thresholds, OOD threshold, test recall of the evaluated model.</td> | |
| </tr> | |
| <tr> | |
| <td><code>data/records.json</code>, <code>vocab.json</code></td> | |
| <td>manifest, splits, configs</td> | |
| <td>Metadata shown on the site, in embedding order.</td> | |
| </tr> | |
| <tr> | |
| <td><code>data/run/</code></td> | |
| <td>latest evaluation run</td> | |
| <td><code>metrics.json</code>, <code>failures.json</code>, <code>report.md</code>, <code>predictions.csv</code>, copied verbatim.</td> | |
| </tr> | |
| <tr> | |
| <td><code>thumbnails/</code> (β 270 MB)</td> | |
| <td>CC0 thumbnails</td> | |
| <td>384-px copies; record views link to the museum for full images.</td> | |
| </tr> | |
| <tr> | |
| <td><code>vendor/</code></td> | |
| <td>npm <code>onnxruntime-web@1.30.0</code>, <code>plotly.js-cartesian-dist-min@4.1.1</code></td> | |
| <td>Served from the site itself; the page requests nothing from third parties (on Hugging Face, large files are delivered through Hugging Face's own CDN).</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Measured fidelity.</strong> Weight formats, compared on 300 held-out test images with the stored reference embeddings: | |
| float32 and float16-stored weights both give cosine β₯ 0.99997 and identical region and period predictions for every | |
| image; dynamic int8 quantisation (92 MB) destroys the representation (median cosine 0.13, 7 % region agreement) and is | |
| not used. End to end (<code>validate_browser.py</code>, 200 held-out test images, headless Chromium): the preprocessed model input | |
| is identical to Python's for every image (the JavaScript resize is a port of Pillow's fixed-point bicubic resampler), and | |
| region and period predictions, abstention decisions and result status agree for every image; the top-5 similar works | |
| agreed exactly for 99β100 % of images in the two builds measured (an ordering difference between near-tied works can | |
| come from the float16 reference embeddings). The exact | |
| figures of the deployed build are shown on the site's Methodology page (<code>data/browser_validation.json</code>).</p> | |
| <p><strong>Requirements.</strong> A browser with WebAssembly (all current browsers). The first analysis downloads β 205 MB. ONNX Runtime holds the | |
| encoder weights in float32 (β 350 MB) plus activations, which may not fit on phones with little memory β the page then | |
| shows an error and no result. With the <code>cross-origin-*</code> headers set in the Space configuration, the page is cross-origin isolated and ONNX | |
| Runtime uses up to 4 threads; inside the Hugging Face page frame it falls back to one thread (slower, same results).</p> | |
| <h2>Server-side alternative: Docker (Hugging Face paid tier or any container host)</h2> | |
| <p><code>scripts/prepare_space.py</code> assembles a Docker bundle of the Streamlit application in <code>build/space/</code>. Hugging Face | |
| refused to create a Docker Space on a free account ("requires a PRO subscription", October 2026), so this route is | |
| prepared and tested locally but not deployed:</p> | |
| <ul> | |
| <li>code (<code>src/</code>, <code>app/</code>, <code>configs/</code>, <code>.streamlit/</code>), docs and screenshots;</li> | |
| <li>the artefacts the website reads: manifest, splits, default-variant embeddings, deployed classifiers, the latest | |
| evaluation run (β 65 MB);</li> | |
| <li>the CC0 thumbnails of all usable records, zipped (β 250 MB) and unpacked when the image is built. Full-size images, raw | |
| API responses, ablation embeddings and the model cache are <strong>not</strong> included; record detail views fall back to the | |
| 384-px thumbnail;</li> | |
| <li>a <code>Dockerfile</code> (Python 3.12, CPU-only PyTorch, exact package versions of the development environment because the | |
| classifiers are pickled scikit-learn objects) that downloads the pinned DINOv2 checkpoint at build time and then sets | |
| <code>HF_HUB_OFFLINE=1</code>, so the running app makes no calls to the Hub;</li> | |
| <li>a <code>README.md</code> with the Space metadata followed by this project's README.</li> | |
| </ul> | |
| <pre><code class="language-bash">python scripts/prepare_space.py --source-url https://huggingface.co/spaces/<user>/artifex/tree/main | |
| hf auth login # write token | |
| hf upload <user>/artifex build/space . --repo-type space | |
| </code></pre> | |
| <p>Hosted-mode settings (environment variables in the Dockerfile):</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Variable</th> | |
| <th>Effect</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>ARTIFEX_HOST</code></td> | |
| <td>Privacy statements say uploads are analysed "on the server hosting this site (β¦)" instead of "on this machine"; the About page adds a note on the host's network path.</td> | |
| </tr> | |
| <tr> | |
| <td><code>ARTIFEX_SOURCE_URL</code></td> | |
| <td>Footer links to the published source.</td> | |
| </tr> | |
| <tr> | |
| <td><code>ARTIFEX_ROOT</code></td> | |
| <td>Project root inside the container.</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>The container binds <code>0.0.0.0:7860</code> (the local default stays <code>localhost</code>) and runs with | |
| <code>--server.enableXsrfProtection=false</code>: Streamlit's XSRF cookie is blocked inside the Hugging Face iframe, which breaks | |
| uploads. Artifex has no accounts or stored state for a forged request to act on.</p> | |
| <p>Before publishing the bundle was tested by unpacking it, running it with the hosted settings on CPU only | |
| (<code>CUDA_VISIBLE_DEVICES=""</code>, <code>HF_HUB_OFFLINE=1</code>) and analysing a test image: scores matched the GPU run to two decimals.</p> | |
| <h3>Checklist for any other host</h3> | |
| <ol> | |
| <li><strong>Host capacity.</strong> DINOv2-B needs β 1.5 GB RAM with PyTorch, plus the reference index; Streamlit Community Cloud's | |
| β 1 GB limit is not enough. DINOv2-S (<code>dinov2s_letterbox_rgb</code>) is a smaller fallback, but the deployed model must | |
| then be retrained and re-evaluated for it.</li> | |
| <li><strong>Model download.</strong> Confirm the host permits downloading from the Hugging Face Hub, or bundle the pinned checkpoint.</li> | |
| <li><strong>Images.</strong> All reference images are CC0 and may be redistributed; do not commit them to Git.</li> | |
| <li><strong>Privacy.</strong> Review the host's request logging and temporary-file behaviour so that uploads are not persisted. Serve | |
| over HTTPS.</li> | |
| <li><strong>Abuse limits.</strong> Keep the upload size and pixel limits; consider rate limiting at the proxy.</li> | |
| <li><strong>Unavailable state.</strong> If the host cannot run inference, the analysis page shows a "model or dataset unavailable" | |
| state β never substitute precomputed or fake predictions.</li> | |
| </ol> | |
| <p>No API keys or secrets are needed for any part of Artifex at runtime; publishing a Space needs the publisher's own | |
| Hugging Face write token, which stays on their machine.</p> |