Update index.html
Browse files- index.html +153 -21
index.html
CHANGED
|
@@ -142,36 +142,83 @@
|
|
| 142 |
<section class="bg-gradient-to-br from-indigo-900 to-purple-800 rounded-2xl p-8 text-white shadow-xl">
|
| 143 |
<h3 class="text-3xl font-bold mb-8 border-b border-purple-400 pb-4">🤖 AI Strategic Partner</h3>
|
| 144 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
| 145 |
-
<!-- Caption Gen -->
|
| 146 |
-
<div class="bg-white text-gray-800 rounded-xl p-6 border-t-8 border-red-500">
|
| 147 |
<h4 class="text-xl font-bold text-purple-800 mb-1">✍️ ผู้ช่วยเขียนแคปชั่น</h4>
|
| 148 |
<p class="text-xs text-red-500 mb-4 font-bold flex items-center gap-1">
|
| 149 |
<span class="w-2 h-2 bg-red-500 rounded-full animate-ping"></span>
|
| 150 |
ระบบตรวจสอบระเบียบ กกต. ทำงานอยู่
|
| 151 |
</p>
|
| 152 |
-
<input type="text" id="captionTopic" class="w-full border p-2 rounded mb-4" placeholder="หัวข้อคอนเทนต์ หรือ
|
| 153 |
<select id="captionPlatform" class="w-full border p-2 rounded mb-4">
|
| 154 |
<option value="TikTok">TikTok (เน้นสั้น/ภาษาอีสาน)</option>
|
| 155 |
<option value="Facebook">Facebook (เน้นข้อมูล/ผลงาน)</option>
|
| 156 |
<option value="Line OA">Line OA (เน้นความใกล้ชิด)</option>
|
| 157 |
</select>
|
| 158 |
-
<button id="btnGenerateCaption" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 rounded-lg transition-all">
|
| 159 |
-
|
| 160 |
</button>
|
| 161 |
<div id="captionOutputArea" class="hidden mt-4">
|
| 162 |
-
<div id="captionOutput" class="p-4 bg-gray-50 rounded-lg border border-gray-200 text-sm whitespace-pre-line"></div>
|
| 163 |
-
<div class="mt-2 p-2 bg-red-50 border border-red-200 rounded text-[10px] text-red-700 font-bold italic">
|
| 164 |
-
⚠️ คำเตือน: ตรวจสอบบัญชีโซเชียลที่ใช้โพสต์ว่า "แจ้ง กกต. แล้ว" และเก็บภาพหน้าจอไว้รายงานค่าใช้จ่าย
|
| 165 |
-
</div>
|
| 166 |
</div>
|
| 167 |
</div>
|
| 168 |
|
| 169 |
-
<!--
|
| 170 |
-
<div class="bg-white text-gray-800 rounded-xl p-6">
|
| 171 |
-
<h4 class="text-xl font-bold text-
|
| 172 |
-
<
|
| 173 |
-
|
| 174 |
-
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 175 |
</div>
|
| 176 |
</div>
|
| 177 |
</section>
|
|
@@ -201,7 +248,7 @@
|
|
| 201 |
<script type="module">
|
| 202 |
import { GoogleGenerativeAI } from "@google/generative-ai";
|
| 203 |
|
| 204 |
-
const apiKey = "
|
| 205 |
const genAI = new GoogleGenerativeAI(apiKey);
|
| 206 |
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash-preview-09-2025" });
|
| 207 |
|
|
@@ -221,17 +268,24 @@
|
|
| 221 |
function setLoading(btnId, outputAreaId, isLoading) {
|
| 222 |
const btn = document.getElementById(btnId);
|
| 223 |
const area = document.getElementById(outputAreaId);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 224 |
if (isLoading) {
|
| 225 |
btn.disabled = true;
|
| 226 |
-
btn.innerHTML = '<span class="loader"></span>
|
| 227 |
if(area) area.classList.remove('hidden');
|
| 228 |
} else {
|
| 229 |
btn.disabled = false;
|
| 230 |
-
btn.innerHTML = btnId
|
| 231 |
}
|
| 232 |
}
|
| 233 |
|
| 234 |
-
// --- Feature: Caption Generator
|
| 235 |
document.getElementById('btnGenerateCaption').addEventListener('click', async () => {
|
| 236 |
const topic = document.getElementById('captionTopic').value;
|
| 237 |
const platform = document.getElementById('captionPlatform').value;
|
|
@@ -256,13 +310,90 @@
|
|
| 256 |
const result = await model.generateContent(prompt);
|
| 257 |
output.innerHTML = result.response.text().trim();
|
| 258 |
} catch (err) {
|
| 259 |
-
|
|
|
|
| 260 |
} finally {
|
| 261 |
setLoading('btnGenerateCaption', null, false);
|
| 262 |
}
|
| 263 |
});
|
| 264 |
|
| 265 |
-
// --- Feature:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 266 |
document.getElementById('btnGenerateStrategy').addEventListener('click', async () => {
|
| 267 |
const situation = document.getElementById('crisisInput').value;
|
| 268 |
if(!situation) return;
|
|
@@ -285,6 +416,7 @@
|
|
| 285 |
const result = await model.generateContent(prompt);
|
| 286 |
output.innerHTML = result.response.text().replace(/\n/g, '<br>');
|
| 287 |
} catch (err) {
|
|
|
|
| 288 |
output.innerHTML = "ไม่สามารถวิเคราะห์ได้ในขณะนี้";
|
| 289 |
} finally {
|
| 290 |
setLoading('btnGenerateStrategy', null, false);
|
|
|
|
| 142 |
<section class="bg-gradient-to-br from-indigo-900 to-purple-800 rounded-2xl p-8 text-white shadow-xl">
|
| 143 |
<h3 class="text-3xl font-bold mb-8 border-b border-purple-400 pb-4">🤖 AI Strategic Partner</h3>
|
| 144 |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8">
|
| 145 |
+
<!-- 1. Caption Gen -->
|
| 146 |
+
<div class="bg-white text-gray-800 rounded-xl p-6 border-t-8 border-red-500 shadow-lg">
|
| 147 |
<h4 class="text-xl font-bold text-purple-800 mb-1">✍️ ผู้ช่วยเขียนแคปชั่น</h4>
|
| 148 |
<p class="text-xs text-red-500 mb-4 font-bold flex items-center gap-1">
|
| 149 |
<span class="w-2 h-2 bg-red-500 rounded-full animate-ping"></span>
|
| 150 |
ระบบตรวจสอบระเบียบ กกต. ทำงานอยู่
|
| 151 |
</p>
|
| 152 |
+
<input type="text" id="captionTopic" class="w-full border p-2 rounded mb-4" placeholder="หัวข้อคอนเทนต์ หรือ นโยบาย...">
|
| 153 |
<select id="captionPlatform" class="w-full border p-2 rounded mb-4">
|
| 154 |
<option value="TikTok">TikTok (เน้นสั้น/ภาษาอีสาน)</option>
|
| 155 |
<option value="Facebook">Facebook (เน้นข้อมูล/ผลงาน)</option>
|
| 156 |
<option value="Line OA">Line OA (เน้นความใกล้ชิด)</option>
|
| 157 |
</select>
|
| 158 |
+
<button id="btnGenerateCaption" class="w-full bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 rounded-lg transition-all shadow-md">
|
| 159 |
+
✨ สร้างแคปชั่น (Safe Mode)
|
| 160 |
</button>
|
| 161 |
<div id="captionOutputArea" class="hidden mt-4">
|
| 162 |
+
<div id="captionOutput" class="p-4 bg-gray-50 rounded-lg border border-gray-200 text-sm whitespace-pre-line max-h-40 overflow-y-auto"></div>
|
|
|
|
|
|
|
|
|
|
| 163 |
</div>
|
| 164 |
</div>
|
| 165 |
|
| 166 |
+
<!-- 2. Comment Reply Assistant -->
|
| 167 |
+
<div class="bg-white text-gray-800 rounded-xl p-6 border-t-8 border-blue-500 shadow-lg">
|
| 168 |
+
<h4 class="text-xl font-bold text-blue-800 mb-1">💬 ผู้ช่วยตอบคอมเมนต์</h4>
|
| 169 |
+
<p class="text-xs text-blue-500 mb-4 font-bold">ตอบเร็ว ตรงประเด็น ได้ใจชาวบ้าน</p>
|
| 170 |
+
|
| 171 |
+
<textarea id="commentInput" rows="3" class="w-full border p-2 rounded mb-3 text-sm" placeholder="วางคอมเมนต์จากชาวเน็ตที่นี่..."></textarea>
|
| 172 |
+
|
| 173 |
+
<select id="replyTone" class="w-full border p-2 rounded mb-4 text-sm">
|
| 174 |
+
<option value="Friendly">เป็นกันเอง + ภาษาอีสาน (สำหรับ FC)</option>
|
| 175 |
+
<option value="Polite">สุภาพทางการ (สำหรับผู้ใหญ่/ข้าราชการ)</option>
|
| 176 |
+
<option value="Clarify">ชี้แจงข้อเท็จจริง (สำหรับคำถามนโยบาย)</option>
|
| 177 |
+
<option value="Deescalate">ลดอุณหภูมิ (สำหรับคอมเมนต์ลบ)</option>
|
| 178 |
+
</select>
|
| 179 |
+
|
| 180 |
+
<button id="btnGenerateReply" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 rounded-lg transition-all shadow-md">
|
| 181 |
+
✨ ร่างคำตอบ
|
| 182 |
+
</button>
|
| 183 |
+
<div id="replyOutputArea" class="hidden mt-4">
|
| 184 |
+
<div id="replyOutput" class="p-4 bg-blue-50 rounded-lg border border-blue-200 text-sm whitespace-pre-line relative group"></div>
|
| 185 |
+
<p class="text-[10px] text-gray-400 mt-1 text-right">คลิกที่ข้อความเพื่อคัดลอก</p>
|
| 186 |
+
</div>
|
| 187 |
+
</div>
|
| 188 |
+
|
| 189 |
+
<!-- 3. Smart Speech Writer (NEW FEATURE) -->
|
| 190 |
+
<div class="bg-white text-gray-800 rounded-xl p-6 border-t-8 border-green-500 shadow-lg">
|
| 191 |
+
<h4 class="text-xl font-bold text-green-700 mb-1">🎤 ผู้ช่วยร่างคำปราศรัย</h4>
|
| 192 |
+
<p class="text-xs text-green-600 mb-4 font-bold">สคริปต์พูดหน้างาน มัดใจคนฟัง</p>
|
| 193 |
+
|
| 194 |
+
<div class="grid grid-cols-2 gap-2 mb-3">
|
| 195 |
+
<select id="speechOccasion" class="border p-2 rounded text-sm w-full">
|
| 196 |
+
<option value="ประชุมหมู่บ้าน">ประชุมหมู่บ้าน</option>
|
| 197 |
+
<option value="งานแต่งงาน">งานแต่งงาน</option>
|
| 198 |
+
<option value="งานศพ">งานขาวดำ (งานศพ)</option>
|
| 199 |
+
<option value="ขึ้นบ้านใหม่">ขึ้นบ้านใหม่</option>
|
| 200 |
+
<option value="เวทีปราศรัยใหญ่">เวทีปราศรัยใหญ่</option>
|
| 201 |
+
</select>
|
| 202 |
+
<input type="text" id="speechLocation" class="border p-2 rounded text-sm w-full" placeholder="สถานที่ (เช่น บ้านหนองกุง)">
|
| 203 |
+
</div>
|
| 204 |
+
<input type="text" id="speechTheme" class="w-full border p-2 rounded mb-4 text-sm" placeholder="ประเด็นที่จะเน้น (เช่น แก้หนี้, น้ำประปา)">
|
| 205 |
+
|
| 206 |
+
<button id="btnGenerateSpeech" class="w-full bg-green-600 hover:bg-green-700 text-white font-bold py-3 rounded-lg transition-all shadow-md">
|
| 207 |
+
✨ ร่างสคริปต์พูด (3 นาที)
|
| 208 |
+
</button>
|
| 209 |
+
<div id="speechOutputArea" class="hidden mt-4">
|
| 210 |
+
<div id="speechOutput" class="p-4 bg-green-50 rounded-lg border border-green-200 text-sm whitespace-pre-line max-h-48 overflow-y-auto"></div>
|
| 211 |
+
</div>
|
| 212 |
+
</div>
|
| 213 |
+
|
| 214 |
+
<!-- 4. Crisis Advisor -->
|
| 215 |
+
<div class="bg-white text-gray-800 rounded-xl p-6 border-t-8 border-gray-800 shadow-lg">
|
| 216 |
+
<h4 class="text-xl font-bold text-gray-800 mb-4">🛡️ ที่ปรึกษาแก้เกมดราม่า</h4>
|
| 217 |
+
<textarea id="crisisInput" rows="3" class="w-full border p-2 rounded mb-4" placeholder="ระบุสถานการณ์หรือข้อกล่าวหา..."></textarea>
|
| 218 |
+
<button id="btnGenerateStrategy" class="w-full bg-gray-800 hover:bg-black text-white font-bold py-3 rounded-lg transition-all shadow-md">
|
| 219 |
+
✨ วิเคราะห์แนวทางแก้เกม
|
| 220 |
+
</button>
|
| 221 |
+
<div id="strategyOutput" class="mt-4 p-4 bg-gray-50 rounded-lg hidden text-sm border-l-4 border-gray-400 max-h-40 overflow-y-auto"></div>
|
| 222 |
</div>
|
| 223 |
</div>
|
| 224 |
</section>
|
|
|
|
| 248 |
<script type="module">
|
| 249 |
import { GoogleGenerativeAI } from "@google/generative-ai";
|
| 250 |
|
| 251 |
+
const apiKey = "AIzaSyCVtDUAm-wrWWShrblLUqHmd_MVzmGAClc"; // API Key will be injected at runtime
|
| 252 |
const genAI = new GoogleGenerativeAI(apiKey);
|
| 253 |
const model = genAI.getGenerativeModel({ model: "gemini-2.5-flash-preview-09-2025" });
|
| 254 |
|
|
|
|
| 268 |
function setLoading(btnId, outputAreaId, isLoading) {
|
| 269 |
const btn = document.getElementById(btnId);
|
| 270 |
const area = document.getElementById(outputAreaId);
|
| 271 |
+
const defaultText = {
|
| 272 |
+
'btnGenerateCaption': '✨ สร้างแคปชั่น (Safe Mode)',
|
| 273 |
+
'btnGenerateReply': '✨ ร่างคำตอบ',
|
| 274 |
+
'btnGenerateStrategy': '✨ วิเคราะห์แนวทางแก้เกม',
|
| 275 |
+
'btnGenerateSpeech': '✨ ร่างสคริปต์พูด (3 นาที)'
|
| 276 |
+
};
|
| 277 |
+
|
| 278 |
if (isLoading) {
|
| 279 |
btn.disabled = true;
|
| 280 |
+
btn.innerHTML = '<span class="loader"></span> กำลังคิด...';
|
| 281 |
if(area) area.classList.remove('hidden');
|
| 282 |
} else {
|
| 283 |
btn.disabled = false;
|
| 284 |
+
btn.innerHTML = defaultText[btnId];
|
| 285 |
}
|
| 286 |
}
|
| 287 |
|
| 288 |
+
// --- Feature 1: Caption Generator ---
|
| 289 |
document.getElementById('btnGenerateCaption').addEventListener('click', async () => {
|
| 290 |
const topic = document.getElementById('captionTopic').value;
|
| 291 |
const platform = document.getElementById('captionPlatform').value;
|
|
|
|
| 310 |
const result = await model.generateContent(prompt);
|
| 311 |
output.innerHTML = result.response.text().trim();
|
| 312 |
} catch (err) {
|
| 313 |
+
console.error(err);
|
| 314 |
+
output.innerHTML = "ขออภัย เกิดข้อผิดพลาดในระบบ AI";
|
| 315 |
} finally {
|
| 316 |
setLoading('btnGenerateCaption', null, false);
|
| 317 |
}
|
| 318 |
});
|
| 319 |
|
| 320 |
+
// --- Feature 2: Comment Reply Assistant ---
|
| 321 |
+
document.getElementById('btnGenerateReply').addEventListener('click', async () => {
|
| 322 |
+
const comment = document.getElementById('commentInput').value;
|
| 323 |
+
const tone = document.getElementById('replyTone').value;
|
| 324 |
+
if(!comment) return;
|
| 325 |
+
|
| 326 |
+
setLoading('btnGenerateReply', 'replyOutputArea', true);
|
| 327 |
+
const output = document.getElementById('replyOutput');
|
| 328 |
+
output.innerHTML = "กำลังร่างคำตอบ...";
|
| 329 |
+
|
| 330 |
+
try {
|
| 331 |
+
const prompt = `
|
| 332 |
+
${complianceInstruction}
|
| 333 |
+
คอมเมนต์จากประชาชน: "${comment}"
|
| 334 |
+
โทนการตอบ: "${tone}"
|
| 335 |
+
|
| 336 |
+
TASK: เขียนคำตอบกลับคอมเมนต์ (Reply) ในนาม "คุณธนอนันต์" (ผู้สมัคร) ตอบด้วยตนเอง
|
| 337 |
+
- ใช้สรรพนามแทนตัวว่า "ผม" หรือ "อ้าย" (ตามความเหมาะสมกับโทน) เพื่อความจริงใจและใกล้ชิด
|
| 338 |
+
- สั้น กระชับ ได้ใจความ เหมือนคุยกับพี่น้อง
|
| 339 |
+
- หากเป็นคำถามเชิงลบ ให้ตอบด้วยความสุภาพ พลิกวิกฤตเป็นโอกาสในการชี้แจง
|
| 340 |
+
- ใช้ภาษาถิ่นอีสานได้ตามความเหมาะสมกับโทนที่เลือก
|
| 341 |
+
- ห้ามสัญญาว่าจะให้ผลตอบแทนเด็ดขาด (Safe 100%)
|
| 342 |
+
`;
|
| 343 |
+
|
| 344 |
+
const result = await model.generateContent(prompt);
|
| 345 |
+
output.innerHTML = result.response.text().trim();
|
| 346 |
+
|
| 347 |
+
output.onclick = () => {
|
| 348 |
+
navigator.clipboard.writeText(output.innerText);
|
| 349 |
+
alert("คัดลอกข้อความแล้ว!");
|
| 350 |
+
};
|
| 351 |
+
} catch (err) {
|
| 352 |
+
console.error(err);
|
| 353 |
+
output.innerHTML = "ไม่สามารถสร้างคำตอบได้ในขณะนี้";
|
| 354 |
+
} finally {
|
| 355 |
+
setLoading('btnGenerateReply', null, false);
|
| 356 |
+
}
|
| 357 |
+
});
|
| 358 |
+
|
| 359 |
+
// --- Feature 3: Smart Speech Writer (NEW) ---
|
| 360 |
+
document.getElementById('btnGenerateSpeech').addEventListener('click', async () => {
|
| 361 |
+
const occasion = document.getElementById('speechOccasion').value;
|
| 362 |
+
const location = document.getElementById('speechLocation').value;
|
| 363 |
+
const theme = document.getElementById('speechTheme').value;
|
| 364 |
+
|
| 365 |
+
if(!location && !theme) return; // Simple validation
|
| 366 |
+
|
| 367 |
+
setLoading('btnGenerateSpeech', 'speechOutputArea', true);
|
| 368 |
+
const output = document.getElementById('speechOutput');
|
| 369 |
+
output.innerHTML = "กำลังร่างสคริปต์ปราศรัย...";
|
| 370 |
+
|
| 371 |
+
try {
|
| 372 |
+
const prompt = `
|
| 373 |
+
${complianceInstruction}
|
| 374 |
+
โอกาส/งาน: "${occasion}"
|
| 375 |
+
สถานที่: "${location}"
|
| 376 |
+
ประเด็นหลักที่ต้องการเน้น: "${theme}"
|
| 377 |
+
|
| 378 |
+
TASK: ร่างสคริปต์คำพูด (Speech Script) สั้นๆ สำหรับคุณธนอนันต์พูดหน้างาน
|
| 379 |
+
- เริ่มต้นด้วยการทักทายพี่น้องชาว "${location}" อย่างเป็นกันเอง (ภาษาอีสาน)
|
| 380 |
+
- แสดงความยินดี/เสียใจ ให้เหมาะสมกับ "${occasion}"
|
| 381 |
+
- เชื่อมโยงเข้าสู่ประเด็น "${theme}" อย่างแนบเนียน ไม่ดูเป็นการหาเสียงที่แข็งกระด้างเกินไป
|
| 382 |
+
- จบด้วยการให้กำลังใจและการฝากเนื้อฝากตัว
|
| 383 |
+
- ใช้เวลาพูดประมาณ 2-3 นาที
|
| 384 |
+
`;
|
| 385 |
+
|
| 386 |
+
const result = await model.generateContent(prompt);
|
| 387 |
+
output.innerHTML = result.response.text().trim();
|
| 388 |
+
} catch (err) {
|
| 389 |
+
console.error(err);
|
| 390 |
+
output.innerHTML = "เกิดข้อผิดพลาดในการร่างสคริปต์";
|
| 391 |
+
} finally {
|
| 392 |
+
setLoading('btnGenerateSpeech', null, false);
|
| 393 |
+
}
|
| 394 |
+
});
|
| 395 |
+
|
| 396 |
+
// --- Feature 4: Crisis Advisor ---
|
| 397 |
document.getElementById('btnGenerateStrategy').addEventListener('click', async () => {
|
| 398 |
const situation = document.getElementById('crisisInput').value;
|
| 399 |
if(!situation) return;
|
|
|
|
| 416 |
const result = await model.generateContent(prompt);
|
| 417 |
output.innerHTML = result.response.text().replace(/\n/g, '<br>');
|
| 418 |
} catch (err) {
|
| 419 |
+
console.error(err);
|
| 420 |
output.innerHTML = "ไม่สามารถวิเคราะห์ได้ในขณะนี้";
|
| 421 |
} finally {
|
| 422 |
setLoading('btnGenerateStrategy', null, false);
|