webapp / index.html
jackyanghxc's picture
Update index.html
c6a890c verified
<!DOCTYPE html>
<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>