luxai / index.html
kritsanan's picture
Update index.html
04d84db verified
<!DOCTYPE html>
<html lang="th">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>TOTO AI Campaign - ทนายโตโต้ เบอร์ 1</title>
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Thai:wght@300;400;500;700;900&display=swap" rel="stylesheet">
<script src="https://unpkg.com/lucide@latest"></script>
<style>
body { font-family: 'Noto Sans Thai', sans-serif; background-color: #f8fafc; }
.glass { background: rgba(255, 255, 255, 0.9); backdrop-filter: blur(10px); }
.bg-toto { background: linear-gradient(135deg, #1e3a8a 0%, #312e81 100%); }
.card-shadow { box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.05); }
.pulse-blue { animation: pulse 2s infinite; }
@keyframes pulse {
0% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0.4); }
70% { box-shadow: 0 0 0 10px rgba(37, 99, 235, 0); }
100% { box-shadow: 0 0 0 0 rgba(37, 99, 235, 0); }
}
</style>
</head>
<body class="pb-20">
<!-- Top Navigation / Header -->
<nav class="bg-toto text-white p-6 sticky top-0 z-50 shadow-lg">
<div class="max-w-4xl mx-auto flex items-center justify-between">
<div class="flex items-center gap-4">
<div class="w-12 h-12 bg-white text-blue-900 rounded-2xl flex items-center justify-center text-2xl font-black shadow-xl">1</div>
<div>
<h1 class="text-xl font-black tracking-tight leading-none">ทนายโตโต้</h1>
<p class="text-[10px] text-blue-200 mt-1 uppercase font-bold tracking-widest">อุดรธานี เขต 6 | พรรคกล้าธรรม</p>
</div>
</div>
<div class="hidden md:flex gap-4">
<span class="bg-white/10 px-3 py-1 rounded-full text-xs border border-white/20">วังสามหมอ</span>
<span class="bg-white/10 px-3 py-1 rounded-full text-xs border border-white/20">ศรีธาตุ</span>
</div>
</div>
</nav>
<main class="max-w-4xl mx-auto p-4 md:p-8 space-y-6">
<!-- Hero Section -->
<div class="bg-white rounded-[2.5rem] p-8 card-shadow border border-slate-100 relative overflow-hidden">
<div class="absolute -right-10 -top-10 opacity-5">
<i data-lucide="scale" size="200"></i>
</div>
<div class="relative z-10">
<div class="flex items-center gap-2 text-blue-600 mb-2 font-bold text-sm">
<i data-lucide="award" size="18"></i> สานต่อตำนาน ส.ส. เกียรติอุดม
</div>
<h2 class="text-3xl font-black text-slate-900 mb-4">เปลี่ยนอุดรฯ ด้วยเทคโนโลยี<br><span class="text-blue-600">พึ่งพาได้ จริงใจ เพื่อพี่น้อง</span></h2>
<div class="flex flex-wrap gap-3">
<button onclick="fillScript('land')" class="bg-blue-50 text-blue-700 px-4 py-2 rounded-xl text-sm font-bold border border-blue-100 hover:bg-blue-600 hover:text-white transition-all">
นโยบายโฉนด
</button>
<button onclick="fillScript('water')" class="bg-blue-50 text-blue-700 px-4 py-2 rounded-xl text-sm font-bold border border-blue-100 hover:bg-blue-600 hover:text-white transition-all">
ธนาคารน้ำ
</button>
<button onclick="fillScript('legal')" class="bg-blue-50 text-blue-700 px-4 py-2 rounded-xl text-sm font-bold border border-blue-100 hover:bg-blue-600 hover:text-white transition-all">
ทนายประจำบ้าน
</button>
</div>
</div>
</div>
<!-- AI Generator Section -->
<div class="grid grid-cols-1 md:grid-cols-12 gap-6">
<!-- Input Area -->
<div class="md:col-span-8 bg-white rounded-[2.5rem] p-6 card-shadow border border-slate-100 space-y-4">
<div class="flex items-center justify-between">
<h3 class="font-black text-slate-800 flex items-center gap-2">
<i data-lucide="wand-2" class="text-blue-600"></i> ปรับจูนบทพูด (อีสาน)
</h3>
<div id="statusIndicator" class="hidden text-[10px] font-black text-blue-500 animate-pulse">AI กำลังทำงาน...</div>
</div>
<textarea id="scriptInput" class="w-full h-48 bg-slate-50 border border-slate-200 rounded-3xl p-6 focus:ring-4 focus:ring-blue-100 focus:outline-none text-lg transition-all" placeholder="พิมพ์ข้อความที่นี่ หรือกดปุ่มนโยบายด้านบน..."></textarea>
<div class="grid grid-cols-2 gap-4">
<button onclick="generateIsanScript()" class="bg-slate-900 text-white py-4 rounded-2xl font-black text-sm flex items-center justify-center gap-2 hover:bg-black transition-all">
<i data-lucide="refresh-cw" size="18"></i> ร่างใหม่ด้วย AI
</button>
<button id="ttsBtn" onclick="generateVoice()" class="bg-blue-600 text-white py-4 rounded-2xl font-black text-sm flex items-center justify-center gap-2 hover:bg-blue-700 transition-all shadow-lg shadow-blue-200 pulse-blue">
<i data-lucide="volume-2" size="18"></i> สร้างเสียงโคลน
</button>
</div>
</div>
<!-- Stats/Settings -->
<div class="md:col-span-4 space-y-4">
<div class="bg-white rounded-[2rem] p-6 card-shadow border border-slate-100">
<label class="text-[10px] font-black text-slate-400 uppercase tracking-widest block mb-3">น้ำเสียง (Voice Profile)</label>
<select id="voiceSelect" class="w-full bg-slate-50 border border-slate-200 p-3 rounded-xl text-xs font-bold focus:outline-none">
<option value="Charon">เสียงทรงพลัง (เวทีปราศรัย)</option>
<option value="Kore">เสียงนุ่มนวล (คุยในบ้าน)</option>
<option value="Zephyr">เสียงวัยรุ่น (ลง TikTok)</option>
</select>
</div>
<div class="bg-blue-600 rounded-[2rem] p-6 text-white shadow-xl relative overflow-hidden">
<i data-lucide="map-pin" class="absolute -right-4 -bottom-4 opacity-20" size="80"></i>
<h4 class="font-black text-sm mb-1">พื้นที่เป้าหมาย</h4>
<p class="text-[10px] opacity-80 mb-4 tracking-tighter">อุดรธานี เขต 6</p>
<div class="space-y-2">
<div class="flex justify-between text-[10px] font-bold">
<span>วังสามหมอ</span>
<span>85%</span>
</div>
<div class="w-full bg-white/20 h-1.5 rounded-full">
<div class="bg-white h-full rounded-full w-[85%]"></div>
</div>
</div>
</div>
</div>
</div>
<!-- Result Section -->
<div id="resultArea" class="hidden space-y-4 animate-in fade-in slide-in-from-bottom-4 duration-500">
<div class="bg-white rounded-[2.5rem] p-8 card-shadow border-t-4 border-blue-600 flex flex-col md:flex-row items-center gap-6">
<div class="p-5 bg-blue-100 rounded-3xl text-blue-600">
<i data-lucide="play-circle" size="40"></i>
</div>
<div class="flex-1 w-full">
<h4 class="font-black text-lg text-slate-800">เสียงโคลนทนายโตโต้พร้อมแล้ว!</h4>
<p class="text-xs font-bold text-slate-500 mb-4">สำเนียงอีสานอุดรฯ | สไตล์คนรุ่นใหม่</p>
<audio id="audioPlayer" controls class="w-full h-10"></audio>
</div>
<div class="flex gap-2 w-full md:w-auto">
<button class="flex-1 md:flex-none bg-slate-900 text-white px-6 py-3 rounded-xl font-bold text-xs hover:bg-black">ดาวน์โหลด</button>
<button class="flex-1 md:flex-none bg-green-600 text-white px-6 py-3 rounded-xl font-bold text-xs hover:bg-green-700">ส่งเข้า LINE</button>
</div>
</div>
</div>
</main>
<!-- Bottom Nav (Mobile) -->
<nav class="fixed bottom-0 left-0 right-0 glass border-t border-slate-200 p-4 flex justify-around md:hidden z-50">
<button class="text-blue-600 flex flex-col items-center gap-1">
<i data-lucide="home" size="20"></i>
<span class="text-[8px] font-bold uppercase">หน้าหลัก</span>
</button>
<button class="text-slate-400 flex flex-col items-center gap-1">
<i data-lucide="mic" size="20"></i>
<span class="text-[8px] font-bold uppercase">ลงพื้นที่</span>
</button>
<button class="text-slate-400 flex flex-col items-center gap-1">
<i data-lucide="users" size="20"></i>
<span class="text-[8px] font-bold uppercase">ชาวบ้าน</span>
</button>
<button class="text-slate-400 flex flex-col items-center gap-1">
<i data-lucide="settings" size="20"></i>
<span class="text-[8px] font-bold uppercase">ตั้งค่า</span>
</button>
</nav>
<script>
// Initialize Icons
lucide.createIcons();
const apiKey = "AIzaSyARfi7LxgfsnYiyZvR179xxpYsFkwc_AOs"; // Runtime provides this
const scriptInput = document.getElementById('scriptInput');
const statusIndicator = document.getElementById('statusIndicator');
const resultArea = document.getElementById('resultArea');
const audioPlayer = document.getElementById('audioPlayer');
const templates = {
land: "พี่น้องเอ้ย! ทนายโตโต้ เบอร์หนึ่ง สัญญาครับ สิพาเปลี่ยน ส.ป.ก. เป็นโฉนด ให้พี่น้องมีที่ดินทำกินที่มั่นคง สานต่ออุดมการณ์พ่อเกียรติอุดมครับ!",
water: "น้ำคือชีวิต! ผมสิเฮ็ดธนาคารน้ำใต้ดิน ให้พี่น้องเขตหก วังสามหมอ ศรีธาตุ มีน้ำใช้ตลอดปี บ่ต้องย่านแล้งอีกต่อไปครับ",
legal: "มีปัญหาข้อกฎหมาย บ่ต้องตกใจ! ทนายโตโต้ ทนายประจำบ้าน พร้อมซ่อยเหลือพี่น้อง ปรึกษาฟรี ตลอด 24 ชั่วโมงครับ"
};
function fillScript(type) {
scriptInput.value = templates[type];
}
async function generateIsanScript() {
if (!scriptInput.value) return;
statusIndicator.classList.remove('hidden');
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-09-2025:generateContent?key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: `ปรับข้อความนี้ให้เป็นภาษาอีสานสำเนียงอุดรธานีที่ฮึกเหิมและจริงใจ สำหรับแคมเปญหาเสียงทนายโตโต้ เบอร์ 1: ${scriptInput.value}` }] }]
})
});
const data = await response.json();
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
if (text) scriptInput.value = text.trim();
} catch (error) {
console.error(error);
} finally {
statusIndicator.classList.add('hidden');
}
}
async function generateVoice() {
if (!scriptInput.value) return;
statusIndicator.classList.remove('hidden');
const voice = document.getElementById('voiceSelect').value;
try {
const response = await fetch(`https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash-preview-tts:generateContent?key=${apiKey}`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
contents: [{ parts: [{ text: `Say in a powerful, natural Isan accent: ${scriptInput.value}` }] }],
generationConfig: {
responseModalities: ["AUDIO"],
speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: voice } } }
}
})
});
const data = await response.json();
const b64 = data.candidates?.[0]?.content?.parts?.[0]?.inlineData?.data;
if (b64) {
const blob = b64ToWavBlob(b64, 24000);
audioPlayer.src = URL.createObjectURL(blob);
resultArea.classList.remove('hidden');
resultArea.scrollIntoView({ behavior: 'smooth' });
}
} catch (error) {
console.error(error);
} finally {
statusIndicator.classList.add('hidden');
}
}
function b64ToWavBlob(b64, sampleRate) {
const bin = atob(b64);
const pcm = new Int16Array(bin.length / 2);
for (let i = 0; i < pcm.length; i++) pcm[i] = (bin.charCodeAt(i * 2 + 1) << 8) | bin.charCodeAt(i * 2);
const buffer = new ArrayBuffer(44 + pcm.length * 2);
const view = new DataView(buffer);
const writeString = (o, s) => { for (let i = 0; i < s.length; i++) view.setUint8(o + i, s.charCodeAt(i)); };
writeString(0, 'RIFF');
view.setUint32(4, 32 + pcm.length * 2, true);
writeString(8, 'WAVE');
writeString(12, 'fmt ');
view.setUint32(16, 16, true);
view.setUint16(20, 1, true);
view.setUint16(22, 1, true);
view.setUint32(24, sampleRate, true);
view.setUint32(28, sampleRate * 2, true);
view.setUint16(32, 2, true);
view.setUint16(34, 16, true);
writeString(36, 'data');
view.setUint32(40, pcm.length * 2, true);
for (let i = 0; i < pcm.length; i++) view.setInt16(44 + i * 2, pcm[i], true);
return new Blob([buffer], { type: 'audio/wav' });
}
</script>
</body>
</html>