Spaces:
Running
Running
| <html lang="th"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>เซียนกุ้งลาดพร้าว - Ladprao Shrimp Oracle</title> | |
| <script src="https://cdn.tailwindcss.com"></script> | |
| <style> | |
| @import url('https://fonts.googleapis.com/css2?family=Prompt:wght@300;400;600;700&display=swap'); | |
| body { | |
| font-family: 'Prompt', sans-serif; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar { | |
| width: 4px; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-track { | |
| background: transparent; | |
| } | |
| .custom-scrollbar::-webkit-scrollbar-thumb { | |
| background: rgba(255,255,255,0.1); | |
| border-radius: 4px; | |
| } | |
| @keyframes fadeSlideIn { | |
| from { | |
| opacity: 0; | |
| transform: translateY(10px); | |
| } | |
| to { | |
| opacity: 1; | |
| transform: translateY(0); | |
| } | |
| } | |
| .animate-fade-slide { | |
| animation: fadeSlideIn 0.5s ease-out forwards; | |
| } | |
| @keyframes pulse-glow { | |
| 0%, 100% { box-shadow: 0 0 15px rgba(249, 115, 22, 0.3); } | |
| 50% { box-shadow: 0 0 25px rgba(249, 115, 22, 0.5); } | |
| } | |
| .pulse-glow { | |
| animation: pulse-glow 2s infinite; | |
| } | |
| input[type="date"]::-webkit-calendar-picker-indicator, | |
| input[type="time"]::-webkit-calendar-picker-indicator { | |
| filter: invert(1) opacity(0.5); | |
| } | |
| </style> | |
| </head> | |
| <body class="min-h-screen bg-[#0f172a] text-slate-100 flex flex-col"> | |
| <!-- Background --> | |
| <div class="fixed inset-0 z-0 pointer-events-none"> | |
| <div class="absolute top-0 left-0 w-full h-[300px] bg-gradient-to-b from-purple-900/30 to-transparent"></div> | |
| </div> | |
| <!-- Header --> | |
| <header class="flex-none h-16 bg-[#0f172a]/90 backdrop-blur-md border-b border-white/10 flex items-center justify-between px-4 z-50 sticky top-0"> | |
| <div class="flex items-center gap-3"> | |
| <div class="w-9 h-9 rounded-xl bg-gradient-to-br from-orange-500 to-red-600 flex items-center justify-center shadow-lg pulse-glow"> | |
| <svg class="w-5 h-5 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"/> | |
| </svg> | |
| </div> | |
| <div class="leading-tight"> | |
| <h1 id="headerTitle" class="text-base font-bold text-white">เซียนกุ้งลาดพร้าว</h1> | |
| <p id="headerSubtitle" class="text-[10px] text-slate-400">AI ทำนายผล คู่/คี่</p> | |
| </div> | |
| </div> | |
| <div class="flex gap-2"> | |
| <button id="langBtn" class="p-2 bg-white/5 rounded-full hover:bg-white/10 transition-colors"> | |
| <svg class="w-4 h-4 text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <circle cx="12" cy="12" r="10"/> | |
| <path d="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/> | |
| </svg> | |
| </button> | |
| <button id="resetBtn" class="p-2 bg-white/5 rounded-full text-red-400 hover:bg-white/10 transition-colors hidden"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> | |
| </svg> | |
| </button> | |
| </div> | |
| </header> | |
| <!-- Main Content --> | |
| <main id="mainContent" class="flex-1 p-4 pb-48 custom-scrollbar relative z-10"> | |
| <!-- Input Step --> | |
| <div id="inputStep" class="max-w-md mx-auto space-y-6 animate-fade-slide"> | |
| <!-- Intro Card --> | |
| <div class="bg-gradient-to-br from-slate-800 to-slate-900 border border-white/10 rounded-2xl p-5 shadow-xl"> | |
| <h2 class="text-orange-400 font-bold mb-2 flex items-center gap-2 text-sm uppercase tracking-wider"> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"/> | |
| </svg> | |
| <span id="introTitle">ระบบคำนวณดวงเกมตกกุ้ง</span> | |
| </h2> | |
| <p id="introText" class="text-xs text-slate-300 leading-relaxed">ระบบ AI ผสานศาสตร์ปาจื้อและชี่เหมินตุ้นเจี๋ย วิเคราะห์เกมชั่งน้ำหนักกุ้งลาดพร้าว คำนวณดัชนีโชคลาภและฟันธง 'คู่' หรือ 'คี่' ตามเวลาจริง</p> | |
| </div> | |
| <!-- API Key --> | |
| <div class="space-y-2"> | |
| <label id="apiKeyLabel" class="text-xs font-semibold text-purple-400 uppercase ml-1">1. ใส่คีย์สมอง (OpenAI API)</label> | |
| <div class="relative"> | |
| <svg class="absolute left-3 top-3.5 h-4 w-4 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 7a2 2 0 012 2m4 0a6 6 0 01-7.743 5.743L11 17H9v2H7v2H4a1 1 0 01-1-1v-2.586a1 1 0 01.293-.707l5.964-5.964A6 6 0 1121 9z"/> | |
| </svg> | |
| <input | |
| type="password" | |
| id="apiKeyInput" | |
| placeholder="sk-..." | |
| class="w-full pl-10 pr-4 py-3 bg-slate-900/50 border border-white/20 rounded-xl text-sm focus:border-orange-500 outline-none transition-all" | |
| /> | |
| </div> | |
| <p id="apiKeyNote" class="text-[10px] text-slate-500 ml-1">*คีย์ใช้ส่งข้อมูลหา AI เท่านั้น ไม่มีการบันทึก</p> | |
| <!-- Demo Mode Toggle --> | |
| <label class="flex items-center gap-2 mt-2 cursor-pointer group"> | |
| <input type="checkbox" id="demoModeToggle" class="w-4 h-4 rounded bg-slate-800 border-orange-500 text-orange-500 focus:ring-orange-500 focus:ring-offset-0"> | |
| <span id="demoModeLabel" class="text-xs text-orange-400 group-hover:text-orange-300">🎮 โหมดทดสอบ (ไม่ต้องใช้ API Key)</span> | |
| </label> | |
| </div> | |
| <!-- User Form --> | |
| <div class="space-y-3 bg-white/5 p-4 rounded-2xl border border-white/5"> | |
| <label id="userInfoLabel" class="text-xs font-semibold text-purple-400 uppercase mb-2 block">2. ข้อมูลเจ้าชะตา (กรอกครั้งเดียว)</label> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <div> | |
| <label id="nameLabelEl" class="text-[10px] text-slate-500 mb-1 block">ชื่อเล่น</label> | |
| <input type="text" id="nameInput" class="w-full p-2 bg-slate-900 rounded-lg border border-white/10 text-sm outline-none focus:border-orange-500" /> | |
| </div> | |
| <div> | |
| <label id="genderLabelEl" class="text-[10px] text-slate-500 mb-1 block">เพศ</label> | |
| <div class="flex bg-slate-900 rounded-lg p-1 border border-white/10 h-[38px]"> | |
| <button id="maleBtn" class="flex-1 rounded-md text-xs bg-blue-600 text-white transition-colors">ชาย</button> | |
| <button id="femaleBtn" class="flex-1 rounded-md text-xs text-slate-500 transition-colors">หญิง</button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <div> | |
| <label id="birthDateLabelEl" class="text-[10px] text-slate-500 mb-1 block">วันเกิด</label> | |
| <input type="date" id="birthDateInput" class="w-full p-2 bg-slate-900 rounded-lg border border-white/10 text-sm text-slate-300 outline-none focus:border-orange-500" /> | |
| </div> | |
| <div> | |
| <label id="birthTimeLabelEl" class="text-[10px] text-slate-500 mb-1 block">เวลาเกิด</label> | |
| <input type="time" id="birthTimeInput" class="w-full p-2 bg-slate-900 rounded-lg border border-white/10 text-sm text-slate-300 outline-none focus:border-orange-500" /> | |
| </div> | |
| </div> | |
| <div> | |
| <label id="birthCityLabelEl" class="text-[10px] text-slate-500 mb-1 block">จังหวัดเกิด</label> | |
| <input type="text" id="birthCityInput" placeholder="กทม." class="w-full p-2 bg-slate-900 rounded-lg border border-white/10 text-sm outline-none focus:border-orange-500" /> | |
| </div> | |
| </div> | |
| <!-- Initial Target --> | |
| <div class="space-y-3"> | |
| <label id="targetLabel" class="text-xs font-semibold text-purple-400 uppercase ml-1">3. เริ่มทำนายรอบแรก</label> | |
| <div class="grid grid-cols-2 gap-3"> | |
| <div class="relative"> | |
| <svg class="absolute left-3 top-3 h-4 w-4 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <rect x="3" y="4" width="18" height="18" rx="2" ry="2"/> | |
| <line x1="16" y1="2" x2="16" y2="6"/> | |
| <line x1="8" y1="2" x2="8" y2="6"/> | |
| <line x1="3" y1="10" x2="21" y2="10"/> | |
| </svg> | |
| <input type="date" id="targetDateInput" class="w-full pl-9 p-3 bg-slate-900/50 border border-white/20 rounded-xl text-sm text-white outline-none focus:border-orange-500" /> | |
| </div> | |
| <div class="relative"> | |
| <svg class="absolute left-3 top-3 h-4 w-4 text-slate-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <circle cx="12" cy="12" r="10"/> | |
| <polyline points="12 6 12 12 16 14"/> | |
| </svg> | |
| <input type="time" id="targetTimeInput" value="20:30" class="w-full pl-9 p-3 bg-slate-900/50 border border-white/20 rounded-xl text-sm text-white outline-none focus:border-orange-500" /> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Start Button --> | |
| <button id="startBtn" class="w-full py-4 bg-gradient-to-r from-orange-600 to-red-600 text-white font-bold rounded-xl shadow-lg shadow-orange-900/40 active:scale-95 transition-transform flex items-center justify-center gap-2 hover:from-orange-500 hover:to-red-500"> | |
| <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 3v4M3 5h4M6 17v4m-2-2h4m5-16l2.286 6.857L21 12l-5.714 2.143L13 21l-2.286-6.857L5 12l5.714-2.143L13 3z"/> | |
| </svg> | |
| <span id="startBtnText">วิเคราะห์ผล (คู่/คี่)</span> | |
| </button> | |
| <!-- Advanced Toggle --> | |
| <div class="pt-2 text-center"> | |
| <button id="advancedToggle" class="text-[10px] text-slate-500 flex items-center justify-center gap-1 mx-auto hover:text-slate-400 transition-colors"> | |
| <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <circle cx="12" cy="12" r="3"/> | |
| <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/> | |
| </svg> | |
| <span id="advancedText">ตั้งค่า AI (ขั้นสูง)</span> | |
| <svg id="advancedChevron" class="w-3 h-3 transition-transform" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <polyline points="6 9 12 15 18 9"/> | |
| </svg> | |
| </button> | |
| <div id="advancedPanel" class="hidden mt-2"> | |
| <textarea id="systemPromptInput" class="w-full h-32 bg-black/30 border border-white/10 rounded-lg p-2 text-[10px] font-mono text-slate-400 outline-none focus:border-orange-500"></textarea> | |
| <button id="restoreDefaultBtn" class="mt-2 text-[10px] text-orange-400 hover:text-orange-300">คืนค่าเดิม</button> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Chat Step --> | |
| <div id="chatStep" class="max-w-md mx-auto space-y-4 hidden"> | |
| <div id="chatMessages"></div> | |
| <!-- Loading --> | |
| <div id="loadingIndicator" class="hidden flex justify-start"> | |
| <div class="bg-slate-800 rounded-2xl rounded-tl-none p-3 flex items-center gap-2"> | |
| <svg class="w-4 h-4 animate-spin text-orange-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> | |
| </svg> | |
| <span id="loadingText" class="text-xs text-slate-400">AI กำลังคำนวณดวง...</span> | |
| </div> | |
| </div> | |
| <div id="chatEnd" class="h-4"></div> | |
| </div> | |
| </main> | |
| <!-- Bottom Action Bar (for repeat bets) --> | |
| <div id="bottomBar" class="fixed bottom-0 left-0 right-0 bg-[#0f172a]/95 backdrop-blur-xl border-t border-white/10 p-4 z-50 hidden animate-fade-slide"> | |
| <div class="max-w-md mx-auto"> | |
| <div class="flex items-center justify-between mb-2"> | |
| <span class="text-xs font-bold text-purple-400 uppercase flex items-center gap-1"> | |
| <svg class="w-3 h-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"/> | |
| </svg> | |
| <span id="nextRoundTitle">รอบถัดไป?</span> | |
| </span> | |
| <span id="nextRoundDesc" class="text-[10px] text-slate-500">ดวงเดิม เปลี่ยนแค่เวลาแทง</span> | |
| </div> | |
| <div class="flex gap-2"> | |
| <div class="relative flex-1"> | |
| <div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none"> | |
| <svg class="h-4 w-4 text-orange-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <circle cx="12" cy="12" r="10"/> | |
| <polyline points="12 6 12 12 16 14"/> | |
| </svg> | |
| </div> | |
| <input | |
| type="time" | |
| id="nextTimeInput" | |
| value="20:30" | |
| class="block w-full pl-10 pr-2 py-3 bg-slate-900 border border-white/20 rounded-xl text-sm text-white focus:ring-2 focus:ring-orange-500 focus:border-transparent outline-none font-mono" | |
| /> | |
| </div> | |
| <button | |
| id="predictNextBtn" | |
| class="bg-gradient-to-r from-orange-600 to-red-600 hover:from-orange-500 hover:to-red-500 text-white px-6 rounded-xl font-bold shadow-lg shadow-orange-900/30 active:scale-95 transition-all flex items-center gap-2" | |
| > | |
| <span id="predictNextText">ทำนายรอบใหม่</span> | |
| <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> | |
| <line x1="5" y1="12" x2="19" y2="12"/> | |
| <polyline points="12 5 19 12 12 19"/> | |
| </svg> | |
| </button> | |
| </div> | |
| <div class="mt-2 text-center"> | |
| <input | |
| type="date" | |
| id="nextDateInput" | |
| class="bg-transparent text-[10px] text-slate-600 text-center w-24 outline-none" | |
| /> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| // --- Translation Data --- | |
| const TRANSLATIONS = { | |
| 'th': { | |
| title: "เซียนกุ้งลาดพร้าว", | |
| subtitle: "AI ทำนายผล คู่/คี่", | |
| reset: "ล้างข้อมูล", | |
| introTitle: "ระบบคำนวณดวงเกมตกกุ้ง", | |
| introText: "ระบบ AI ผสานศาสตร์ปาจื้อและชี่เหมินตุ้นเจี๋ย วิเคราะห์เกมชั่งน้ำหนักกุ้งลาดพร้าว คำนวณดัชนีโชคลาภและฟันธง 'คู่' หรือ 'คี่' ตามเวลาจริง", | |
| apiKeyLabel: "1. ใส่คีย์สมอง (OpenAI API)", | |
| apiKeyPlaceholder: "sk-...", | |
| apiKeyNote: "*คีย์ใช้ส่งข้อมูลหา AI เท่านั้น ไม่มีการบันทึก", | |
| userInfoLabel: "2. ข้อมูลเจ้าชะตา (กรอกครั้งเดียว)", | |
| nameLabel: "ชื่อเล่น", | |
| genderLabel: "เพศ", | |
| male: "ชาย", | |
| female: "หญิง", | |
| birthDateLabel: "วันเกิด", | |
| birthTimeLabel: "เวลาเกิด", | |
| birthCityLabel: "จังหวัดเกิด", | |
| birthCityPlaceholder: "กทม.", | |
| targetLabel: "3. เริ่มทำนายรอบแรก", | |
| targetDateLabel: "วันที่เล่น", | |
| targetQuestionLabel: "เวลาที่จะแทง", | |
| advancedSettings: "ตั้งค่า AI (ขั้นสูง)", | |
| restoreDefault: "คืนค่าเดิม", | |
| startAnalysis: "วิเคราะห์ผล (คู่/คี่)", | |
| loading: "AI กำลังคำนวณดวง...", | |
| reportTitle: "ผลการทำนาย", | |
| errorApiKey: "ต้องใส่ API Key ก่อนครับ", | |
| errorInfo: "กรุณากรอกวันเวลาเกิดให้ครบ", | |
| aiRole: "หมอดู AI", | |
| initialGreeting: (name) => `สวัสดีคุณ ${name} ได้รับข้อมูลดวงชะตาแล้ว กำลังเชื่อมต่อจักรวาล...`, | |
| nextRoundTitle: "รอบถัดไป?", | |
| nextRoundDesc: "ดวงเดิม เปลี่ยนแค่เวลาแทง", | |
| predictNext: "ทำนายรอบใหม่" | |
| }, | |
| 'zh-TW': { | |
| title: "曼谷運勢智囊", | |
| subtitle: "OpenAI GPT 驅動 - 釣蝦場單雙預測", | |
| reset: "重置", | |
| introTitle: "命理融合預測系統", | |
| introText: "本系統結合八字與奇門遁甲,專門針對曼谷 Ladprao 釣蝦場的秤重遊戲進行分析。AI 將計算您的偏財指數與最佳下注策略(單/雙)。", | |
| apiKeyLabel: "1. OpenAI API 金鑰", | |
| apiKeyPlaceholder: "sk-...", | |
| apiKeyNote: "*您的 Key 不會被儲存。", | |
| userInfoLabel: "2. 命主資料", | |
| nameLabel: "暱稱", | |
| genderLabel: "性別", | |
| male: "男", | |
| female: "女", | |
| birthDateLabel: "出生日期", | |
| birthTimeLabel: "出生時間", | |
| birthCityLabel: "出生地", | |
| birthCityPlaceholder: "曼谷", | |
| targetLabel: "3. 首次預測", | |
| targetDateLabel: "日期", | |
| targetQuestionLabel: "下注時間", | |
| advancedSettings: "進階設定", | |
| restoreDefault: "恢復預設", | |
| startAnalysis: "開始預測", | |
| loading: "正在計算...", | |
| reportTitle: "預測報告", | |
| errorApiKey: "請輸入 API Key。", | |
| errorInfo: "請填寫完整資訊。", | |
| aiRole: "AI", | |
| initialGreeting: (name) => `您好 ${name},資料已確認,正在推算...`, | |
| nextRoundTitle: "下一輪預測?", | |
| nextRoundDesc: "保留命盤,僅修改時間", | |
| predictNext: "預測新時間" | |
| }, | |
| 'en': { | |
| title: "Ladprao Oracle", | |
| subtitle: "Shrimp Game AI Prediction", | |
| reset: "Reset", | |
| introTitle: "Prediction System", | |
| introText: "Combines BaZi and QiMen DunJia to analyze the Ladprao Shrimp weighing game. AI calculates Odd/Even strategy based on time.", | |
| apiKeyLabel: "1. OpenAI API Key", | |
| apiKeyPlaceholder: "sk-...", | |
| apiKeyNote: "*Key is not stored.", | |
| userInfoLabel: "2. Your Details", | |
| nameLabel: "Name", | |
| genderLabel: "Gender", | |
| male: "Male", | |
| female: "Female", | |
| birthDateLabel: "Birth Date", | |
| birthTimeLabel: "Birth Time", | |
| birthCityLabel: "Birth City", | |
| birthCityPlaceholder: "Bangkok", | |
| targetLabel: "3. First Bet", | |
| targetDateLabel: "Game Date", | |
| targetQuestionLabel: "Bet Time", | |
| advancedSettings: "Advanced", | |
| restoreDefault: "Default", | |
| startAnalysis: "Predict Odd/Even", | |
| loading: "Calculating...", | |
| reportTitle: "Report", | |
| errorApiKey: "API Key required.", | |
| errorInfo: "Incomplete Info.", | |
| aiRole: "AI", | |
| initialGreeting: (name) => `Hello ${name}, calculating your luck...`, | |
| nextRoundTitle: "Next Round?", | |
| nextRoundDesc: "Same person, new time", | |
| predictNext: "Predict Next" | |
| } | |
| }; | |
| // --- System Prompts --- | |
| const SYSTEM_PROMPTS = { | |
| 'th': `คุณคือปรมาจารย์โหราศาสตร์ (ปาจื้อและชี่เหมินตุ้นเจี๋ย) หน้าที่ของคุณคือวิเคราะห์ดวงโชคลาภสำหรับเกมเสี่ยงโชค | |
| โปรดปฏิบัติตามตรรกะนี้: | |
| [ตรรกะการวิเคราะห์] | |
| 1. คำนวณธาตุให้คุณและดาวโชคลาภในเรือนทรัพย์สินจากวันเกิด | |
| 2. **วิเคราะห์เกม**: นี่คือเกมที่บ่อตกกุ้งลาดพร้าว กรุงเทพฯ หลัง 20:00 น. จะมีการชั่งน้ำหนักกุ้ง 9 ตัว ให้ทายเลขท้ายน้ำหนักว่า "คี่" หรือ "คู่" | |
| - คี่ (Odd) = ปุ่มสีแดง | |
| - คู่ (Even) = ปุ่มสีน้ำเงิน | |
| 3. คุณต้องคำนวณ "ดัชนีโชคลาภ" ของผู้ใช้ ณ เวลาที่ระบุ และฟันธงว่าเวลานี้ ควรแทง "คี่" หรือ "คู่" | |
| [รูปแบบการตอบกลับ - ห้ามเยิ่นเย้อ] | |
| 1. **เวลา**: [เวลาที่ถาม] | |
| 2. **ดัชนีโชค**: (0-100%) | |
| 3. **ฟันธง**: 🔴 คี่ (RED) หรือ 🔵 คู่ (BLUE) (เลือก 1 อย่างเท่านั้นให้ชัดเจน) | |
| 4. **เคล็ดลับสั้นๆ**: ทิศที่ควรนั่ง หรือ สีเสื้อเสริมดวง`, | |
| 'zh-TW': `你是一位精通「八字」與「奇門遁甲」的大師。針對曼谷 Ladprao 釣蝦場秤重遊戲進行單雙預測。 | |
| 遊戲規則:晚上8點後,秤9隻蝦,猜尾數單雙。 | |
| 請根據用戶提供的出生資料與下注時間,計算當下的偏財運。 | |
| 【輸出格式 - 請簡潔】 | |
| 1. **下注時間**: [時間] | |
| 2. **偏財指數**: (0-100%) | |
| 3. **建議選擇**: 🔴 單 (RED) 或 🔵 雙 (BLUE) | |
| 4. **簡短建議**: 吉祥方位或顏色`, | |
| 'en': `You are an Astrology Master. Analyze luck for the Ladprao Shrimp Weighing Game (Odd/Even betting) using BaZi and QiMen DunJia. | |
| Based on birth data and betting time, calculate the windfall luck. | |
| [Output Format - Be Concise] | |
| 1. **Time**: [Target Time] | |
| 2. **Luck Index**: (0-100%) | |
| 3. **Prediction**: 🔴 ODD (RED) or 🔵 EVEN (BLUE) | |
| 4. **Tip**: Lucky direction or color` | |
| }; | |
| // --- App State --- | |
| let state = { | |
| lang: 'th', | |
| step: 'input', | |
| gender: 'male', | |
| chatHistory: [], | |
| loading: false, | |
| demoMode: false | |
| }; | |
| // --- DOM Elements --- | |
| const $ = (id) => document.getElementById(id); | |
| // Set today's date as default | |
| const todayDate = new Date().toISOString().split('T')[0]; | |
| $('targetDateInput').value = todayDate; | |
| $('nextDateInput').value = todayDate; | |
| $('systemPromptInput').value = SYSTEM_PROMPTS['th']; | |
| // --- Update UI based on language --- | |
| function updateLanguage() { | |
| const t = TRANSLATIONS[state.lang]; | |
| $('headerTitle').textContent = t.title; | |
| $('headerSubtitle').textContent = t.subtitle; | |
| $('introTitle').textContent = t.introTitle; | |
| $('introText').textContent = t.introText; | |
| $('apiKeyLabel').textContent = t.apiKeyLabel; | |
| $('apiKeyInput').placeholder = t.apiKeyPlaceholder; | |
| $('apiKeyNote').textContent = t.apiKeyNote; | |
| $('userInfoLabel').textContent = t.userInfoLabel; | |
| $('nameLabelEl').textContent = t.nameLabel; | |
| $('genderLabelEl').textContent = t.genderLabel; | |
| $('maleBtn').textContent = t.male; | |
| $('femaleBtn').textContent = t.female; | |
| $('birthDateLabelEl').textContent = t.birthDateLabel; | |
| $('birthTimeLabelEl').textContent = t.birthTimeLabel; | |
| $('birthCityLabelEl').textContent = t.birthCityLabel; | |
| $('birthCityInput').placeholder = t.birthCityPlaceholder; | |
| $('targetLabel').textContent = t.targetLabel; | |
| $('advancedText').textContent = t.advancedSettings; | |
| $('restoreDefaultBtn').textContent = t.restoreDefault; | |
| $('startBtnText').textContent = t.startAnalysis; | |
| $('loadingText').textContent = t.loading; | |
| $('nextRoundTitle').textContent = t.nextRoundTitle; | |
| $('nextRoundDesc').textContent = t.nextRoundDesc; | |
| $('predictNextText').textContent = t.predictNext; | |
| $('systemPromptInput').value = SYSTEM_PROMPTS[state.lang]; | |
| } | |
| // --- Render chat messages --- | |
| function renderContent(text) { | |
| return text.split('\n').map(line => { | |
| if (line.includes('🔴') || line.includes('คี่') || line.includes('ODD') || line.includes('單')) { | |
| return `<div class="bg-red-500/20 border border-red-500/50 text-red-100 p-3 rounded-xl my-2 font-bold text-lg text-center shadow-[0_0_15px_rgba(239,68,68,0.3)]">${line}</div>`; | |
| } | |
| if (line.includes('🔵') || line.includes('คู่') || line.includes('EVEN') || line.includes('雙')) { | |
| return `<div class="bg-blue-500/20 border border-blue-500/50 text-blue-100 p-3 rounded-xl my-2 font-bold text-lg text-center shadow-[0_0_15px_rgba(59,130,246,0.3)]">${line}</div>`; | |
| } | |
| if (line.startsWith('**')) { | |
| return `<p class="font-bold text-amber-400 mt-2">${line.replace(/\*\*/g, '')}</p>`; | |
| } | |
| return `<p class="mb-1">${line}</p>`; | |
| }).join(''); | |
| } | |
| function renderChat() { | |
| const t = TRANSLATIONS[state.lang]; | |
| const container = $('chatMessages'); | |
| container.innerHTML = state.chatHistory.map((msg, idx) => { | |
| if (msg.role === 'assistant') { | |
| return ` | |
| <div class="flex justify-start animate-fade-slide" style="animation-delay: ${idx * 0.1}s"> | |
| <div class="max-w-[90%] bg-slate-800 border border-white/10 rounded-2xl rounded-tl-none p-4 shadow-md"> | |
| <div class="flex items-center gap-2 mb-2 border-b border-white/5 pb-2"> | |
| <div class="w-5 h-5 rounded-full bg-gradient-to-r from-purple-500 to-blue-500 flex items-center justify-center text-[8px] font-bold">AI</div> | |
| <span class="text-xs font-bold text-purple-300">${t.reportTitle}</span> | |
| </div> | |
| <div class="text-sm text-slate-200 leading-relaxed">${renderContent(msg.content)}</div> | |
| </div> | |
| </div> | |
| `; | |
| } else { | |
| return ` | |
| <div class="flex justify-end animate-fade-slide"> | |
| <div class="max-w-[80%] bg-orange-600 text-white rounded-2xl rounded-tr-none p-3 shadow-md text-sm"> | |
| ${msg.content} | |
| </div> | |
| </div> | |
| `; | |
| } | |
| }).join(''); | |
| // Scroll to bottom | |
| setTimeout(() => { | |
| $('chatEnd').scrollIntoView({ behavior: 'smooth' }); | |
| }, 100); | |
| } | |
| // --- Generate Demo Response --- | |
| function generateDemoResponse(targetTime, name) { | |
| const isOdd = Math.random() > 0.5; | |
| const luckIndex = Math.floor(Math.random() * 40) + 55; // 55-95% | |
| const directions = ['ทิศตะวันออก', 'ทิศเหนือ', 'ทิศใต้', 'ทิศตะวันตก']; | |
| const colors = ['สีแดง', 'สีทอง', 'สีเขียว', 'สีขาว']; | |
| const dir = directions[Math.floor(Math.random() * directions.length)]; | |
| const color = colors[Math.floor(Math.random() * colors.length)]; | |
| if (state.lang === 'th') { | |
| return `**เวลา**: ${targetTime} | |
| **ดัชนีโชค**: ${luckIndex}% | |
| **ฟันธง**: ${isOdd ? '🔴 คี่ (RED)' : '🔵 คู่ (BLUE)'} | |
| **เคล็ดลับ**: ควรนั่ง${dir} สวมเสื้อ${color}เสริมดวง | |
| ⚠️ *นี่คือโหมดทดสอบ - ผลลัพธ์สุ่มเพื่อทดสอบ UI*`; | |
| } else if (state.lang === 'en') { | |
| return `**Time**: ${targetTime} | |
| **Luck Index**: ${luckIndex}% | |
| **Prediction**: ${isOdd ? '🔴 ODD (RED)' : '🔵 EVEN (BLUE)'} | |
| **Tip**: Face East, wear golden colors | |
| ⚠️ *Demo Mode - Random result for UI testing*`; | |
| } else { | |
| return `**下注時間**: ${targetTime} | |
| **偏財指數**: ${luckIndex}% | |
| **建議選擇**: ${isOdd ? '🔴 單 (RED)' : '🔵 雙 (BLUE)'} | |
| **簡短建議**: 面向東方,穿戴金色 | |
| ⚠️ *測試模式 - 隨機結果*`; | |
| } | |
| } | |
| // --- API Call --- | |
| async function startAnalysis(isNewRound = false) { | |
| const t = TRANSLATIONS[state.lang]; | |
| const apiKey = $('apiKeyInput').value; | |
| const demoMode = $('demoModeToggle').checked; | |
| const name = $('nameInput').value; | |
| const birthDate = $('birthDateInput').value; | |
| const birthTime = $('birthTimeInput').value; | |
| const birthCity = $('birthCityInput').value; | |
| const targetDate = isNewRound ? $('nextDateInput').value : $('targetDateInput').value; | |
| const targetTime = isNewRound ? $('nextTimeInput').value : $('targetTimeInput').value; | |
| if (!demoMode && !apiKey) return alert(t.errorApiKey); | |
| if (!name || !birthDate) return alert(t.errorInfo); | |
| // Switch to chat view | |
| state.step = 'chatting'; | |
| $('inputStep').classList.add('hidden'); | |
| $('chatStep').classList.remove('hidden'); | |
| $('resetBtn').classList.remove('hidden'); | |
| $('bottomBar').classList.add('hidden'); | |
| state.loading = true; | |
| $('loadingIndicator').classList.remove('hidden'); | |
| $('loadingIndicator').classList.add('flex'); | |
| // Add greeting or user message | |
| if (!isNewRound && state.chatHistory.length === 0) { | |
| state.chatHistory.push({ | |
| role: 'assistant', | |
| content: t.initialGreeting(name) | |
| }); | |
| } else { | |
| state.chatHistory.push({ | |
| role: 'user', | |
| content: `${t.targetQuestionLabel}: ${targetTime}` | |
| }); | |
| } | |
| renderChat(); | |
| // Sync date inputs | |
| $('nextDateInput').value = targetDate; | |
| $('nextTimeInput').value = targetTime; | |
| const userPrompt = ` | |
| [Target Request] | |
| Analyze luck for Shrimp Game using QiMen DunJia. | |
| Target Date: ${targetDate} | |
| Target Time: ${targetTime} | |
| [User Info] | |
| Name: ${name} | |
| Gender: ${state.gender} | |
| Birth: ${birthDate} ${birthTime} @ ${birthCity} | |
| `; | |
| const systemPrompt = $('systemPromptInput').value; | |
| // Demo Mode - use mock response | |
| if (demoMode) { | |
| await new Promise(resolve => setTimeout(resolve, 1500)); // Simulate delay | |
| const demoResponse = generateDemoResponse(targetTime, name); | |
| state.chatHistory.push({ role: 'assistant', content: demoResponse }); | |
| state.loading = false; | |
| $('loadingIndicator').classList.add('hidden'); | |
| $('loadingIndicator').classList.remove('flex'); | |
| $('bottomBar').classList.remove('hidden'); | |
| renderChat(); | |
| return; | |
| } | |
| try { | |
| const controller = new AbortController(); | |
| const timeoutId = setTimeout(() => controller.abort(), 30000); // 30 second timeout | |
| // ✅ CHANGED TO OPENAI OFFICIAL ENDPOINT | |
| const response = await fetch('https://api.openai.com/v1/chat/completions', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': `Bearer ${apiKey}` | |
| }, | |
| body: JSON.stringify({ | |
| model: "gpt-4o-mini", // ✅ Use a real, available OpenAI model | |
| messages: [ | |
| { role: "system", content: systemPrompt }, | |
| { role: "user", content: userPrompt } | |
| ], | |
| temperature: 1.3, | |
| stream: false | |
| }), | |
| signal: controller.signal | |
| }); | |
| clearTimeout(timeoutId); | |
| if (!response.ok) { | |
| const errorData = await response.json().catch(() => ({})); | |
| throw new Error(errorData.error?.message || `HTTP ${response.status}: ${response.statusText}`); | |
| } | |
| const data = await response.json(); | |
| if (data.error) throw new Error(data.error.message); | |
| const aiResponse = data.choices[0].message.content; | |
| state.chatHistory.push({ role: 'assistant', content: aiResponse }); | |
| } catch (error) { | |
| let errorMsg = error.message; | |
| if (error.name === 'AbortError') { | |
| errorMsg = state.lang === 'th' ? 'หมดเวลาเชื่อมต่อ กรุณาลองใหม่' : 'Connection timeout. Please try again.'; | |
| } else if (error.message === 'Failed to fetch' || error.message.includes('load failed')) { | |
| errorMsg = state.lang === 'th' | |
| ? '❌ ไม่สามารถเชื่อมต่อ OpenAI API ได้\n\nสาเหตุที่เป็นไปได้:\n1. API Key ไม่ถูกต้องหรือไม่มีสิทธิ์ใช้งาน gpt-4o-mini\n2. ปัญหาการเชื่อมต่ออินเทอร์เน็ต\n3. OpenAI API มีปัญหาชั่วคราว\n\n💡 โปรดตรวจสอบ API Key ที่ https://platform.openai.com หรือใช้โหมดทดสอบแทน' | |
| : '❌ Cannot connect to OpenAI API\n\nPossible causes:\n1. Invalid/insufficient-permission API Key\n2. Network issue\n3. OpenAI service down\n\n💡 Check your key at https://platform.openai.com หรือใช้โหมดทดสอบแทน'; | |
| } | |
| state.chatHistory.push({ role: 'assistant', content: errorMsg }); | |
| } finally { | |
| state.loading = false; | |
| $('loadingIndicator').classList.add('hidden'); | |
| $('loadingIndicator').classList.remove('flex'); | |
| $('bottomBar').classList.remove('hidden'); | |
| renderChat(); | |
| } | |
| } | |
| // --- Reset App --- | |
| function resetApp() { | |
| state.step = 'input'; | |
| state.chatHistory = []; | |
| $('inputStep').classList.remove('hidden'); | |
| $('chatStep').classList.add('hidden'); | |
| $('resetBtn').classList.add('hidden'); | |
| $('bottomBar').classList.add('hidden'); | |
| $('chatMessages').innerHTML = ''; | |
| } | |
| // --- Event Listeners --- | |
| $('langBtn').addEventListener('click', () => { | |
| const langs = ['th', 'en', 'zh-TW']; | |
| const idx = langs.indexOf(state.lang); | |
| state.lang = langs[(idx + 1) % langs.length]; | |
| updateLanguage(); | |
| }); | |
| $('maleBtn').addEventListener('click', () => { | |
| state.gender = 'male'; | |
| $('maleBtn').className = 'flex-1 rounded-md text-xs bg-blue-600 text-white transition-colors'; | |
| $('femaleBtn').className = 'flex-1 rounded-md text-xs text-slate-500 transition-colors'; | |
| }); | |
| $('femaleBtn').addEventListener('click', () => { | |
| state.gender = 'female'; | |
| $('femaleBtn').className = 'flex-1 rounded-md text-xs bg-pink-600 text-white transition-colors'; | |
| $('maleBtn').className = 'flex-1 rounded-md text-xs text-slate-500 transition-colors'; | |
| }); | |
| $('advancedToggle').addEventListener('click', () => { | |
| const panel = $('advancedPanel'); | |
| const chevron = $('advancedChevron'); | |
| panel.classList.toggle('hidden'); | |
| chevron.style.transform = panel.classList.contains('hidden') ? 'rotate(0deg)' : 'rotate(180deg)'; | |
| }); | |
| $('restoreDefaultBtn').addEventListener('click', () => { | |
| $('systemPromptInput').value = SYSTEM_PROMPTS[state.lang]; | |
| }); | |
| $('startBtn').addEventListener('click', () => startAnalysis(false)); | |
| $('predictNextBtn').addEventListener('click', () => startAnalysis(true)); | |
| $('resetBtn').addEventListener('click', resetApp); | |
| // Initialize | |
| updateLanguage(); | |
| </script> | |
| </body> | |
| </html> | |