siilats commited on
Commit
2a44dd2
·
unverified ·
1 Parent(s): b0cbf77
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .dockerignore +14 -1
  2. .eslintignore +13 -0
  3. .eslintrc.cjs +44 -0
  4. .gitignore +17 -0
  5. .prettierignore +14 -0
  6. .prettierrc +7 -0
  7. chart/Chart.yaml +5 -0
  8. chart/env/prod.yaml +724 -0
  9. chart/templates/_helpers.tpl +22 -0
  10. chart/templates/config.yaml +10 -0
  11. chart/templates/deployment.yaml +81 -0
  12. chart/templates/hpa.yaml +45 -0
  13. chart/templates/infisical.yaml +24 -0
  14. chart/templates/ingress-internal.yaml +32 -0
  15. chart/templates/ingress.yaml +32 -0
  16. chart/templates/network-policy.yaml +36 -0
  17. chart/templates/service-account.yaml +13 -0
  18. chart/templates/service-monitor.yaml +15 -0
  19. chart/templates/service.yaml +21 -0
  20. chart/values.yaml +74 -0
  21. package-lock.json +0 -0
  22. package.json +128 -11
  23. postcss.config.js +6 -0
  24. scripts/config.ts +64 -0
  25. scripts/populate.ts +391 -0
  26. scripts/samples.txt +194 -0
  27. scripts/setups/vitest-setup-client.ts +0 -0
  28. scripts/setups/vitest-setup-server.ts +49 -0
  29. scripts/updateLocalEnv.ts +48 -0
  30. static/chatui/apple-touch-icon.png +3 -0
  31. static/chatui/favicon.ico +0 -0
  32. static/chatui/favicon.svg +3 -0
  33. static/chatui/icon-128x128.png +3 -0
  34. static/chatui/icon-256x256.png +3 -0
  35. static/chatui/icon-512x512.png +3 -0
  36. static/chatui/icon.svg +3 -0
  37. static/chatui/logo.svg +6 -0
  38. static/chatui/manifest.json +24 -0
  39. static/huggingchat/apple-touch-icon.png +3 -0
  40. static/huggingchat/assistants-thumbnail.png +3 -0
  41. static/huggingchat/favicon.ico +0 -0
  42. static/huggingchat/favicon.svg +7 -0
  43. static/huggingchat/icon-128x128.png +3 -0
  44. static/huggingchat/icon-144x144.png +3 -0
  45. static/huggingchat/icon-192x192.png +3 -0
  46. static/huggingchat/icon-256x256.png +3 -0
  47. static/huggingchat/icon-36x36.png +3 -0
  48. static/huggingchat/icon-48x48.png +3 -0
  49. static/huggingchat/icon-512x512.png +3 -0
  50. static/huggingchat/icon-72x72.png +3 -0
.dockerignore CHANGED
@@ -1,2 +1,15 @@
1
  node_modules
2
- .git
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  node_modules
2
+ .git
3
+ Dockerfile
4
+ .vscode/
5
+ .idea
6
+ .gitignore
7
+ LICENSE
8
+ README.md
9
+ node_modules/
10
+ .svelte-kit/
11
+ .env*
12
+ !.env
13
+ .env.local
14
+ db
15
+ models/**
.eslintignore ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .DS_Store
2
+ node_modules
3
+ /build
4
+ /.svelte-kit
5
+ /package
6
+ .env
7
+ .env.*
8
+ !.env.example
9
+
10
+ # Ignore files for PNPM, NPM and YARN
11
+ pnpm-lock.yaml
12
+ package-lock.json
13
+ yarn.lock
.eslintrc.cjs ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ module.exports = {
2
+ root: true,
3
+ parser: "@typescript-eslint/parser",
4
+ extends: [
5
+ "eslint:recommended",
6
+ "plugin:@typescript-eslint/recommended",
7
+ "plugin:svelte/recommended",
8
+ "prettier",
9
+ ],
10
+ plugins: ["@typescript-eslint"],
11
+ ignorePatterns: ["*.cjs"],
12
+ overrides: [
13
+ {
14
+ files: ["*.svelte"],
15
+ parser: "svelte-eslint-parser",
16
+ parserOptions: {
17
+ parser: "@typescript-eslint/parser",
18
+ },
19
+ },
20
+ ],
21
+ parserOptions: {
22
+ sourceType: "module",
23
+ ecmaVersion: 2020,
24
+ extraFileExtensions: [".svelte"],
25
+ },
26
+ rules: {
27
+ "require-yield": "off",
28
+ "@typescript-eslint/no-explicit-any": "error",
29
+ "@typescript-eslint/no-non-null-assertion": "error",
30
+ "@typescript-eslint/no-unused-vars": [
31
+ // prevent variables with a _ prefix from being marked as unused
32
+ "error",
33
+ {
34
+ argsIgnorePattern: "^_",
35
+ },
36
+ ],
37
+ "object-shorthand": ["error", "always"],
38
+ },
39
+ env: {
40
+ browser: true,
41
+ es2017: true,
42
+ node: true,
43
+ },
44
+ };
.gitignore CHANGED
@@ -1,3 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  node_modules
2
 
3
  # Output
 
1
+ .DS_Store
2
+ node_modules
3
+ /build
4
+ /.svelte-kit
5
+ /package
6
+ .env
7
+ .env.*
8
+ vite.config.js.timestamp-*
9
+ vite.config.ts.timestamp-*
10
+ SECRET_CONFIG
11
+ .idea
12
+ !.env.ci
13
+ !.env
14
+ gcp-*.json
15
+ db
16
+ models/*
17
+ !models/add-your-models-here.txt
18
  node_modules
19
 
20
  # Output
.prettierignore ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .DS_Store
2
+ node_modules
3
+ /build
4
+ /.svelte-kit
5
+ /package
6
+ /chart
7
+ .env
8
+ .env.*
9
+ !.env.example
10
+
11
+ # Ignore files for PNPM, NPM and YARN
12
+ pnpm-lock.yaml
13
+ package-lock.json
14
+ yarn.lock
.prettierrc ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ {
2
+ "useTabs": true,
3
+ "trailingComma": "es5",
4
+ "printWidth": 100,
5
+ "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"],
6
+ "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
7
+ }
chart/Chart.yaml ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ apiVersion: v2
2
+ name: chat-ui
3
+ version: 0.0.1-latest
4
+ type: application
5
+ icon: https://huggingface.co/front/assets/huggingface_logo-noborder.svg
chart/env/prod.yaml ADDED
@@ -0,0 +1,724 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ image:
2
+ repository: huggingface
3
+ name: chat-ui
4
+
5
+ nodeSelector:
6
+ role-huggingchat: "true"
7
+
8
+ tolerations:
9
+ - key: "huggingface.co/huggingchat"
10
+ operator: "Equal"
11
+ value: "true"
12
+ effect: "NoSchedule"
13
+
14
+ serviceAccount:
15
+ enabled: true
16
+ create: true
17
+ name: huggingchat-prod
18
+
19
+ ingress:
20
+ path: "/chat"
21
+ annotations:
22
+ alb.ingress.kubernetes.io/healthcheck-path: "/healthcheck"
23
+ alb.ingress.kubernetes.io/listen-ports: "[{\"HTTP\": 80}, {\"HTTPS\": 443}]"
24
+ alb.ingress.kubernetes.io/group.name: "hub-prod"
25
+ alb.ingress.kubernetes.io/scheme: "internet-facing"
26
+ alb.ingress.kubernetes.io/ssl-redirect: "443"
27
+ alb.ingress.kubernetes.io/tags: "Env=prod,Project=hub,Terraform=true"
28
+ alb.ingress.kubernetes.io/target-node-labels: "role-hub-utils=true"
29
+ kubernetes.io/ingress.class: "alb"
30
+
31
+ ingressInternal:
32
+ enabled: true
33
+ path: "/chat"
34
+ annotations:
35
+ alb.ingress.kubernetes.io/group.name: hub-prod-internal-public
36
+ alb.ingress.kubernetes.io/healthcheck-path: "/healthcheck"
37
+ alb.ingress.kubernetes.io/listen-ports: "[{\"HTTP\": 80}, {\"HTTPS\": 443}]"
38
+ alb.ingress.kubernetes.io/load-balancer-name: hub-prod-internal-public
39
+ alb.ingress.kubernetes.io/target-group-attributes: deregistration_delay.timeout_seconds=30
40
+ alb.ingress.kubernetes.io/target-node-labels: role-hub-lb=true
41
+ alb.ingress.kubernetes.io/target-type: ip
42
+ kubernetes.io/ingress.class: "alb"
43
+
44
+ envVars:
45
+ ADDRESS_HEADER: 'X-Forwarded-For'
46
+ ADMIN_CLI_LOGIN: "false"
47
+ ALTERNATIVE_REDIRECT_URLS: '["huggingchat://login/callback"]'
48
+ APP_BASE: "/chat"
49
+ ALLOW_IFRAME: "false"
50
+ COMMUNITY_TOOLS: "true"
51
+ COOKIE_SAMESITE: "lax"
52
+ COOKIE_SECURE: "true"
53
+ ENABLE_ASSISTANTS: "true"
54
+ ENABLE_ASSISTANTS_RAG: "true"
55
+ ENABLE_CONFIG_MANAGER: "false"
56
+ METRICS_PORT: 5565
57
+ LOG_LEVEL: "debug"
58
+ METRICS_ENABLED: "true"
59
+ MODELS: >
60
+ [
61
+ {
62
+ "name": "meta-llama/Llama-3.3-70B-Instruct",
63
+ "id": "meta-llama/Llama-3.3-70B-Instruct",
64
+ "description": "Ideal for everyday use. A fast and extremely capable model matching closed source models' capabilities. Now with the latest Llama 3.3 weights!",
65
+ "modelUrl": "https://huggingface.co/meta-llama/Llama-3.3-70B-Instruct",
66
+ "websiteUrl": "https://llama.meta.com/",
67
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/meta-logo.png",
68
+ "tools": true,
69
+ "preprompt": "",
70
+ "parameters": {
71
+ "stop": ["<|endoftext|>", "<|eot_id|>"],
72
+ "temperature": 0.6,
73
+ "max_new_tokens": 1024,
74
+ "truncate": 7167
75
+ },
76
+ "endpoints": [{"type" : "inference-client"}],
77
+ "promptExamples": [
78
+ {
79
+ "title": "Write an email",
80
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
81
+ },
82
+ {
83
+ "title": "Code a game",
84
+ "prompt": "Code a basic snake game in python, give explanations for each step."
85
+ },
86
+ {
87
+ "title": "Recipe help",
88
+ "prompt": "How do I make a delicious lemon cheesecake?"
89
+ }
90
+ ]
91
+ },
92
+ {
93
+ "name": "Qwen/Qwen3-235B-A22B",
94
+ "description": "Qwen's flagship model featuring optional reasoning. Exceptional performance with benchmarks rivaling R1 and o1.",
95
+ "modelUrl": "https://huggingface.co/Qwen/Qwen3-235B-A22B",
96
+ "websiteUrl": "https://qwenlm.github.io/blog/qwen3/",
97
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/qwen-logo.png",
98
+ "preprompt": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant.",
99
+ "reasoning": {
100
+ "type": "tokens",
101
+ "beginToken": "<think>",
102
+ "endToken": "</think>"
103
+ },
104
+ "parameters": {
105
+ "stop": ["<|endoftext|>", "<|im_end|>"],
106
+ "temperature": 0.6,
107
+ },
108
+ "tools": true,
109
+ "promptExamples": [
110
+ {
111
+ "title": "Write an email",
112
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12) /nothink"
113
+ },
114
+ {
115
+ "title": "Build a website",
116
+ "prompt": "Generate a snazzy static landing page for a local coffee shop using HTML and CSS. You can use tailwind using <script src='https://cdn.tailwindcss.com'></script>."
117
+ },
118
+ {
119
+ "title": "Larger number",
120
+ "prompt": "9.11 or 9.9 which number is larger?"
121
+ },
122
+ ],
123
+ "endpoints": [
124
+ {
125
+ "type": "inference-client",
126
+ "baseURL": "https://api-inference.endpoints.huggingface.tech/models/Qwen/Qwen3-235B-A22B/v1"
127
+ }
128
+ ]
129
+ },
130
+ {
131
+ "name": "Qwen/Qwen2.5-72B-Instruct",
132
+ "description": "The latest Qwen open model with improved role-playing, long text generation and structured data understanding.",
133
+ "modelUrl": "https://huggingface.co/Qwen/Qwen2.5-72B-Instruct",
134
+ "websiteUrl": "https://qwenlm.github.io/blog/qwen2.5/",
135
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/qwen-logo.png",
136
+ "preprompt": "You are Qwen, created by Alibaba Cloud. You are a helpful assistant.",
137
+ "parameters": {
138
+ "stop": ["<|endoftext|>", "<|im_end|>"],
139
+ "temperature": 0.6,
140
+ "truncate": 28672,
141
+ "max_new_tokens": 3072
142
+ },
143
+ "tools": true,
144
+ "endpoints": [{"type" : "inference-client"}],
145
+ "promptExamples": [
146
+ {
147
+ "title": "Write an email",
148
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
149
+ },
150
+ {
151
+ "title": "Code a game",
152
+ "prompt": "Code a basic snake game in python, give explanations for each step."
153
+ },
154
+ {
155
+ "title": "Recipe help",
156
+ "prompt": "How do I make a delicious lemon cheesecake?"
157
+ }
158
+ ]
159
+ },
160
+ {
161
+ "name": "CohereLabs/c4ai-command-r-plus-08-2024",
162
+ "description": "Cohere's largest language model, optimized for conversational interaction and tool use. Now with the 2024 update!",
163
+ "modelUrl": "https://huggingface.co/CohereLabs/c4ai-command-r-plus-08-2024",
164
+ "websiteUrl": "https://docs.cohere.com/docs/command-r-plus",
165
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/cohere-logo.png",
166
+ "tools": true,
167
+ "systemRoleSupported": false,
168
+ "parameters": {
169
+ "stop": ["<|END_OF_TURN_TOKEN|>", "<|im_end|>"],
170
+ "truncate": 28672,
171
+ "max_new_tokens": 2048,
172
+ "temperature": 0.3
173
+ },
174
+ "endpoints": [{"type" : "inference-client"}],
175
+ "promptExamples": [
176
+ {
177
+ "title": "Generate image",
178
+ "prompt": "Generate the portrait of a scientific mouse in its laboratory."
179
+ },
180
+ {
181
+ "title": "Review code",
182
+ "prompt": "Review this pull request: https://github.com/huggingface/chat-ui/pull/1131/files"
183
+ },
184
+ {
185
+ "title": "Code a game",
186
+ "prompt": "Code a basic snake game in python, give explanations for each step."
187
+ }
188
+ ]
189
+ },
190
+ {
191
+ "name": "deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
192
+ "modelUrl": "https://huggingface.co/deepseek-ai/DeepSeek-R1-Distill-Qwen-32B",
193
+ "websiteUrl": "https://deepseek.com/",
194
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/deepseek-logo.png",
195
+ "description": "The first reasoning model from DeepSeek, distilled into a 32B dense model. Outperforms o1-mini on multiple benchmarks.",
196
+ "reasoning": {
197
+ "type": "tokens",
198
+ "beginToken": "",
199
+ "endToken": "</think>"
200
+ },
201
+ "tools": true,
202
+ "promptExamples": [
203
+ {
204
+ "title": "Rs in strawberry",
205
+ "prompt": "how many R in strawberry?"
206
+ },
207
+ {
208
+ "title": "Larger number",
209
+ "prompt": "9.11 or 9.9 which number is larger?"
210
+ },
211
+ {
212
+ "title": "Measuring 6 liters",
213
+ "prompt": "I have a 6- and a 12-liter jug. I want to measure exactly 6 liters."
214
+ }
215
+ ],
216
+ "endpoints": [
217
+ {
218
+ "type": "inference-client",
219
+ "baseURL": "https://b8xf586h164t4vk7.us-east-1.aws.endpoints.huggingface.cloud/v1"
220
+ }
221
+ ]
222
+ },
223
+ {
224
+ "name": "nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
225
+ "modelUrl": "https://huggingface.co/nvidia/Llama-3.1-Nemotron-70B-Instruct-HF",
226
+ "websiteUrl": "https://www.nvidia.com/",
227
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/nvidia-logo.png",
228
+ "description": "Nvidia's latest Llama fine-tune, topping alignment benchmarks and optimized for instruction following.",
229
+ "parameters": {
230
+ "stop": ["<|eot_id|>", "<|im_end|>"],
231
+ "temperature": 0.5,
232
+ "truncate": 28672,
233
+ "max_new_tokens": 2048
234
+ },
235
+ "promptExamples": [
236
+ {
237
+ "title": "Rs in strawberry",
238
+ "prompt": "how many R in strawberry?"
239
+ },
240
+ {
241
+ "title": "Larger number",
242
+ "prompt": "9.11 or 9.9 which number is larger?"
243
+ },
244
+ {
245
+ "title": "Measuring 6 liters",
246
+ "prompt": "I have a 6- and a 12-liter jug. I want to measure exactly 6 liters."
247
+ }
248
+ ],
249
+ "endpoints": [
250
+ {
251
+ "type": "inference-client",
252
+ "baseURL": "https://api-inference.endpoints.huggingface.tech/models/nvidia/Llama-3.1-Nemotron-70B-Instruct-HF/v1"
253
+ }
254
+ ]
255
+ },
256
+ {
257
+ "name": "Qwen/QwQ-32B",
258
+ "tools": true,
259
+ "preprompt": "You are a helpful and harmless assistant. You are Qwen developed by Alibaba. You should think step-by-step.",
260
+ "modelUrl": "https://huggingface.co/Qwen/QwQ-32B",
261
+ "websiteUrl": "https://qwenlm.github.io/blog/qwq-32b/",
262
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/qwen-logo.png",
263
+ "description": "QwQ is the latest reasoning model released by the Qwen team, approaching the capabilities of R1 in benchmarks.",
264
+ "reasoning": {
265
+ "type": "tokens",
266
+ "beginToken": "",
267
+ "endToken": "</think>"
268
+ },
269
+ "promptExamples": [
270
+ {
271
+ "title": "Rs in strawberry",
272
+ "prompt": "how many R in strawberry?"
273
+ },
274
+ {
275
+ "title": "Larger number",
276
+ "prompt": "9.11 or 9.9 which number is larger?"
277
+ },
278
+ {
279
+ "title": "Measuring 6 liters",
280
+ "prompt": "I have a 6- and a 12-liter jug. I want to measure exactly 6 liters."
281
+ }
282
+ ],
283
+ "endpoints": [
284
+ {
285
+ "type": "inference-client",
286
+ }
287
+ ]
288
+ },
289
+ {
290
+ "name": "google/gemma-3-27b-it",
291
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/google-logo.png",
292
+ "multimodal": true,
293
+ "tools": true,
294
+ "systemRoleSupported" : false,
295
+ "description": "Google's latest open model with great multilingual performance, supports image inputs natively.",
296
+ "websiteUrl": "https://blog.google/technology/developers/gemma-3/",
297
+ "promptExamples": [
298
+ {
299
+ "title": "Write an email",
300
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
301
+ },
302
+ {
303
+ "title": "Code a game",
304
+ "prompt": "Code a basic snake game in python, give explanations for each step."
305
+ },
306
+ {
307
+ "title": "Recipe help",
308
+ "prompt": "How do I make a delicious lemon cheesecake?"
309
+ }
310
+ ],
311
+ "endpoints": [
312
+ {
313
+ "type": "inference-client",
314
+ "baseURL": "https://wp0d3hn6s3k8jk22.us-east-1.aws.endpoints.huggingface.cloud/v1",
315
+ "multimodal": {
316
+ "image": {
317
+ "maxSizeInMB": 10,
318
+ "maxWidth": 560,
319
+ "maxHeight": 560,
320
+ "supportedMimeTypes": ["image/jpeg", "image/png", "image/webp"],
321
+ "preferredMimeType": "image/webp"
322
+ }
323
+ }
324
+ }
325
+ ]
326
+ },
327
+ {
328
+ "name": "mistralai/Mistral-Small-3.1-24B-Instruct-2503",
329
+ "tools": true,
330
+ "displayName": "mistralai/Mistral-Small-3.1-24B-Instruct-2503",
331
+ "description": "A small model with good capabilities in language understanding and commonsense reasoning.",
332
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/mistral-logo.png",
333
+ "websiteUrl": "https://mistral.ai/news/mistral-nemo/",
334
+ "modelUrl": "https://huggingface.co/mistralai/Mistral-Small-3.1-24B-Instruct-2503",
335
+ "preprompt": "",
336
+ "promptExamples": [
337
+ {
338
+ "title": "Write an email",
339
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
340
+ },
341
+ {
342
+ "title": "Code a game",
343
+ "prompt": "Code a basic snake game in python, give explanations for each step."
344
+ },
345
+ {
346
+ "title": "Recipe help",
347
+ "prompt": "How do I make a delicious lemon cheesecake?"
348
+ }
349
+ ],
350
+
351
+ "endpoints": [
352
+ {
353
+ "type": "inference-client",
354
+ "baseURL": "https://hkjfqcryevvq9cie.us-east-1.aws.endpoints.huggingface.cloud/v1"
355
+ }
356
+ ]
357
+ },
358
+ {
359
+ "name": "Qwen/Qwen2.5-VL-32B-Instruct",
360
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/qwen-logo.png",
361
+ "description": "The latest multimodal model from Qwen! Supports image inputs natively.",
362
+ "websiteUrl": "https://qwenlm.github.io/blog/qwen2.5-vl/",
363
+ "modelUrl": "https://huggingface.co/Qwen/Qwen2.5-VL-32B-Instruct",
364
+ "multimodal": true,
365
+ "promptExamples": [
366
+ {
367
+ "title": "Write an email",
368
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
369
+ },
370
+ {
371
+ "title": "Code a game",
372
+ "prompt": "Code a basic snake game in python, give explanations for each step."
373
+ },
374
+ {
375
+ "title": "Recipe help",
376
+ "prompt": "How do I make a delicious lemon cheesecake?"
377
+ }
378
+ ],
379
+ "endpoints": [
380
+ {
381
+ "type": "inference-client",
382
+ "multimodal": {
383
+ "image": {
384
+ "maxSizeInMB": 10,
385
+ "maxWidth": 1024,
386
+ "maxHeight": 1024,
387
+ "supportedMimeTypes": ["image/png", "image/jpeg", "image/webp"],
388
+ "preferredMimeType": "image/webp"
389
+ }
390
+ }
391
+ }
392
+ ]
393
+ },
394
+ {
395
+ "name": "microsoft/Phi-4",
396
+ "tools": true,
397
+ "systemRoleSupported": false,
398
+ "description": "One of the best small models, super fast for simple tasks.",
399
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/microsoft-logo.png",
400
+ "modelUrl": "https://huggingface.co/microsoft/Phi-4",
401
+ "websiteUrl": "https://techcommunity.microsoft.com/blog/aiplatformblog/introducing-phi-4-microsoft%E2%80%99s-newest-small-language-model-specializing-in-comple/4357090",
402
+ "preprompt": "",
403
+ "parameters": {
404
+ "stop": ["<|end|>", "<|endoftext|>", "<|assistant|>"],
405
+ "temperature": 0.6,
406
+ "truncate": 28672,
407
+ "max_new_tokens": 3072
408
+ },
409
+ "promptExamples": [
410
+ {
411
+ "title": "Write an email",
412
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
413
+ },
414
+ {
415
+ "title": "Code a game",
416
+ "prompt": "Code a basic snake game in python, give explanations for each step."
417
+ },
418
+ {
419
+ "title": "Recipe help",
420
+ "prompt": "How do I make a delicious lemon cheesecake?"
421
+ }
422
+ ],
423
+ "endpoints": [
424
+ {
425
+ "type": "inference-client",
426
+ "baseURL": "https://up5ijetg6a2e9zlb.us-east-1.aws.endpoints.huggingface.cloud/v1"
427
+ }
428
+ ]
429
+ },
430
+ {
431
+ "name": "NousResearch/Hermes-3-Llama-3.1-8B",
432
+ "description": "Nous Research's latest Hermes 3 release in 8B size. Follows instruction closely.",
433
+ "tools": true,
434
+ "logoUrl": "https://huggingface.co/datasets/huggingchat/models-logo/resolve/main/nous-logo.png",
435
+ "websiteUrl": "https://nousresearch.com/",
436
+ "modelUrl": "https://huggingface.co/NousResearch/Hermes-3-Llama-3.1-8B",
437
+ "promptExamples": [
438
+ {
439
+ "title": "Write an email",
440
+ "prompt": "As a restaurant owner, write a professional email to the supplier to get these products every week: \n\n- Wine (x10)\n- Eggs (x24)\n- Bread (x12)"
441
+ },
442
+ {
443
+ "title": "Code a game",
444
+ "prompt": "Code a basic snake game in python, give explanations for each step."
445
+ },
446
+ {
447
+ "title": "Recipe help",
448
+ "prompt": "How do I make a delicious lemon cheesecake?"
449
+ }
450
+ ],
451
+ "parameters": {
452
+ "stop": ["<|im_end|>"],
453
+ "temperature": 0.6,
454
+ "truncate": 14336,
455
+ "max_new_tokens": 1536
456
+ },
457
+ "endpoints": [{"type" : "inference-client"}]
458
+ }
459
+ ]
460
+
461
+ NODE_ENV: "prod"
462
+ NODE_LOG_STRUCTURED_DATA: true
463
+ OLD_MODELS: >
464
+ [
465
+ { "name": "bigcode/starcoder" },
466
+ { "name": "OpenAssistant/oasst-sft-6-llama-30b-xor" },
467
+ { "name": "HuggingFaceH4/zephyr-7b-alpha" },
468
+ { "name": "openchat/openchat_3.5" },
469
+ { "name": "openchat/openchat-3.5-1210" },
470
+ { "name": "tiiuae/falcon-180B-chat" },
471
+ { "name": "codellama/CodeLlama-34b-Instruct-hf" },
472
+ { "name": "google/gemma-7b-it" },
473
+ { "name": "meta-llama/Llama-2-70b-chat-hf" },
474
+ { "name": "codellama/CodeLlama-70b-Instruct-hf" },
475
+ { "name": "openchat/openchat-3.5-0106" },
476
+ { "name": "meta-llama/Meta-Llama-3-70B-Instruct" },
477
+ { "name": "meta-llama/Meta-Llama-3.1-405B-Instruct-FP8" },
478
+ {
479
+ "name": "CohereForAI/c4ai-command-r-plus-08-2024",
480
+ "transferTo": "CohereLabs/c4ai-command-r-plus-08-2024"
481
+ },
482
+ {
483
+ "name": "CohereForAI/c4ai-command-r-plus",
484
+ "transferTo": "CohereLabs/c4ai-command-r-plus-08-2024"
485
+ },
486
+ {
487
+ "name": "01-ai/Yi-1.5-34B-Chat",
488
+ "transferTo": "CohereLabs/c4ai-command-r-plus-08-2024"
489
+ },
490
+ {
491
+ "name": "mistralai/Mixtral-8x7B-Instruct-v0.1",
492
+ "transferTo": "mistralai/Mistral-Small-3.1-24B-Instruct-2503"
493
+ },
494
+ {
495
+ "name": "NousResearch/Nous-Hermes-2-Mixtral-8x7B-DPO",
496
+ "transferTo": "NousResearch/Hermes-3-Llama-3.1-8B"
497
+ },
498
+ {
499
+ "name": "mistralai/Mistral-7B-Instruct-v0.3",
500
+ "transferTo": "mistralai/Mistral-Small-3.1-24B-Instruct-2503"
501
+ },
502
+ {
503
+ "name": "microsoft/Phi-3-mini-4k-instruct",
504
+ "transferTo": "microsoft/Phi-4"
505
+ },
506
+ {
507
+ "name": "meta-llama/Meta-Llama-3.1-70B-Instruct",
508
+ "transferTo": "meta-llama/Llama-3.3-70B-Instruct"
509
+ },
510
+ {
511
+ "name": "Qwen/QwQ-32B-Preview",
512
+ "transferTo": "Qwen/QwQ-32B"
513
+ },
514
+ {
515
+ "name": "mistralai/Mistral-Nemo-Instruct-2407",
516
+ "transferTo": "mistralai/Mistral-Small-3.1-24B-Instruct-2503"
517
+ },
518
+ {
519
+ "name": "microsoft/Phi-3.5-mini-instruct",
520
+ "transferTo": "microsoft/Phi-4"
521
+ },
522
+ {
523
+ "name": "Qwen/Qwen2.5-Coder-32B-Instruct",
524
+ "transferTo": "Qwen/QwQ-32B"
525
+ },
526
+ {
527
+ "name": "meta-llama/Llama-3.2-11B-Vision-Instruct",
528
+ "transferTo" : "Qwen/Qwen2.5-VL-32B-Instruct"
529
+ }
530
+ ]
531
+ PUBLIC_ORIGIN: "https://huggingface.co"
532
+ PUBLIC_SHARE_PREFIX: "https://hf.co/chat"
533
+ PUBLIC_ANNOUNCEMENT_BANNERS: >
534
+ [
535
+ {
536
+ "title": "Qwen 3 235B is available!",
537
+ "linkTitle": "Try it out!",
538
+ "linkHref": "https://huggingface.co/chat/models/Qwen/Qwen3-235B-A22B"
539
+ }
540
+ ]
541
+ PUBLIC_APP_NAME: "HuggingChat"
542
+ PUBLIC_APP_ASSETS: "huggingchat"
543
+ PUBLIC_APP_COLOR: "yellow"
544
+ PUBLIC_APP_DESCRIPTION: "Making the community's best AI chat models available to everyone."
545
+ PUBLIC_APP_DISCLAIMER_MESSAGE: "Disclaimer: AI is an area of active research with known problems such as biased generation and misinformation. Do not use this application for high-stakes decisions or advice."
546
+ PUBLIC_APP_GUEST_MESSAGE: "Sign in with a free Hugging Face account to continue using HuggingChat."
547
+ PUBLIC_APP_DATA_SHARING: 0
548
+ PUBLIC_APP_DISCLAIMER: 1
549
+ PUBLIC_PLAUSIBLE_SCRIPT_URL: "/js/script.js"
550
+ REQUIRE_FEATURED_ASSISTANTS: "true"
551
+ TASK_MODEL: >
552
+ {
553
+ "name": "NousResearch/Hermes-3-Llama-3.1-8B",
554
+ "unlisted": true,
555
+ "endpoints": [{"type" : "inference-client"}],
556
+ "parameters": {
557
+ "temperature": 0.1,
558
+ "max_new_tokens": 256
559
+ }
560
+ }
561
+
562
+
563
+ TEXT_EMBEDDING_MODELS: >
564
+ [{
565
+ "name": "bge-base-en-v1-5-sxa",
566
+ "displayName": "bge-base-en-v1-5-sxa",
567
+ "chunkCharLength": 512,
568
+ "endpoints": [{
569
+ "type": "tei",
570
+ "url": "https://huggingchat-tei.hf.space/"
571
+ }]
572
+ }]
573
+ WEBSEARCH_BLOCKLIST: '["youtube.com", "twitter.com"]'
574
+ XFF_DEPTH: '2'
575
+ TOOLS: >
576
+ [
577
+ {
578
+ "_id": "000000000000000000000001",
579
+ "displayName": "Image Generation",
580
+ "description": "Use this tool to generate images based on a prompt.",
581
+ "color": "yellow",
582
+ "icon": "camera",
583
+ "baseUrl": "black-forest-labs/FLUX.1-schnell",
584
+ "name": "image_generation",
585
+ "endpoint": "/infer",
586
+ "inputs": [
587
+ {
588
+ "name": "prompt",
589
+ "description": "A prompt to generate an image from",
590
+ "paramType": "required",
591
+ "type": "str"
592
+ },
593
+ { "name": "seed", "paramType": "fixed", "value": "0", "type": "float" },
594
+ {
595
+ "name": "randomize_seed",
596
+ "paramType": "fixed",
597
+ "value": "true",
598
+ "type": "bool"
599
+ },
600
+ {
601
+ "name": "width",
602
+ "description": "numeric value between 256 and 2048",
603
+ "paramType": "optional",
604
+ "default": 1024,
605
+ "type": "float"
606
+ },
607
+ {
608
+ "name": "height",
609
+ "description": "numeric value between 256 and 2048",
610
+ "paramType": "optional",
611
+ "default": 1024,
612
+ "type": "float"
613
+ },
614
+ {
615
+ "name": "num_inference_steps",
616
+ "paramType": "fixed",
617
+ "value": "4",
618
+ "type": "float"
619
+ }
620
+ ],
621
+ "outputComponent": "image",
622
+ "outputComponentIdx": 0,
623
+ "showOutput": true
624
+ },
625
+ {
626
+ "_id": "000000000000000000000002",
627
+ "displayName": "Document Parser",
628
+ "description": "Use this tool to parse any document and get its content in markdown format.",
629
+ "color": "yellow",
630
+ "icon": "cloud",
631
+ "baseUrl": "huggingchat/document-parser",
632
+ "name": "document_parser",
633
+ "endpoint": "/predict",
634
+ "inputs": [
635
+ {
636
+ "name": "document",
637
+ "description": "Filename of the document to parse",
638
+ "paramType": "required",
639
+ "type": "file",
640
+ "mimeTypes": 'application/*'
641
+ },
642
+ {
643
+ "name": "filename",
644
+ "paramType": "fixed",
645
+ "value": "document.pdf",
646
+ "type": "str"
647
+ }
648
+ ],
649
+ "outputComponent": "textbox",
650
+ "outputComponentIdx": 0,
651
+ "showOutput": false,
652
+ "isHidden": true
653
+ },
654
+ {
655
+ "_id": "000000000000000000000003",
656
+ "name": "edit_image",
657
+ "baseUrl": "multimodalart/cosxl",
658
+ "endpoint": "/run_edit",
659
+ "inputs": [
660
+ {
661
+ "name": "image",
662
+ "description": "The image path to be edited",
663
+ "paramType": "required",
664
+ "type": "file",
665
+ "mimeTypes": 'image/*'
666
+ },
667
+ {
668
+ "name": "prompt",
669
+ "description": "The prompt with which to edit the image",
670
+ "paramType": "required",
671
+ "type": "str"
672
+ },
673
+ {
674
+ "name": "negative_prompt",
675
+ "paramType": "fixed",
676
+ "value": "",
677
+ "type": "str"
678
+ },
679
+ {
680
+ "name": "guidance_scale",
681
+ "paramType": "fixed",
682
+ "value": 6.5,
683
+ "type": "float"
684
+ },
685
+ {
686
+ "name": "steps",
687
+ "paramType": "fixed",
688
+ "value": 30,
689
+ "type": "float"
690
+ }
691
+ ],
692
+ "outputComponent": "image",
693
+ "showOutput": true,
694
+ "displayName": "Image Editor",
695
+ "color": "green",
696
+ "icon": "camera",
697
+ "description": "This tool lets you edit images",
698
+ "outputComponentIdx": 0
699
+ }
700
+ ]
701
+ HF_ORG_ADMIN: '644171cfbd0c97265298aa99'
702
+ HF_ORG_EARLY_ACCESS: '5e67bd5b1009063689407478'
703
+ HF_API_ROOT: 'https://api-inference.endpoints.huggingface.tech/models'
704
+ infisical:
705
+ enabled: true
706
+ env: "prod-us-east-1"
707
+
708
+ autoscaling:
709
+ enabled: true
710
+ minReplicas: 12
711
+ maxReplicas: 30
712
+ targetMemoryUtilizationPercentage: "50"
713
+ targetCPUUtilizationPercentage: "50"
714
+
715
+ resources:
716
+ requests:
717
+ cpu: 2
718
+ memory: 4Gi
719
+ limits:
720
+ cpu: 4
721
+ memory: 8Gi
722
+
723
+ monitoring:
724
+ enabled: true
chart/templates/_helpers.tpl ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- define "name" -}}
2
+ {{- default $.Release.Name | trunc 63 | trimSuffix "-" -}}
3
+ {{- end -}}
4
+
5
+ {{- define "app.name" -}}
6
+ chat-ui
7
+ {{- end -}}
8
+
9
+ {{- define "labels.standard" -}}
10
+ release: {{ $.Release.Name | quote }}
11
+ heritage: {{ $.Release.Service | quote }}
12
+ chart: "{{ include "name" . }}"
13
+ app: "{{ include "app.name" . }}"
14
+ {{- end -}}
15
+
16
+ {{- define "labels.resolver" -}}
17
+ release: {{ $.Release.Name | quote }}
18
+ heritage: {{ $.Release.Service | quote }}
19
+ chart: "{{ include "name" . }}"
20
+ app: "{{ include "app.name" . }}-resolver"
21
+ {{- end -}}
22
+
chart/templates/config.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: v1
2
+ kind: ConfigMap
3
+ metadata:
4
+ labels: {{ include "labels.standard" . | nindent 4 }}
5
+ name: {{ include "name" . }}
6
+ namespace: {{ .Release.Namespace }}
7
+ data:
8
+ {{- range $key, $value := $.Values.envVars }}
9
+ {{ $key }}: {{ $value | quote }}
10
+ {{- end }}
chart/templates/deployment.yaml ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: apps/v1
2
+ kind: Deployment
3
+ metadata:
4
+ labels: {{ include "labels.standard" . | nindent 4 }}
5
+ name: {{ include "name" . }}
6
+ namespace: {{ .Release.Namespace }}
7
+ {{- if .Values.infisical.enabled }}
8
+ annotations:
9
+ secrets.infisical.com/auto-reload: "true"
10
+ {{- end }}
11
+ spec:
12
+ progressDeadlineSeconds: 600
13
+ {{- if not $.Values.autoscaling.enabled }}
14
+ replicas: {{ .Values.replicas }}
15
+ {{- end }}
16
+ revisionHistoryLimit: 10
17
+ selector:
18
+ matchLabels: {{ include "labels.standard" . | nindent 6 }}
19
+ strategy:
20
+ rollingUpdate:
21
+ maxSurge: 25%
22
+ maxUnavailable: 25%
23
+ type: RollingUpdate
24
+ template:
25
+ metadata:
26
+ labels: {{ include "labels.standard" . | nindent 8 }}
27
+ annotations:
28
+ checksum/config: {{ include (print $.Template.BasePath "/config.yaml") . | sha256sum }}
29
+ {{- if $.Values.envVars.NODE_LOG_STRUCTURED_DATA }}
30
+ co.elastic.logs/json.expand_keys: "true"
31
+ {{- end }}
32
+ spec:
33
+ {{- if .Values.serviceAccount.enabled }}
34
+ serviceAccountName: "{{ .Values.serviceAccount.name | default (include "name" .) }}"
35
+ {{- end }}
36
+ containers:
37
+ - name: chat-ui
38
+ image: "{{ .Values.image.repository }}/{{ .Values.image.name }}:{{ .Values.image.tag }}"
39
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
40
+ readinessProbe:
41
+ failureThreshold: 30
42
+ periodSeconds: 10
43
+ httpGet:
44
+ path: {{ $.Values.envVars.APP_BASE | default "" }}/healthcheck
45
+ port: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
46
+ livenessProbe:
47
+ failureThreshold: 30
48
+ periodSeconds: 10
49
+ httpGet:
50
+ path: {{ $.Values.envVars.APP_BASE | default "" }}/healthcheck
51
+ port: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
52
+ ports:
53
+ - containerPort: {{ $.Values.envVars.APP_PORT | default 3000 | int }}
54
+ name: http
55
+ protocol: TCP
56
+ {{- if $.Values.monitoring.enabled }}
57
+ - containerPort: {{ $.Values.envVars.METRICS_PORT | default 5565 | int }}
58
+ name: metrics
59
+ protocol: TCP
60
+ {{- end }}
61
+ resources: {{ toYaml .Values.resources | nindent 12 }}
62
+ {{- with $.Values.extraEnv }}
63
+ env:
64
+ {{- toYaml . | nindent 14 }}
65
+ {{- end }}
66
+ envFrom:
67
+ - configMapRef:
68
+ name: {{ include "name" . }}
69
+ {{- if $.Values.infisical.enabled }}
70
+ - secretRef:
71
+ name: {{ include "name" $ }}-secs
72
+ {{- end }}
73
+ {{- with $.Values.extraEnvFrom }}
74
+ {{- toYaml . | nindent 14 }}
75
+ {{- end }}
76
+ nodeSelector: {{ toYaml .Values.nodeSelector | nindent 8 }}
77
+ tolerations: {{ toYaml .Values.tolerations | nindent 8 }}
78
+ volumes:
79
+ - name: config
80
+ configMap:
81
+ name: {{ include "name" . }}
chart/templates/hpa.yaml ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if $.Values.autoscaling.enabled }}
2
+ apiVersion: autoscaling/v2
3
+ kind: HorizontalPodAutoscaler
4
+ metadata:
5
+ labels: {{ include "labels.standard" . | nindent 4 }}
6
+ name: {{ include "name" . }}
7
+ namespace: {{ .Release.Namespace }}
8
+ spec:
9
+ scaleTargetRef:
10
+ apiVersion: apps/v1
11
+ kind: Deployment
12
+ name: {{ include "name" . }}
13
+ minReplicas: {{ $.Values.autoscaling.minReplicas }}
14
+ maxReplicas: {{ $.Values.autoscaling.maxReplicas }}
15
+ metrics:
16
+ {{- if ne "" $.Values.autoscaling.targetMemoryUtilizationPercentage }}
17
+ - type: Resource
18
+ resource:
19
+ name: memory
20
+ target:
21
+ type: Utilization
22
+ averageUtilization: {{ $.Values.autoscaling.targetMemoryUtilizationPercentage | int }}
23
+ {{- end }}
24
+ {{- if ne "" $.Values.autoscaling.targetCPUUtilizationPercentage }}
25
+ - type: Resource
26
+ resource:
27
+ name: cpu
28
+ target:
29
+ type: Utilization
30
+ averageUtilization: {{ $.Values.autoscaling.targetCPUUtilizationPercentage | int }}
31
+ {{- end }}
32
+ behavior:
33
+ scaleDown:
34
+ stabilizationWindowSeconds: 600
35
+ policies:
36
+ - type: Percent
37
+ value: 10
38
+ periodSeconds: 60
39
+ scaleUp:
40
+ stabilizationWindowSeconds: 0
41
+ policies:
42
+ - type: Pods
43
+ value: 1
44
+ periodSeconds: 30
45
+ {{- end }}
chart/templates/infisical.yaml ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if .Values.infisical.enabled }}
2
+ apiVersion: secrets.infisical.com/v1alpha1
3
+ kind: InfisicalSecret
4
+ metadata:
5
+ name: {{ include "name" $ }}-infisical-secret
6
+ namespace: {{ $.Release.Namespace }}
7
+ spec:
8
+ authentication:
9
+ universalAuth:
10
+ credentialsRef:
11
+ secretName: {{ .Values.infisical.operatorSecretName | quote }}
12
+ secretNamespace: {{ .Values.infisical.operatorSecretNamespace | quote }}
13
+ secretsScope:
14
+ envSlug: {{ .Values.infisical.env | quote }}
15
+ projectSlug: {{ .Values.infisical.project | quote }}
16
+ secretsPath: /
17
+ hostAPI: {{ .Values.infisical.url | quote }}
18
+ managedSecretReference:
19
+ creationPolicy: Owner
20
+ secretName: {{ include "name" $ }}-secs
21
+ secretNamespace: {{ .Release.Namespace | quote }}
22
+ secretType: Opaque
23
+ resyncInterval: {{ .Values.infisical.resyncInterval }}
24
+ {{- end }}
chart/templates/ingress-internal.yaml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if $.Values.ingressInternal.enabled }}
2
+ apiVersion: networking.k8s.io/v1
3
+ kind: Ingress
4
+ metadata:
5
+ annotations: {{ toYaml .Values.ingressInternal.annotations | nindent 4 }}
6
+ labels: {{ include "labels.standard" . | nindent 4 }}
7
+ name: {{ include "name" . }}-internal
8
+ namespace: {{ .Release.Namespace }}
9
+ spec:
10
+ {{ if $.Values.ingressInternal.className }}
11
+ ingressClassName: {{ .Values.ingressInternal.className }}
12
+ {{ end }}
13
+ {{- with .Values.ingressInternal.tls }}
14
+ tls:
15
+ - hosts:
16
+ - {{ $.Values.domain | quote }}
17
+ {{- with .secretName }}
18
+ secretName: {{ . }}
19
+ {{- end }}
20
+ {{- end }}
21
+ rules:
22
+ - host: {{ .Values.domain }}
23
+ http:
24
+ paths:
25
+ - backend:
26
+ service:
27
+ name: {{ include "name" . }}
28
+ port:
29
+ name: http
30
+ path: {{ $.Values.ingressInternal.path | default "/" }}
31
+ pathType: Prefix
32
+ {{- end }}
chart/templates/ingress.yaml ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if $.Values.ingress.enabled }}
2
+ apiVersion: networking.k8s.io/v1
3
+ kind: Ingress
4
+ metadata:
5
+ annotations: {{ toYaml .Values.ingress.annotations | nindent 4 }}
6
+ labels: {{ include "labels.standard" . | nindent 4 }}
7
+ name: {{ include "name" . }}
8
+ namespace: {{ .Release.Namespace }}
9
+ spec:
10
+ {{ if $.Values.ingress.className }}
11
+ ingressClassName: {{ .Values.ingress.className }}
12
+ {{ end }}
13
+ {{- with .Values.ingress.tls }}
14
+ tls:
15
+ - hosts:
16
+ - {{ $.Values.domain | quote }}
17
+ {{- with .secretName }}
18
+ secretName: {{ . }}
19
+ {{- end }}
20
+ {{- end }}
21
+ rules:
22
+ - host: {{ .Values.domain }}
23
+ http:
24
+ paths:
25
+ - backend:
26
+ service:
27
+ name: {{ include "name" . }}
28
+ port:
29
+ name: http
30
+ path: {{ $.Values.ingress.path | default "/" }}
31
+ pathType: Prefix
32
+ {{- end }}
chart/templates/network-policy.yaml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if $.Values.networkPolicy.enabled }}
2
+ apiVersion: networking.k8s.io/v1
3
+ kind: NetworkPolicy
4
+ metadata:
5
+ name: {{ include "name" . }}
6
+ namespace: {{ .Release.Namespace }}
7
+ spec:
8
+ egress:
9
+ - ports:
10
+ - port: 53
11
+ protocol: UDP
12
+ to:
13
+ - namespaceSelector:
14
+ matchLabels:
15
+ kubernetes.io/metadata.name: kube-system
16
+ podSelector:
17
+ matchLabels:
18
+ k8s-app: kube-dns
19
+ - to:
20
+ {{- range $ip := .Values.networkPolicy.allowedBlocks }}
21
+ - ipBlock:
22
+ cidr: {{ $ip | quote }}
23
+ {{- end }}
24
+ - to:
25
+ - ipBlock:
26
+ cidr: 0.0.0.0/0
27
+ except:
28
+ - 10.0.0.0/8
29
+ - 172.16.0.0/12
30
+ - 192.168.0.0/16
31
+ - 169.254.169.254/32
32
+ podSelector:
33
+ matchLabels: {{ include "labels.standard" . | nindent 6 }}
34
+ policyTypes:
35
+ - Egress
36
+ {{- end }}
chart/templates/service-account.yaml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if and .Values.serviceAccount.enabled .Values.serviceAccount.create }}
2
+ apiVersion: v1
3
+ kind: ServiceAccount
4
+ automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
5
+ metadata:
6
+ name: "{{ .Values.serviceAccount.name | default (include "name" .) }}"
7
+ namespace: {{ .Release.Namespace }}
8
+ labels: {{ include "labels.standard" . | nindent 4 }}
9
+ {{- with .Values.serviceAccount.annotations }}
10
+ annotations:
11
+ {{- toYaml . | nindent 4 }}
12
+ {{- end }}
13
+ {{- end }}
chart/templates/service-monitor.yaml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {{- if $.Values.monitoring.enabled }}
2
+ apiVersion: monitoring.coreos.com/v1
3
+ kind: ServiceMonitor
4
+ metadata:
5
+ labels: {{ include "labels.standard" . | nindent 4 }}
6
+ name: {{ include "name" . }}
7
+ namespace: {{ .Release.Namespace }}
8
+ spec:
9
+ selector:
10
+ matchLabels: {{ include "labels.standard" . | nindent 6 }}
11
+ endpoints:
12
+ - port: metrics
13
+ path: /metrics
14
+ interval: 15s
15
+ {{- end }}
chart/templates/service.yaml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ apiVersion: v1
2
+ kind: Service
3
+ metadata:
4
+ name: "{{ include "name" . }}"
5
+ annotations: {{ toYaml .Values.service.annotations | nindent 4 }}
6
+ namespace: {{ .Release.Namespace }}
7
+ labels: {{ include "labels.standard" . | nindent 4 }}
8
+ spec:
9
+ ports:
10
+ - name: http
11
+ port: 80
12
+ protocol: TCP
13
+ targetPort: http
14
+ {{- if $.Values.monitoring.enabled }}
15
+ - name: metrics
16
+ port: 5565
17
+ protocol: TCP
18
+ targetPort: metrics
19
+ {{- end }}
20
+ selector: {{ include "labels.standard" . | nindent 4 }}
21
+ type: {{.Values.service.type}}
chart/values.yaml ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ image:
2
+ repository: ghcr.io/huggingface
3
+ name: chat-ui
4
+ tag: 0.0.0-latest
5
+ pullPolicy: IfNotPresent
6
+
7
+ replicas: 3
8
+
9
+ domain: huggingface.co
10
+
11
+ networkPolicy:
12
+ enabled: false
13
+ allowedBlocks: []
14
+
15
+ service:
16
+ type: NodePort
17
+ annotations: { }
18
+
19
+ serviceAccount:
20
+ enabled: false
21
+ create: false
22
+ name: ""
23
+ automountServiceAccountToken: true
24
+ annotations: { }
25
+
26
+ ingress:
27
+ enabled: true
28
+ path: "/"
29
+ annotations: { }
30
+ # className: "nginx"
31
+ tls: { }
32
+ # secretName: XXX
33
+
34
+ ingressInternal:
35
+ enabled: false
36
+ path: "/"
37
+ annotations: { }
38
+ # className: "nginx"
39
+ tls: { }
40
+
41
+ resources:
42
+ requests:
43
+ cpu: 2
44
+ memory: 4Gi
45
+ limits:
46
+ cpu: 2
47
+ memory: 4Gi
48
+ nodeSelector: {}
49
+ tolerations: []
50
+
51
+ envVars: { }
52
+
53
+ infisical:
54
+ enabled: false
55
+ env: ""
56
+ project: "huggingchat-v2-a1"
57
+ url: ""
58
+ resyncInterval: 60
59
+ operatorSecretName: "huggingchat-operator-secrets"
60
+ operatorSecretNamespace: "hub-utils"
61
+
62
+ # Allow to environment injections on top or instead of infisical
63
+ extraEnvFrom: []
64
+ extraEnv: []
65
+
66
+ autoscaling:
67
+ enabled: false
68
+ minReplicas: 1
69
+ maxReplicas: 2
70
+ targetMemoryUtilizationPercentage: ""
71
+ targetCPUUtilizationPercentage: ""
72
+
73
+ monitoring:
74
+ enabled: false
package-lock.json CHANGED
The diff for this file is too large to render. See raw diff
 
package.json CHANGED
@@ -9,21 +9,138 @@
9
  "preview": "vite preview",
10
  "prepare": "svelte-kit sync || echo ''",
11
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
 
 
 
 
 
13
  },
14
  "devDependencies": {
15
- "@fontsource/fira-mono": "^5.0.0",
16
- "@neoconfetti/svelte": "^2.0.0",
17
- "@sveltejs/adapter-auto": "^6.0.0",
 
 
 
 
 
 
18
  "@sveltejs/adapter-node": "^5.2.12",
19
- "@sveltejs/kit": "^2.16.0",
20
- "@sveltejs/vite-plugin-svelte": "^5.0.0",
21
- "svelte": "^5.25.0",
22
- "svelte-check": "^4.0.0",
23
- "typescript": "^5.0.0",
24
- "vite": "^6.2.6"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
  },
26
  "optionalDependencies": {
27
- "@rollup/rollup-linux-x64-musl": "4.44.*"
 
 
 
 
 
 
 
 
 
 
 
28
  }
29
  }
 
9
  "preview": "vite preview",
10
  "prepare": "svelte-kit sync || echo ''",
11
  "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
12
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
13
+ "format": "prettier --write .",
14
+ "test": "vitest",
15
+ "updateLocalEnv": "vite-node --options.transformMode.ssr='/.*/' scripts/updateLocalEnv.ts",
16
+ "populate": "vite-node --options.transformMode.ssr='/.*/' scripts/populate.ts",
17
+ "config": "vite-node --options.transformMode.ssr='/.*/' scripts/config.ts"
18
  },
19
  "devDependencies": {
20
+ "@elysiajs/cors": "^1.3.3",
21
+ "@elysiajs/eden": "^1.3.2",
22
+ "@elysiajs/node": "^1.3.0",
23
+ "@faker-js/faker": "^9.8.0",
24
+ "@fontsource/fira-mono": "^5.2.6",
25
+ "@iconify-json/carbon": "^1.2.10",
26
+ "@iconify-json/eos-icons": "^1.2.2",
27
+ "@neoconfetti/svelte": "^2.2.2",
28
+ "@sveltejs/adapter-auto": "^6.0.1",
29
  "@sveltejs/adapter-node": "^5.2.12",
30
+ "@sveltejs/kit": "^2.22.2",
31
+ "@sveltejs/vite-plugin-svelte": "^6.0.0-next.1",
32
+ "@tailwindcss/typography": "^0.5.16",
33
+ "@types/express": "^5.0.3",
34
+ "@types/fs-extra": "^11.0.4",
35
+ "@types/js-yaml": "^4.0.9",
36
+ "@types/jsdom": "^21.1.7",
37
+ "@types/jsonpath": "^0.2.4",
38
+ "@types/katex": "^0.16.7",
39
+ "@types/mime-types": "^3.0.1",
40
+ "@types/minimist": "^1.2.5",
41
+ "@types/node": "^22.15.33",
42
+ "@types/parquetjs": "^0.10.6",
43
+ "@types/sbd": "^1.0.5",
44
+ "@types/uuid": "^10.0.0",
45
+ "@typescript-eslint/eslint-plugin": "^8.35.0",
46
+ "@typescript-eslint/parser": "^8.35.0",
47
+ "bson-objectid": "^2.0.4",
48
+ "dompurify": "^3.2.6",
49
+ "elysia": "^1.3.5",
50
+ "eslint": "^9.29.0",
51
+ "eslint-config-prettier": "^10.1.5",
52
+ "eslint-plugin-svelte": "^3.10.1",
53
+ "fs-extra": "^11.3.0",
54
+ "husky": "^9.1.7",
55
+ "isomorphic-dompurify": "^2.25.0",
56
+ "js-yaml": "^4.1.0",
57
+ "jsonrepair": "^3.12.0",
58
+ "minimist": "^1.2.8",
59
+ "mongodb-memory-server": "^10.1.4",
60
+ "node-llama-cpp": "^3.10.0",
61
+ "prettier": "^3.6.1",
62
+ "prettier-plugin-svelte": "^3.4.0",
63
+ "prettier-plugin-tailwindcss": "^0.6.13",
64
+ "prom-client": "^15.1.3",
65
+ "sade": "^1.8.1",
66
+ "superjson": "^2.2.2",
67
+
68
+ "svelte": "^5.34.8",
69
+ "svelte-check": "^4.2.2",
70
+ "svelte-gestures": "^5.1.4",
71
+ "ts-node": "^10.9.2",
72
+ "tslib": "^2.8.1",
73
+ "typescript": "^5.8.3",
74
+ "unplugin-icons": "^22.1.0",
75
+ "vite": "^7.0.0",
76
+ "vite-node": "^3.2.4",
77
+ "vitest": "^3.2.4"
78
+ },
79
+ "dependencies": {
80
+ "@aws-sdk/credential-providers": "^3.835.0",
81
+ "@elysiajs/swagger": "^1.3.0",
82
+ "@ghostery/adblocker-playwright": "^2.8.0",
83
+ "@gradio/client": "^1.15.3",
84
+ "@huggingface/hub": "^2.2.0",
85
+ "@huggingface/inference": "^4.0.6",
86
+ "@huggingface/mcp-client": "^0.2.0",
87
+ "@huggingface/tasks": "^0.19.19",
88
+ "@huggingface/transformers": "^3.6.0",
89
+ "@iconify-json/bi": "^1.2.4",
90
+ "@playwright/browser-chromium": "^1.53.1",
91
+ "@resvg/resvg-js": "^2.6.2",
92
+ "autoprefixer": "^10.4.21",
93
+ "aws-sigv4-fetch": "^4.4.1",
94
+ "aws4": "^1.13.2",
95
+ "date-fns": "^4.1.0",
96
+ "dotenv": "^16.6.0",
97
+ "express": "^5.1.0",
98
+ "file-type": "^21.0.0",
99
+ "google-auth-library": "^10.1.0",
100
+ "handlebars": "^4.7.8",
101
+ "highlight.js": "^11.11.1",
102
+ "image-size": "^2.0.2",
103
+ "ip-address": "^10.0.1",
104
+ "jose": "^6.0.11",
105
+ "jsdom": "^26.1.0",
106
+ "json5": "^2.2.3",
107
+ "jsonpath": "^1.1.1",
108
+ "katex": "^0.16.22",
109
+ "lint-staged": "^16.1.2",
110
+ "marked": "^15.0.12",
111
+ "mongodb": "^6.17.0",
112
+ "nanoid": "^5.1.5",
113
+ "natural": "^8.1.0",
114
+ "openid-client": "^6.6.1",
115
+ "parquetjs": "^0.11.2",
116
+ "pino": "^9.7.0",
117
+ "pino-pretty": "^13.0.0",
118
+ "playwright": "^1.53.1",
119
+ "postcss": "^8.5.6",
120
+ "saslprep": "^1.0.3",
121
+ "satori": "^0.15.2",
122
+ "satori-html": "^0.3.2",
123
+ "sbd": "^1.0.19",
124
+ "serpapi": "^2.1.0",
125
+ "sharp": "^0.34.2",
126
+ "tailwind-scrollbar": "^4.0.2",
127
+ "tailwindcss": "^4.1.11",
128
+ "uuid": "^11.1.0",
129
+ "vitest-browser-svelte": "^1.0.0",
130
+ "zod": "^3.25.67"
131
  },
132
  "optionalDependencies": {
133
+ "@rollup/rollup-linux-x64-musl": "4.44.*",
134
+ "@anthropic-ai/sdk": "^0.32.1",
135
+ "@anthropic-ai/vertex-sdk": "^0.4.1",
136
+ "@aws-sdk/client-bedrock-runtime": "^3.631.0",
137
+ "@google-cloud/vertexai": "^1.1.0",
138
+ "@google/generative-ai": "^0.24.0",
139
+ "aws4fetch": "^1.0.17",
140
+ "cohere-ai": "^7.9.0",
141
+ "openai": "^4.44.0"
142
+ },
143
+ "overrides": {
144
+ "@reflink/reflink": "file:stub/@reflink/reflink"
145
  }
146
  }
postcss.config.js ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ export default {
2
+ plugins: {
3
+ tailwindcss: {},
4
+ autoprefixer: {},
5
+ },
6
+ };
scripts/config.ts ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sade from "sade";
2
+
3
+ // @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
4
+ import { config, ready } from "$lib/server/config";
5
+
6
+ const prog = sade("config");
7
+ await ready;
8
+ prog
9
+ .command("clear")
10
+ .describe("Clear all config keys")
11
+ .action(async () => {
12
+ console.log("Clearing config...");
13
+ await clear();
14
+ });
15
+
16
+ prog
17
+ .command("add <key> <value>")
18
+ .describe("Add a new config key")
19
+ .action(async (key: string, value: string) => {
20
+ await add(key, value);
21
+ });
22
+
23
+ prog
24
+ .command("remove <key>")
25
+ .describe("Remove a config key")
26
+ .action(async (key: string) => {
27
+ console.log(`Removing ${key}`);
28
+ await remove(key);
29
+ process.exit(0);
30
+ });
31
+
32
+ prog
33
+ .command("help")
34
+ .describe("Show help information")
35
+ .action(() => {
36
+ prog.help();
37
+ process.exit(0);
38
+ });
39
+
40
+ async function clear() {
41
+ await config.clear();
42
+ process.exit(0);
43
+ }
44
+
45
+ async function add(key: string, value: string) {
46
+ if (!key || !value) {
47
+ console.error("Key and value are required");
48
+ process.exit(1);
49
+ }
50
+ await config.set(key as keyof typeof config.keysFromEnv, value);
51
+ process.exit(0);
52
+ }
53
+
54
+ async function remove(key: string) {
55
+ if (!key) {
56
+ console.error("Key is required");
57
+ process.exit(1);
58
+ }
59
+ await config.delete(key as keyof typeof config.keysFromEnv);
60
+ process.exit(0);
61
+ }
62
+
63
+ // Parse arguments and handle help automatically
64
+ prog.parse(process.argv);
scripts/populate.ts ADDED
@@ -0,0 +1,391 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import readline from "readline";
2
+ import minimist from "minimist";
3
+
4
+ // @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
5
+ import { env } from "$env/dynamic/private";
6
+
7
+ import { faker } from "@faker-js/faker";
8
+ import { ObjectId } from "mongodb";
9
+
10
+ // @ts-expect-error: vite-node makes the var available but the typescript compiler doesn't see them
11
+ import { ready } from "$lib/server/config";
12
+ import { collections } from "$lib/server/database.ts";
13
+ import { models } from "../src/lib/server/models.ts";
14
+ import type { User } from "../src/lib/types/User";
15
+ import type { Assistant } from "../src/lib/types/Assistant";
16
+ import type { Conversation } from "../src/lib/types/Conversation";
17
+ import type { Settings } from "../src/lib/types/Settings";
18
+ import type { CommunityToolDB, ToolLogoColor, ToolLogoIcon } from "../src/lib/types/Tool";
19
+ import { defaultEmbeddingModel } from "../src/lib/server/embeddingModels.ts";
20
+ import { Message } from "../src/lib/types/Message.ts";
21
+
22
+ import { addChildren } from "../src/lib/utils/tree/addChildren.ts";
23
+ import { generateSearchTokens } from "../src/lib/utils/searchTokens.ts";
24
+ import { ReviewStatus } from "../src/lib/types/Review.ts";
25
+ import fs from "fs";
26
+ import path from "path";
27
+ import { MessageUpdateType } from "../src/lib/types/MessageUpdate.ts";
28
+ import { MessageReasoningUpdateType } from "../src/lib/types/MessageUpdate.ts";
29
+
30
+ const rl = readline.createInterface({
31
+ input: process.stdin,
32
+ output: process.stdout,
33
+ });
34
+
35
+ await ready;
36
+
37
+ rl.on("close", function () {
38
+ process.exit(0);
39
+ });
40
+
41
+ const samples = fs.readFileSync(path.join(__dirname, "samples.txt"), "utf8").split("\n---\n");
42
+
43
+ const possibleFlags = ["reset", "all", "users", "settings", "assistants", "conversations", "tools"];
44
+ const argv = minimist(process.argv.slice(2));
45
+ const flags = argv["_"].filter((flag) => possibleFlags.includes(flag));
46
+
47
+ async function generateMessages(preprompt?: string): Promise<Message[]> {
48
+ const isLinear = faker.datatype.boolean(0.5);
49
+ const isInterrupted = faker.datatype.boolean(0.05);
50
+
51
+ const messages: Message[] = [];
52
+
53
+ messages.push({
54
+ id: crypto.randomUUID(),
55
+ from: "system",
56
+ content: preprompt ?? "",
57
+ createdAt: faker.date.recent({ days: 30 }),
58
+ updatedAt: faker.date.recent({ days: 30 }),
59
+ });
60
+
61
+ let isUser = true;
62
+ let lastId = messages[0].id;
63
+ if (isLinear) {
64
+ const convLength = faker.number.int({ min: 1, max: 25 }) * 2; // must always be even
65
+
66
+ for (let i = 0; i < convLength; i++) {
67
+ const hasReasoning = Math.random() < 0.2;
68
+ lastId = addChildren(
69
+ {
70
+ messages,
71
+ rootMessageId: messages[0].id,
72
+ },
73
+ {
74
+ from: isUser ? "user" : "assistant",
75
+ content:
76
+ faker.lorem.sentence({
77
+ min: 10,
78
+ max: isUser ? 50 : 200,
79
+ }) +
80
+ (!isUser && Math.random() < 0.1
81
+ ? "\n```\n" + faker.helpers.arrayElement(samples) + "\n```\n"
82
+ : ""),
83
+ createdAt: faker.date.recent({ days: 30 }),
84
+ updatedAt: faker.date.recent({ days: 30 }),
85
+ reasoning: hasReasoning ? faker.lorem.paragraphs(2) : undefined,
86
+ updates: hasReasoning
87
+ ? [
88
+ {
89
+ type: MessageUpdateType.Reasoning,
90
+ subtype: MessageReasoningUpdateType.Status,
91
+ uuid: crypto.randomUUID(),
92
+ status: "thinking",
93
+ },
94
+ ]
95
+ : [],
96
+ interrupted: !isUser && i === convLength - 1 && isInterrupted,
97
+ },
98
+ lastId
99
+ );
100
+ isUser = !isUser;
101
+ }
102
+ } else {
103
+ const convLength = faker.number.int({ min: 2, max: 200 });
104
+
105
+ for (let i = 0; i < convLength; i++) {
106
+ const hasReasoning = Math.random() < 0.2;
107
+ addChildren(
108
+ {
109
+ messages,
110
+ rootMessageId: messages[0].id,
111
+ },
112
+ {
113
+ from: isUser ? "user" : "assistant",
114
+ content:
115
+ faker.lorem.sentence({
116
+ min: 10,
117
+ max: isUser ? 50 : 200,
118
+ }) +
119
+ (!isUser && Math.random() < 0.1
120
+ ? "\n```\n" + faker.helpers.arrayElement(samples) + "\n```\n"
121
+ : ""),
122
+ reasoning: hasReasoning ? faker.lorem.paragraphs(2) : undefined,
123
+ updates: hasReasoning
124
+ ? [
125
+ {
126
+ type: MessageUpdateType.Reasoning,
127
+ subtype: MessageReasoningUpdateType.Status,
128
+ uuid: crypto.randomUUID(),
129
+ status: "thinking",
130
+ },
131
+ ]
132
+ : [],
133
+ createdAt: faker.date.recent({ days: 30 }),
134
+ updatedAt: faker.date.recent({ days: 30 }),
135
+ interrupted: !isUser && i === convLength - 1 && isInterrupted,
136
+ },
137
+ faker.helpers.arrayElement([
138
+ messages[0].id,
139
+ ...messages.filter((m) => m.from === (isUser ? "assistant" : "user")).map((m) => m.id),
140
+ ])
141
+ );
142
+
143
+ isUser = !isUser;
144
+ }
145
+ }
146
+ return messages;
147
+ }
148
+
149
+ async function seed() {
150
+ console.log("Seeding...");
151
+ const modelIds = models.map((model) => model.id);
152
+
153
+ if (flags.includes("reset")) {
154
+ console.log("Starting reset of DB");
155
+ await collections.users.deleteMany({});
156
+ await collections.settings.deleteMany({});
157
+ await collections.assistants.deleteMany({});
158
+ await collections.conversations.deleteMany({});
159
+ await collections.tools.deleteMany({});
160
+ await collections.migrationResults.deleteMany({});
161
+ await collections.semaphores.deleteMany({});
162
+ console.log("Reset done");
163
+ }
164
+
165
+ if (flags.includes("users") || flags.includes("all")) {
166
+ console.log("Creating 100 new users");
167
+ const newUsers: User[] = Array.from({ length: 100 }, () => ({
168
+ _id: new ObjectId(),
169
+ createdAt: faker.date.recent({ days: 30 }),
170
+ updatedAt: faker.date.recent({ days: 30 }),
171
+ username: faker.internet.userName(),
172
+ name: faker.person.fullName(),
173
+ hfUserId: faker.string.alphanumeric(24),
174
+ avatarUrl: faker.image.avatar(),
175
+ }));
176
+
177
+ await collections.users.insertMany(newUsers);
178
+ console.log("Done creating users.");
179
+ }
180
+
181
+ const users = await collections.users.find().toArray();
182
+ if (flags.includes("settings") || flags.includes("all")) {
183
+ console.log("Updating settings for all users");
184
+ users.forEach(async (user) => {
185
+ const settings: Settings = {
186
+ userId: user._id,
187
+ shareConversationsWithModelAuthors: faker.datatype.boolean(0.25),
188
+ hideEmojiOnSidebar: faker.datatype.boolean(0.25),
189
+ ethicsModalAcceptedAt: faker.date.recent({ days: 30 }),
190
+ activeModel: faker.helpers.arrayElement(modelIds),
191
+ createdAt: faker.date.recent({ days: 30 }),
192
+ updatedAt: faker.date.recent({ days: 30 }),
193
+ disableStream: faker.datatype.boolean(0.25),
194
+ directPaste: faker.datatype.boolean(0.25),
195
+ customPrompts: {},
196
+ assistants: [],
197
+ };
198
+ await collections.settings.updateOne(
199
+ { userId: user._id },
200
+ { $set: { ...settings } },
201
+ { upsert: true }
202
+ );
203
+ });
204
+ console.log("Done updating settings.");
205
+ }
206
+
207
+ if (flags.includes("assistants") || flags.includes("all")) {
208
+ console.log("Creating assistants for all users");
209
+ await Promise.all(
210
+ users.map(async (user) => {
211
+ const name = faker.animal.insect();
212
+ const assistants = faker.helpers.multiple<Assistant>(
213
+ () => ({
214
+ _id: new ObjectId(),
215
+ name,
216
+ createdById: user._id,
217
+ createdByName: user.username,
218
+ createdAt: faker.date.recent({ days: 30 }),
219
+ updatedAt: faker.date.recent({ days: 30 }),
220
+ userCount: faker.number.int({ min: 1, max: 100000 }),
221
+ review: faker.helpers.enumValue(ReviewStatus),
222
+ modelId: faker.helpers.arrayElement(modelIds),
223
+ description: faker.lorem.sentence(),
224
+ preprompt: faker.hacker.phrase(),
225
+ exampleInputs: faker.helpers.multiple(() => faker.lorem.sentence(), {
226
+ count: faker.number.int({ min: 0, max: 4 }),
227
+ }),
228
+ searchTokens: generateSearchTokens(name),
229
+ last24HoursCount: faker.number.int({ min: 0, max: 1000 }),
230
+ }),
231
+ { count: faker.number.int({ min: 3, max: 10 }) }
232
+ );
233
+ await collections.assistants.insertMany(assistants);
234
+ await collections.settings.updateOne(
235
+ { userId: user._id },
236
+ { $set: { assistants: assistants.map((a) => a._id.toString()) } },
237
+ { upsert: true }
238
+ );
239
+ })
240
+ );
241
+ console.log("Done creating assistants.");
242
+ }
243
+
244
+ if (flags.includes("conversations") || flags.includes("all")) {
245
+ console.log("Creating conversations for all users");
246
+ await Promise.all(
247
+ users.map(async (user) => {
248
+ const conversations = faker.helpers.multiple(
249
+ async () => {
250
+ const settings = await collections.settings.findOne<Settings>({ userId: user._id });
251
+
252
+ const assistantId =
253
+ settings?.assistants && settings.assistants.length > 0 && faker.datatype.boolean(0.1)
254
+ ? faker.helpers.arrayElement<ObjectId>(settings.assistants)
255
+ : undefined;
256
+
257
+ const preprompt =
258
+ (assistantId
259
+ ? await collections.assistants
260
+ .findOne({ _id: assistantId })
261
+ .then((assistant: Assistant) => assistant?.preprompt ?? "")
262
+ : faker.helpers.maybe(() => faker.hacker.phrase(), { probability: 0.5 })) ?? "";
263
+
264
+ const messages = await generateMessages(preprompt);
265
+
266
+ const conv = {
267
+ _id: new ObjectId(),
268
+ userId: user._id,
269
+ assistantId,
270
+ preprompt,
271
+ createdAt: faker.date.recent({ days: 145 }),
272
+ updatedAt: faker.date.recent({ days: 145 }),
273
+ model: faker.helpers.arrayElement(modelIds),
274
+ title: faker.internet.emoji() + " " + faker.hacker.phrase(),
275
+ embeddingModel: defaultEmbeddingModel.id,
276
+ messages,
277
+ rootMessageId: messages[0].id,
278
+ } satisfies Conversation;
279
+
280
+ return conv;
281
+ },
282
+ { count: faker.number.int({ min: 10, max: 200 }) }
283
+ );
284
+
285
+ await collections.conversations.insertMany(await Promise.all(conversations));
286
+ })
287
+ );
288
+ console.log("Done creating conversations.");
289
+ }
290
+
291
+ // generate Community Tools
292
+ if (flags.includes("tools") || flags.includes("all")) {
293
+ const tools = await Promise.all(
294
+ faker.helpers.multiple(
295
+ () => {
296
+ const _id = new ObjectId();
297
+ const displayName = faker.company.catchPhrase();
298
+ const description = faker.company.catchPhrase();
299
+ const color = faker.helpers.arrayElement([
300
+ "purple",
301
+ "blue",
302
+ "green",
303
+ "yellow",
304
+ "red",
305
+ ]) satisfies ToolLogoColor;
306
+ const icon = faker.helpers.arrayElement([
307
+ "wikis",
308
+ "tools",
309
+ "camera",
310
+ "code",
311
+ "email",
312
+ "cloud",
313
+ "terminal",
314
+ "game",
315
+ "chat",
316
+ "speaker",
317
+ "video",
318
+ ]) satisfies ToolLogoIcon;
319
+ const baseUrl = faker.helpers.arrayElement([
320
+ "stabilityai/stable-diffusion-3-medium",
321
+ "multimodalart/cosxl",
322
+ "gokaygokay/SD3-Long-Captioner",
323
+ "xichenhku/MimicBrush",
324
+ ]);
325
+
326
+ // keep empty for populate for now
327
+
328
+ const user: User = faker.helpers.arrayElement(users);
329
+ const createdById = user._id;
330
+ const createdByName = user.username ?? user.name;
331
+
332
+ return {
333
+ type: "community" as const,
334
+ _id,
335
+ createdById,
336
+ createdByName,
337
+ displayName,
338
+ name: displayName.toLowerCase().replace(" ", "_"),
339
+ endpoint: "/test",
340
+ description,
341
+ color,
342
+ icon,
343
+ baseUrl,
344
+ inputs: [],
345
+ outputPath: null,
346
+ outputType: "str" as const,
347
+ showOutput: false,
348
+ useCount: faker.number.int({ min: 0, max: 100000 }),
349
+ last24HoursUseCount: faker.number.int({ min: 0, max: 1000 }),
350
+ createdAt: faker.date.recent({ days: 30 }),
351
+ updatedAt: faker.date.recent({ days: 30 }),
352
+ searchTokens: generateSearchTokens(displayName),
353
+ review: faker.helpers.enumValue(ReviewStatus),
354
+ outputComponent: null,
355
+ outputComponentIdx: null,
356
+ };
357
+ },
358
+ { count: faker.number.int({ min: 10, max: 200 }) }
359
+ )
360
+ );
361
+
362
+ await collections.tools.insertMany(tools satisfies CommunityToolDB[]);
363
+ }
364
+ }
365
+
366
+ // run seed
367
+ (async () => {
368
+ try {
369
+ rl.question(
370
+ "You're about to run a seeding script on the following MONGODB_URL: \x1b[31m" +
371
+ env.MONGODB_URL +
372
+ "\x1b[0m\n\n With the following flags: \x1b[31m" +
373
+ flags.join("\x1b[0m , \x1b[31m") +
374
+ "\x1b[0m\n \n\n Are you sure you want to continue? (yes/no): ",
375
+ async (confirm) => {
376
+ if (confirm !== "yes") {
377
+ console.log("Not 'yes', exiting.");
378
+ rl.close();
379
+ process.exit(0);
380
+ }
381
+ console.log("Starting seeding...");
382
+ await seed();
383
+ console.log("Seeding done.");
384
+ rl.close();
385
+ }
386
+ );
387
+ } catch (e) {
388
+ console.error(e);
389
+ process.exit(1);
390
+ }
391
+ })();
scripts/samples.txt ADDED
@@ -0,0 +1,194 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Observable, of, from, interval, throwError } from 'rxjs';
2
+ import { map, filter, catchError, switchMap, take, tap } from 'rxjs/operators';
3
+
4
+ // Mock function to fetch stock prices (simulates API call)
5
+ const fetchStockPrice = (ticker: string): Observable<number> => {
6
+ return new Observable<number>((observer) => {
7
+ const intervalId = setInterval(() => {
8
+ if (Math.random() < 0.1) { // Simulating an error 10% of the time
9
+ observer.error(`Error fetching stock price for ${ticker}`);
10
+ } else {
11
+ const price = parseFloat((Math.random() * 1000).toFixed(2));
12
+ observer.next(price);
13
+ }
14
+ }, 1000);
15
+
16
+ return () => {
17
+ clearInterval(intervalId);
18
+ console.log(`Stopped fetching prices for ${ticker}`);
19
+ };
20
+ });
21
+ };
22
+
23
+ // Example usage: Tracking stock price updates
24
+ const stockTicker = 'AAPL';
25
+ const stockPrice$ = fetchStockPrice(stockTicker).pipe(
26
+ map(price => ({ ticker: stockTicker, price })), // Transform data
27
+ filter(data => data.price > 500), // Only keep prices above 500
28
+ tap(data => console.log(`Price update:`, data)), // Side effect: Logging
29
+ catchError(err => {
30
+ console.error(err);
31
+ return of({ ticker: stockTicker, price: null }); // Fallback observable
32
+ })
33
+ );
34
+
35
+ // Subscribe to the stock price updates
36
+ const subscription = stockPrice$.subscribe({
37
+ next: data => console.log(`Subscriber received:`, data),
38
+ error: err => console.error(`Subscription error:`, err),
39
+ complete: () => console.log('Stream complete'),
40
+ });
41
+
42
+ // Automatically unsubscribe after 10 seconds
43
+ setTimeout(() => {
44
+ subscription.unsubscribe();
45
+ console.log('Unsubscribed from stock price updates.');
46
+ }, 10000);
47
+ ---
48
+ class EnforceAttrsMeta(type):
49
+ """
50
+ Metaclass that enforces the presence of specific attributes in a class
51
+ and automatically decorates methods with a logging wrapper.
52
+ """
53
+
54
+ required_attributes = ['name', 'version']
55
+
56
+ def __new__(cls, name, bases, class_dict):
57
+ """
58
+ Create a new class with enforced attributes and method logging.
59
+
60
+ :param name: Name of the class being created.
61
+ :param bases: Tuple of base classes.
62
+ :param class_dict: Dictionary of attributes and methods of the class.
63
+ :return: Newly created class object.
64
+ """
65
+ # Ensure required attributes exist
66
+ for attr in cls.required_attributes:
67
+ if attr not in class_dict:
68
+ raise TypeError(f"Class '{name}' is missing required attribute '{attr}'")
69
+
70
+ # Wrap all methods in a logging decorator
71
+ for key, value in class_dict.items():
72
+ if callable(value): # Check if it's a method
73
+ class_dict[key] = cls.log_calls(value)
74
+
75
+ return super().__new__(cls, name, bases, class_dict)
76
+
77
+ @staticmethod
78
+ def log_calls(func):
79
+ """
80
+ Decorator that logs method calls and arguments.
81
+
82
+ :param func: Function to be wrapped.
83
+ :return: Wrapped function with logging.
84
+ """
85
+ def wrapper(*args, **kwargs):
86
+ print(f"Calling {func.__name__} with args={args} kwargs={kwargs}")
87
+ result = func(*args, **kwargs)
88
+ print(f"{func.__name__} returned {result}")
89
+ return result
90
+ return wrapper
91
+
92
+
93
+ class PluginBase(metaclass=EnforceAttrsMeta):
94
+ """
95
+ Base class for plugins that enforces required attributes and logging.
96
+ """
97
+ name = "BasePlugin"
98
+ version = "1.0"
99
+
100
+ def run(self, data):
101
+ """
102
+ Process the input data.
103
+
104
+ :param data: The data to be processed.
105
+ :return: Processed result.
106
+ """
107
+ return f"Processed {data}"
108
+
109
+
110
+ class CustomPlugin(PluginBase):
111
+ """
112
+ Custom plugin that extends PluginBase and adheres to enforced rules.
113
+ """
114
+ name = "CustomPlugin"
115
+ version = "2.0"
116
+
117
+ def run(self, data):
118
+ """
119
+ Custom processing logic.
120
+
121
+ :param data: The data to process.
122
+ :return: Modified data.
123
+ """
124
+ return f"Custom processing of {data}"
125
+
126
+
127
+ # Uncommenting the following class definition will raise a TypeError
128
+ # because 'version' attribute is missing.
129
+ # class InvalidPlugin(PluginBase):
130
+ # name = "InvalidPlugin"
131
+
132
+
133
+ if __name__ == "__main__":
134
+ # Instantiate and use the plugin
135
+ plugin = CustomPlugin()
136
+ print(plugin.run("example data"))
137
+ ---
138
+ <!DOCTYPE html>
139
+ <html lang="en">
140
+ <head>
141
+ <meta charset="UTF-8">
142
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
143
+ <title>Click the Box Game</title>
144
+ <style>
145
+ body {
146
+ text-align: center;
147
+ font-family: Arial, sans-serif;
148
+ }
149
+ #game-container {
150
+ position: relative;
151
+ width: 300px;
152
+ height: 300px;
153
+ margin: 20px auto;
154
+ border: 2px solid black;
155
+ overflow: hidden;
156
+ }
157
+ #target {
158
+ width: 50px;
159
+ height: 50px;
160
+ background-color: red;
161
+ position: absolute;
162
+ cursor: pointer;
163
+ }
164
+ </style>
165
+ </head>
166
+ <body>
167
+ <h1>Click the Box!</h1>
168
+ <p>Score: <span id="score">0</span></p>
169
+ <div id="game-container">
170
+ <div id="target"></div>
171
+ </div>
172
+ <script>
173
+ let score = 0;
174
+ const target = document.getElementById("target");
175
+ const scoreDisplay = document.getElementById("score");
176
+ const container = document.getElementById("game-container");
177
+
178
+ function moveTarget() {
179
+ const maxX = container.clientWidth - target.clientWidth;
180
+ const maxY = container.clientHeight - target.clientHeight;
181
+ target.style.left = Math.random() * maxX + "px";
182
+ target.style.top = Math.random() * maxY + "px";
183
+ }
184
+
185
+ target.addEventListener("click", function() {
186
+ score++;
187
+ scoreDisplay.textContent = score;
188
+ moveTarget();
189
+ });
190
+
191
+ moveTarget();
192
+ </script>
193
+ </body>
194
+ </html>
scripts/setups/vitest-setup-client.ts ADDED
File without changes
scripts/setups/vitest-setup-server.ts ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { vi, afterAll } from "vitest";
2
+ import dotenv from "dotenv";
3
+ import { resolve } from "path";
4
+ import fs from "fs";
5
+ import { MongoMemoryServer } from "mongodb-memory-server";
6
+
7
+ let mongoServer: MongoMemoryServer;
8
+ // Load the .env file
9
+ const envPath = resolve(__dirname, "../../.env");
10
+ dotenv.config({ path: envPath });
11
+
12
+ // Read the .env file content
13
+ const envContent = fs.readFileSync(envPath, "utf-8");
14
+
15
+ // Parse the .env content
16
+ const envVars = dotenv.parse(envContent);
17
+
18
+ // Separate public and private variables
19
+ const publicEnv = {};
20
+ const privateEnv = {};
21
+
22
+ for (const [key, value] of Object.entries(envVars)) {
23
+ if (key.startsWith("PUBLIC_")) {
24
+ publicEnv[key] = value;
25
+ } else {
26
+ privateEnv[key] = value;
27
+ }
28
+ }
29
+
30
+ vi.mock("$env/dynamic/public", () => ({
31
+ env: publicEnv,
32
+ }));
33
+
34
+ vi.mock("$env/dynamic/private", async () => {
35
+ mongoServer = await MongoMemoryServer.create();
36
+
37
+ return {
38
+ env: {
39
+ ...privateEnv,
40
+ MONGODB_URL: mongoServer.getUri(),
41
+ },
42
+ };
43
+ });
44
+
45
+ afterAll(async () => {
46
+ if (mongoServer) {
47
+ await mongoServer.stop();
48
+ }
49
+ });
scripts/updateLocalEnv.ts ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import fs from "fs";
2
+ import yaml from "js-yaml";
3
+
4
+ const file = fs.readFileSync("chart/env/prod.yaml", "utf8");
5
+
6
+ // have to do a weird stringify/parse because of some node error
7
+ const prod = JSON.parse(JSON.stringify(yaml.load(file)));
8
+ const vars = prod.envVars as Record<string, string>;
9
+
10
+ let PUBLIC_CONFIG = "";
11
+
12
+ Object.entries(vars)
13
+ // filter keys used in prod with the proxy
14
+ .filter(
15
+ ([key]) =>
16
+ ![
17
+ "XFF_DEPTH",
18
+ "ADDRESS_HEADER",
19
+ "APP_BASE",
20
+ "PUBLIC_ORIGIN",
21
+ "PUBLIC_SHARE_PREFIX",
22
+ "ADMIN_CLI_LOGIN",
23
+ ].includes(key)
24
+ )
25
+ .forEach(([key, value]) => {
26
+ PUBLIC_CONFIG += `${key}=\`${value}\`\n`;
27
+ });
28
+
29
+ const SECRET_CONFIG =
30
+ (fs.existsSync(".env.SECRET_CONFIG")
31
+ ? fs.readFileSync(".env.SECRET_CONFIG", "utf8")
32
+ : process.env.SECRET_CONFIG) ?? "";
33
+
34
+ // Prepend the content of the env variable SECRET_CONFIG
35
+ let full_config = `${PUBLIC_CONFIG}\n${SECRET_CONFIG}`;
36
+
37
+ // replace the internal proxy url with the public endpoint
38
+ full_config = full_config.replaceAll(
39
+ "https://internal.api-inference.huggingface.co",
40
+ "https://router.huggingface.co/hf-inference"
41
+ );
42
+
43
+ full_config = full_config.replaceAll("COOKIE_SECURE=`true`", "COOKIE_SECURE=`false`");
44
+ full_config = full_config.replaceAll("LOG_LEVEL=`debug`", "LOG_LEVEL=`info`");
45
+ full_config = full_config.replaceAll("NODE_ENV=`prod`", "NODE_ENV=`development`");
46
+
47
+ // Write full_config to .env.local
48
+ fs.writeFileSync(".env.local", full_config);
static/chatui/apple-touch-icon.png ADDED

Git LFS Details

  • SHA256: 38ce30784eebfed8f3ddb6759cb95685a8c2b00f3a93b2d13d8358e7c5e3d0e4
  • Pointer size: 129 Bytes
  • Size of remote file: 1.61 kB
static/chatui/favicon.ico ADDED
static/chatui/favicon.svg ADDED
static/chatui/icon-128x128.png ADDED

Git LFS Details

  • SHA256: dc1cebb3ff19349040c8b41b81a52817a749cd7631e5409cbf7db0c680c64a18
  • Pointer size: 129 Bytes
  • Size of remote file: 1.18 kB
static/chatui/icon-256x256.png ADDED

Git LFS Details

  • SHA256: 8bc6dcb0af8a7acf4e9135e632589f86dfc1b4cff3105a352fc58dddf5575589
  • Pointer size: 129 Bytes
  • Size of remote file: 2.32 kB
static/chatui/icon-512x512.png ADDED

Git LFS Details

  • SHA256: ba23f927ad462e43bd6b0c3a20c6acafb8b333bb10cca7dfdd21bcdc364addd2
  • Pointer size: 129 Bytes
  • Size of remote file: 4.81 kB
static/chatui/icon.svg ADDED
static/chatui/logo.svg ADDED
static/chatui/manifest.json ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "background_color": "#ffffff",
3
+ "name": "Chat UI",
4
+ "short_name": "Chat UI",
5
+ "display": "standalone",
6
+ "start_url": "/",
7
+ "icons": [
8
+ {
9
+ "src": "/chatui/icon-128x128.png",
10
+ "sizes": "128x128",
11
+ "type": "image/png"
12
+ },
13
+ {
14
+ "src": "/chatui/icon-256x256.png",
15
+ "sizes": "256x256",
16
+ "type": "image/png"
17
+ },
18
+ {
19
+ "src": "/chatui/icon-512x512.png",
20
+ "sizes": "512x512",
21
+ "type": "image/png"
22
+ }
23
+ ]
24
+ }
static/huggingchat/apple-touch-icon.png ADDED

Git LFS Details

  • SHA256: 08a796f8cd63c025022f7c05c8b8494e73c2b1f5069b50cc1f3120d6a960448d
  • Pointer size: 129 Bytes
  • Size of remote file: 2.7 kB
static/huggingchat/assistants-thumbnail.png ADDED

Git LFS Details

  • SHA256: eac57333013a9eba9db97d68588d37cdb3b1d9658fed41e3e69eb98d194d34e4
  • Pointer size: 131 Bytes
  • Size of remote file: 211 kB
static/huggingchat/favicon.ico ADDED
static/huggingchat/favicon.svg ADDED
static/huggingchat/icon-128x128.png ADDED

Git LFS Details

  • SHA256: b29470941a3fa93e445cba9431fb216a3310561f2a6e6ffb13f9c4f2635c08ef
  • Pointer size: 129 Bytes
  • Size of remote file: 1.99 kB
static/huggingchat/icon-144x144.png ADDED

Git LFS Details

  • SHA256: dac31b23945b49e5b6b2c9c8072ae214eafea69b04278989bfe5b59346d688fa
  • Pointer size: 129 Bytes
  • Size of remote file: 4.45 kB
static/huggingchat/icon-192x192.png ADDED

Git LFS Details

  • SHA256: 281dc76253360885f124ba19670f6410b0283eaf5e60503d2f2835f797eeff84
  • Pointer size: 129 Bytes
  • Size of remote file: 5.89 kB
static/huggingchat/icon-256x256.png ADDED

Git LFS Details

  • SHA256: 21c1b7d723da49ec890adda367604cdd5adbea251d526049423874c9603f862f
  • Pointer size: 129 Bytes
  • Size of remote file: 3.77 kB
static/huggingchat/icon-36x36.png ADDED

Git LFS Details

  • SHA256: da0514109a0ef5b919a8fcf94c1e3f7c4cf08e42e44e259bb89dd65441051f75
  • Pointer size: 129 Bytes
  • Size of remote file: 1.15 kB
static/huggingchat/icon-48x48.png ADDED

Git LFS Details

  • SHA256: 1634899dee70e0591f8780071c938909ce30f5ce50fcff68d14cd22a7c5dcc8d
  • Pointer size: 129 Bytes
  • Size of remote file: 1.41 kB
static/huggingchat/icon-512x512.png ADDED

Git LFS Details

  • SHA256: cd8cb0d6ea945d929e559377266951b34605b1ac0c80d56a036b3138195aa7a1
  • Pointer size: 129 Bytes
  • Size of remote file: 7.72 kB
static/huggingchat/icon-72x72.png ADDED

Git LFS Details

  • SHA256: 162723246818f482dd19d600b84f415284674d0d40c2de260f5841bed22852e8
  • Pointer size: 129 Bytes
  • Size of remote file: 2.28 kB