Spaces:
Running
Running
Delete index.html
Browse files- 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="เต็มจอ">□</button>
|
413 |
-
<button onclick="window.location.reload()" title="รีเฟรช">■</button>
|
414 |
-
<button onclick="window.close()" title="ปิด">✖</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 ? "■" : "□";
|
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>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|