Repository navigation
Expand file tree
/
Copy pathTaskfile.yml
More file actions
387 lines (359 loc) · 15.7 KB
/
Copy pathTaskfile.yml
File metadata and controls
387 lines (359 loc) · 15.7 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
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
version: '3'
# https://taskfile.dev/usage/#env-files
dotenv: [ '.env.docker.local', '.env.local', '.env' ]
vars:
# https://taskfile.dev/reference/templating/
BASE_URL: '{{.TASK_BASE_URL | default .COMPOSE_SERVER_DOMAIN | default .COMPOSE_DOMAIN }}'
DOCKER_COMPOSE: '{{ .TASK_DOCKER_COMPOSE | default "itkdev-docker-compose" }}'
OPEN_WEBUI_REPO: 'https://github.com/os2ai/open-webui.git'
IMAGE_NAME: 'ghcr.io/os2ai/open-webui'
# Versions
OPEN_WEBUI_PREV_VERSION: 'v0.11.3'
OPEN_WEBUI_VERSION: 'v0.11.4'
PROD_OPEN_WEBUI_VERSION: 'v0.11.4-1'
TARGET_DIR: 'open-webui'
PATCHES:
- name: 'Pinned info banner'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/1.diff'
branch: 'patch/pinned-info-banner'
- name: 'Add token to TTS requests'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/2.diff'
branch: 'patch/tts-token'
- name: 'Extra permissions'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/3.diff'
branch: 'patch/extra-permissions'
- name: 'Fixed null error in auth database session handling'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/4.diff'
branch: 'patch/oauth_token_expire'
- name: 'Route MCP tool results through the existing citation pipeline (agentic search)'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/5.diff'
branch: 'patch/agentic-search'
- name: 'Template for rag queries'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/6.diff'
branch: 'patch/rag-query-template'
- name: 'Add ability to turn off prompt suggestions displaying at all'
url: 'https://patch-diff.githubusercontent.com/raw/os2ai/open-webui/pull/7.diff'
branch: 'patch/add-enable-prompt-suggestions'
tasks:
default:
desc: 'List all tasks'
cmds:
- task --list-all
silent: true
compose:
desc: "Run `docker compose` command. Example: task compose -- up --detach"
cmds:
- cmd: '{{ .DOCKER_COMPOSE }} {{ .CLI_ARGS }}'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml {{ .CLI_ARGS }}'
platforms: [arm64]
####
## Git helpers
####
git:sync:tags:
desc: "Sync tags from upstream repos"
dir: "{{ .TARGET_DIR }}"
cmds:
- |
echo "This assumes that you already have synced the main and dev branches with upstream on github!"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Sync cancelled."
exit 1
fi
- git remote add upstream https://github.com/open-webui/open-webui
- git fetch --tags upstream
- git push --tags
- git remote rm upstream
silent: true
git:clone:
desc: "Clone open-webui core"
cmds:
- git clone {{ .OPEN_WEBUI_REPO }}
- cd "{{ .TARGET_DIR }}" && git checkout {{ .OPEN_WEBUI_VERSION }}
silent: true
git:checkout:dev:
desc: "Checkout open-webui dev branch"
dir: "{{ .TARGET_DIR }}"
cmds:
- git reset --hard
- git checkout .
- git checkout dev
silent: true
git:reset:
desc: "Reset open-webui checkout to a specific version"
dir: "{{ .TARGET_DIR }}"
cmds:
- git reset --hard
- git checkout .
- git clean -fd
- git checkout {{ .OPEN_WEBUI_VERSION }}
silent: true
patches:apply:
desc: "Patch open-webui with custom patches"
dir: "{{ .TARGET_DIR }}"
cmds:
- for: { var: PATCHES }
cmd: |
curl -H 'Cache-Control: no-cache, no-store' -sSL {{ .ITEM.url }} | git apply --verbose -
silent: false
patches:download:
desc: "Download all patch diffs to patches/{{ .OPEN_WEBUI_VERSION }}/, named after the patch name"
vars:
PATCHES_DIR: 'patches/{{ .OPEN_WEBUI_VERSION }}'
cmds:
- for: { var: PATCHES }
task: patches:download:one
vars:
PATCH_DIR: '{{ .PATCHES_DIR }}'
PATCH_NAME: '{{ .ITEM.name }}'
PATCH_URL: '{{ .ITEM.url }}'
- echo "Downloaded patches to {{ .PATCHES_DIR }}/"
silent: true
patches:download:one:
desc: "Download a single patch diff into PATCH_DIR"
internal: true
cmds:
- |
mkdir -p {{ .PATCH_DIR }}
# Slugify the patch name into a file name.
file="{{ .PATCH_DIR }}/$(printf '%s' '{{ .PATCH_NAME }}' | tr '[:upper:]' '[:lower:]' | tr -cs 'a-z0-9' '-' | sed -e 's/^-//' -e 's/-$//').diff"
echo "Downloading '{{ .PATCH_NAME }}' -> $file"
curl -H 'Cache-Control: no-cache, no-store' -sSL --fail -o "$file" {{ .PATCH_URL }}
silent: true
install:
desc: "Install new web-ui"
cmds:
- |
echo "This will reset all changes and install a new version of open-webui:"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Install cancelled."
exit 1
fi
- if [ ! -d "{{ .TARGET_DIR }}" ]; then task git:clone; fi
- task git:reset
- task patch:aarhus
- task rag:clone
- task copy:config
- task compose -- pull
- task compose -- up --detach --force-recreate
- task wui:frontend:build
silent: true
open:
desc: "Open-webui in the browser"
cmds:
- open http://{{ .BASE_URL }}
silent: true
copy:config:
desc: "Copy config file from example, if it does not exist"
cmds:
- if ! [ -f .env ]; then cp .env.default .env; fi
silent: true
wui:npmrc:
desc: "Raise the node heap in open-webui/.npmrc for the vite build"
internal: true
dir: "{{ .TARGET_DIR }}"
cmds:
# vite OOMs at node's default ~4 GB heap while rendering chunks. npm exports
# `node-options` as NODE_OPTIONS for lifecycle scripts, so this reaches vite
# inside the image build as well - no Dockerfile patch needed.
- |
grep -v '^node-options=' .npmrc > .npmrc.tmp 2>/dev/null || true
echo 'node-options=--max-old-space-size={{ .NODE_BUILD_MEMORY | default "8192" }}' >> .npmrc.tmp
mv .npmrc.tmp .npmrc
silent: true
wui:backend:build:
desc: "Build container with newest requirements"
cmds:
- task: wui:npmrc
- task compose -- build --pull
silent: true
wui:frontend:build:
desc: "Build frontend"
cmds:
- task: wui:npmrc
- task compose -- run --rm -it node npm ci --force
- task compose -- run --rm -it node npm run build
silent: true
wui:frontend:dev:build:
desc: "Build frontend with environment set to dev (enables console logs etc.)"
cmds:
- task: wui:npmrc
- task compose -- run --rm -it -e ENV=dev node npm ci --force
- task compose -- run --rm -it -e ENV=dev node npm run build
silent: true
####
## Database helpers
####
db:dump:
desc: "Dump the Open WebUI postgres database. Example: task db:dump -- backup.sql (default: dump.sql)"
vars:
DUMP_FILE: '{{ .CLI_ARGS | default "dump.sql" }}'
cmds:
- cmd: '{{ .DOCKER_COMPOSE }} exec -T postgres pg_dump -U "${POSTGRES_USER:-postgres}" --clean --if-exists -d postgres > {{ .DUMP_FILE }}'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml exec -T postgres pg_dump -U "${POSTGRES_USER:-postgres}" --clean --if-exists -d postgres > {{ .DUMP_FILE }}'
platforms: [arm64]
- echo "Dumped Open WebUI database to {{ .DUMP_FILE }}"
silent: true
db:import:
desc: "Import a SQL dump into the Open WebUI postgres database (EMPTIES the database first, then imports). Example: task db:import -- dump.sql"
vars:
DUMP_FILE: '{{ .CLI_ARGS | default "dump.sql" }}'
cmds:
- |
echo "This will EMPTY the local Open WebUI postgres database and import '{{ .DUMP_FILE }}'."
echo "Tip: stop the openwebui container first for a clean restore (task compose -- stop openwebui)."
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Import cancelled."
exit 1
fi
- cmd: '{{ .DOCKER_COMPOSE }} exec -T postgres psql -U "${POSTGRES_USER:-postgres}" -d postgres -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml exec -T postgres psql -U "${POSTGRES_USER:-postgres}" -d postgres -c "DROP SCHEMA public CASCADE; CREATE SCHEMA public;"'
platforms: [arm64]
- cmd: '{{ .DOCKER_COMPOSE }} exec -T postgres psql -U "${POSTGRES_USER:-postgres}" -d postgres < {{ .DUMP_FILE }}'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml exec -T postgres psql -U "${POSTGRES_USER:-postgres}" -d postgres < {{ .DUMP_FILE }}'
platforms: [arm64]
- echo "Imported {{ .DUMP_FILE }} into the Open WebUI database"
silent: true
####
## Storage (S3) helpers
####
s3:dump:
desc: "Dump the Open WebUI S3 bucket to a local folder. Example: task s3:dump -- backup-dir (default: s3-dump)"
vars:
DUMP_DIR: '{{ .CLI_ARGS | default "s3-dump" }}'
BUCKET: 'openwebui'
cmds:
- mkdir -p {{ .DUMP_DIR }}
- cmd: '{{ .DOCKER_COMPOSE }} run --rm -T --user "$(id -u):$(id -g)" -e RCLONE_CONFIG=/tmp/rclone.conf -e RCLONE_CONFIG_GARAGE_TYPE=s3 -e RCLONE_CONFIG_GARAGE_PROVIDER=Other -e RCLONE_CONFIG_GARAGE_ENDPOINT=http://garage:3900 -e RCLONE_CONFIG_GARAGE_ACCESS_KEY_ID=${INGESTION_S3_ROOT_USER:-s3adminkey} -e RCLONE_CONFIG_GARAGE_SECRET_ACCESS_KEY=${S3_ROOT_PASSWORD:-s3passwords3password} -v "${PWD}/{{ .DUMP_DIR }}:/dump" --entrypoint rclone garage-init sync -P garage:{{ .BUCKET }} /dump'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml run --rm -T --user "$(id -u):$(id -g)" -e RCLONE_CONFIG=/tmp/rclone.conf -e RCLONE_CONFIG_GARAGE_TYPE=s3 -e RCLONE_CONFIG_GARAGE_PROVIDER=Other -e RCLONE_CONFIG_GARAGE_ENDPOINT=http://garage:3900 -e RCLONE_CONFIG_GARAGE_ACCESS_KEY_ID=${INGESTION_S3_ROOT_USER:-s3adminkey} -e RCLONE_CONFIG_GARAGE_SECRET_ACCESS_KEY=${S3_ROOT_PASSWORD:-s3passwords3password} -v "${PWD}/{{ .DUMP_DIR }}:/dump" --entrypoint rclone garage-init sync -P garage:{{ .BUCKET }} /dump'
platforms: [arm64]
- echo "Dumped S3 bucket '{{ .BUCKET }}' to {{ .DUMP_DIR }}/ (use scp/rsync to move it)"
silent: true
s3:import:
desc: "Restore an S3 dump folder into the Open WebUI bucket (OVERWRITES current objects). Example: task s3:import -- backup-dir (default: s3-dump)"
vars:
DUMP_DIR: '{{ .CLI_ARGS | default "s3-dump" }}'
BUCKET: 'openwebui'
cmds:
- |
echo "This will OVERWRITE the local Open WebUI S3 bucket '{{ .BUCKET }}' with the contents of '{{ .DUMP_DIR }}/'."
echo "Objects in the bucket that are not in the dump will be DELETED."
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Import cancelled."
exit 1
fi
- cmd: '{{ .DOCKER_COMPOSE }} run --rm -T --user "$(id -u):$(id -g)" -e RCLONE_CONFIG=/tmp/rclone.conf -e RCLONE_CONFIG_GARAGE_TYPE=s3 -e RCLONE_CONFIG_GARAGE_PROVIDER=Other -e RCLONE_CONFIG_GARAGE_ENDPOINT=http://garage:3900 -e RCLONE_CONFIG_GARAGE_ACCESS_KEY_ID=${INGESTION_S3_ROOT_USER:-s3adminkey} -e RCLONE_CONFIG_GARAGE_SECRET_ACCESS_KEY=${S3_ROOT_PASSWORD:-s3passwords3password} -v "${PWD}/{{ .DUMP_DIR }}:/dump" --entrypoint rclone garage-init sync -P /dump garage:{{ .BUCKET }}'
platforms: [amd64]
- cmd: '{{ .DOCKER_COMPOSE }} -f docker-compose.arm.yml run --rm -T --user "$(id -u):$(id -g)" -e RCLONE_CONFIG=/tmp/rclone.conf -e RCLONE_CONFIG_GARAGE_TYPE=s3 -e RCLONE_CONFIG_GARAGE_PROVIDER=Other -e RCLONE_CONFIG_GARAGE_ENDPOINT=http://garage:3900 -e RCLONE_CONFIG_GARAGE_ACCESS_KEY_ID=${INGESTION_S3_ROOT_USER:-s3adminkey} -e RCLONE_CONFIG_GARAGE_SECRET_ACCESS_KEY=${S3_ROOT_PASSWORD:-s3passwords3password} -v "${PWD}/{{ .DUMP_DIR }}:/dump" --entrypoint rclone garage-init sync -P /dump garage:{{ .BUCKET }}'
platforms: [arm64]
- echo "Imported {{ .DUMP_DIR }}/ into the S3 bucket '{{ .BUCKET }}'"
silent: true
####
## Update webui version helpers (<-- danger zone -->)
####
patches:rebase:
desc: "Rebase patch to laste release"
dir: "{{ .TARGET_DIR }}"
cmds:
- |
echo "This will rebase all patches to open-webui {{ .OPEN_WEBUI_VERSION }} from {{ .OPEN_WEBUI_PREV_VERSION }}:"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Install cancelled."
exit 1
fi
- for: { var: PATCHES }
cmd: |
if [ -n "{{ .ITEM.branch }}" ]; then
echo "Processing patch: {{ .ITEM.name }}"
git checkout {{ .ITEM.branch }}
git pull
git rebase --onto upstream/{{ .OPEN_WEBUI_VERSION }} upstream/{{ .OPEN_WEBUI_PREV_VERSION }}
else
echo "No branch specified for this '{{ .ITEM.name }}', skipping rebase"
fi
- git checkout {{ .OPEN_WEBUI_VERSION }}
silent: true
patches:reset:
desc: "Rest patch branched to GitHub version"
dir: "{{ .TARGET_DIR }}"
cmds:
- |
echo "This will reset all patches to open-webui to current version on Github:"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Install cancelled."
exit 1
fi
- for: { var: PATCHES }
cmd: |
if [ -n "{{ .ITEM.branch }}" ]; then
echo "Resetting patch: {{ .ITEM.name }}"
git checkout {{ .ITEM.branch }}
git reset --hard origin/{{ .ITEM.branch }}
git pull
else
echo "No branch specified for this '{{ .ITEM.name }}', skipping rebase"
fi
- git checkout {{ .OPEN_WEBUI_VERSION }}
silent: true
patches:force:
desc: "Force push all patches branches"
dir: "{{ .TARGET_DIR }}"
cmds:
- |
echo "This will force push all patches branches:"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Push cancelled."
exit 1
fi
- for: { var: PATCHES }
cmd: |
if [ -n "{{ .ITEM.branch }}" ]; then
git push origin {{ .ITEM.branch }} --force-with-lease
else
echo "No branch specified for this '{{ .ITEM.name }}', skipping push"
fi
silent: true
####
## Production build
####
prod:build:
desc: "Build and push docker image with custom registry and image name"
cmds:
- |
echo "You are about to build and push production images:"
echo " - {{ .IMAGE_NAME }}:{{.PROD_OPEN_WEBUI_VERSION}}"
echo " - {{ .IMAGE_NAME }}:latest"
echo ""
read -p "Are you sure you want to continue? (y/N): " confirm
if [ "$confirm" != "y" ] && [ "$confirm" != "Y" ]; then
echo "Build cancelled."
exit 1
fi
- task: git:reset
- task: '{{ .PATCH_TASK }}'
- task: wui:npmrc
- task: patches:apply
- COMPOSE_BAKE=true docker compose --file docker-compose.yml build --no-cache --pull openwebui
- docker tag openwebui-openwebui {{ .IMAGE_NAME }}:{{.PROD_OPEN_WEBUI_VERSION}}
- docker tag openwebui-openwebui {{ .IMAGE_NAME }}:latest
- docker push {{ .IMAGE_NAME }}:{{.PROD_OPEN_WEBUI_VERSION}}
- docker push {{ .IMAGE_NAME }}:latest
silent: true