Files
xiaoxue_admin 8f9c98c5b5 feat: 高考志愿网站初始版本
- ai-chat.html: AI对话咨询页
- ai-tool.html: AI智能推荐页 (需 /api/recommend 路由)
- plan.html: 志愿填写助手
- school.html: 查校对比
- major.html: 查专业录取分
- qa.html: 常见问题
- diag.html: 高考诊断
- gaokao-chat-server-v2.py: Flask后端 (port 8080)
- scripts/: 数据采集和处理工具
2026-06-18 16:59:13 +08:00

172 lines
11 KiB
HTML

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>AI 志愿咨询 - 河南高考</title>
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Microsoft YaHei", sans-serif; background: #0a0a0f; height: 100vh; display: flex; flex-direction: column; color: #e0e0e0; }
.header { background: rgba(20,20,30,0.95); backdrop-filter: blur(20px); border-bottom: 1px solid rgba(255,255,255,0.08); color: white; padding: 14px 20px; display: flex; align-items: center; gap: 12px; position: sticky; top: 0; z-index: 100; }
.header-back { color: #a0a0a0; text-decoration: none; font-size: 14px; display: flex; align-items: center; gap: 4px; transition: color 0.3s; }
.header-back:hover { color: #667eea; }
.header h1 { font-size: 17px; font-weight: 600; flex: 1; display: flex; align-items: center; gap: 8px; }
.header-new { background: rgba(102,126,234,0.2); border: 1px solid rgba(102,126,234,0.4); color: #667eea; padding: 6px 14px; border-radius: 20px; font-size: 13px; cursor: pointer; text-decoration: none; transition: all 0.3s; }
.header-new:hover { background: rgba(102,126,234,0.3); }
.chat-container { flex: 1; overflow-y: auto; padding: 20px; display: flex; flex-direction: column; gap: 16px; background: #0a0a0f; }
.message { display: flex; gap: 10px; max-width: 85%; animation: fadeIn 0.3s ease; }
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.message.ai { align-self: flex-start; }
.message.user { align-self: flex-end; flex-direction: row-reverse; }
.avatar { width: 36px; height: 36px; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 16px; flex-shrink: 0; }
.message.ai .avatar { background: linear-gradient(135deg, #667eea, #764ba2); color: white; }
.message.user .avatar { background: rgba(255,255,255,0.1); color: #a0a0a0; border: 1px solid rgba(255,255,255,0.1); }
.bubble { padding: 12px 16px; border-radius: 16px; font-size: 15px; line-height: 1.7; word-break: break-word; }
.message.ai .bubble { background: rgba(255,255,255,0.06); color: #d0d0d0; border: 1px solid rgba(255,255,255,0.08); border-top-left-radius: 4px; }
.message.user .bubble { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border-top-right-radius: 4px; }
.bubble h1,.bubble h2,.bubble h3,.bubble h4 { color: #e8e8e8; margin: 12px 0 6px; font-size: 15px; font-weight: 600; }
.bubble h1:first-child,.bubble h2:first-child,.bubble h3:first-child { margin-top: 0; }
.bubble h3 { color: #c0c0c0; font-size: 14px; }
.bubble hr { border: none; border-top: 1px solid rgba(255,255,255,0.1); margin: 12px 0; }
.bubble p { margin: 6px 0; }
.bubble p:first-child { margin-top: 0; }
.bubble p:last-child { margin-bottom: 0; }
.bubble strong { color: #fff; font-weight: 600; }
.bubble em { color: #a0a0a0; font-style: italic; }
.bubble ul,.bubble ol { padding-left: 20px; margin: 6px 0; }
.bubble li { margin: 3px 0; }
.bubble .tag { display: inline-block; font-size: 11px; padding: 1px 6px; border-radius: 4px; margin-right: 4px; }
.bubble .tag.冲 { background: rgba(251,191,36,0.15); color: #fbbf24; }
.bubble .tag.稳 { background: rgba(34,197,94,0.15); color: #4ade80; }
.bubble .tag.保 { background: rgba(59,130,246,0.15); color: #60a5fa; }
.bubble table { border-collapse: collapse; width: 100%; margin: 8px 0; font-size: 13px; }
.bubble th { color: #667eea; padding: 4px 8px; border: 1px solid rgba(255,255,255,0.08); text-align: left; }
.bubble td { color: #ccc; padding: 4px 8px; border: 1px solid rgba(255,255,255,0.06); }
.bubble code { background: rgba(255,255,255,0.08); padding: 1px 5px; border-radius: 4px; font-size: 13px; }
.typing { display: flex; gap: 10px; align-self: flex-start; max-width: 85%; }
.typing .avatar { background: linear-gradient(135deg, #667eea, #764ba2); color: white; }
.typing-dots { background: rgba(255,255,255,0.06); border: 1px solid rgba(255,255,255,0.08); padding: 12px 16px; border-radius: 16px; border-top-left-radius: 4px; display: flex; gap: 5px; align-items: center; }
.typing-dots span { width: 7px; height: 7px; background: #667eea; border-radius: 50%; animation: typing 1.4s infinite; }
.typing-dots span:nth-child(2) { animation-delay: 0.2s; }
.typing-dots span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing { 0%,60%,100% { transform: translateY(0); opacity: 0.4; } 30% { transform: translateY(-6px); opacity: 1; } }
.input-area { background: rgba(20,20,30,0.95); backdrop-filter: blur(20px); padding: 14px 16px; display: flex; gap: 10px; border-top: 1px solid rgba(255,255,255,0.08); }
.input-area input { flex: 1; padding: 12px 16px; border: 1.5px solid rgba(255,255,255,0.12); border-radius: 24px; font-size: 15px; outline: none; background: rgba(255,255,255,0.06); color: #fff; transition: border-color 0.2s; }
.input-area input:focus { border-color: #667eea; }
.input-area input::placeholder { color: #555; }
.input-area button { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 10px 22px; border-radius: 24px; font-size: 15px; cursor: pointer; font-weight: 600; transition: opacity 0.2s; }
.input-area button:disabled { opacity: 0.5; cursor: not-allowed; }
.start-screen { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 40px 20px; text-align: center; gap: 24px; background: #0a0a0f; }
.start-screen .icon { background: linear-gradient(135deg, #667eea, #764ba2); -webkit-background-clip: text; -webkit-text-fill-color: transparent; font-size: 80px; line-height: 1; }
.start-screen h2 { font-size: 22px; color: #fff; }
.start-screen p { color: #888; font-size: 15px; line-height: 1.7; max-width: 340px; }
.start-btn { background: linear-gradient(135deg, #667eea, #764ba2); color: white; border: none; padding: 14px 40px; border-radius: 30px; font-size: 16px; cursor: pointer; font-weight: 600; box-shadow: 0 4px 20px rgba(102,126,234,0.35); transition: transform 0.2s, box-shadow 0.2s; }
.start-btn:hover { transform: scale(1.03); box-shadow: 0 6px 25px rgba(102,126,234,0.5); }
.start-features { display: flex; gap: 20px; flex-wrap: wrap; justify-content: center; margin-top: 5px; }
.start-features span { color: #888; font-size: 13px; display: flex; align-items: center; gap: 5px; }
.start-features span::before { content: '✓'; color: #667eea; }
.hidden { display: none !important; }
.msg-time { text-align: center; color: #444; font-size: 12px; margin: 10px 0; }
@media (max-width: 480px) { .chat-container { padding: 12px; gap: 12px; } .bubble { font-size: 15px; padding: 10px 14px; } .avatar { width: 30px; height: 30px; font-size: 14px; } .start-screen { padding: 30px 15px; } .start-screen .icon { font-size: 64px; } .input-area { padding: 10px 12px; padding-bottom: max(10px, env(safe-area-inset-bottom)); gap: 8px; } .input-area input { padding: 10px 14px; font-size: 16px; } .input-area button { padding: 10px 16px; font-size: 14px; } .header h1 { font-size: 15px; } .message { max-width: 90%; } }
</style>
</head>
<body>
<div class="header">
<a href="/" class="header-back">← 返回首页</a>
<h1>🤖 AI 志愿咨询</h1>
<a href="#" class="header-new" onclick="startNew(); return false;">新对话</a>
</div>
<div id="startScreen" class="start-screen">
<div class="icon">🎓</div>
<h2>河南高考志愿推荐</h2>
<p>AI 智能对话,收集分数、意向专业和地区偏好,为你推荐冲 / 稳 / 保院校方案</p>
<button class="start-btn" onclick="startChat()">开始咨询</button>
<div class="start-features"><span>分数分析</span><span>智能推荐</span><span>冲稳保方案</span></div>
</div>
<div id="chatContainer" class="chat-container hidden"></div>
<div id="typingIndicator" class="typing hidden" style="padding: 0 20px;">
<div class="avatar">🤖</div>
<div class="typing-dots"><span></span><span></span><span></span></div>
</div>
<div id="inputArea" class="input-area hidden">
<input type="text" id="userInput" placeholder="输入你的回答…" onkeydown="if(event.key==='Enter')sendMessage()" autocomplete="off">
<button id="sendBtn" onclick="sendMessage()">发送</button>
</div>
<script>
marked.setOptions({ breaks: true, gfm: true });
let sessionId = '';
let loading = false;
async function startChat() {
document.getElementById('startScreen').classList.add('hidden');
document.getElementById('chatContainer').classList.remove('hidden');
document.getElementById('inputArea').classList.remove('hidden');
const res = await fetch('/api/chat/start', { method: 'POST' });
const data = await res.json();
sessionId = data.session_id;
addMessage('ai', data.message);
document.getElementById('userInput').focus();
}
async function sendMessage() {
if (loading) return;
const input = document.getElementById('userInput');
const text = input.value.trim();
if (!text) return;
loading = true;
document.getElementById('sendBtn').disabled = true;
addMessage('user', text);
input.value = '';
document.getElementById('typingIndicator').classList.remove('hidden');
scrollBottom();
try {
const res = await fetch('/api/chat/respond', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session_id: sessionId, message: text }),
});
const data = await res.json();
document.getElementById('typingIndicator').classList.add('hidden');
if (data.error) { addMessage('ai', '⚠️ ' + data.error); }
else {
addMessage('ai', data.message);
if (data.done) { addMessage('ai', '📋 以上就是为你推荐的院校方案。如有其他问题(如同专业院校对比、录取规则等)欢迎继续咨询!'); }
}
} catch(e) {
document.getElementById('typingIndicator').classList.add('hidden');
addMessage('ai', '⚠️ 网络异常,请检查网络连接后重试。');
}
loading = false;
document.getElementById('sendBtn').disabled = false;
input.focus();
}
function addMessage(role, content) {
const container = document.getElementById('chatContainer');
const div = document.createElement('div');
div.className = 'message ' + role;
const avatar = role === 'ai' ? '🤖' : '👤';
const formatted = role === 'ai' ? marked.parse(content) : content;
div.innerHTML = '<div class="avatar">'+avatar+'</div><div class="bubble">'+formatted+'</div>';
container.appendChild(div);
scrollBottom();
}
function scrollBottom() {
const container = document.getElementById('chatContainer');
requestAnimationFrame(() => { container.scrollTop = 1e9; });
}
async function startNew() {
sessionId = '';
document.getElementById('chatContainer').innerHTML = '';
document.getElementById('startScreen').classList.remove('hidden');
document.getElementById('chatContainer').classList.add('hidden');
document.getElementById('inputArea').classList.add('hidden');
}
</script>
</body>
</html>