File size: 5,347 Bytes
b40b895
f9e1f80
5dab1e8
 
 
 
 
 
 
 
 
 
 
 
b48a476
5dab1e8
1bd5e53
 
5dab1e8
 
b40b895
 
b48a476
 
 
5dab1e8
 
 
 
1bd5e53
 
f9e1f80
 
dfd692a
714bb89
5dab1e8
 
06c7c70
fc0631a
06c7c70
8a2120c
 
fc0631a
 
 
 
 
 
 
 
 
 
 
06c7c70
279e5cf
f9e1f80
 
279e5cf
 
5dab1e8
f9e1f80
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# A-EYE backend. The application code is private; the container fetches it when it starts.
FROM python:3.11-slim@sha256:e88e9763f943ec1834f992a4b51e0f24500486803e8bc534e5767af9ea65f6ce

ENV PYTHONUNBUFFERED=1 \
    PIP_NO_CACHE_DIR=1

RUN useradd -m -u 1000 appuser
ENV HOME=/home/appuser \
    HF_HOME=/home/appuser/.cache/huggingface

WORKDIR /app

RUN pip install --upgrade pip \
    && pip install torch==2.8.0 torchvision==0.23.0 --index-url https://download.pytorch.org/whl/cpu \
    && pip install 'annotated-doc==0.0.5' 'annotated-types==0.8.0' 'anyio==4.15.1' 'certifi==2026.7.22' 'charset-normalizer==3.5.2' 'click==8.5.0' 'fastapi==0.141.1' 'filelock==3.32.3' 'fsspec==2026.7.0' 'h11==0.16.0' 'hf-xet==1.7.0' 'httptools==0.8.0' 'huggingface_hub==0.36.2' 'idna==3.20' 'Jinja2==3.1.6' 'MarkupSafe==3.0.3' 'mpmath==1.3.0' 'networkx==3.6.1' 'numpy==2.4.6' 'packaging==26.3' 'pillow==12.3.0' 'pydantic==2.14.0' 'pydantic_core==2.50.0' 'python-dotenv==1.2.4' 'python-multipart==0.0.32' 'PyYAML==6.0.3' 'regex==2026.9.29' 'requests==2.34.2' 'safetensors==0.8.0' 'scipy==1.17.1' 'starlette==1.7.0' 'sympy==1.14.0' 'tokenizers==0.22.2' 'tqdm==4.70.1' 'transformers==4.57.6' 'typing-inspection==0.4.4' 'typing_extensions==4.16.0' 'urllib3==2.8.0' 'uvicorn==0.34.0' 'uvloop==0.23.0' 'watchfiles==1.3.0' 'websockets==17.2'

RUN python -c "from transformers import CLIPVisionModelWithProjection as M; M.from_pretrained('openai/clip-vit-large-patch14', revision='32bd64288804d66eefd0ccbe215aa642df71cc41')" \
    && python -c "from transformers import AutoModel; AutoModel.from_pretrained('facebook/dinov2-small', revision='ed25f3a31f01632728cabb09d1542f84ab7b0056')" \
    && chown -R appuser:appuser /home/appuser/.cache

RUN chown appuser:appuser /app
ENV AEYE_CODE_REPO=wonjun12/aeye-weights \
    AEYE_CODE_REVISION=515b3df3b6fb7913b2ba7d790daae3e923c654b2 \
    AEYE_CODE_FILE=code/aeye-backend-81962887e0d17f58.tar.gz \
    AEYE_CODE_SHA256=81962887e0d17f5843bc5baa582a50b828a35ccc1172387995d61843bb1e1a23

USER appuser

ENV AEYE_DEVICE=cpu \
    AEYE_TORCH_THREADS=2 \
    AEYE_MAX_CONCURRENCY=1 \
    AEYE_KEY_PER_MINUTE=10 \
    AEYE_KEY_PER_DAY=1000 \
    AEYE_HEATMAP_STYLE=spotlight \
    AEYE_INPUT_KIND=on \
    TRANSFORMERS_OFFLINE=1

ENV AEYE_WEIGHTS_REPO=wonjun12/aeye-weights \
    AEYE_WEIGHTS_REVISION=f042633672aa30361234674c43d6c35373e0d71a \
    AEYE_WEIGHTS_SHA256_BEST49=145c18f4cd7fc430d223cdec7f6abac1e29124155f8628648a5ef86173975134 \
    AEYE_WEIGHTS_SHA256_BEST63=b93733e88c69b76581d49150d097dafd686e21f9d355d4665dcb0ffbee30742d \
    AEYE_WEIGHTS_SHA256_BEST69=0f423cc566a7dfc8aa991f81ddf4e6410291106309841fdc09265c387aebf0df \
    AEYE_WEIGHTS_SHA256_BEST69_LOC=6562f22ecd262aecdad5aaf54a8554cd239f2e1d40b6671adbdb2d9ecdc0ee82 \
    AEYE_WEIGHTS_SHA256_BEST91=d3dc13a6f68947c187af515a5b75aa2609696b44f3c829b9e5297836db7e8ffe \
    AEYE_WEIGHTS_SHA256_BEST91_LOC=fe5997eb90c22a75e3a31a66decfdf73c0775fe6650ad1d178ccbafa3bd0f1d9

ENV VERDICT_MODEL_PATH=/app/models/best91.pt \
    HEATMAP_MODEL_PATH=/app/models/best91_loc.pt \
    AEYE_BAND_T5=0.854339 \
    AEYE_BAND_T1=0.981525 \
    AEYE_BANDS_FOR=246d25f0c991bb95 \
    AEYE_FUSION=on \
    AEYE_FUSION_PATH=./fusion/fusion_rc2.json

ENV AEYE_SCREEN_PATH=on \
    AEYE_SCREEN_PATH_RULE=./screen_rules/screen_head_v3.json \
    AEYE_SCREEN_PATH_RULE_ID=39f10adf3dbdae13 \
    AEYE_SCREEN_PATH_FOR=246d25f0c991bb95

EXPOSE 7860
CMD ["python", "-c", "import compileall, hashlib, io, os, sys, tarfile, time, requests\nARGV = ['python', '-m', 'uvicorn', 'main_hybrid:app', '--host', '0.0.0.0', '--port', '7860', '--workers', '1', '--limit-concurrency', '64', '--timeout-keep-alive', '5', '--no-access-log']\nrepo, rev, path, want = (os.environ[k] for k in ('AEYE_CODE_REPO', 'AEYE_CODE_REVISION', 'AEYE_CODE_FILE', 'AEYE_CODE_SHA256'))\nurl = 'https://huggingface.co/%s/resolve/%s/%s' % (repo, rev, path)\ntoken = os.environ.get('HF_TOKEN', '').strip()\ndelay, deadline = 5, time.time() + 600\nwhile True:\n    try:\n        r = requests.get(url, headers={'Authorization': 'Bearer ' + token}, timeout=(10, 300))\n        why = 'HTTP %d' % r.status_code\n    except requests.RequestException as exc:\n        r, why = None, type(exc).__name__\n    if r is not None and r.status_code == 200:\n        break\n    if r is not None and r.status_code in (401, 403, 404):\n        sys.exit('[start] the code bundle is not readable (%s) - is the Space secret HF_TOKEN set?' % why)\n    if time.time() > deadline:\n        sys.exit('[start] the code bundle could not be downloaded for 10 minutes (%s)' % why)\n    print('[start] code download: %s - retrying in %ds' % (why, delay), flush=True)\n    time.sleep(delay)\n    delay = min(delay * 2, 60)\ndata = r.content\ngot = hashlib.sha256(data).hexdigest()\nif got != want:\n    sys.exit('[start] code bundle sha256 %s is not the pinned %s' % (got, want))\ntarfile.open(fileobj=io.BytesIO(data), mode='r:gz').extractall('/app', filter='data')\nif not compileall.compile_dir('/app', legacy=True, quiet=1):\n    sys.exit('[start] the code bundle did not compile')\nfor folder, _, names in os.walk('/app'):\n    for name in names:\n        if name.endswith('.py'):\n            os.remove(os.path.join(folder, name))\nprint('[start] code %s (%s) ready' % (path, got[:16]), flush=True)\nos.chdir('/app')\nos.execvp(ARGV[0], ARGV)"]