liumaolin commited on
Commit
065b0f6
·
1 Parent(s): c723658

Add Electron app scaffolding with loading screen and Python backend integration

Browse files
electron-app/loading.html ADDED
@@ -0,0 +1,440 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Loading...</title>
7
+ <style>
8
+ :root {
9
+ --mac-accent: #0071e3;
10
+ --mac-accent-light: #2d8aeb;
11
+ --mac-accent-dark: #0060bf;
12
+ --mac-bg: #f5f5f7;
13
+ --mac-text: #1d1d1f;
14
+ --mac-text-secondary: #86868b;
15
+ --mac-white: #ffffff;
16
+ --mac-border-radius: 10px;
17
+ --mac-blur-bg: rgba(255, 255, 255, 0.7);
18
+ }
19
+
20
+ * {
21
+ margin: 0;
22
+ padding: 0;
23
+ box-sizing: border-box;
24
+ }
25
+
26
+ body {
27
+ margin: 0;
28
+ padding: 0;
29
+ display: flex;
30
+ justify-content: center;
31
+ align-items: center;
32
+ min-height: 100vh;
33
+ background-color: var(--mac-bg);
34
+ font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Text', 'Helvetica Neue', Helvetica, Arial, sans-serif;
35
+ overflow: hidden;
36
+ position: relative;
37
+ }
38
+
39
+ .window-container {
40
+ width: 480px;
41
+ max-width: 90%;
42
+ backdrop-filter: blur(20px);
43
+ -webkit-backdrop-filter: blur(20px);
44
+ background-color: var(--mac-blur-bg);
45
+ border-radius: 12px;
46
+ box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
47
+ overflow: hidden;
48
+ animation: fadeIn 0.5s ease;
49
+ }
50
+
51
+ .window-header {
52
+ height: 40px;
53
+ background-color: rgba(255, 255, 255, 0.9);
54
+ border-bottom: 1px solid rgba(0, 0, 0, 0.05);
55
+ display: flex;
56
+ align-items: center;
57
+ padding: 0 12px;
58
+ }
59
+
60
+ .window-controls {
61
+ display: flex;
62
+ gap: 8px;
63
+ }
64
+
65
+ .window-button {
66
+ width: 12px;
67
+ height: 12px;
68
+ border-radius: 50%;
69
+ }
70
+
71
+ .close-button {
72
+ background-color: #ff5f57;
73
+ }
74
+
75
+ .minimize-button {
76
+ background-color: #febc2e;
77
+ }
78
+
79
+ .maximize-button {
80
+ background-color: #28c840;
81
+ }
82
+
83
+ .window-title {
84
+ position: absolute;
85
+ left: 0;
86
+ right: 0;
87
+ text-align: center;
88
+ color: var(--mac-text-secondary);
89
+ font-size: 13px;
90
+ font-weight: 500;
91
+ }
92
+
93
+ .window-content {
94
+ padding: 40px 30px;
95
+ width: 100%;
96
+ display: flex;
97
+ flex-direction: column;
98
+ align-items: center;
99
+ }
100
+
101
+ .app-icon {
102
+ width: 80px;
103
+ height: 80px;
104
+ margin-bottom: 24px;
105
+ position: relative;
106
+ animation: iconPulse 2s ease-in-out infinite;
107
+ }
108
+
109
+ .app-icon-inner {
110
+ width: 80px;
111
+ height: 80px;
112
+ border-radius: 20px;
113
+ background: linear-gradient(135deg, #5AC8FA, #007AFF);
114
+ box-shadow: 1px 1px 6px 2px rgba(0, 122, 255, 0.3);
115
+ display: flex;
116
+ justify-content: center;
117
+ align-items: center;
118
+ color: white;
119
+ font-size: 40px;
120
+ font-weight: 600;
121
+ }
122
+
123
+ .app-title {
124
+ color: var(--mac-text);
125
+ font-size: 22px;
126
+ font-weight: 600;
127
+ margin-bottom: 8px;
128
+ }
129
+
130
+ .app-subtitle {
131
+ color: var(--mac-text-secondary);
132
+ font-size: 14px;
133
+ margin-bottom: 32px;
134
+ text-align: center;
135
+ max-width: 340px;
136
+ }
137
+
138
+ .spinner {
139
+ width: 22px;
140
+ height: 22px;
141
+ margin-bottom: 24px;
142
+ border: 2px solid rgba(0, 113, 227, 0.2);
143
+ border-left-color: var(--mac-accent);
144
+ border-radius: 50%;
145
+ animation: spin 1s linear infinite;
146
+ }
147
+
148
+ .progress-container {
149
+ width: 80%;
150
+ height: 6px;
151
+ background-color: rgba(0, 113, 227, 0.1);
152
+ border-radius: 3px;
153
+ overflow: hidden;
154
+ margin-bottom: 12px;
155
+ }
156
+
157
+ .progress-bar {
158
+ height: 100%;
159
+ background-color: var(--mac-accent);
160
+ width: 0%;
161
+ transition: width 0.4s ease;
162
+ border-radius: 3px;
163
+ }
164
+
165
+ .status-container {
166
+ display: flex;
167
+ justify-content: space-between;
168
+ align-items: center;
169
+ width: 80%;
170
+ margin-bottom: 28px;
171
+ }
172
+ .status-text {
173
+ color: var(--mac-text-secondary);
174
+ font-size: 12px;
175
+ }
176
+
177
+ .percent-text {
178
+ color: var(--mac-text-secondary);
179
+ font-size: 12px;
180
+ font-feature-settings: "tnum";
181
+ font-variant-numeric: tabular-nums;
182
+ }
183
+
184
+ .notification {
185
+ width: 80%;
186
+ padding: 14px;
187
+ border-radius: 8px;
188
+ background-color: rgba(0, 0, 0, 0.03);
189
+ display: flex;
190
+ align-items: flex-start;
191
+ margin-top: 8px;
192
+ }
193
+
194
+ .notification-icon {
195
+ margin-right: 12px;
196
+ margin-top: 2px;
197
+ }
198
+
199
+ .notification-icon svg {
200
+ width: 16px;
201
+ height: 16px;
202
+ color: var(--mac-accent);
203
+ }
204
+
205
+ .notification-content {
206
+ flex: 1;
207
+ }
208
+
209
+ .notification-title {
210
+ font-size: 13px;
211
+ font-weight: 500;
212
+ color: var(--mac-text);
213
+ margin-bottom: 4px;
214
+ }
215
+
216
+ .notification-text {
217
+ font-size: 12px;
218
+ color: var(--mac-text-secondary);
219
+ line-height: 1.5;
220
+ }
221
+
222
+ @keyframes spin {
223
+ 0% { transform: rotate(0deg); }
224
+ 100% { transform: rotate(360deg); }
225
+ }
226
+
227
+ @keyframes iconPulse {
228
+ 0% { transform: scale(1); }
229
+ 50% { transform: scale(1.05); }
230
+ 100% { transform: scale(1); }
231
+ }
232
+
233
+ @keyframes fadeIn {
234
+ 0% { opacity: 0; transform: translateY(10px); }
235
+ 100% { opacity: 1; transform: translateY(0); }
236
+ }
237
+
238
+ @keyframes warningPulse {
239
+ 0% { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); }
240
+ 50% { box-shadow: 0 8px 32px rgba(255, 193, 7, 0.3); }
241
+ 100% { box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); }
242
+ }
243
+
244
+ .notification.warning-theme {
245
+ animation: warningPulse 1s ease-in-out infinite;
246
+ background-color: rgba(255, 0, 0, 0.1);
247
+ }
248
+ </style>
249
+ </head>
250
+ <body>
251
+ <div class="">
252
+
253
+ </div>
254
+ <div class="window-content">
255
+ <div class="app-icon">
256
+ <div class="app-icon-inner"><img width="100" height="100" src="./build/icon.png" alt=""></div>
257
+ </div>
258
+ <h1 class="app-title">Voice Dialogue</h1>
259
+ <!-- <p class="app-subtitle">Please wait while we prepare everything for you</p> -->
260
+ <p class="app-subtitle">&nbsp;</p>
261
+ <div class="spinner"></div>
262
+ <p class="app-subtitle">&nbsp;</p>
263
+ <div class="progress-container">
264
+ <div class="progress-bar" id="progressBar"></div>
265
+ </div>
266
+
267
+ <div class="status-container">
268
+ <div class="status-text" id="statusText">Initializing...</div>
269
+ <div class="percent-text" id="percentText">0%</div>
270
+ </div>
271
+
272
+ <div class="notification info-theme" id="firstRunNotification" style="display: none;">
273
+ <div class="notification-icon">
274
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor">
275
+ <path fill-rule="evenodd" d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z" clip-rule="evenodd" />
276
+ </svg>
277
+ </div>
278
+ <div class="notification-content">
279
+ <h3 class="notification-title">First Launch Notice</h3>
280
+ <p class="notification-text">
281
+ First launch may take longer as we set up your environment and optimize resources. Subsequent launches will be much faster.
282
+ </p>
283
+ </div>
284
+ </div>
285
+
286
+ <div class="notification warning-theme" id="resourceWarningNotification" style="display: none;">
287
+ <div class="notification-icon">
288
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" style="color: #ffc107;">
289
+ <path fill-rule="evenodd" d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z" clip-rule="evenodd" />
290
+ </svg>
291
+ </div>
292
+ <div class="notification-content">
293
+ <h3 class="notification-title">System Resource Warning</h3>
294
+ <p class="notification-text" id="resourceWarningText">
295
+ Your system resources are running low. This may affect app performance. Please consider closing other applications or freeing up memory.
296
+ </p>
297
+ </div>
298
+ </div>
299
+ </div>
300
+ </div>
301
+
302
+ <script>
303
+ // Check if this is the first run and show notification accordingly
304
+ async function checkFirstRun() {
305
+ try {
306
+ if (window.electronAPI && window.electronAPI.getFirstRunStatus) {
307
+ const isFirstRun = await window.electronAPI.getFirstRunStatus();
308
+ console.log('isFirstRun', isFirstRun);
309
+ if (isFirstRun) {
310
+ const notification = document.getElementById('firstRunNotification');
311
+ if (notification) {
312
+ notification.style.display = 'flex';
313
+ }
314
+ }
315
+ }
316
+ } catch (error) {
317
+ console.log('Could not check first run status:', error);
318
+ }
319
+ }
320
+
321
+ // Call checkFirstRun when the page loads
322
+ checkFirstRun();
323
+
324
+ // Check system resources and show warning if needed
325
+ async function checkSystemResources() {
326
+ try {
327
+ if (window.electronAPI && window.electronAPI.getSystemCpuUsage && window.electronAPI.getSystemFreeMemory) {
328
+ const [cpuUsage, memoryFree] = await Promise.all([
329
+ window.electronAPI.getSystemCpuUsage(),
330
+ window.electronAPI.getSystemFreeMemory()
331
+ ]);
332
+
333
+ console.log('CPU Usage:', cpuUsage + '%');
334
+ console.log('Memory Info:', memoryFree);
335
+
336
+ // Check thresholds
337
+ const isCpuHigh = cpuUsage > 80;
338
+ const isMemoryLow = memoryFree < 3; // Less than 4GB available
339
+ console.log('isCpuHigh', isCpuHigh);
340
+ console.log('isMemoryLow', isMemoryLow);
341
+ if (isCpuHigh || isMemoryLow) {
342
+ const notification = document.getElementById('resourceWarningNotification');
343
+ const warningText = document.getElementById('resourceWarningText');
344
+
345
+ let warningMessage = '';
346
+ if (isCpuHigh && isMemoryLow) {
347
+ warningMessage = `High CPU usage and insufficient memory detected. This may significantly affect app performance. Please close other applications to free up resources.`;
348
+ } else if (isCpuHigh) {
349
+ warningMessage = `High CPU usage detected. This may affect app performance. Please close CPU-intensive applications.`;
350
+ } else if (isMemoryLow) {
351
+ warningMessage = `Insufficient memory detected. This may affect app performance. Please close some applications to free up memory.`;
352
+ }
353
+
354
+ warningText.textContent = warningMessage;
355
+ notification.style.display = 'flex';
356
+ notification.classList.add('warning-notification');
357
+ }
358
+ }
359
+ } catch (error) {
360
+ console.log('Could not check system resources:', error);
361
+ }
362
+ }
363
+
364
+ checkSystemResources();
365
+ // Simulate loading progress
366
+ let progress = 0;
367
+ const progressBar = document.getElementById('progressBar');
368
+ const percentText = document.getElementById('percentText');
369
+ const statusText = document.getElementById('statusText');
370
+
371
+ const statusMessages = [
372
+ "Initializing...",
373
+ "Checking system requirements...",
374
+ "Loading components...",
375
+ "Preparing documents...",
376
+ "Optimizing performance...",
377
+ "Almost ready..."
378
+ ];
379
+
380
+ function updateProgress() {
381
+ if (progress < 100) {
382
+ // Make progress more naturalistic with varying speeds
383
+ let increment;
384
+
385
+ if (progress < 20) {
386
+ // Quick start
387
+ increment = Math.random() * 2 + 0.5;
388
+ } else if (progress < 50) {
389
+ // Slow middle (Mac apps typically slow down in the middle)
390
+ increment = Math.random() * 1 + 0.2;
391
+ } else if (progress < 85) {
392
+ // Speed up again
393
+ increment = Math.random() * 1.5 + 0.3;
394
+ } else {
395
+ // Slow finish (typical macOS behavior)
396
+ increment = Math.random() * 0.8 + 0.1;
397
+
398
+ // Hold at 99% for a bit
399
+ if (progress > 99) progress = 99;
400
+ }
401
+
402
+ progress += increment;
403
+ progress = Math.min(progress, 99.9);
404
+
405
+ // Update UI
406
+ progressBar.style.width = progress + '%';
407
+ percentText.textContent = Math.floor(progress) + '%';
408
+
409
+ // Update status message based on progress
410
+ const statusIndex = Math.min(Math.floor(progress / 20), statusMessages.length - 1);
411
+ statusText.textContent = statusMessages[statusIndex];
412
+
413
+ // Typical macOS loading behavior has varying speeds
414
+ let delay;
415
+ if (progress < 30) {
416
+ delay = 100 + Math.random() * 200;
417
+ } else if (progress < 60) {
418
+ delay = 200 + Math.random() * 300;
419
+ } else if (progress < 85) {
420
+ delay = 150 + Math.random() * 250;
421
+ } else {
422
+ delay = 300 + Math.random() * 500;
423
+ }
424
+
425
+ setTimeout(updateProgress, delay);
426
+ } else {
427
+ // Complete loading
428
+ progressBar.style.width = '100%';
429
+ percentText.textContent = '100%';
430
+ statusText.textContent = 'Ready';
431
+
432
+ // In a real app, you'd launch the main window here
433
+ }
434
+ }
435
+
436
+ // Start with a slight delay like real macOS apps
437
+ setTimeout(updateProgress, 600);
438
+ </script>
439
+ </body>
440
+ </html>
electron-app/main.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cccca0b11d8649d4822fcb83abc7a594bf63bb85680106b3f1c6d2c94970a7d0
3
+ size 6443
electron-app/notarize.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1adb9f71746cd3518662e8b81583a632d772e62d98705ec1fae80085b82beb05
3
+ size 949
electron-app/package.json ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ab529c9444e6c6824b290cb3b7860f943f0b6b1190ec82c2bccd8a5ad4bc194b
3
+ size 2844
electron-app/preload.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:295e12bf6fb9d9ac34460606fffe1d90278873c77d32a96682f79d680886002e
3
+ size 952
electron-app/utils.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c4bac68a368fb5234d18984394771063d8bda786db8cd33f256a9e285e2dfe7d
3
+ size 6790