SamuelLance73 commited on
Commit
5bfe384
·
verified ·
1 Parent(s): 2664e37

Automated deployment update from ML build

Browse files
Files changed (3) hide show
  1. app.py +9 -5
  2. config/loading.html +350 -0
  3. services/nginx_service.py +40 -12
app.py CHANGED
@@ -48,11 +48,15 @@ def fake_model(text):
48
  B=_LOG_CMDS.get(A)
49
  if B:return _read_log(*B)
50
  return f"Model processed: {text}"
51
- import json
52
  def is_open_webui_enabled():
53
- try:
54
- with open('/home/user/config/enabled_services.json','r')as A:B=json.load(A)
55
- C=B.get('services')or[];return any(A.strip().lower()=='open_webui'for A in C if A)
56
- except Exception:return False
 
 
 
 
57
  root_path='/gradio'if is_open_webui_enabled()else None
58
  gr.Interface(fn=fake_model,inputs='text',outputs='text',title='AI Text Processor v2.1').launch(server_name='127.0.0.1',server_port=7861,root_path=root_path)
 
48
  B=_LOG_CMDS.get(A)
49
  if B:return _read_log(*B)
50
  return f"Model processed: {text}"
51
+ import json,os
52
  def is_open_webui_enabled():
53
+ B=['/home/user/config/enabled_services.json','config/enabled_services.json','main/config/enabled_services.json']
54
+ for A in B:
55
+ try:
56
+ if os.path.exists(A):
57
+ with open(A,'r')as C:D=json.load(C)
58
+ E=D.get('services')or[];return any(A.strip().lower()=='open_webui'for A in E if A)
59
+ except Exception:pass
60
+ return False
61
  root_path='/gradio'if is_open_webui_enabled()else None
62
  gr.Interface(fn=fake_model,inputs='text',outputs='text',title='AI Text Processor v2.1').launch(server_name='127.0.0.1',server_port=7861,root_path=root_path)
config/loading.html ADDED
@@ -0,0 +1,350 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Initializing Sanctuary AI</title>
7
+ <link rel="preconnect" href="https://fonts.googleapis.com">
8
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
9
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;600;800&display=swap" rel="stylesheet">
10
+ <style>
11
+ :root {
12
+ --bg-color: #0d0b18;
13
+ --card-bg: rgba(22, 19, 39, 0.45);
14
+ --card-border: rgba(255, 255, 255, 0.08);
15
+ --text-primary: #f3f1f6;
16
+ --text-secondary: #a39eb9;
17
+ --accent-glow: rgba(139, 92, 246, 0.15);
18
+ --primary-gradient: linear-gradient(135deg, #a78bfa 0%, #8b5cf6 50%, #6d28d9 100%);
19
+ --secondary-gradient: linear-gradient(135deg, #4b5563 0%, #374151 100%);
20
+ }
21
+
22
+ * {
23
+ box-sizing: border-box;
24
+ margin: 0;
25
+ padding: 0;
26
+ }
27
+
28
+ body {
29
+ font-family: 'Outfit', sans-serif;
30
+ background-color: var(--bg-color);
31
+ color: var(--text-primary);
32
+ min-height: 100vh;
33
+ display: flex;
34
+ align-items: center;
35
+ justify-content: center;
36
+ overflow: hidden;
37
+ position: relative;
38
+ }
39
+
40
+ /* Animated background glows */
41
+ .bg-glow {
42
+ position: absolute;
43
+ width: 600px;
44
+ height: 600px;
45
+ border-radius: 50%;
46
+ background: radial-gradient(circle, var(--accent-glow) 0%, rgba(0,0,0,0) 70%);
47
+ z-index: 1;
48
+ filter: blur(80px);
49
+ animation: drift 20s infinite alternate ease-in-out;
50
+ }
51
+
52
+ .glow-1 {
53
+ top: -10%;
54
+ left: -10%;
55
+ }
56
+
57
+ .glow-2 {
58
+ bottom: -10%;
59
+ right: -10%;
60
+ animation-delay: -10s;
61
+ }
62
+
63
+ @keyframes drift {
64
+ 0% { transform: translate(0, 0) scale(1); }
65
+ 100% { transform: translate(100px, 50px) scale(1.2); }
66
+ }
67
+
68
+ /* Container & Glassmorphism Card */
69
+ .container {
70
+ position: relative;
71
+ z-index: 10;
72
+ width: 100%;
73
+ max-width: 520px;
74
+ padding: 24px;
75
+ }
76
+
77
+ .card {
78
+ background: var(--card-bg);
79
+ backdrop-filter: blur(20px);
80
+ -webkit-backdrop-filter: blur(20px);
81
+ border: 1px solid var(--card-border);
82
+ border-radius: 24px;
83
+ padding: 40px;
84
+ box-shadow: 0 20px 50px rgba(0, 0, 0, 0.4),
85
+ inset 0 1px 0 rgba(255, 255, 255, 0.1);
86
+ text-align: center;
87
+ display: flex;
88
+ flex-direction: column;
89
+ align-items: center;
90
+ }
91
+
92
+ /* Logo & Spinner */
93
+ .logo-area {
94
+ position: relative;
95
+ margin-bottom: 32px;
96
+ width: 100px;
97
+ height: 100px;
98
+ }
99
+
100
+ .spinner-outer {
101
+ position: absolute;
102
+ top: 0;
103
+ left: 0;
104
+ width: 100%;
105
+ height: 100%;
106
+ border-radius: 50%;
107
+ border: 3px solid transparent;
108
+ border-top-color: #8b5cf6;
109
+ border-bottom-color: #d8b4fe;
110
+ animation: spin 2s linear infinite;
111
+ }
112
+
113
+ .spinner-inner {
114
+ position: absolute;
115
+ top: 10px;
116
+ left: 10px;
117
+ width: 80px;
118
+ height: 80px;
119
+ border-radius: 50%;
120
+ border: 3px solid transparent;
121
+ border-left-color: #6366f1;
122
+ border-right-color: #a5b4fc;
123
+ animation: spin-reverse 1.5s linear infinite;
124
+ }
125
+
126
+ .logo-icon {
127
+ position: absolute;
128
+ top: 25px;
129
+ left: 25px;
130
+ width: 50px;
131
+ height: 50px;
132
+ display: flex;
133
+ align-items: center;
134
+ justify-content: center;
135
+ background: var(--primary-gradient);
136
+ border-radius: 50%;
137
+ font-size: 24px;
138
+ font-weight: 800;
139
+ color: #ffffff;
140
+ box-shadow: 0 0 20px rgba(139, 92, 246, 0.4);
141
+ animation: pulse 2s infinite alternate ease-in-out;
142
+ }
143
+
144
+ @keyframes spin {
145
+ 0% { transform: rotate(0deg); }
146
+ 100% { transform: rotate(360deg); }
147
+ }
148
+
149
+ @keyframes spin-reverse {
150
+ 0% { transform: rotate(360deg); }
151
+ 100% { transform: rotate(0deg); }
152
+ }
153
+
154
+ @keyframes pulse {
155
+ 0% { transform: scale(0.95); box-shadow: 0 0 15px rgba(139, 92, 246, 0.3); }
156
+ 100% { transform: scale(1.05); box-shadow: 0 0 25px rgba(139, 92, 246, 0.6); }
157
+ }
158
+
159
+ /* Typography */
160
+ h1 {
161
+ font-size: 28px;
162
+ font-weight: 800;
163
+ letter-spacing: -0.5px;
164
+ background: linear-gradient(135deg, #ffffff 0%, #d8b4fe 100%);
165
+ -webkit-background-clip: text;
166
+ -webkit-text-fill-color: transparent;
167
+ margin-bottom: 12px;
168
+ }
169
+
170
+ .subtitle {
171
+ color: var(--text-secondary);
172
+ font-size: 15px;
173
+ line-height: 1.6;
174
+ margin-bottom: 32px;
175
+ font-weight: 300;
176
+ }
177
+
178
+ /* Status List */
179
+ .status-list {
180
+ width: 100%;
181
+ background: rgba(0, 0, 0, 0.15);
182
+ border-radius: 16px;
183
+ padding: 16px 20px;
184
+ margin-bottom: 32px;
185
+ text-align: left;
186
+ border: 1px solid rgba(255, 255, 255, 0.03);
187
+ }
188
+
189
+ .status-item {
190
+ display: flex;
191
+ align-items: center;
192
+ justify-content: space-between;
193
+ margin-bottom: 12px;
194
+ font-size: 14px;
195
+ }
196
+
197
+ .status-item:last-child {
198
+ margin-bottom: 0;
199
+ }
200
+
201
+ .status-label {
202
+ color: var(--text-secondary);
203
+ }
204
+
205
+ .status-value {
206
+ font-weight: 600;
207
+ display: flex;
208
+ align-items: center;
209
+ gap: 6px;
210
+ }
211
+
212
+ .status-dot {
213
+ width: 8px;
214
+ height: 8px;
215
+ border-radius: 50%;
216
+ display: inline-block;
217
+ }
218
+
219
+ .dot-green {
220
+ background-color: #10b981;
221
+ box-shadow: 0 0 10px rgba(16, 185, 129, 0.5);
222
+ }
223
+
224
+ .dot-pulse {
225
+ background-color: #f59e0b;
226
+ box-shadow: 0 0 10px rgba(245, 158, 11, 0.5);
227
+ animation: blink 1.5s infinite alternate;
228
+ }
229
+
230
+ @keyframes blink {
231
+ 0% { opacity: 0.4; }
232
+ 100% { opacity: 1; }
233
+ }
234
+
235
+ /* Action Buttons */
236
+ .btn {
237
+ display: inline-flex;
238
+ align-items: center;
239
+ justify-content: center;
240
+ width: 100%;
241
+ padding: 14px 28px;
242
+ font-family: inherit;
243
+ font-size: 15px;
244
+ font-weight: 600;
245
+ border-radius: 14px;
246
+ border: none;
247
+ cursor: pointer;
248
+ text-decoration: none;
249
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
250
+ color: #ffffff;
251
+ margin-bottom: 12px;
252
+ }
253
+
254
+ .btn-primary {
255
+ background: var(--primary-gradient);
256
+ box-shadow: 0 4px 15px rgba(139, 92, 246, 0.25);
257
+ }
258
+
259
+ .btn-primary:hover {
260
+ transform: translateY(-2px);
261
+ box-shadow: 0 6px 20px rgba(139, 92, 246, 0.4);
262
+ filter: brightness(1.1);
263
+ }
264
+
265
+ .btn-secondary {
266
+ background: var(--secondary-gradient);
267
+ border: 1px solid rgba(255, 255, 255, 0.05);
268
+ }
269
+
270
+ .btn-secondary:hover {
271
+ transform: translateY(-2px);
272
+ background: linear-gradient(135deg, #525c6a 0%, #3e4856 100%);
273
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
274
+ }
275
+
276
+ .btn:active {
277
+ transform: translateY(0);
278
+ }
279
+
280
+ .footer {
281
+ font-size: 12px;
282
+ color: rgba(163, 158, 185, 0.4);
283
+ margin-top: 12px;
284
+ }
285
+ </style>
286
+ </head>
287
+ <body>
288
+ <div class="bg-glow glow-1"></div>
289
+ <div class="bg-glow glow-2"></div>
290
+
291
+ <div class="container">
292
+ <div class="card">
293
+ <div class="logo-area">
294
+ <div class="spinner-outer"></div>
295
+ <div class="spinner-inner"></div>
296
+ <div class="logo-icon">S</div>
297
+ </div>
298
+
299
+ <h1>Initializing Sanctuary</h1>
300
+ <p class="subtitle">Please hold on. Sanctuary's neural engine and primary web interface are warming up and will be ready in a few seconds.</p>
301
+
302
+ <div class="status-list">
303
+ <div class="status-item">
304
+ <span class="status-label">Local API proxy (LiteLLM)</span>
305
+ <span class="status-value"><span class="status-dot dot-green"></span>Active</span>
306
+ </div>
307
+ <div class="status-item">
308
+ <span class="status-label">Open WebUI Engine</span>
309
+ <span class="status-value"><span class="status-dot dot-pulse"></span>Initializing</span>
310
+ </div>
311
+ <div class="status-item">
312
+ <span class="status-label">Primary Route (Port 7860)</span>
313
+ <span class="status-value" style="color: var(--text-secondary);">Redirecting soon</span>
314
+ </div>
315
+ </div>
316
+
317
+ <a href="/gradio/" class="btn btn-secondary">
318
+ Go to Gradio Diagnostics
319
+ </a>
320
+
321
+ <div class="footer">
322
+ Auto-reconnecting when online...
323
+ </div>
324
+ </div>
325
+ </div>
326
+
327
+ <script>
328
+ async function checkStatus() {
329
+ try {
330
+ // Fetch root path with cache buster to avoid caching the 502/503/504
331
+ const res = await fetch('/?t=' + Date.now(), { cache: 'no-store' });
332
+ // If we get any status other than 502, 503, or 504, it means Nginx is
333
+ // successfully proxying to the running Open WebUI backend (e.g. 200, 302, 401, etc.)
334
+ if (res.status !== 502 && res.status !== 503 && res.status !== 504) {
335
+ console.log("Service is ready (Status: " + res.status + "). Reloading...");
336
+ window.location.reload();
337
+ }
338
+ } catch (err) {
339
+ // If there's a connection error, just wait and try again
340
+ console.log("Polling network or connection error:", err);
341
+ }
342
+ }
343
+
344
+ // Start checking status every 2 seconds
345
+ setInterval(checkStatus, 2000);
346
+ // Initial check
347
+ setTimeout(checkStatus, 500);
348
+ </script>
349
+ </body>
350
+ </html>
services/nginx_service.py CHANGED
@@ -1,18 +1,46 @@
 
1
  import subprocess
2
  from loguru import logger
3
  from.utils import decode_cmd
4
- import json
5
  def is_open_webui_enabled():
6
- try:
7
- with open('/home/user/config/enabled_services.json','r')as A:B=json.load(A)
8
- C=B.get('services')or[];return any(A.strip().lower()=='open_webui'for A in C if A)
9
- except Exception:return False
 
 
 
 
10
  def start(nginx_log):
11
- E='ERROR_LOCATION';D='ERROR_FALLBACK';C='BACKEND_PORT';B=nginx_log;logger.info('Enabling Nginx smart frontend on port 7860...')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  try:
13
- with open('/home/user/config/nginx.conf.template','r')as F:A=F.read()
14
- if is_open_webui_enabled():A=A.replace(C,'3000');A=A.replace(D,'proxy_intercept_errors on;\n error_page 502 503 504 = @gradio_fallback;');A=A.replace(E,'location @gradio_fallback {\n proxy_pass http://127.0.0.1:7861;\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection $cu;\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_read_timeout 86400s;\n proxy_send_timeout 86400s;\n }')
15
- else:A=A.replace(C,'7861');A=A.replace(D,'');A=A.replace(E,'')
16
- with open('/home/user/nginx.conf','w')as G:G.write(A)
17
- except Exception as H:logger.error(f"Failed to prepare nginx config: {H}");return
18
- B.write('[*] Testing nginx configuration...\n');B.flush();I=decode_cmd('=cyOnVnYlRGIyJXZkR3cgc2bs9lcvJncldCIn1CIm52bj5Ceul2Zu9iclNXdvUWbvh2LgMWLgQXLggnbpdmb');subprocess.run(I,shell=True,stdout=B,stderr=subprocess.STDOUT);B.write('[*] Starting nginx daemon...\n');B.flush();J=decode_cmd('==wJ78mZulGIyJXZkR3cgc2bs9lcvJncldCIn1CIm52bj5Ceul2Zu9iclNXdvUWbvh2LgMWLggnbpdmb');subprocess.Popen(J,shell=True,stdout=B,stderr=subprocess.STDOUT)
 
 
 
 
 
 
 
 
1
+ _A=False
2
  import subprocess
3
  from loguru import logger
4
  from.utils import decode_cmd
5
+ import json,os,shutil
6
  def is_open_webui_enabled():
7
+ B=['/home/user/config/enabled_services.json','config/enabled_services.json','main/config/enabled_services.json']
8
+ for A in B:
9
+ try:
10
+ if os.path.exists(A):
11
+ with open(A,'r')as C:D=json.load(C)
12
+ E=D.get('services')or[];return any(A.strip().lower()=='open_webui'for A in E if A)
13
+ except Exception:pass
14
+ return _A
15
  def start(nginx_log):
16
+ L='ERROR_LOCATION';K='ERROR_FALLBACK';J='BACKEND_PORT';D=True;C=nginx_log;logger.info('Enabling Nginx smart frontend on port 7860...')
17
+ try:
18
+ E='/home/user/static'
19
+ if not os.path.isdir(E):E='static'
20
+ os.makedirs(E,exist_ok=D);M=['/home/user/config/loading.html','config/loading.html','main/config/loading.html'];G=_A
21
+ for B in M:
22
+ if os.path.exists(B):shutil.copy(B,os.path.join(E,'loading.html'));G=D;break
23
+ if not G:logger.warning('Could not find loading.html to copy to static directory.')
24
+ except Exception as F:logger.error(f"Failed to copy loading.html to static directory: {F}")
25
+ A=None;N=['/home/user/config/nginx.conf.template','config/nginx.conf.template','main/config/nginx.conf.template']
26
+ for B in N:
27
+ try:
28
+ if os.path.exists(B):
29
+ with open(B,'r')as O:A=O.read()
30
+ break
31
+ except Exception:pass
32
+ if A is None:logger.error('Failed to prepare nginx config: nginx.conf.template not found.');return
33
  try:
34
+ if is_open_webui_enabled():A=A.replace(J,'3000');A=A.replace(K,'proxy_intercept_errors on;\n error_page 502 503 504 = @loading_fallback;');A=A.replace(L,'location @loading_fallback {\n root /home/user/static;\n try_files /loading.html =502;\n }')
35
+ else:A=A.replace(J,'7861');A=A.replace(K,'');A=A.replace(L,'')
36
+ P=['/home/user/nginx.conf','nginx.conf'];H=_A
37
+ for B in P:
38
+ try:
39
+ I=os.path.dirname(os.path.abspath(B))
40
+ if os.path.isdir(I)and os.access(I,os.W_OK):
41
+ with open(B,'w')as Q:Q.write(A)
42
+ H=D;break
43
+ except Exception:pass
44
+ if not H:raise PermissionError('Could not write nginx.conf to any expected path.')
45
+ except Exception as F:logger.error(f"Failed to prepare nginx config: {F}");return
46
+ C.write('[*] Testing nginx configuration...\n');C.flush();R=decode_cmd('=cyOnVnYlRGIyJXZkR3cgc2bs9lcvJncldCIn1CIm52bj5Ceul2Zu9iclNXdvUWbvh2LgMWLgQXLggnbpdmb');subprocess.run(R,shell=D,stdout=C,stderr=subprocess.STDOUT);C.write('[*] Starting nginx daemon...\n');C.flush();S=decode_cmd('==wJ78mZulGIyJXZkR3cgc2bs9lcvJncldCIn1CIm52bj5Ceul2Zu9iclNXdvUWbvh2LgMWLggnbpdmb');subprocess.Popen(S,shell=D,stdout=C,stderr=subprocess.STDOUT)