-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcompose.demo.yml
More file actions
204 lines (195 loc) · 7.1 KB
/
Copy pathcompose.demo.yml
File metadata and controls
204 lines (195 loc) · 7.1 KB
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# The whole loop, in containers:
#
# podman compose -f compose.demo.yml up --build -d
# podman compose -f compose.demo.yml exec backend bun apps/backend/src/cli/wuzzy.ts crawl https://docs.base.org/ --max=60
# podman compose -f compose.demo.yml exec backend bun apps/backend/src/cli/wuzzy.ts embed
# open http://localhost:8080
#
# Two services here are stand-ins so the loop runs with no API key, no funds and
# no mainnet. Both say so loudly in their own source, and neither belongs in a
# real deployment. Everything else is the real thing.
# Postgres is declared here rather than included from compose.yml: `include`
# merges list fields by appending, so an overridden `ports` would try to bind
# 5432 as well as 5433 and collide with whatever already holds it.
services:
# The crawl queue's broker. A commissioned crawl is asked for by the API and
# done by a worker, so that a page someone paid for starts being fetched in
# seconds rather than whenever a nightly job next runs.
redis:
image: docker.io/library/redis:7-alpine
command: ["redis-server", "--save", "", "--appendonly", "no"]
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 5
postgres:
image: docker.io/pgvector/pgvector:pg16
environment:
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
# 5433 so this can run alongside another project already on 5432.
ports:
- "5433:5432"
# Named, so a rebuild cannot take the corpus with it. Without this the data
# sits in the container's writable layer and any `up --build` that decides
# to recreate postgres silently destroys a crawl that took hours.
volumes:
- demo-pgdata:/var/lib/postgresql/data
# The default 64MB /dev/shm is too small to build the hnsw index over a
# populated chunks table: a restore fails with "could not resize shared
# memory segment". Migrations create that index on an empty table, so the
# problem only appears when restoring a real corpus, which is exactly when
# it hurts most.
shm_size: 1gb
healthcheck:
test: ["CMD-SHELL", "pg_isready -U app -d app"]
interval: 5s
timeout: 3s
retries: 5
# NOT an embedding model: deterministic hashed bag of words. Enough to show
# retrieval wiring end to end, useless for real relevance.
embeddings:
image: docker.io/oven/bun:1-alpine
working_dir: /demo
volumes:
- ./scripts/demo:/demo:z,ro
command: ["bun", "/demo/stub-embeddings.ts"]
expose:
- "39500"
# Approves every well-formed payment and settles NOTHING. Real settlement is
# the @mainnet @manual scenario in contracts/payment.feature.
facilitator:
image: docker.io/oven/bun:1-alpine
working_dir: /demo
volumes:
- ./scripts/demo:/demo:z,ro
command: ["bun", "/demo/mock-facilitator.ts"]
expose:
- "39600"
# The open API the browser talks to. Also owns the schema migration.
backend:
build:
context: .
dockerfile: apps/backend/Dockerfile
environment:
NODE_ENV: production
DB_MIGRATIONS_RUN: "true"
PORT: "3000"
POSTGRES_HOST: postgres
REDIS_HOST: redis
POSTGRES_PORT: "5432"
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
EMBEDDING_BASE_URL: http://embeddings:39500
EMBEDDING_MODEL: stub-embeddings
EMBEDDING_DIMENSIONS: "1536"
# A browser cannot sign an x402 payment, so the UI talks to an open
# instance. The metered path is `backend-metered` below.
X402_ENABLED: "false"
# The admin view is opt-in and read-only. Left untokened here because the
# demo binds to localhost; set ADMIN_TOKEN for anything reachable.
ADMIN_ENABLED: "true"
# The free, rate-limited box on the public site. Opt-in, and separate from
# the meter: this is the route a browser can use, since it cannot sign a
# payment. The site is served from :8080 here rather than wuzzy.io.
WEB_SEARCH_ENABLED: "true"
WEB_SEARCH_ORIGINS: http://localhost:8080
# Nothing is in front of this container in the demo, so there is no
# X-Forwarded-For to trust and the socket address is the client.
WEB_SEARCH_PROXY_HOPS: "0"
ports:
- "3000:3000"
depends_on:
postgres:
condition: service_healthy
# The same image with the meter on, for the demo agent to pay.
backend-metered:
build:
context: .
dockerfile: apps/backend/Dockerfile
environment:
NODE_ENV: production
PORT: "3000"
POSTGRES_HOST: postgres
REDIS_HOST: redis
POSTGRES_PORT: "5432"
POSTGRES_USER: app
POSTGRES_PASSWORD: app
POSTGRES_DB: app
EMBEDDING_BASE_URL: http://embeddings:39500
EMBEDDING_MODEL: stub-embeddings
EMBEDDING_DIMENSIONS: "1536"
X402_ENABLED: "true"
X402_NETWORK: base-sepolia
X402_PRICE: $$0.01
X402_PAY_TO: "0x2222222222222222222222222222222222222222"
X402_FACILITATOR_URL: http://facilitator:39600
ports:
- "3001:3000"
depends_on:
postgres:
condition: service_healthy
frontend:
build:
context: .
dockerfile: apps/frontend/Dockerfile
# Read while the pages are rendered, not at run time. The demo points at
# itself rather than at the public hostnames.
args:
SITE_ORIGIN: http://localhost:8080
API_ORIGIN: http://localhost:3001
SEARCH_ENABLED: "true"
environment:
BACKEND_ORIGIN: http://backend:3000
ports:
- "8080:80"
depends_on:
- backend
# A crawl worker. Same image as the backend, no HTTP: it takes jobs off the
# queue until stopped. `--scale worker=3` is how a slow crawl goes faster;
# each index is only ever crawled by one of them at a time.
worker:
build:
context: .
dockerfile: apps/backend/Dockerfile
command: ["bun", "apps/backend/src/worker.ts"]
# The image healthchecks an HTTP port the worker does not listen on, so
# without this it reports unhealthy for its whole life while crawling
# perfectly well.
healthcheck:
disable: true
environment:
POSTGRES_HOST: postgres
REDIS_HOST: redis
POSTGRES_DB: app
POSTGRES_USER: app
POSTGRES_PASSWORD: app
EMBEDDING_BASE_URL: http://embeddings:39500
EMBEDDING_MODEL: stub-embeddings
EMBEDDING_DIMENSIONS: "1536"
depends_on:
# The backend owns the migration, and the worker's first query is against
# a table it creates. Waiting on postgres alone is a race that only shows
# itself on a fresh volume, as an undefined-table crash on boot.
backend:
condition: service_healthy
redis:
condition: service_healthy
# A separate app on its own origin, so it can be kept off the public internet
# rather than hidden behind a path on the public site. Bound to loopback here:
# the demo runs it without a token.
admin:
build:
context: .
dockerfile: apps/admin/Dockerfile
environment:
BACKEND_ORIGIN: http://backend:3000
ports:
- "127.0.0.1:8081:80"
depends_on:
- backend
volumes:
demo-pgdata: