protae5544 commited on
Commit
1482483
·
verified ·
1 Parent(s): 006afa7

Delete index.html

Browse files
Files changed (1) hide show
  1. index.html +0 -737
index.html DELETED
@@ -1,737 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="th">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width,initial-scale=1.0">
6
- <title>AI Chat - Typhoon & Qwen2.5-Coder</title>
7
- <script src="https://cdn.tailwindcss.com"></script>
8
-
9
- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/vs.min.css">
10
- <style>
11
- html, body { height: 100%; margin: 0; }
12
- body {
13
- font-family: 'IBM Plex Mono', 'Consolas', 'Courier New', monospace;
14
- background: #008080;
15
- height: 100vh;
16
- margin: 0;
17
- display: flex;
18
- flex-direction: column;
19
- align-items: center;
20
- justify-content: center;
21
- min-height: 100vh;
22
- }
23
- .win95window {
24
- background: #c0c0c0;
25
- border: 2px solid #fff;
26
- border-bottom: 2px solid #808080;
27
- border-right: 2px solid #808080;
28
- box-shadow: 4px 8px 0px #0008, 0 0 0 8px #6664;
29
- min-width: 320px;
30
- max-width: 500px;
31
- width: 100%;
32
- min-height: 600px;
33
- display: flex;
34
- flex-direction: column;
35
- position: relative;
36
- transition: all 0.29s cubic-bezier(.4,.85,.59,1.02);
37
- z-index: 1;
38
- }
39
- .win95window.fullscreen {
40
- position: ;
41
- left: 0; top: 0; right: 0; bottom: 0;
42
- min-width: 100vw; min-height: 100vh; max-width: none; max-height: none;
43
- width: 100vw; height: 100vh;
44
- border-radius: 0;
45
- box-shadow: none;
46
- z-index: 9999;
47
- }
48
- .win95titlebar {
49
- background: linear-gradient(90deg, #000080 80%, #1080c0 100%);
50
- color: #fff;
51
- padding: 7px 10px 7px 10px;
52
- font-weight: bold;
53
- font-size: 1.05em;
54
- letter-spacing: .5px;
55
- display: flex;
56
- align-items: center;
57
- justify-content: space-between;
58
- border-bottom: 2px solid #808080;
59
- user-select: none;
60
- }
61
- .win95titlebar .title {
62
- display: flex;
63
- align-items: center;
64
- gap: 10px;
65
- }
66
- .win95titlebar .win95controls {
67
- display: flex;
68
- gap: 2px;
69
- }
70
- .win95titlebar button {
71
- width: 18px; height: 18px; font-size: 1em;
72
- border: 2px outset #fff;
73
- background: #c0c0c0;
74
- color: #000;
75
- line-height: 1;
76
- cursor: pointer;
77
- outline: none;
78
- margin-left: 2px;
79
- padding: 0;
80
- border-radius: 0;
81
- }
82
- .win95titlebar button:active {
83
- border: 2px inset #808080;
84
- background: #aaa;
85
- }
86
- .win95titlebar button:focus { outline: 1px dotted #fff; }
87
- .win95content {
88
- flex: 1 1 0%;
89
- overflow: hidden;
90
- display: flex;
91
- flex-direction: column;
92
- padding: 0;
93
- min-height: 0;
94
- }
95
- .settings95 {
96
- background: #e0e0e0;
97
- border-bottom: 2px solid #808080;
98
- padding: 10px 12px;
99
- display: flex;
100
- flex-wrap: wrap;
101
- align-items: center;
102
- font-size: 0.98em;
103
- gap: 8px;
104
- }
105
- .settings95 label {
106
- margin-right: 2px;
107
- }
108
- .settings95 select,
109
- .settings95 input[type="text"] {
110
- font-family: inherit;
111
- font-size: 1em;
112
- background: #fff;
113
- border: 2px inset #808080;
114
- padding: 2px 6px;
115
- outline: none;
116
- min-width: 96px;
117
- max-width: 170px;
118
- }
119
- .settings95 input[type="text"]#apiKey95 {
120
- min-width: 180px;
121
- width: 150px;
122
- max-width: 99vw;
123
- }
124
- .settings95 button {
125
- font-family: inherit;
126
- font-size: 1em;
127
- background: #e0e0e0;
128
- border: 2px outset #fff;
129
- color: #000;
130
- padding: 2.5px 14px;
131
- margin-left: 2px;
132
- cursor: pointer;
133
- border-radius: 0;
134
- }
135
- .settings95 button:active {
136
- border: 2px inset #808080;
137
- background: #c0c0c0;
138
- }
139
- .settings95 button:focus { outline: 1px dotted #fff; }
140
- .settings95 .api-status {
141
- font-size: 0.95em;
142
- color: #008000;
143
- margin-left: 4px;
144
- min-width: 80px;
145
- }
146
- .system-preset-area {
147
- background: #f0f0f0;
148
- border-bottom: 2px solid #808080;
149
- padding: 8px 12px;
150
- display: flex;
151
- flex-wrap: wrap;
152
- align-items: center;
153
- font-size: 0.95em;
154
- gap: 8px;
155
- }
156
- .system-preset-area label {
157
- margin-right: 4px;
158
- font-weight: bold;
159
- }
160
- .system-preset-area select {
161
- font-family: inherit;
162
- font-size: 1em;
163
- background: #fff;
164
- border: 2px inset #808080;
165
- padding: 2px 6px;
166
- outline: none;
167
- min-width: 120px;
168
- max-width: 200px;
169
- }
170
- .chat-container95 {
171
- flex: 1 1 0%;
172
- overflow-y: auto;
173
- background: #fff;
174
- padding: 16px 8px;
175
- border-top: 2px solid #fff;
176
- border-bottom: 2px solid #808080;
177
- display: flex;
178
- flex-direction: column;
179
- gap: 8px;
180
- font-size: 1.01em;
181
- min-height: 0;
182
- }
183
- .message95 {
184
- max-width: 95%; word-break: break-word;
185
- border: 2px solid #fff;
186
- border-bottom: 2px solid #808080;
187
- border-right: 2px solid #808080;
188
- background: #e0e0e0;
189
- margin-bottom: 0;
190
- padding: 7px 10px;
191
- border-radius: 0;
192
- box-shadow: 2px 2px 0 #b0b0b0;
193
- min-width: 70px;
194
- position: relative;
195
- }
196
- .message95.ai { align-self: flex-start; background: #fffffe; }
197
- .message95.user { align-self: flex-end; background: #c0e0ff; }
198
- .message95 .image-preview { max-width: 200px; margin: 8px 0; border: 2px inset #808080; }
199
- .message95 pre { background: #fff; border: 2px inset #808080; padding: 9px 5px 15px 5px; position: relative; white-space: pre-wrap; word-break: break-all; margin-bottom: 10px; margin-top: 7px; overflow-x: auto; }
200
- .code-tools { position: absolute; right: 7px; top: 5px; z-index: 2; display: flex; gap: 3px; }
201
- .code-tools button { font-size: 0.95em; padding: 1.5px 7px; background: #e0e0e0; border: 2px outset #fff; border-radius: 0; cursor: pointer; color: #222; }
202
- .code-tools button:active { border: 2px inset #808080; background: #c0c0c0; }
203
- .code-tools button:disabled { color: #aaa; border-color: #b0b0b0; }
204
- .input-area95 {
205
- background: #e0e0e0;
206
- border-top: 2px solid #fff;
207
- padding: 10px 10px 10px 10px;
208
- display: flex;
209
- gap: 10px;
210
- align-items: stretch;
211
- flex-wrap: wrap;
212
- position: relative;
213
- }
214
- .input-area95 input[type="text"] {
215
- font-family: inherit;
216
- font-size: 1em;
217
- border: 2px inset #808080;
218
- background: #fff;
219
- flex: 1 1 0%;
220
- padding: 4px 8px;
221
- min-width: 0;
222
- }
223
- .input-area95 button {
224
- font-family: inherit;
225
- font-size: 1em;
226
- background: #e0e0e0;
227
- border: 2px outset #fff;
228
- color: #000;
229
- padding: 3px 18px;
230
- cursor: pointer;
231
- border-radius: 0;
232
- }
233
- .input-area95 button:active {
234
- border: 2px inset #808080;
235
- background: #c0c0c0;
236
- }
237
- .input-area95 button:disabled {
238
- background: #e0e0e0;
239
- color: #aaa;
240
- border: 2px outset #b0b0b0;
241
- cursor: not-allowed;
242
- }
243
- .input-area95 .file-attach-btn {
244
- position: relative;
245
- overflow: hidden;
246
- padding: 3px 8px;
247
- font-size: 1em;
248
- min-width: 1.5em;
249
- border: 2px outset #fff;
250
- background: #e0e0e0;
251
- color: #333;
252
- border-radius: 0;
253
- cursor: pointer;
254
- margin-right: 0;
255
- margin-left: 0;
256
- }
257
- .input-area95 .file-attach-btn input[type="file"] {
258
- position: absolute;
259
- left: 0; top: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer;
260
- }
261
- .input-area95 .file-attach-btn:active { border: 2px inset #808080; background: #c0c0c0; }
262
- .input-area95 .file-name {
263
- font-size: 0.98em; color: #333; margin-left: 5px; align-self: center; max-width: 110px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
264
- }
265
- .dropzone95 {
266
- border: 2px dashed #008080;
267
- background: #e6ffff;
268
- color: #008080;
269
- text-align: center;
270
- font-size: 1.05em;
271
- padding: 24px 5px 18px;
272
- border-radius: 8px;
273
- margin: 12px 5px;
274
- transition: background 0.2s;
275
- display: none;
276
- z-index: 99;
277
- position: absolute;
278
- left: 0; right: 0; top: 0; bottom: 0;
279
- pointer-events: all;
280
- }
281
- .error-message95 {
282
- color: #b00;
283
- background: #fff3f3;
284
- border: 1px solid #d99;
285
- padding: 7px 10px 7px 30px;
286
- margin: 0;
287
- font-size: 0.98em;
288
- min-height: 20px;
289
- background-image: url('data:image/svg+xml;utf8,<svg width="16" height="16" fill="red" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" r="7" fill="white" stroke="red" stroke-width="1"/><text x="8" y="12" text-anchor="middle" font-size="12" fill="red" font-family="Arial" dy="-2">!</text></svg>');
290
- background-repeat: no-repeat;
291
- background-position: 6px 7px;
292
- background-size: 16px 16px;
293
- }
294
- #contextSaveArea95 {
295
- padding: 10px 10px 12px;
296
- background: #f8f8e0;
297
- border-top: 2px solid #fff;
298
- border-bottom: 2px solid #808080;
299
- display: none;
300
- font-size: 0.98em;
301
- }
302
- #contextSaveArea95 h4 { margin: 0 0 8px 0; color: #444; font-size: 1.08em; }
303
- #contextSaveArea95 pre {
304
- background: #fff;
305
- border: 2px inset #808080;
306
- padding: 8px 5px;
307
- font-size: 0.95em;
308
- max-height: 120px;
309
- overflow: auto;
310
- margin: 7px 0;
311
- white-space: pre-wrap;
312
- word-break: break-all;
313
- }
314
- #contextSaveArea95 label { font-weight: bold; }
315
- #contextSaveArea95 input[type="text"] {
316
- width: 98%;
317
- min-width: 0;
318
- border: 2px inset #808080;
319
- background: #fff;
320
- font-size: 1em;
321
- margin-bottom: 3px;
322
- padding: 4px 8px;
323
- }
324
- #contextSaveArea95 button {
325
- margin-top: 6px;
326
- font-size: 1em;
327
- background: #e0e0e0;
328
- border: 2px outset #fff;
329
- color: #000;
330
- padding: 2.5px 14px;
331
- cursor: pointer;
332
- border-radius: 0;
333
- }
334
- #contextSaveArea95 button:active { background: #c0c0c0; border: 2px inset #808080; }
335
- #contextSaveArea95 button:disabled { background: #e0e0e0; color: #bbb; border: 2px outset #b0b0b0; }
336
- .model-pair-selection {
337
- background: #f8f8f8;
338
- border-bottom: 2px solid #808080;
339
- padding: 8px 12px;
340
- display: flex;
341
- flex-wrap: wrap;
342
- align-items: center;
343
- font-size: 0.95em;
344
- gap: 8px;
345
- }
346
- .model-pair-selection label {
347
- margin-right: 4px;
348
- font-weight: bold;
349
- color: #444;
350
- }
351
- .model-pair-selection select {
352
- font-family: inherit;
353
- font-size: 1em;
354
- background: #fff;
355
- border: 2px inset #808080;
356
- padding: 2px 6px;
357
- outline: none;
358
- min-width: 120px;
359
- max-width: 180px;
360
- }
361
- @media (max-width: 650px) {
362
- .win95window {
363
- min-width: 0;
364
- max-width: 98vw;
365
- box-shadow: 1px 2px 0px #0006, 0 0 0 2px #6664;
366
- }
367
- .win95content { padding: 0; }
368
- .settings95 {
369
- flex-direction: column;
370
- align-items: flex-start;
371
- gap: 4px;
372
- padding: 8px 4px;
373
- }
374
- .system-preset-area {
375
- flex-direction: column;
376
- align-items: flex-start;
377
- gap: 4px;
378
- padding: 6px 4px;
379
- }
380
- .model-pair-selection {
381
- flex-direction: column;
382
- align-items: flex-start;
383
- gap: 4px;
384
- padding: 6px 4px;
385
- }
386
- .input-area95 {
387
- flex-direction: column;
388
- gap: 8px;
389
- padding: 8px 4px;
390
- }
391
- .chat-container95 {
392
- padding: 10px 2px;
393
- font-size: 0.98em;
394
- }
395
- .dropzone95 {
396
- font-size: 1em;
397
- padding: 20px 2px 14px;
398
- }
399
- }
400
- </style>
401
- </head>
402
- <body>
403
- <div class="win95window" id="win95window">
404
- <div class="win95titlebar" id="titlebar">
405
- <div class="title">
406
- <span style="display:inline-block;width:18px;height:18px;background:#fff;border:1px solid #808080;margin-right:7px;box-shadow:inset 2px 2px #c0c0c0;">
407
- <span style="display:inline-block;width:9px;height:9px;background:#008080;margin:4px 0 0 4px;vertical-align:middle;"></span>
408
- </span>
409
- AI Chat - Typhoon & Qwen2.5-Coder
410
- </div>
411
- <div class="win95controls">
412
- <button id="maximizeBtn" title="เต็มจอ">&#9633;</button>
413
- <button onclick="window.location.reload()" title="รีเฟรช">&#9632;</button>
414
- <button onclick="window.close()" title="ปิด">&#10006;</button>
415
- </div>
416
- </div>
417
- <div class="win95content">
418
- <form class="settings95" id="settingsForm95" autocomplete="off" onsubmit="return false;">
419
- <label for="apiKey95">HuggingFace API Key:</label>
420
- <input type="text" id="apiKey95" placeholder="กรอก HuggingFace API Key">
421
- <button id="confirmApiKeyBtn95" type="button">บันทึก</button>
422
- <span class="api-status" id="apiKeyStatus95"></span>
423
- </form>
424
-
425
- <div class="model-pair-selection" id="multiModalSelection">
426
- <label for="modelSelect95">เลือกโมเดล:</label>
427
- <select id="modelSelect95">
428
- <option value="scb10x/typhoon-v1.5x-72b-instruct">Typhoon OCR 72B</option>
429
- <option value="Qwen/Qwen2.5-Coder-32B-Instruct">Qwen2.5-Coder 32B</option>
430
- </select>
431
- </div>
432
-
433
- <div class="system-preset-area">
434
- <label for="systemPresetSelect95">ระบบ:</label>
435
- <select id="systemPresetSelect95">
436
- <option value="general">แชทธรรมดา</option>
437
- <option value="code-full">ส่งโค้ดเต็ม</option>
438
- <option value="code-function">ส่งเฉพาะฟังก์ชัน</option>
439
- <option value="multimodal">Multi-Modal Analysis</option>
440
- <option value="custom">กำหนดเอง</option>
441
- </select>
442
- <input type="text" id="customSystemPrompt95" placeholder="ใส่ System Prompt ของคุณ" style="display:none; flex: 1; min-width: 200px;">
443
- </div>
444
-
445
- <div id="contextSaveArea95">
446
- <h4>Context ปัจจุบัน</h4>
447
- <div id="warningMessage95" style="color:orange;font-weight:bold;"></div>
448
- <div>โค้ดล่าสุดที่ตรวจพบ:</div>
449
- <pre id="savedCodeDisplay95">ยังไม่พบโค้ด หรือโค้ดยังไม่แสดง</pre>
450
- <label for="goalInput95">สรุปเป้าหมาย/คำอธิบาย:</label>
451
- <input type="text" id="goalInput95" placeholder="เช่น เพิ่มระบบล็อกอิน">
452
- <button id="confirmSaveBtn95">ยืนยัน context และเริ่มแชทใหม่</button>
453
- </div>
454
- <div class="chat-container95" id="messagesDiv95">
455
- <div class="message95 ai">สวัสดี! AI Chat พร้อมใช้งาน 🎉<br>เลือกระหว่าง Typhoon OCR 72B หรือ Qwen2.5-Coder 32B!</div>
456
- </div>
457
- <form id="chatForm95" class="input-area95" autocomplete="off">
458
- <button type="button" class="file-attach-btn" id="fileAttachBtn" title="แนบไฟล์">
459
- 📎<input type="file" id="fileInput" multiple accept="image/*,text/*,.pdf,.docx,.xlsx">
460
- </button>
461
- <span class="file-name" id="fileName"></span>
462
- <input type="text" id="userInput95" placeholder="พิมพ์คำถามหรือข้อความ..." autocomplete="off">
463
- <button type="submit">ส่ง</button>
464
- <div class="dropzone95" id="dropzone95">วางไฟล์ที่นี่เพื่อแนบ</div>
465
- </form>
466
- <div id="errorMessage95" class="error-message95"></div>
467
- </div>
468
- </div>
469
- <script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
470
- <script>
471
- // --- ฟีเจอร์ Fullscreen ---
472
- const win95window = document.getElementById('win95window');
473
- const maximizeBtn = document.getElementById('maximizeBtn');
474
- let isFullscreen = false;
475
-
476
- maximizeBtn.onclick = function() {
477
- isFullscreen = !isFullscreen;
478
- win95window.classList.toggle('fullscreen', isFullscreen);
479
- maximizeBtn.innerHTML = isFullscreen ? "&#9632;" : "&#9633;";
480
- maximizeBtn.title = isFullscreen ? "คืนหน้าต่าง" : "เต็มจอ";
481
- };
482
-
483
- // --- API Setup ---
484
- const apiKeyInput = document.getElementById('apiKey95');
485
- const confirmApiKeyBtn = document.getElementById('confirmApiKeyBtn95');
486
- const apiKeyStatus = document.getElementById('apiKeyStatus95');
487
- const messagesDiv = document.getElementById('messagesDiv95');
488
- const userInput = document.getElementById('userInput95');
489
- const chatForm = document.getElementById('chatForm95');
490
- const errorMessageDiv = document.getElementById('errorMessage95');
491
- const systemPresetSelect = document.getElementById('systemPresetSelect95');
492
- const customSystemPromptInput = document.getElementById('customSystemPrompt95');
493
- const contextSaveArea = document.getElementById('contextSaveArea95');
494
- const savedCodeDisplay = document.getElementById('savedCodeDisplay95');
495
- const goalInput = document.getElementById('goalInput95');
496
- const confirmSaveBtn = document.getElementById('confirmSaveBtn95');
497
- const fileInput = document.getElementById('fileInput');
498
- const fileNameSpan = document.getElementById('fileName');
499
- const dropzone = document.getElementById('dropzone95');
500
- const modelSelect = document.getElementById('modelSelect95');
501
-
502
- let currentApiKey = '';
503
- let conversationHistory = [];
504
- let attachedFiles = []; // Stores file objects
505
- let lastDetectedCode = '';
506
- let savedGoal = '';
507
-
508
- // --- Save/Load API Key from Local Storage ---
509
- function saveApiKey(key) {
510
- localStorage.setItem('huggingface_apiKey', key);
511
- updateApiKeyStatus(true);
512
- }
513
-
514
- function loadApiKey() {
515
- return localStorage.getItem('huggingface_apiKey') || '';
516
- }
517
-
518
- function updateApiKeyStatus(isSuccess) {
519
- if (isSuccess) {
520
- apiKeyStatus.textContent = "บันทึกแล้ว!";
521
- apiKeyStatus.style.color = '#008000';
522
- } else {
523
- apiKeyStatus.textContent = "ไม่ได้บันทึก";
524
- apiKeyStatus.style.color = '#b00';
525
- }
526
- setTimeout(() => apiKeyStatus.textContent = '', 3000);
527
- }
528
-
529
- confirmApiKeyBtn.addEventListener('click', () => {
530
- currentApiKey = apiKeyInput.value.trim();
531
- saveApiKey(currentApiKey);
532
- });
533
-
534
- // Initialize API key on load
535
- apiKeyInput.value = loadApiKey();
536
- currentApiKey = apiKeyInput.value.trim();
537
-
538
- // --- System Preset and Custom Prompt ---
539
- systemPresetSelect.addEventListener('change', (event) => {
540
- if (event.target.value === 'custom') {
541
- customSystemPromptInput.style.display = 'block';
542
- } else {
543
- customSystemPromptInput.style.display = 'none';
544
- }
545
- });
546
-
547
- // --- Chat Message Display ---
548
- function addMessage(text, sender, imageUrl = null, codeLanguage = null) {
549
- const messageDiv = document.createElement('div');
550
- messageDiv.classList.add('message95', sender);
551
-
552
- if (imageUrl) {
553
- const img = document.createElement('img');
554
- img.src = imageUrl;
555
- img.classList.add('image-preview');
556
- messageDiv.appendChild(img);
557
- }
558
-
559
- // Check for code blocks and apply highlighting
560
- const codeBlockRegex = /```(\w+)?\n([\s\S]+?)\n```/g;
561
- let lastIndex = 0;
562
- let match;
563
- let contentHtml = '';
564
-
565
- while ((match = codeBlockRegex.exec(text)) !== null) {
566
- // Add text before the code block
567
- if (match.index > lastIndex) {
568
- contentHtml += formatText(text.substring(lastIndex, match.index));
569
- }
570
-
571
- const language = match[1] || 'plaintext';
572
- const code = match[2];
573
-
574
- // Store the last detected code if it's the latest message and from AI
575
- if (sender === 'ai') {
576
- lastDetectedCode = code;
577
- savedCodeDisplay.textContent = code;
578
- }
579
-
580
- contentHtml += `<pre><div class="code-tools">
581
- <button onclick="copyCode(this)">คัดลอก</button>
582
- <button onclick="pasteCodeToInput(this)" title="วางโค้ดลงในช่องพิมพ์">ส่งต่อ</button>
583
- </div><code class="language-${language}">${hljs.highlight(code, {language: language, ignoreIllegals: true}).value}</code></pre>`;
584
- lastIndex = codeBlockRegex.lastIndex;
585
- }
586
-
587
- // Add any remaining text after the last code block
588
- if (lastIndex < text.length) {
589
- contentHtml += formatText(text.substring(lastIndex));
590
- }
591
-
592
- messageDiv.innerHTML += contentHtml;
593
- messagesDiv.appendChild(messageDiv);
594
- messagesDiv.scrollTop = messagesDiv.scrollHeight;
595
- }
596
-
597
- function formatText(text) {
598
- // Basic formatting for bold, italic, and links outside code blocks
599
- let formattedText = text.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>'); // Bold
600
- formattedText = formattedText.replace(/\*(.*?)\*/g, '<em>$1</em>'); // Italic
601
- formattedText = formattedText.replace(/\[(.*?)\]\((.*?)\)/g, '<a href="$2" target="_blank">$1</a>'); // Links
602
- return formattedText;
603
- }
604
-
605
- function copyCode(button) {
606
- const codeElement = button.closest('pre').querySelector('code');
607
- navigator.clipboard.writeText(codeElement.textContent);
608
- button.textContent = 'คัดลอกแล้ว!';
609
- setTimeout(() => button.textContent = 'คัดลอก', 2000);
610
- }
611
-
612
- function pasteCodeToInput(button) {
613
- const codeElement = button.closest('pre').querySelector('code');
614
- userInput.value = codeElement.textContent;
615
- userInput.focus();
616
- }
617
-
618
- // --- Error Handling ---
619
- function displayError(message) {
620
- errorMessageDiv.textContent = `ข้อผิดพลาด: ${message}`;
621
- errorMessageDiv.style.display = 'block';
622
- setTimeout(() => {
623
- errorMessageDiv.style.display = 'none';
624
- errorMessageDiv.textContent = '';
625
- }, 5000);
626
- }
627
-
628
- // --- Context Saving Feature ---
629
- confirmSaveBtn.addEventListener('click', () => {
630
- const goal = goalInput.value.trim();
631
- if (lastDetectedCode || goal) {
632
- savedGoal = goal;
633
- conversationHistory = [
634
- { role: 'system', content: `ผู้ใช้กำลังทำงานกับโค้ดต่อไปนี้:\n\`\`\`\n${lastDetectedCode}\n\`\`\`\nเป้าหมายคือ: ${savedGoal || 'ไม่มีเป้าหมายเฉพาะเจาะจง'}` }
635
- ];
636
- addMessage("Context ถูกบันทึกและเริ่มต้นการแชทใหม่แล้ว!", "ai");
637
- contextSaveArea.style.display = 'none';
638
- savedCodeDisplay.textContent = '';
639
- goalInput.value = '';
640
- lastDetectedCode = '';
641
- } else {
642
- displayError("ไม่มีโค้ดหรือเป้าหมายให้บันทึก");
643
- }
644
- });
645
-
646
- // --- Drag and Drop for Files ---
647
- ['dragenter', 'dragover', 'dragleave', 'drop'].forEach(eventName => {
648
- chatForm.addEventListener(eventName, preventDefaults, false);
649
- });
650
-
651
- function preventDefaults(e) {
652
- e.preventDefault();
653
- e.stopPropagation();
654
- }
655
-
656
- ['dragenter', 'dragover'].forEach(eventName => {
657
- chatForm.addEventListener(eventName, () => dropzone.style.display = 'flex', false);
658
- });
659
-
660
- ['dragleave', 'drop'].forEach(eventName => {
661
- chatForm.addEventListener(eventName, () => dropzone.style.display = 'none', false);
662
- });
663
-
664
- dropzone.addEventListener('drop', handleDrop, false);
665
-
666
- function handleDrop(e) {
667
- const dt = e.dataTransfer;
668
- const files = dt.files;
669
- handleFiles(files);
670
- }
671
-
672
- fileInput.addEventListener('change', (e) => {
673
- handleFiles(e.target.files);
674
- });
675
-
676
- function handleFiles(files) {
677
- attachedFiles = [];
678
- fileNameSpan.textContent = '';
679
- if (files.length > 0) {
680
- for (const file of files) {
681
- if (file.type.startsWith('image/')) {
682
- attachedFiles.push({ type: 'image', file: file });
683
- } else if (file.type.startsWith('text/') || file.name.endsWith('.txt') || file.name.endsWith('.md') || file.name.endsWith('.html') || file.name.endsWith('.css') || file.name.endsWith('.js')) {
684
- attachedFiles.push({ type: 'text', file: file });
685
- } else if (file.type === 'application/pdf' || file.name.endsWith('.pdf')) {
686
- attachedFiles.push({ type: 'pdf', file: file }); // Handle PDF
687
- } else if (file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' || file.name.endsWith('.docx')) {
688
- attachedFiles.push({ type: 'docx', file: file }); // Handle DOCX
689
- } else if (file.type === 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' || file.name.endsWith('.xlsx')) {
690
- attachedFiles.push({ type: 'xlsx', file: file }); // Handle XLSX
691
- } else {
692
- displayError(`ไม่รองรับไฟล์ประเภท: ${file.type}.`);
693
- return;
694
- }
695
- }
696
- fileNameSpan.textContent = attachedFiles.map(f => f.file.name).join(', ');
697
- }
698
- }
699
-
700
- async function readFileAsBase64(file) {
701
- return new Promise((resolve, reject) => {
702
- const reader = new FileReader();
703
- reader.onload = () => resolve(reader.result.split(',')[1]); // Get base64 string
704
- reader.onerror = error => reject(error);
705
- reader.readAsDataURL(file);
706
- });
707
- }
708
-
709
- async function readFileAsText(file) {
710
- return new Promise((resolve, reject) => {
711
- const reader = new FileReader();
712
- reader.onload = () => resolve(reader.result);
713
- reader.onerror = error => reject(error);
714
- reader.readAsText(file);
715
- });
716
- }
717
-
718
- // --- Main Chat Logic ---
719
- chatForm.addEventListener('submit', async (e) => {
720
- e.preventDefault();
721
- const userMessage = userInput.value.trim();
722
- if (!userMessage && attachedFiles.length === 0) {
723
- displayError("กรุณาพิมพ์ข้อความหรือแนบไฟล์");
724
- return;
725
- }
726
-
727
- const selectedModel = modelSelect.value;
728
- const apiKey = currentApiKey;
729
- const systemPreset = systemPresetSelect.value;
730
- let systemPrompt = '';
731
-
732
- if (systemPreset === 'custom') {
733
- systemPrompt = customSystemPromptInput.value.trim();
734
- } else if (systemPreset === 'code-full') {
735
- if (lastDetectedCode) {
736
- systemPrompt = `คุณคือผู้ช่วยพัฒนาเว็บที่มีความสามารถสูงในการเขียนโค้ดและสร้าง artifact ได้อย่างสมบูรณ์แบบตามคำสั่งของผู้ใช้ คุณจะทำงานร่วมกับผู้ใช้เพื่อแก้ไขและปรับปรุง artifact ที่มีอยู่ โค้ดทั้งหมดจะต้องถูกเขียนใน code block เดียว เพื่อเป็นไฟล์โค้ดที่สมบูรณ์และพร้อมใช้งาน โดยไม่มีการแยกโค้ด HTML และ JavaScript ในการตอบกลับของคุณ ให้เอาต์พุตเฉพาะโค้ด HTML โดยไม่มีข้อความอธิบายใดๆ เพิ่มเติม เมื่อใดก็ตามที่ได้รับคำสั่ง คุณจะตรวจสอบการรันโค้ดอีกครั้งเพื่อให้แน่ใจว่าไม่มีข้อผิดพลาดในการเอาต์พุต ผู้ใช้ได้ให้โค้ด HTML/CSS/JS ล่าสุดแก่คุณแล้ว และต้องการให้คุณช่วยเหลือในการพัฒนาต่อ. โค้ดปัจจุบันคือ: \n\`\`\`html\n${lastDetectedCode}\n\`\`\`\nเป้าหมายของโค้ดนี้คือ: ${saved
737
- </html>