Elias207 commited on
Commit
d5cd931
·
verified ·
1 Parent(s): fabd896

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +540 -706
index.html CHANGED
@@ -1,727 +1,561 @@
1
  <!DOCTYPE html>
2
  <html lang="fa" dir="rtl">
3
  <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>QR Code Studio | استودیو کیوآر کد</title>
7
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css">
8
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
- <style>
10
- :root {
11
- --primary-gradient: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
12
- --secondary-gradient: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
13
- --success-gradient: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
14
- --warning-gradient: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
15
- --dark-bg: #0f0f23;
16
- --card-bg: rgba(255, 255, 255, 0.05);
17
- --glass-bg: rgba(255, 255, 255, 0.1);
18
- --text-primary: #ffffff;
19
- --text-secondary: #b8c5d6;
20
- --accent-color: #64ffda;
21
- --border-color: rgba(255, 255, 255, 0.15);
22
- --shadow-light: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
23
- --shadow-hover: 0 15px 35px rgba(31, 38, 135, 0.5);
24
- }
25
-
26
- * {
27
- margin: 0;
28
- padding: 0;
29
- box-sizing: border-box;
30
- }
31
-
32
- body {
33
- font-family: 'Vazirmatn', sans-serif;
34
- background: var(--dark-bg);
35
- background-image:
36
- radial-gradient(circle at 20% 50%, rgba(120, 119, 198, 0.3) 0%, transparent 50%),
37
- radial-gradient(circle at 80% 20%, rgba(255, 119, 198, 0.3) 0%, transparent 50%),
38
- radial-gradient(circle at 40% 80%, rgba(120, 219, 255, 0.3) 0%, transparent 50%);
39
- color: var(--text-primary);
40
- min-height: 100vh;
41
- overflow-x: hidden;
42
- position: relative;
43
- }
44
-
45
- /* خطوط پس‌زمینه برای جلوه QR */
46
- body::before {
47
- content: '';
48
- position: fixed;
49
- top: 0;
50
- left: 0;
51
- width: 100%;
52
- height: 100%;
53
- background-image:
54
- linear-gradient(90deg, rgba(255,255,255,0.02) 1px, transparent 1px),
55
- linear-gradient(rgba(255,255,255,0.02) 1px, transparent 1px);
56
- background-size: 50px 50px;
57
- pointer-events: none;
58
- z-index: -1;
59
- }
60
-
61
- .container {
62
- max-width: 1200px;
63
- margin: 0 auto;
64
- padding: 20px;
65
- min-height: 100vh;
66
- display: flex;
67
- flex-direction: column;
68
- }
69
-
70
- /* هدر */
71
- .header {
72
- text-align: center;
73
- margin-bottom: 3rem;
74
- position: relative;
75
- }
76
-
77
- .main-title {
78
- font-size: clamp(2rem, 5vw, 3.5rem);
79
- font-weight: 700;
80
- background: var(--primary-gradient);
81
- background-clip: text;
82
- -webkit-background-clip: text;
83
- -webkit-text-fill-color: transparent;
84
- margin-bottom: 0.5rem;
85
- position: relative;
86
- }
87
-
88
- .subtitle {
89
- font-size: 1.1rem;
90
- color: var(--text-secondary);
91
- font-weight: 300;
92
- }
93
-
94
- /* منطقه اصلی */
95
- .main-content {
96
- display: grid;
97
- grid-template-columns: 1fr;
98
- gap: 2rem;
99
- flex: 1;
100
- }
101
-
102
- @media (min-width: 768px) {
103
- .main-content {
104
- grid-template-columns: 1fr 1fr;
105
- gap: 3rem;
106
- }
107
- }
108
-
109
- /* کارت‌ها */
110
- .card {
111
- background: var(--card-bg);
112
- backdrop-filter: blur(20px);
113
- border: 1px solid var(--border-color);
114
- border-radius: 24px;
115
- padding: 2rem;
116
- position: relative;
117
- overflow: hidden;
118
- transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275);
119
- box-shadow: var(--shadow-light);
120
- }
121
-
122
- .card::before {
123
- content: '';
124
- position: absolute;
125
- top: 0;
126
- left: 0;
127
- right: 0;
128
- height: 4px;
129
- background: var(--primary-gradient);
130
- transform: scaleX(0);
131
- transition: transform 0.3s ease;
132
- }
133
-
134
- .card:hover {
135
- transform: translateY(-8px);
136
- box-shadow: var(--shadow-hover);
137
- }
138
-
139
- .card:hover::before {
140
- transform: scaleX(1);
141
- }
142
-
143
- .card-header {
144
- display: flex;
145
- align-items: center;
146
- gap: 1rem;
147
- margin-bottom: 2rem;
148
- }
149
-
150
- .card-icon {
151
- width: 50px;
152
- height: 50px;
153
- border-radius: 12px;
154
- display: flex;
155
- align-items: center;
156
- justify-content: center;
157
- font-size: 1.5rem;
158
- color: white;
159
- position: relative;
160
- overflow: hidden;
161
- }
162
-
163
- .generate-card .card-icon {
164
- background: var(--primary-gradient);
165
- }
166
-
167
- .read-card .card-icon {
168
- background: var(--secondary-gradient);
169
- }
170
-
171
- .card-title {
172
- font-size: 1.4rem;
173
- font-weight: 600;
174
- color: var(--text-primary);
175
- }
176
-
177
- /* فرم عناصر */
178
- .form-group {
179
- margin-bottom: 1.5rem;
180
- }
181
-
182
- .form-label {
183
- display: block;
184
- margin-bottom: 0.5rem;
185
- color: var(--text-secondary);
186
- font-size: 0.9rem;
187
- font-weight: 500;
188
- }
189
-
190
- .form-input {
191
- width: 100%;
192
- padding: 1rem;
193
- border: 2px solid var(--border-color);
194
- border-radius: 12px;
195
- background: var(--glass-bg);
196
- color: var(--text-primary);
197
- font-size: 1rem;
198
- transition: all 0.3s ease;
199
- backdrop-filter: blur(10px);
200
- resize: vertical;
201
- min-height: 120px;
202
- }
203
-
204
- .form-input::placeholder {
205
- color: var(--text-secondary);
206
- }
207
-
208
- .form-input:focus {
209
- outline: none;
210
- border-color: var(--accent-color);
211
- box-shadow: 0 0 0 3px rgba(100, 255, 218, 0.1);
212
- transform: translateY(-2px);
213
- }
214
-
215
- /* فایل آپلود */
216
- .file-upload {
217
- position: relative;
218
- overflow: hidden;
219
- border: 2px dashed var(--border-color);
220
- border-radius: 12px;
221
- padding: 2rem;
222
- text-align: center;
223
- cursor: pointer;
224
- transition: all 0.3s ease;
225
- background: var(--glass-bg);
226
- }
227
-
228
- .file-upload:hover {
229
- border-color: var(--accent-color);
230
- background: rgba(100, 255, 218, 0.05);
231
- }
232
-
233
- .file-upload input {
234
- position: absolute;
235
- left: -9999px;
236
- }
237
-
238
- .file-upload-icon {
239
- font-size: 2rem;
240
- color: var(--accent-color);
241
- margin-bottom: 1rem;
242
- }
243
-
244
- .file-upload-text {
245
- color: var(--text-secondary);
246
- font-size: 0.9rem;
247
- }
248
-
249
- .file-name {
250
- margin-top: 1rem;
251
- padding: 0.5rem 1rem;
252
- background: rgba(100, 255, 218, 0.1);
253
- border-radius: 8px;
254
- color: var(--accent-color);
255
- font-size: 0.85rem;
256
- display: none;
257
- }
258
-
259
- /* دکمه‌ها */
260
- .btn {
261
- width: 100%;
262
- padding: 1rem 2rem;
263
- border: none;
264
- border-radius: 12px;
265
- font-size: 1rem;
266
- font-weight: 600;
267
- cursor: pointer;
268
- position: relative;
269
- overflow: hidden;
270
- transition: all 0.3s ease;
271
- display: flex;
272
- align-items: center;
273
- justify-content: center;
274
- gap: 0.5rem;
275
- color: white;
276
- text-transform: none;
277
- }
278
-
279
- .btn-primary {
280
- background: var(--primary-gradient);
281
- box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4);
282
- }
283
-
284
- .btn-secondary {
285
- background: var(--secondary-gradient);
286
- box-shadow: 0 4px 15px rgba(245, 87, 108, 0.4);
287
- }
288
-
289
- .btn:hover:not(:disabled) {
290
- transform: translateY(-3px);
291
- box-shadow: 0 8px 25px rgba(0, 0, 0, 0.3);
292
- }
293
-
294
- .btn:disabled {
295
- opacity: 0.6;
296
- cursor: not-allowed;
297
- transform: none;
298
- }
299
-
300
- .btn::before {
301
- content: '';
302
- position: absolute;
303
- top: 0;
304
- left: -100%;
305
- width: 100%;
306
- height: 100%;
307
- background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.2), transparent);
308
- transition: left 0.5s;
309
- }
310
-
311
- .btn:hover::before {
312
- left: 100%;
313
- }
314
-
315
- /* نتایج */
316
- .result-box {
317
- margin-top: 1.5rem;
318
- padding: 2rem;
319
- background: var(--glass-bg);
320
- border: 1px solid var(--border-color);
321
- border-radius: 16px;
322
- min-height: 200px;
323
- display: flex;
324
- align-items: center;
325
- justify-content: center;
326
- text-align: center;
327
- backdrop-filter: blur(10px);
328
- position: relative;
329
- overflow: hidden;
330
- }
331
-
332
- .result-empty {
333
- color: var(--text-secondary);
334
- font-style: italic;
335
- }
336
-
337
- #qr-code-display img {
338
- max-width: 100%;
339
- height: auto;
340
- border-radius: 12px;
341
- box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
342
- animation: zoomIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275);
343
- }
344
-
345
- .decoded-result {
346
- background: rgba(100, 255, 218, 0.1);
347
- border: 1px solid var(--accent-color);
348
- border-radius: 12px;
349
- padding: 1.5rem;
350
- color: var(--text-primary);
351
- word-break: break-all;
352
- line-height: 1.6;
353
- }
354
-
355
- /* لودر */
356
- .loader {
357
- width: 50px;
358
- height: 50px;
359
- border: 3px solid var(--border-color);
360
- border-top: 3px solid var(--accent-color);
361
- border-radius: 50%;
362
- animation: spin 1s linear infinite;
363
- }
364
-
365
- /* انیمیشن‌ها */
366
- @keyframes spin {
367
- 0% { transform: rotate(0deg); }
368
- 100% { transform: rotate(360deg); }
369
- }
370
-
371
- @keyframes zoomIn {
372
- from {
373
- opacity: 0;
374
- transform: scale(0.5);
375
- }
376
- to {
377
- opacity: 1;
378
- transform: scale(1);
379
- }
380
- }
381
-
382
- @keyframes slideInUp {
383
- from {
384
- opacity: 0;
385
- transform: translateY(30px);
386
- }
387
- to {
388
- opacity: 1;
389
- transform: translateY(0);
390
- }
391
- }
392
-
393
- .card {
394
- animation: slideInUp 0.6s ease-out forwards;
395
- }
396
-
397
- .generate-card {
398
- animation-delay: 0.1s;
399
- }
400
 
401
- .read-card {
402
- animation-delay: 0.2s;
403
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
404
 
405
- /* ریسپانسیو */
406
- @media (max-width: 767px) {
407
- .container {
408
- padding: 1rem;
409
- }
410
-
411
- .card {
412
- padding: 1.5rem;
413
- }
414
-
415
- .main-content {
416
- gap: 1.5rem;
417
- }
418
- }
419
 
420
- /* اسکرول بار سفارشی */
421
- ::-webkit-scrollbar {
422
- width: 8px;
423
- }
 
 
424
 
425
- ::-webkit-scrollbar-track {
426
- background: rgba(255, 255, 255, 0.1);
427
- border-radius: 4px;
428
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
 
430
- ::-webkit-scrollbar-thumb {
431
- background: var(--accent-color);
432
- border-radius: 4px;
433
- }
 
 
 
434
 
435
- ::-webkit-scrollbar-thumb:hover {
436
- background: rgba(100, 255, 218, 0.8);
437
- }
438
- </style>
439
- </head>
440
- <body>
441
- <div class="container">
442
- <!-- هدر -->
443
- <header class="header">
444
- <h1 class="main-title">
445
- <i class="fas fa-qrcode"></i>
446
- QR Code Studio
447
- </h1>
448
- <p class="subtitle">ابزار کامل ساخت و خواندن کد QR</p>
449
- </header>
450
-
451
- <!-- محتوای اصلی -->
452
- <div class="main-content">
453
- <!-- بخش ساخت QR -->
454
- <div class="card generate-card">
455
- <div class="card-header">
456
- <div class="card-icon">
457
- <i class="fas fa-plus-circle"></i>
458
- </div>
459
- <h2 class="card-title">ساخت QR Code</h2>
460
- </div>
461
-
462
- <div class="form-group">
463
- <label class="form-label" for="text-input">
464
- <i class="fas fa-edit"></i>
465
- متن یا لینک خود را وارد کنید
466
- </label>
467
- <textarea
468
- id="text-input"
469
- class="form-input"
470
- placeholder="مثال: https://google.com یا هر متن دلخواه">سلام دنیا</textarea>
471
- </div>
472
-
473
- <button id="generate-btn" class="btn btn-primary">
474
- <i class="fas fa-magic"></i>
475
- <span>ساخت QR Code</span>
476
- </button>
477
-
478
- <div class="result-box">
479
- <div id="generate-loader" class="loader" style="display: none;"></div>
480
- <div id="qr-code-display">
481
- <span class="result-empty">QR Code شما اینجا نمایش داده می‌شود</span>
482
- </div>
483
- </div>
484
- </div>
485
-
486
- <!-- بخش خواندن QR -->
487
- <div class="card read-card">
488
- <div class="card-header">
489
- <div class="card-icon">
490
- <i class="fas fa-search"></i>
491
- </div>
492
- <h2 class="card-title">خواندن QR Code</h2>
493
- </div>
494
-
495
- <div class="form-group">
496
- <label class="form-label">
497
- <i class="fas fa-image"></i>
498
- تصویر QR Code را انتخاب کنید
499
- </label>
500
- <div class="file-upload" onclick="document.getElementById('file-input').click()">
501
- <input type="file" id="file-input" accept="image/*">
502
- <div class="file-upload-icon">
503
- <i class="fas fa-cloud-upload-alt"></i>
504
- </div>
505
- <div class="file-upload-text">
506
- کلیک کنید یا فایل را اینجا بکشید
507
- </div>
508
- <div id="file-name" class="file-name"></div>
509
- </div>
510
- </div>
511
-
512
- <button id="read-btn" class="btn btn-secondary">
513
- <i class="fas fa-eye"></i>
514
- <span>خواندن QR Code</span>
515
- </button>
516
-
517
- <div class="result-box">
518
- <div id="read-loader" class="loader" style="display: none;"></div>
519
- <div id="decoded-text" class="result-empty">نتیجه خواندن اینجا نمایش داده می‌شود</div>
520
- </div>
521
- </div>
522
  </div>
523
- </div>
524
 
525
- <script>
526
- const SPACE_URL = "https://cultrix-qrcode-read-generate.hf.space";
527
-
528
- // دریافت عناصر DOM
529
- const generateBtn = document.getElementById('generate-btn');
530
- const readBtn = document.getElementById('read-btn');
531
- const textInput = document.getElementById('text-input');
532
- const fileInput = document.getElementById('file-input');
533
- const qrCodeDisplay = document.getElementById('qr-code-display');
534
- const decodedText = document.getElementById('decoded-text');
535
- const generateLoader = document.getElementById('generate-loader');
536
- const readLoader = document.getElementById('read-loader');
537
- const fileNameDisplay = document.getElementById('file-name');
538
-
539
- // نمایش نام فایل انتخاب شده
540
- fileInput.addEventListener('change', () => {
541
- if (fileInput.files.length > 0) {
542
- fileNameDisplay.textContent = `فایل انتخاب شده: ${fileInput.files[0].name}`;
543
- fileNameDisplay.style.display = 'block';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
544
  } else {
545
- fileNameDisplay.style.display = 'none';
546
- }
547
- });
548
-
549
- // توابع کمکی
550
- const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
551
-
552
- const listenForData = (sessionHash, onResult, onError) => {
553
- const eventSource = new EventSource(`${SPACE_URL}/gradio_api/queue/data?session_hash=${sessionHash}`);
554
-
555
- eventSource.onmessage = (event) => {
556
- const data = JSON.parse(event.data);
557
- if (data.msg === "process_completed") {
558
- eventSource.close();
559
- if (data.output.error) {
560
- onError(data.output.error);
561
- } else {
562
- onResult(data.output.data);
563
- }
564
- } else if (data.msg === "process_starts") {
565
- console.log("پردازش شروع شد...");
566
- } else if (data.msg === "process_failed") {
567
- eventSource.close();
568
- onError("پردازش با خطا مواجه شد.");
569
- }
570
- };
571
-
572
- eventSource.onerror = (err) => {
573
- console.error("EventSource failed:", err);
574
- eventSource.close();
575
- onError("خطا در ارتباط با سرور.");
576
- };
577
- };
578
-
579
- // منطق ساخت QR Code
580
- generateBtn.addEventListener('click', async () => {
581
- const text = textInput.value.trim();
582
- if (!text) {
583
- alert("لطفاً متنی را وارد کنید.");
584
- textInput.focus();
585
- return;
586
- }
587
-
588
- generateLoader.style.display = 'block';
589
- qrCodeDisplay.innerHTML = '';
590
- generateBtn.disabled = true;
591
-
592
- const sessionHash = generateSessionHash();
593
-
594
- try {
595
- const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
596
- method: 'POST',
597
- headers: { 'Content-Type': 'application/json' },
598
- body: JSON.stringify({ fn_index: 0, data: [text], session_hash: sessionHash })
599
- });
600
-
601
- if (!joinResponse.ok) throw new Error(`خطا در ارسال درخواست: ${joinResponse.statusText}`);
602
-
603
- listenForData(
604
- sessionHash,
605
- (result) => {
606
- if (result && result[0]) {
607
- qrCodeDisplay.innerHTML = result[0];
608
- } else {
609
- qrCodeDisplay.innerHTML = '<span class="result-empty">خطا: خروجی معتبر دریافت نشد.</span>';
610
- }
611
- },
612
- (error) => {
613
- alert(`خطا در پردازش: ${error}`);
614
- qrCodeDisplay.innerHTML = '<span class="result-empty">خطا در ساخت تصویر.</span>';
615
- }
616
- );
617
- } catch (error) {
618
- alert(`یک خطا رخ داد: ${error.message}`);
619
- qrCodeDisplay.innerHTML = '<span class="result-empty">خطا در ساخت QR Code</span>';
620
- } finally {
621
- generateLoader.style.display = 'none';
622
- generateBtn.disabled = false;
623
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
  });
625
 
626
- // منطق خواندن QR Code
627
- readBtn.addEventListener('click', async () => {
628
- const file = fileInput.files[0];
629
- if (!file) {
630
- alert("لطفاً یک فایل تصویر انتخاب کنید.");
631
- return;
632
- }
633
 
634
- readLoader.style.display = 'block';
635
- decodedText.innerHTML = '';
636
- readBtn.disabled = true;
637
-
638
- try {
639
- const formData = new FormData();
640
- formData.append('files', file);
641
-
642
- const uploadResponse = await fetch(`${SPACE_URL}/gradio_api/upload`, {
643
- method: 'POST',
644
- body: formData
645
- });
646
- if (!uploadResponse.ok) throw new Error(`خطا در آپلود فایل: ${uploadResponse.statusText}`);
647
-
648
- const uploadResult = await uploadResponse.json();
649
- const serverFilePath = uploadResult[0];
650
-
651
- const fileDataObject = {
652
- path: serverFilePath,
653
- url: `${SPACE_URL}/gradio_api/file=${serverFilePath}`,
654
- orig_name: file.name,
655
- };
656
-
657
- const sessionHash = generateSessionHash();
658
- const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
659
- method: 'POST',
660
- headers: { 'Content-Type': 'application/json' },
661
- body: JSON.stringify({ fn_index: 1, data: [fileDataObject], session_hash: sessionHash })
662
- });
663
- if (!joinResponse.ok) throw new Error(`خطا در ارسال به صف: ${joinResponse.statusText}`);
664
-
665
- listenForData(
666
- sessionHash,
667
- (result) => {
668
- decodedText.innerHTML = `<div class="decoded-result"><strong>متن خوانده شده:</strong><br>${result[0]}</div>`;
669
- },
670
- (error) => {
671
- alert(`خطا در پردازش: ${error}`);
672
- decodedText.innerHTML = '<span class="result-empty">خطا در خواندن کد.</span>';
673
- }
674
- );
675
- } catch (error) {
676
- alert(`یک خطا رخ داد: ${error.message}`);
677
- decodedText.innerHTML = '<span class="result-empty">خطا در پردازش فایل</span>';
678
- } finally {
679
- readLoader.style.display = 'none';
680
- readBtn.disabled = false;
681
  }
682
- });
683
-
684
- // افکت drag & drop برای فایل آپلود
685
- const fileUpload = document.querySelector('.file-upload');
686
-
687
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
688
- fileUpload.addEventListener(eventName, preventDefaults, false);
689
- });
690
-
691
- function preventDefaults(e) {
692
- e.preventDefault();
693
- e.stopPropagation();
694
- }
695
-
696
- ['dragenter', 'dragover'].forEach(eventName => {
697
- fileUpload.addEventListener(eventName, highlight, false);
698
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
699
 
700
- ['dragleave', 'drop'].forEach(eventName => {
701
- fileUpload.addEventListener(eventName, unhighlight, false);
 
 
 
702
  });
703
-
704
- function highlight(e) {
705
- fileUpload.style.borderColor = 'var(--accent-color)';
706
- fileUpload.style.background = 'rgba(100, 255, 218, 0.1)';
707
- }
708
-
709
- function unhighlight(e) {
710
- fileUpload.style.borderColor = 'var(--border-color)';
711
- fileUpload.style.background = 'var(--glass-bg)';
712
- }
713
-
714
- fileUpload.addEventListener('drop', handleDrop, false);
715
-
716
- function handleDrop(e) {
717
- const dt = e.dataTransfer;
718
- const files = dt.files;
719
-
720
- if (files.length > 0) {
721
- fileInput.files = files;
722
- fileInput.dispatchEvent(new Event('change'));
723
- }
724
- }
725
- </script>
726
  </body>
727
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="fa" dir="rtl">
3
  <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
6
+ <title>ابزار مدرن QR Code طراحی جدید</title>
7
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/rastikerdar/vazirmatn@v33.003/Vazirmatn-font-face.css">
8
+
9
+ <style>
10
+ :root{
11
+ --bg-1:#0f1226;
12
+ --bg-2:#1a1f3f;
13
+ --bg-3:#0b0f23;
14
+ --text:#eaf1ff;
15
+ --muted:#b2bdd6;
16
+
17
+ --accent-1:#8e44ad;
18
+ --accent-2:#3498db;
19
+ --accent-3:#00e676;
20
+
21
+ --card-bg:rgba(255,255,255,.06);
22
+ --card-bg-strong:rgba(255,255,255,.08);
23
+ --border:rgba(255,255,255,.14);
24
+ --divider:rgba(255,255,255,.08);
25
+
26
+ --shadow:0 18px 45px rgba(0,0,0,.35);
27
+ --radius:16px;
28
+ }
29
+
30
+ *{box-sizing:border-box}
31
+ html,body{height:100%}
32
+ body{
33
+ margin:0;
34
+ font-family:'Vazirmatn',system-ui,Segoe UI,Roboto,Arial,sans-serif;
35
+ color:var(--text);
36
+ background:
37
+ radial-gradient(1000px 600px at -10% 10%, rgba(124,77,255,.18), transparent 50%),
38
+ radial-gradient(800px 500px at 110% 110%, rgba(0,230,118,.12), transparent 50%),
39
+ linear-gradient(135deg, var(--bg-2), var(--bg-1) 40%, var(--bg-3));
40
+ overflow:hidden; /* اسکرول داخل هر پنل انجام می‌شود */
41
+ }
42
+
43
+ /* هدر مینیمال */
44
+ .topbar{
45
+ height:64px;
46
+ display:flex;
47
+ align-items:center;
48
+ justify-content:center;
49
+ gap:12px;
50
+ padding:0 16px;
51
+ position:relative;
52
+ z-index:2;
53
+ }
54
+ .topbar .logo{
55
+ inline-size:28px;
56
+ block-size:28px;
57
+ display:inline-flex;
58
+ align-items:center;
59
+ justify-content:center;
60
+ color:#fff;
61
+ background:linear-gradient(135deg, var(--accent-1), var(--accent-2));
62
+ border-radius:8px;
63
+ box-shadow:0 6px 18px rgba(52,152,219,.35), 0 4px 14px rgba(142,68,173,.25);
64
+ }
65
+ .topbar h1{
66
+ margin:0;
67
+ font-size:1.25rem;
68
+ font-weight:700;
69
+ letter-spacing:.2px;
70
+ color:#fff;
71
+ }
72
+ .topbar span{
73
+ font-weight:300;
74
+ color:var(--muted);
75
+ margin-inline-start:8px;
76
+ font-size:.95rem;
77
+ }
78
+
79
+ /* صفحه دو ستونه همیشه (حتی موبایل) */
80
+ .split{
81
+ display:grid;
82
+ grid-template-columns: 1fr 1fr; /* همیشه کنار هم */
83
+ height:calc(100dvh - 64px);
84
+ width:100%;
85
+ position:relative;
86
+ z-index:1;
87
+ }
88
+ .split::after{ /* خط جداکننده وسط */
89
+ content:"";
90
+ position:absolute;
91
+ inset-block:0;
92
+ inset-inline-start:50%;
93
+ width:1px;
94
+ background:linear-gradient(to bottom, transparent, var(--divider), transparent);
95
+ z-index:0;
96
+ }
97
+
98
+ /* پنل‌ها */
99
+ .panel{
100
+ position:relative;
101
+ padding:20px 16px;
102
+ display:flex;
103
+ align-items:center;
104
+ justify-content:center;
105
+ overflow:auto;
106
+ isolation:isolate;
107
+ }
108
+ .panel::before{ /* الگوی نقطه‌ای QR */
109
+ content:"";
110
+ position:absolute; inset:0;
111
+ background-image: radial-gradient(rgba(255,255,255,.09) 1px, transparent 1.2px);
112
+ background-size:20px 20px;
113
+ opacity:.45;
114
+ mask-image:linear-gradient(to bottom, rgba(0,0,0,.25), rgba(0,0,0,.9) 35%, rgba(0,0,0,.5));
115
+ pointer-events:none;
116
+ z-index:-1;
117
+ }
118
+
119
+ .panel.generate{
120
+ background:linear-gradient(180deg, transparent, rgba(142,68,173,.12));
121
+ }
122
+ .panel.read{
123
+ background:linear-gradient(180deg, transparent, rgba(52,152,219,.12));
124
+ }
125
+
126
+ /* کارت ابزار داخل هر پنل */
127
+ .tool-card{
128
+ width:min(540px, 92%);
129
+ background:var(--card-bg);
130
+ border:1px solid var(--border);
131
+ border-radius:var(--radius);
132
+ padding:18px;
133
+ box-shadow:var(--shadow);
134
+ backdrop-filter:blur(10px);
135
+ -webkit-backdrop-filter:blur(10px);
136
+ display:flex; flex-direction:column; gap:14px;
137
+ position:relative;
138
+ }
139
+
140
+ .tool-card .title{
141
+ display:flex; align-items:center; gap:10px;
142
+ border-bottom:1px solid var(--divider);
143
+ padding-bottom:10px; margin-bottom:6px;
144
+ }
145
+ .title .badge{
146
+ display:inline-flex; align-items:center; justify-content:center;
147
+ width:32px; height:32px; border-radius:10px; color:#fff;
148
+ box-shadow:0 8px 24px rgba(0,0,0,.25);
149
+ }
150
+ .generate .title .badge{ background:linear-gradient(135deg, var(--accent-1), var(--accent-2)); }
151
+ .read .title .badge{ background:linear-gradient(135deg, var(--accent-2), var(--accent-3)); }
152
+
153
+ .title h2{
154
+ margin:0; font-size:1.05rem; font-weight:700; color:#fff;
155
+ }
156
+ .subtitle{
157
+ font-size:.9rem; color:var(--muted); margin-top:-4px;
158
+ }
159
+
160
+ label{
161
+ font-size:.88rem; color:#cdd6f7; opacity:.9;
162
+ }
163
+
164
+ textarea, .input-like{
165
+ width:100%;
166
+ padding:12px 12px;
167
+ border-radius:12px;
168
+ border:1px solid var(--border);
169
+ background:var(--card-bg-strong);
170
+ color:var(--text);
171
+ font-size:1rem;
172
+ outline:none;
173
+ transition:.25s ease;
174
+ }
175
+ textarea::placeholder{ color:#93a0bf; }
176
+ textarea:focus, .input-like:focus-within{
177
+ border-color:color-mix(in oklab, var(--accent-2) 55%, white);
178
+ box-shadow:0 0 0 6px rgba(52,152,219,.08), 0 6px 24px rgba(52,152,219,.18);
179
+ }
180
+
181
+ .actions{
182
+ display:flex; gap:10px; flex-wrap:wrap; align-items:center;
183
+ }
184
+ button{
185
+ padding:12px 16px;
186
+ background:linear-gradient(135deg, var(--accent-1), var(--accent-2));
187
+ color:#fff;
188
+ border:none; border-radius:12px;
189
+ font-weight:700; cursor:pointer;
190
+ display:inline-flex; align-items:center; gap:10px;
191
+ transition:transform .15s ease, box-shadow .25s ease, filter .25s ease;
192
+ box-shadow:0 8px 22px rgba(142,68,173,.25), 0 8px 22px rgba(52,152,219,.22);
193
+ }
194
+ .read button{ background:linear-gradient(135deg, var(--accent-2), var(--accent-3)); }
195
+ button:hover:not(:disabled){ transform:translateY(-2px); filter:saturate(1.1); }
196
+ button:disabled{ opacity:.6; cursor:not-allowed; filter:saturate(.8); }
197
+
198
+ /* نتیجه‌ها */
199
+ .result-box{
200
+ margin-top:6px;
201
+ padding:16px;
202
+ background:rgba(255,255,255,.05);
203
+ border:1px solid var(--border);
204
+ border-radius:14px;
205
+ min-height:120px;
206
+ display:flex; align-items:center; justify-content:center;
207
+ text-align:center; word-wrap:break-word;
208
+ position:relative; overflow:hidden;
209
+ }
210
+
211
+ /* نمایش QR */
212
+ #qr-code-display img{
213
+ max-width:100%;
214
+ height:auto;
215
+ border-radius:10px;
216
+ border:2px solid rgba(255,255,255,.9);
217
+ box-shadow:0 14px 32px rgba(0,0,0,.35);
218
+ animation:fadeIn .45s ease-in-out both;
219
+ }
220
+ @keyframes fadeIn{
221
+ from{opacity:0; transform:scale(.96)}
222
+ to{opacity:1; transform:scale(1)}
223
+ }
224
+
225
+ /* اسپینر */
226
+ .loader{
227
+ border:3px solid rgba(255,255,255,.26);
228
+ border-top:3px solid var(--accent-2);
229
+ border-right:3px solid var(--accent-1);
230
+ border-radius:50%;
231
+ width:28px; height:28px;
232
+ animation:spin 1s linear infinite;
233
+ display:none;
234
+ }
235
+ @keyframes spin{ to{ transform:rotate(360deg) } }
236
+
237
+ /* Drop Zone برای خواندن QR */
238
+ .drop-zone{
239
+ width:100%;
240
+ background:var(--card-bg-strong);
241
+ border:1.5px dashed color-mix(in oklab, var(--accent-2) 65%, #fff 10%);
242
+ border-radius:12px;
243
+ padding:14px;
244
+ display:flex; align-items:center; justify-content:center; gap:10px;
245
+ color:#d7e0ff;
246
+ cursor:pointer;
247
+ transition: border-color .2s ease, box-shadow .25s ease, background .25s ease;
248
+ }
249
+ .drop-zone:hover{
250
+ border-color:color-mix(in oklab, var(--accent-3) 65%, white 10%);
251
+ box-shadow:0 0 0 6px rgba(0,230,118,.08), inset 0 0 30px rgba(0,230,118,.06);
252
+ background:rgba(0,0,0,.18);
253
+ }
254
+ .drop-zone.dragging{
255
+ border-color:var(--accent-3);
256
+ box-shadow:0 0 0 6px rgba(0,230,118,.1), inset 0 0 45px rgba(0,230,118,.08);
257
+ background:rgba(0,0,0,.22);
258
+ }
259
+ .file-name{
260
+ margin:0; font-size:.86rem; color:#bdc8ea; opacity:.9;
261
+ }
262
+ input[type="file"]{ display:none; }
263
+
264
+ /* متن خروجی */
265
+ #decoded-text{
266
+ margin:0; white-space:pre-wrap; line-height:1.6;
267
+ }
268
+
269
+ /* گوشه‌های اسکنر تزئینی */
270
+ .corners{
271
+ pointer-events:none;
272
+ position:absolute; inset:8px;
273
+ display:grid; grid-template-columns: 1fr 1fr;
274
+ grid-template-rows: 1fr 1fr;
275
+ }
276
+ .corner{
277
+ width:26px; height:26px; border:2px solid rgba(255,255,255,.85);
278
+ border-radius:6px;
279
+ }
280
+ .corner.tl{ justify-self:start; align-self:start; border-right:none; border-bottom:none; }
281
+ .corner.tr{ justify-self:end; align-self:start; border-left:none; border-bottom:none; }
282
+ .corner.bl{ justify-self:start; align-self:end; border-right:none; border-top:none; }
283
+ .corner.br{ justify-self:end; align-self:end; border-left:none; border-top:none; }
284
+
285
+ /* اسکرول‌بار لطیف داخل پنل‌ها */
286
+ .panel::-webkit-scrollbar{ width:10px; height:10px; }
287
+ .panel::-webkit-scrollbar-thumb{
288
+ background:linear-gradient(180deg, rgba(142,68,173,.45), rgba(52,152,219,.45));
289
+ border-radius:10px;
290
+ }
291
+ .panel::-webkit-scrollbar-track{ background:transparent; }
292
+
293
+ /* ریزبهینه‌سازی اندازه فونت در خیلی عرض کم */
294
+ @media (max-width: 380px){
295
+ .title h2{ font-size:1rem }
296
+ textarea{ font-size:.95rem }
297
+ button{ font-size:.95rem }
298
+ }
299
+ </style>
300
+ </head>
301
+ <body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302
 
303
+ <header class="topbar">
304
+ <div class="logo" aria-hidden="true">
305
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="currentColor"><path d="M3 3h8v8H3zM5 5v4h4V5H5zM13 3h8v8h-8zM15 5v4h4V5h-4zM3 13h8v8H3zM5 15v4h4v-4H5zM13 13h3v3h-3zM17 13h4v4h-4zM13 17h3v4h-3zM17 21v-3h4v3z"/></svg>
306
+ </div>
307
+ <h1>ابزار مدرن QR Code <span>— ساخت و خواندن کنار هم</span></h1>
308
+ </header>
309
+
310
+ <main class="split">
311
+ <!-- پنل ساخت QR -->
312
+ <section class="panel generate">
313
+ <div class="tool-card">
314
+ <div class="title">
315
+ <div class="badge" aria-hidden="true">
316
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" fill="currentColor" viewBox="0 0 24 24"><path d="M3 3h8v8H3zM5 5v4h4V5H5zM13 3h8v8h-8zM15 5v4h4V5h-4zM3 13h8v8H3zM5 15v4h4v-4H5z"/></svg>
317
+ </div>
318
+ <div>
319
+ <h2>ساخت QR Code از متن</h2>
320
+ <div class="subtitle">متن یا لینک خود را بنویسید و یک QR براق تحویل بگیرید ✨</div>
321
+ </div>
322
+ </div>
323
 
324
+ <label for="text-input">متن خود را وارد کنید:</label>
325
+ <textarea id="text-input" rows="4" placeholder="مثلا: https://example.com">سلام دنیا</textarea>
 
 
 
 
 
 
 
 
 
 
 
 
326
 
327
+ <div class="actions">
328
+ <button id="generate-btn" title="ساخت QR Code">
329
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2v0z"/><path d="M12 8l4 4-4 4"/><path d="M8 12h7"/></svg>
330
+ <span>ساخت QR Code</span>
331
+ </button>
332
+ </div>
333
 
334
+ <div class="result-box">
335
+ <div id="generate-loader" class="loader"></div>
336
+ <div id="qr-code-display"></div>
337
+ <div class="corners" aria-hidden="true">
338
+ <div class="corner tl"></div>
339
+ <div class="corner tr"></div>
340
+ <div class="corner bl"></div>
341
+ <div class="corner br"></div>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ </section>
346
+
347
+ <!-- پنل خواندن QR -->
348
+ <section class="panel read">
349
+ <div class="tool-card">
350
+ <div class="title">
351
+ <div class="badge" aria-hidden="true">
352
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
353
+ </div>
354
+ <div>
355
+ <h2>خواندن متن از QR Code</h2>
356
+ <div class="subtitle">تصویر QR را بکشید و رها کنید یا فایل را انتخاب کنید</div>
357
+ </div>
358
+ </div>
359
 
360
+ <label for="file-input">فایل تصویر QR Code را انتخاب کنید:</label>
361
+ <div id="drop-zone" class="drop-zone">
362
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/></svg>
363
+ <span>کلیک کنید یا فایل را اینجا رها کنید</span>
364
+ <input type="file" id="file-input" accept="image/*" />
365
+ </div>
366
+ <p id="file-name" class="file-name"></p>
367
 
368
+ <div class="actions">
369
+ <button id="read-btn" title="خواندن QR Code">
370
+ <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" stroke="currentColor" fill="none" stroke-width="2" viewBox="0 0 24 24"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/></svg>
371
+ <span>خواندن QR Code</span>
372
+ </button>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  </div>
 
374
 
375
+ <div class="result-box">
376
+ <div id="read-loader" class="loader"></div>
377
+ <p id="decoded-text">نتیجه در اینجا نمایش داده می‌شود.</p>
378
+ <div class="corners" aria-hidden="true">
379
+ <div class="corner tl"></div>
380
+ <div class="corner tr"></div>
381
+ <div class="corner bl"></div>
382
+ <div class="corner br"></div>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ </section>
387
+ </main>
388
+
389
+ <script>
390
+ const SPACE_URL = "https://cultrix-qrcode-read-generate.hf.space";
391
+
392
+ // عناصر DOM
393
+ const generateBtn = document.getElementById('generate-btn');
394
+ const readBtn = document.getElementById('read-btn');
395
+ const textInput = document.getElementById('text-input');
396
+ const fileInput = document.getElementById('file-input');
397
+ const qrCodeDisplay = document.getElementById('qr-code-display');
398
+ const decodedText = document.getElementById('decoded-text');
399
+ const generateLoader = document.getElementById('generate-loader');
400
+ const readLoader = document.getElementById('read-loader');
401
+ const fileNameDisplay = document.getElementById('file-name');
402
+ const dropZone = document.getElementById('drop-zone');
403
+
404
+ // نمایش نام فایل هنگام انتخاب
405
+ fileInput.addEventListener('change', () => {
406
+ if (fileInput.files.length > 0) {
407
+ fileNameDisplay.textContent = `فایل انتخاب شده: ${fileInput.files[0].name}`;
408
+ } else {
409
+ fileNameDisplay.textContent = '';
410
+ }
411
+ });
412
+
413
+ // Drop Zone رفتار
414
+ dropZone.addEventListener('click', () => fileInput.click());
415
+ dropZone.addEventListener('dragover', (e) => {
416
+ e.preventDefault();
417
+ dropZone.classList.add('dragging');
418
+ });
419
+ dropZone.addEventListener('dragleave', () => {
420
+ dropZone.classList.remove('dragging');
421
+ });
422
+ dropZone.addEventListener('drop', (e) => {
423
+ e.preventDefault();
424
+ dropZone.classList.remove('dragging');
425
+ const file = e.dataTransfer.files?.[0];
426
+ if (file) {
427
+ const dt = new DataTransfer();
428
+ dt.items.add(file);
429
+ fileInput.files = dt.files;
430
+ fileNameDisplay.textContent = `فایل انتخاب شده: ${file.name}`;
431
+ }
432
+ });
433
+
434
+ // توابع کمکی
435
+ const generateSessionHash = () => Math.random().toString(36).substring(2, 15);
436
+
437
+ const listenForData = (sessionHash, onResult, onError) => {
438
+ const eventSource = new EventSource(`${SPACE_URL}/gradio_api/queue/data?session_hash=${sessionHash}`);
439
+
440
+ eventSource.onmessage = (event) => {
441
+ try {
442
+ const data = JSON.parse(event.data);
443
+ if (data.msg === "process_completed") {
444
+ eventSource.close();
445
+ if (data.output?.error) {
446
+ onError(data.output.error);
447
  } else {
448
+ onResult(data.output.data);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
449
  }
450
+ } else if (data.msg === "process_failed") {
451
+ eventSource.close();
452
+ onError("پردازش با خطا مواجه شد.");
453
+ }
454
+ } catch (e) {
455
+ // در برخی پیام‌های keep-alive داده خالی است
456
+ }
457
+ };
458
+
459
+ eventSource.onerror = (err) => {
460
+ console.error("EventSource failed:", err);
461
+ eventSource.close();
462
+ onError("خطا در ارتباط با سرور.");
463
+ };
464
+ };
465
+
466
+ // ساخت QR
467
+ generateBtn.addEventListener('click', async () => {
468
+ const text = textInput.value.trim();
469
+ if (!text) return alert("لطفاً متنی را وارد کنید.");
470
+
471
+ generateLoader.style.display = 'inline-block';
472
+ qrCodeDisplay.innerHTML = '';
473
+ generateBtn.disabled = true;
474
+
475
+ const sessionHash = generateSessionHash();
476
+
477
+ try {
478
+ const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
479
+ method: 'POST',
480
+ headers: { 'Content-Type': 'application/json' },
481
+ body: JSON.stringify({ fn_index: 0, data: [text], session_hash: sessionHash })
482
  });
483
 
484
+ if (!joinResponse.ok) throw new Error(`خطا در ارسال درخواست: ${joinResponse.statusText}`);
 
 
 
 
 
 
485
 
486
+ listenForData(
487
+ sessionHash,
488
+ (result) => {
489
+ if (result && result[0]) {
490
+ qrCodeDisplay.innerHTML = result[0];
491
+ } else {
492
+ qrCodeDisplay.innerText = "خطا: خروجی معتبر دریافت نشد.";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
493
  }
494
+ },
495
+ (error) => {
496
+ alert(`خطا در پردازش: ${error}`);
497
+ qrCodeDisplay.innerText = "خطا در ساخت تصویر.";
498
+ }
499
+ );
500
+ } catch (error) {
501
+ alert(`یک خطا رخ داد: ${error.message}`);
502
+ } finally {
503
+ generateLoader.style.display = 'none';
504
+ generateBtn.disabled = false;
505
+ }
506
+ });
507
+
508
+ // خواندن QR
509
+ readBtn.addEventListener('click', async () => {
510
+ const file = fileInput.files[0];
511
+ if (!file) return alert("لطفاً یک فایل تصویر انتخاب کنید.");
512
+
513
+ readLoader.style.display = 'inline-block';
514
+ decodedText.innerText = '';
515
+ readBtn.disabled = true;
516
+
517
+ try {
518
+ const formData = new FormData();
519
+ formData.append('files', file);
520
+
521
+ const uploadResponse = await fetch(`${SPACE_URL}/gradio_api/upload`, { method:'POST', body: formData });
522
+ if (!uploadResponse.ok) throw new Error(`خطا در آپلود فایل: ${uploadResponse.statusText}`);
523
+
524
+ const uploadResult = await uploadResponse.json();
525
+ const serverFilePath = uploadResult[0];
526
+
527
+ const fileDataObject = {
528
+ path: serverFilePath,
529
+ url: `${SPACE_URL}/gradio_api/file=${serverFilePath}`,
530
+ orig_name: file.name,
531
+ };
532
 
533
+ const sessionHash = generateSessionHash();
534
+ const joinResponse = await fetch(`${SPACE_URL}/gradio_api/queue/join`, {
535
+ method:'POST',
536
+ headers:{ 'Content-Type':'application/json' },
537
+ body: JSON.stringify({ fn_index: 1, data: [fileDataObject], session_hash: sessionHash })
538
  });
539
+ if (!joinResponse.ok) throw new Error(`خطا در ارسال به صف: ${joinResponse.statusText}`);
540
+
541
+ listenForData(
542
+ sessionHash,
543
+ (result) => {
544
+ decodedText.innerText = `متن خوانده شده:\n${result?.[0] ?? ''}`;
545
+ },
546
+ (error) => {
547
+ alert(`خطا در پردازش: ${error}`);
548
+ decodedText.innerText = "خطا در خواندن کد.";
549
+ }
550
+ );
551
+ } catch (error) {
552
+ alert(`یک خطا رخ داد: ${error.message}`);
553
+ decodedText.innerText = "نتیجه در اینجا نمایش داده می‌شود.";
554
+ } finally {
555
+ readLoader.style.display = 'none';
556
+ readBtn.disabled = false;
557
+ }
558
+ });
559
+ </script>
 
 
560
  </body>
561
  </html>