同步当前架构和数据 (2026-06-11)
- 训练脚本: train_v2.py + llm_chat_improved.py - API生成: api_correction.py - 高温多样化: regenerate_all_high_temp.py - 每日数据生成: daily_data_gen.py - 数据: xiaoli_train_v2.json(40776条) + vocab_v2.json - 蒸馏问题: exam_distill_questions等 - Web服务: web_server.py + chat.html - 新增 .gitignore 排除旧版文件
This commit is contained in:
1 parent
4df3254569
commit
7f8f607f26
17 files changed
+1643
-17
No files matched your search
@@ -0,0 +1,284 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小狸 v1.2 聊天</title>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body {
|
||||
font-family: 'PingFang SC', 'Microsoft YaHei', sans-serif;
|
||||
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
background: white;
|
||||
border-radius: 24px;
|
||||
box-shadow: 0 20px 60px rgba(0,0,0,0.15);
|
||||
overflow: hidden;
|
||||
}
|
||||
.header {
|
||||
background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
.header .avatar {
|
||||
width: 64px; height: 64px;
|
||||
background: white;
|
||||
border-radius: 50%;
|
||||
margin: 0 auto 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 32px;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.1);
|
||||
}
|
||||
.header h1 { font-size: 24px; color: white; }
|
||||
.header p { color: rgba(255,255,255,0.9); font-size: 12px; margin-top: 2px; }
|
||||
.chat-box {
|
||||
height: 420px;
|
||||
overflow-y: auto;
|
||||
padding: 16px;
|
||||
background: #fafafa;
|
||||
}
|
||||
.chat-box::-webkit-scrollbar { width: 5px; }
|
||||
.chat-box::-webkit-scrollbar-thumb { background: #ddd; border-radius: 10px; }
|
||||
.msg { margin-bottom: 14px; display: flex; animation: fadeIn 0.3s ease; }
|
||||
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
|
||||
.msg.user { justify-content: flex-end; }
|
||||
.msg.bot { justify-content: flex-start; }
|
||||
.bubble {
|
||||
max-width: 80%;
|
||||
padding: 10px 14px;
|
||||
border-radius: 16px;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
word-break: break-word;
|
||||
}
|
||||
.msg.user .bubble {
|
||||
background: #ff9a9e;
|
||||
color: white;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
.msg.bot .bubble {
|
||||
background: white;
|
||||
color: #333;
|
||||
border-bottom-left-radius: 4px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.06);
|
||||
}
|
||||
.msg.bot .avatar-small {
|
||||
width: 30px; height: 30px;
|
||||
background: linear-gradient(135deg, #ff9a9e, #fecfef);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 15px;
|
||||
margin-right: 8px;
|
||||
flex-shrink: 0;
|
||||
color: white;
|
||||
}
|
||||
.time-tag { font-size: 11px; color: #bbb; margin-top: 3px; }
|
||||
.input-area {
|
||||
padding: 12px 16px;
|
||||
background: white;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
}
|
||||
.input-area input {
|
||||
flex: 1;
|
||||
padding: 10px 14px;
|
||||
border: 2px solid #f0f0f0;
|
||||
border-radius: 25px;
|
||||
font-size: 14px;
|
||||
outline: none;
|
||||
}
|
||||
.input-area input:focus { border-color: #ff9a9e; }
|
||||
.input-area button {
|
||||
width: 42px; height: 42px;
|
||||
background: linear-gradient(135deg, #ff9a9e, #fecfef);
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
cursor: pointer;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
.input-area button:hover { transform: scale(1.08); }
|
||||
.input-area button:disabled { opacity: 0.5; cursor: not-allowed; }
|
||||
.typing-indicator { display: none; padding: 10px 14px; background: white; border-radius: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
|
||||
.typing-indicator.active { display: flex; }
|
||||
.typing-indicator span {
|
||||
width: 7px; height: 7px; background: #ff9a9e; border-radius: 50%;
|
||||
margin: 0 2px; animation: bounce 1.4s infinite;
|
||||
}
|
||||
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
||||
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
||||
@keyframes bounce { 0%,80%,100% { transform: translateY(0); } 40% { transform: translateY(-8px); } }
|
||||
.controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 6px 16px;
|
||||
background: #fff8f8;
|
||||
border-top: 1px solid #f0f0f0;
|
||||
}
|
||||
.controls label { font-size: 12px; color: #999; }
|
||||
.controls input[type=range] { flex: 1; accent-color: #ff9a9e; height: 4px; }
|
||||
.controls .val { font-size: 12px; color: #e07070; font-weight: bold; min-width: 30px; }
|
||||
.controls .clear-btn {
|
||||
font-size: 11px; color: #ccc; cursor: pointer; padding: 3px 8px; border-radius: 10px; border: 1px solid #eee;
|
||||
}
|
||||
.controls .clear-btn:hover { color: #e07070; border-color: #ffd4d4; }
|
||||
.status-bar { padding: 4px 16px; font-size: 11px; color: #bbb; text-align: center; background: #fafafa; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<div class="header">
|
||||
<div class="avatar">🦊</div>
|
||||
<h1>小狸 v1.2</h1>
|
||||
<p id="headerInfo">V2架构 · 21M参数 · 新训练启动 🔥</p>
|
||||
</div>
|
||||
|
||||
<div class="chat-box" id="chatBox"></div>
|
||||
|
||||
<!-- 温度控制 -->
|
||||
<div class="controls">
|
||||
<label>🌡️</label>
|
||||
<input type="range" id="tempSlider" min="0.05" max="0.5" step="0.05" value="0.15">
|
||||
<span class="val" id="tempVal">0.15</span>
|
||||
<span class="clear-btn" onclick="clearChat()">🗑️ 清空</span>
|
||||
</div>
|
||||
|
||||
<div class="input-area">
|
||||
<input type="text" id="input" placeholder="跟小狸说点什么吧..." autofocus>
|
||||
<button id="sendBtn" onclick="send()">➤</button>
|
||||
</div>
|
||||
<div class="status-bar" id="statusBar">按回车发送 · 建议温度 0.1~0.2</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
const chatBox = document.getElementById('chatBox');
|
||||
const input = document.getElementById('input');
|
||||
const sendBtn = document.getElementById('sendBtn');
|
||||
const statusBar = document.getElementById('statusBar');
|
||||
const tempSlider = document.getElementById('tempSlider');
|
||||
const tempVal = document.getElementById('tempVal');
|
||||
|
||||
// 对话历史(用于多轮)
|
||||
let history = [];
|
||||
|
||||
tempSlider.addEventListener('input', () => {
|
||||
tempVal.textContent = parseFloat(tempSlider.value).toFixed(2);
|
||||
});
|
||||
|
||||
addMsg('bot', '你好呀!我是小狸,一个8岁的小女孩~🦊\n你可以连续跟我聊天,我会记住之前说过的话哦!');
|
||||
|
||||
function addMsg(role, text) {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'msg ' + role;
|
||||
if (role === 'bot') {
|
||||
const av = document.createElement('div');
|
||||
av.className = 'avatar-small';
|
||||
av.textContent = '🦊';
|
||||
div.appendChild(av);
|
||||
}
|
||||
const bubble = document.createElement('div');
|
||||
bubble.className = 'bubble';
|
||||
bubble.innerHTML = text.replace(/\n/g, '<br>');
|
||||
div.appendChild(bubble);
|
||||
|
||||
const time = document.createElement('div');
|
||||
time.className = 'time-tag';
|
||||
time.textContent = new Date().toLocaleTimeString('zh-CN', {hour:'2-digit',minute:'2-digit'});
|
||||
if (role === 'user') {
|
||||
bubble.appendChild(document.createElement('br'));
|
||||
bubble.appendChild(time);
|
||||
} else {
|
||||
bubble.appendChild(document.createElement('br'));
|
||||
bubble.appendChild(time);
|
||||
}
|
||||
chatBox.appendChild(div);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
|
||||
function showTyping() {
|
||||
const div = document.createElement('div');
|
||||
div.className = 'msg bot';
|
||||
div.id = 'typing';
|
||||
const av = document.createElement('div');
|
||||
av.className = 'avatar-small';
|
||||
av.textContent = '🦊';
|
||||
div.appendChild(av);
|
||||
const indicator = document.createElement('div');
|
||||
indicator.className = 'typing-indicator active';
|
||||
for (let i = 0; i < 3; i++) indicator.innerHTML += '<span>';
|
||||
div.appendChild(indicator);
|
||||
chatBox.appendChild(div);
|
||||
chatBox.scrollTop = chatBox.scrollHeight;
|
||||
}
|
||||
|
||||
function hideTyping() {
|
||||
const t = document.getElementById('typing');
|
||||
if (t) t.remove();
|
||||
}
|
||||
|
||||
async function send() {
|
||||
const q = input.value.trim();
|
||||
if (!q) return;
|
||||
input.value = '';
|
||||
sendBtn.disabled = true;
|
||||
statusBar.textContent = '小狸正在思考...';
|
||||
|
||||
addMsg('user', q);
|
||||
showTyping();
|
||||
|
||||
try {
|
||||
const res = await fetch('/api/chat', {
|
||||
method: 'POST',
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: JSON.stringify({
|
||||
question: q,
|
||||
temperature: parseFloat(tempSlider.value),
|
||||
history: history.length > 0 ? history : null
|
||||
})
|
||||
});
|
||||
const data = await res.json();
|
||||
hideTyping();
|
||||
if (data.answer) {
|
||||
// 记录到历史
|
||||
history.push({q: q, a: data.answer});
|
||||
addMsg('bot', data.answer + ' <span style="color:#ccc;font-size:11px">' + data.time + '</span>');
|
||||
} else {
|
||||
addMsg('bot', '唔…我没想好怎么回答😅');
|
||||
}
|
||||
} catch (e) {
|
||||
hideTyping();
|
||||
addMsg('bot', '哎呀,出错了…再试试?');
|
||||
}
|
||||
sendBtn.disabled = false;
|
||||
statusBar.textContent = '按回车发送 · 温度 ' + parseFloat(tempSlider.value).toFixed(2);
|
||||
input.focus();
|
||||
}
|
||||
|
||||
function clearChat() {
|
||||
chatBox.innerHTML = '';
|
||||
history = [];
|
||||
addMsg('bot', '🔄 对话已重置!重新开始吧~');
|
||||
}
|
||||
|
||||
input.addEventListener('keydown', e => {
|
||||
if (e.key === 'Enter') send();
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in new issue
Block a user