52 Commits
Author SHA1 Message Date
shuiyuPyLab 9f85944646 chore: 项目已迁移至 Gitee/GitHub,仅保留迁移说明 (tombstone) 2026-08-09 10:17:30 +08:00
shuiyuPyLab 2154bba21d chore: 项目已迁移至 Gitee/GitHub,仅保留迁移说明 (tombstone) 2026-08-09 10:06:11 +08:00
shuiyu 69859f0084 chore: relicense to MIT 2026-08-02 18:32:36 +08:00
shuiyu1123 fc5e2a4dc1 delete test file 2026-07-09 07:38:52 +00:00
shuiyu1123 d287de8ed2 update data/expanded_distilled.json via distill_expand 2026-07-09 07:38:32 +00:00
shuiyu1123 d4dfd10f9a update test via put 2026-07-09 07:37:55 +00:00
shuiyu1123 723829d38c create test 2026-07-09 07:37:14 +00:00
shuiyu1123 6c7c1d38a1 update data/expanded_distilled.json via distill_expand 2026-07-09 06:44:26 +00:00
XiaLi Bot 3aa8e9d205 XiaLi-Next统一架构: RoPE+GQA+SwiGLU+WeightTying 2026-06-21 04:40:59 +00:00
shuiyu1123 6dbc1405c6 云端训练脚本 + 新词表 + gen_pretrain优化 2026-06-21 02:00:43 +00:00
shuiyu1123 16458aea92 feat: Astron 5并发API + 修复蒸馏P2/P3 + 两阶段训练脚本 + 持续蒸馏守护
- api_correction.py: 嵌入 Astron key, max_workers=5, 修复 batch_convert/multi_temp 返回空列表bug
- scripts/api_correction.py: 同步更新
- train_max.py: 两阶段训练(预训练+角色对齐), Warmup+Cosine, 分层LR, AMP
- distill_daemon.py: 持续蒸馏守护脚本, 15大类种子话题, 5并发
2026-06-21 02:00:43 +00:00
shuiyu1123 463cf697fd [自动] 云端一键部署脚本 2026-06-21 01:58:21 +00:00
shuiyu1123 c369804d3c [自动] 云端GPU训练脚本 2026-06-21 01:58:19 +00:00
shuiyu1123 0ccce55ab0 v5: 两阶段生成 - Phase1纯API种子 + Phase2语义扩展 2026-06-20 15:40:47 +00:00
shuiyu1123 c53f4c9049 增加system_prompt和max_tokens参数 - 支持自定义角色设定 2026-06-20 14:47:16 +00:00
shuiyu1123 2bb3b60f18 v4: 双AI互相对话架构 - 2个师生对话对 + 话题生成器 2026-06-20 14:47:06 +00:00
shuiyu1123 70abc8e7ff fix: 同步移除硬编码API key 2026-06-20 13:56:46 +00:00
shuiyu1123 693e7a51e7 fix: 移除硬编码API key, 改为环境变量 2026-06-20 13:56:44 +00:00
shuiyu1123 f8fac5946b feat: 通用知识预训练数据生成器 20大类 2026-06-20 13:52:34 +00:00
shuiyu1123 2ba1ee3416 fix: scripts API同步 2026-06-20 13:24:49 +00:00
shuiyu1123 623a29bafd fix: Astron 5并发 + 修复蒸馏bug 2026-06-20 13:24:47 +00:00
shuiyu1123 1bc19e4c90 feat: 持续蒸馏守护脚本 2026-06-20 13:24:25 +00:00
shuiyu1123 b2c0af564f feat: 两阶段训练脚本 2026-06-20 13:24:24 +00:00
cnb.cEr0mSxFAFA bc6fb0ffe5 remove LFS files for Gitee push (Gitee free tier doesn't support LFS) 2026-06-19 10:50:21 +08:00
cnb.cEr0mSxFAFA 2acde6ae75 chore: enable git LFS for zip and pth files 2026-06-19 10:49:22 +08:00
cnb.cEr0mSxFAFA a88c47e273 feat: v1.3-lite-flash 训练代码 + 新词表(vocab_size=47725)
- 用 CharTokenizer.build_vocab 从 977K 数据生成词表 (vocab_size=47725)
- train_cnb.py: batch=224 + accum=2 (等效448) + AMP + torch.compile
- build_vocab.py: 词表生成脚本
- vocab_full.json: 含特殊token完整词表
- 模型 41.85M参数, L40 GPU训练
2026-06-19 10:34:37 +08:00
shuiyu1123 a0047a012d revert: restore original Dockerfile that was working 2026-06-18 20:36:04 +00:00
shuiyu1123 7b47faac50 fix: add vscode-server dir to Dockerfile, use vscode event for SSH 2026-06-18 20:18:20 +00:00
shuiyu1123 c6ff7be55a chore: revert to version 3 tasks format for SSH support 2026-06-18 20:05:41 +00:00
shuiyu1123 f5dd3e5874 chore: add vscode service to enable SSH in workspace 2026-06-18 19:53:09 +00:00
shuiyu1123 ac07c7f06a chore: revert to workspace format (version 3) 2026-06-18 19:22:03 +00:00
shuiyu1123 230d47cade fix: CI pipeline clones repo to /workspace directly, not subdir 2026-06-18 19:09:10 +00:00
shuiyu1123 5732229ed5 chore: add debug echo to pipeline script 2026-06-18 19:06:17 +00:00
shuiyu1123 ffb5825407 fix: correct vocab_size to max_id+1 (was len(vocab)) 2026-06-18 18:43:47 +00:00
shuiyu1123 a02401aa75 fix: LLMTrainer supports lr param 2026-06-18 18:40:25 +00:00
shuiyu1123 edf3a83e3c chore: rewrite .cnb.yml to CI pipeline format with api_trigger event 2026-06-18 18:27:38 +00:00
shuiyu1123 9799aa00c5 chore: set training epochs to 100 2026-06-18 18:25:44 +00:00
shuiyu1123 456c443e9c feat: add CNB cloud training config (GPU Dockerfile + .cnb.yml + train_cnb.py) 2026-06-18 18:09:59 +00:00
shuiyu1123 eb7717e9ce feat: add new general distill script, merged dataset v3 (977K pairs), legacy vocab_v2 2026-06-18 17:56:40 +00:00
shuiyu1123 231af72de9 大整理: 仓库重组 + 新词表 + 新README
- 清理仓库: 删除所有废弃的generate_*脚本和旧版数据文件
- 目录重组:
  - data/       → 训练数据
  - scripts/    → 数据生成脚本
  - templates/  → Web UI
- 重命名:
  - train_v2.py  → train.py
  - vocab_v3.json → vocab.json (BPE, 6.8k tokens)
- 更新 train.py 指向新词表路径
- 重写 README.md 完整文档
- 更新 .gitignore
2026-06-18 11:17:30 +00:00
shuiyu1123 6e0ced4772 添加v3词表 (BPE, 6.8k tokens, 666k数据训练)
- 从666k条训练数据自动学习
- 5812单字 + 1000高频词组
- 编码效率提升33%
- 含小狸特色词组: 捉迷藏/冰淇淋/为什么等
2026-06-17 14:31:25 +00:00
shuiyu1123 aead65192e 整理仓库: 清理旧分片/测试文件, 更新.gitignore, 添加训练数据 2026-06-16 14:12:33 +00:00
shuiyu1123 075492e391 添加训练数据 (666k条, 2分片) 2026-06-16 14:01:47 +00:00
shuiyu1123 8efb4faf73 添加合并脚本: bash merge_model.sh 2026-06-16 12:48:39 +00:00
shuiyu1123 2976bf2030 添加模型文件 (Epoch 7, 分2片, bash merge_model.sh合并) 2026-06-16 12:47:34 +00:00
shuiyu1123 9cef1d9ba1 添加模型文件分片 (Epoch 7, 3 parts + merge script) 2026-06-16 12:10:24 +00:00
shuiyu1123 91db488ad4 同步代码更新 (2026-06-16)
- 移除 generate_diverse_answers.py(多样化回答已废止)
- 更新 generate_fresh_qa.py(目标50万条新问答)
- 更新 generate_multiturn.py(6~12轮长对话,目标50万)
- 更新 regenerate_all_high_temp.py(独立保存,不追加训练集)
- 更新 .gitignore(忽略新输出目录)
- 所有API Key改为环境变量读取
2026-06-16 11:48:30 +00:00
shuiyu1123 eb1d62f85c 紧急修复:移除所有硬编码API Key,改为环境变量 ASTRON_KEY 2026-06-13 04:04:02 +00:00
shuiyu1123 7f27812efd 更新README:旨在最小设备上运行的闲聊心理治疗模型 2026-06-12 15:16:56 +00:00
shuiyu1123 d962c768a5 同步:更新daily_data_gen.py,200+话题+3000条/天 (2026-06-12) 2026-06-12 15:12:40 +00:00
shuiyu1123 7f8f607f26 同步当前架构和数据 (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 排除旧版文件
2026-06-11 14:07:52 +00:00
shuiyu1123 4df3254569 add LICENSE.
Signed-off-by: shuiyu1123 <f17376088816@163.com>
2026-06-06 00:26:36 +00:00
9 changed files with 12 additions and 1782 deletions

No files matched your search

-2
View File
@@ -1,2 +0,0 @@
*.json filter=lfs diff=lfs merge=lfs -text
llm_model_* filter=lfs diff=lfs merge=lfs -text
-36
View File
@@ -1,36 +0,0 @@
# xiaoli-llm-chat
#### Description
小狸AI - 自研中文对话大模型
#### Software Architecture
Software architecture description
#### Installation
1. xxxx
2. xxxx
3. xxxx
#### Instructions
1. xxxx
2. xxxx
3. xxxx
#### Contribution
1. Fork the repository
2. Create Feat_xxx branch
3. Commit your code
4. Create Pull Request
#### Gitee Feature
1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
4. The most valuable open source project [GVP](https://gitee.com/gvp)
5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
6. The most popular members [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
+12 -32
View File
@@ -1,37 +1,17 @@
# xiaoli-llm-chat # 项目已迁移 ✨
#### 介绍 你好呀~这个仓库已经搬到更好用的地方啦。
小狸AI - 自研中文对话大模型
#### 软件架构 为了让代码管理更清爽、多平台同步更省心,我们把原先分散的镜像统一收拢到主仓维护,这里就只保留这张"迁移小纸条"咯。
软件架构说明
📦 新家在这里:
- Gitee:https://gitee.com/shuiyu1123/xiaoli-llm-chat
- GitHub:https://github.com/shuiyu67/xiaoli-llm-chat
#### 安装教程 📋 内部评估:
- 镜像分散在多个平台,重复维护成本高、容易漏更;
- 自托管 Gitea 实例为个人非管理员环境,长期可用性与备份缺乏保障;
- 代码已稳定收拢至 Gitee / GitHub 主仓,原镜像不再承载更新职责;
- 统一主仓后便于协作、CI 与备份,减少多端同步负担。
1. xxxx 旧镜像不再更新,但代码都好好的在新家继续生长。感谢你一路的关注与陪伴 💛
2. xxxx
3. xxxx
#### 使用说明
1. xxxx
2. xxxx
3. xxxx
#### 参与贡献
1. Fork 本仓库
2. 新建 Feat_xxx 分支
3. 提交代码
4. 新建 Pull Request
#### 特技
1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md
2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com)
3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目
4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目
5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help)
6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
-3
View File
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:136863dba34ed2300a56611600b9cd758aa6e01cdd7e3dcdd35d0371be32d41c
size 43711
-143
View File
@@ -1,143 +0,0 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
小狸聊天 Web 服务 v2 - 支持多轮对话
"""
import sys, os, json, re
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
from flask import Flask, render_template, request, jsonify
import torch
from llm_chat_improved import (
CharTokenizer, build_vocabulary, LLMModel, LLMChat, load_training_data
)
app = Flask(__name__)
# 全局模型
llm_chat = None
vocab = None
def clean_text(text):
"""清洗文本"""
text = text.replace('\n', '')
text = re.sub(r'\*\*([^*]+)\*\*', r'\1', text)
text = re.sub(r'\([^)]*[ω。ノ♡^][^)]*\)', '', text)
emoji_pattern = re.compile(
'[\U0001F600-\U0001F64F\U0001F300-\U0001F5FF\U0001F680-\U0001F6FF\U0001F1E0-\U0001F1FF\U00002702-\U000027B0\U0001f926-\U0001f937\u2640-\u2642\u2600-\u2B55\u200d\u23cf\u23e9\u231a\ufe0f\u3030\u2728\u2714\u2716\u27a1\u2b05\u2b06\u2b07\u2b1b\u2b1c\u2b50\u2b55\u2934\u2935\u25aa\u25ab\u25b6\u25c0\u25fb\u25fc\u25fd\u25fe]+',
flags=re.UNICODE
)
text = emoji_pattern.sub('', text)
text = re.sub(r'[ \t]+', ' ', text)
return text.strip()
def load_model():
"""加载训练好的模型"""
global llm_chat, vocab
print("🐱 正在加载小狸模型...")
device = 'cpu'
# 直接从模型文件加载 vocab 和配置 (v4大模型)
checkpoint = torch.load('xiaoli_final_v4.pth', map_location=device)
vocab = checkpoint['vocab']
config = checkpoint.get('model_config', {})
print(f" 词汇表大小: {len(vocab)}")
# 创建模型 - 使用保存的配置(v4大模型带MoE+Thinking+Memory)
model = LLMModel(
vocab_size=config.get('vocab_size', len(vocab)),
d_model=config.get('d_model', 384),
n_heads=config.get('n_heads', 8),
n_layers=config.get('n_layers', 6),
d_ff=config.get('d_ff', 1536),
max_len=config.get('max_len', 128),
dropout=0.0,
use_memory=config.get('use_memory', True),
use_thinking=config.get('use_thinking', True),
use_moe=config.get('use_moe', True),
num_experts=config.get('num_experts', 4),
top_k=config.get('top_k', 2),
)
# 加载权重
model.load_state_dict(checkpoint['model_state_dict'])
llm_chat = LLMChat(model, vocab, device, 128)
print("✅ 小狸已就绪!")
# 存储会话历史
session_history = {}
@app.route('/')
def index():
return render_template('chat.html')
@app.route('/chat', methods=['POST'])
def chat():
data = request.json
message = data.get('message', '').strip()
session_id = data.get('session_id', 'default')
if not message:
return jsonify({'response': '请输入内容哦~'})
if llm_chat is None:
return jsonify({'response': '模型加载中,请稍后再试'})
try:
# 获取会话历史
history = session_history.get(session_id, [])
# 构建带上下文的输入(使用与训练一致的格式)
# 训练格式: <SOS>问题<SEP><START>
# 多轮格式: <SOS>历史问题1<SEP>历史回答1<SEP>历史问题2<SEP>历史回答2<SEP>当前问题<SEP><START>
if history and len(history) >= 2:
# 只保留最近2轮对话(4条记录)
recent_history = history[-4:]
# 提取问题和答案
context_parts = []
for i in range(0, len(recent_history), 2):
if i + 1 < len(recent_history):
q = recent_history[i].replace("用户:", "")
a = recent_history[i+1].replace("小狸:", "")
context_parts.append(f"{q}<SEP>{a}")
if context_parts:
context = "<SEP>".join(context_parts)
full_input = f"{context}<SEP>{message}"
else:
full_input = message
else:
full_input = message
# 限制输入长度(字符数)
if len(full_input) > 80:
full_input = full_input[-80:]
response = llm_chat.generate_response(full_input, max_length=50, temperature=0.3)
# 更新历史
history.append(f"用户:{message}")
history.append(f"小狸:{response}")
# 只保留最近6轮(12条记录)
session_history[session_id] = history[-12:]
return jsonify({'response': response})
except Exception as e:
import traceback
return jsonify({'response': f'出错了: {str(e)}\n{traceback.format_exc()}'})
@app.route('/clear', methods=['POST'])
def clear_history():
data = request.json
session_id = data.get('session_id', 'default')
session_history[session_id] = []
return jsonify({'status': 'ok'})
if __name__ == '__main__':
load_model()
print("\n🌐 启动 Web 服务: http://0.0.0.0:5000")
app.run(host='0.0.0.0', port=5000, debug=False)
-1251
View File
File diff suppressed because it is too large. Load diff
-3
View File
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7c4d05531958838c1c6750216a98fc781ea13085b278a0154eb1378680959fe9
size 10038
-309
View File
@@ -1,309 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>小狸 - AI 聊天</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
.chat-container {
width: 90%;
max-width: 500px;
height: 80vh;
background: white;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
display: flex;
flex-direction: column;
overflow: hidden;
}
.chat-header {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 20px;
text-align: center;
}
.chat-header h1 {
font-size: 24px;
margin-bottom: 5px;
}
.chat-header p {
font-size: 12px;
opacity: 0.9;
}
.chat-messages {
flex: 1;
overflow-y: auto;
padding: 20px;
background: #f5f5f5;
}
.message {
margin-bottom: 15px;
display: flex;
align-items: flex-start;
}
.message.user {
justify-content: flex-end;
}
.message.bot {
justify-content: flex-start;
}
.message-content {
max-width: 70%;
padding: 12px 16px;
border-radius: 18px;
font-size: 14px;
line-height: 1.5;
word-wrap: break-word;
}
.message.user .message-content {
background: #667eea;
color: white;
border-bottom-right-radius: 4px;
}
.message.bot .message-content {
background: white;
color: #333;
border-bottom-left-radius: 4px;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.avatar {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
margin: 0 8px;
}
.chat-input {
padding: 15px 20px;
background: white;
border-top: 1px solid #eee;
display: flex;
gap: 10px;
}
.chat-input input {
flex: 1;
padding: 12px 16px;
border: 2px solid #e0e0e0;
border-radius: 25px;
font-size: 14px;
outline: none;
transition: border-color 0.3s;
}
.chat-input input:focus {
border-color: #667eea;
}
.chat-input button {
padding: 12px 24px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 25px;
font-size: 14px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.chat-input button:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(102, 126, 234, 0.4);
}
.chat-input button:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.typing {
display: flex;
gap: 4px;
padding: 12px 16px;
}
.typing span {
width: 8px;
height: 8px;
background: #999;
border-radius: 50%;
animation: typing 1.4s infinite;
}
.typing span:nth-child(2) { animation-delay: 0.2s; }
.typing span:nth-child(3) { animation-delay: 0.4s; }
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-10px); }
}
.start-overlay {
position: fixed;
top: 0; left: 0; right: 0; bottom: 0;
background: rgba(0,0,0,0.6);
display: flex;
justify-content: center;
align-items: center;
z-index: 1000;
}
.start-overlay.hidden {
display: none;
}
.start-card {
background: white;
border-radius: 24px;
padding: 50px 40px;
text-align: center;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
animation: popIn 0.5s ease;
}
@keyframes popIn {
0% { transform: scale(0.8); opacity: 0; }
100% { transform: scale(1); opacity: 1; }
}
.start-avatar {
font-size: 64px;
margin-bottom: 15px;
}
.start-card h2 {
color: #333;
font-size: 28px;
margin-bottom: 10px;
}
.start-card p {
color: #666;
font-size: 16px;
margin-bottom: 30px;
}
.start-btn {
padding: 16px 40px;
font-size: 18px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
border-radius: 30px;
cursor: pointer;
transition: transform 0.2s, box-shadow 0.2s;
}
.start-btn:hover {
transform: translateY(-3px);
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.5);
}
</style>
</head>
<body>
<div class="chat-container">
<div class="chat-header">
<h1>🐱 小狸</h1>
<p>你的 AI 小伙伴</p>
</div>
<div class="chat-messages" id="messages">
<div class="message bot">
<div class="avatar">🐱</div>
<div class="message-content">你好!我是小狸,很高兴见到你!有什么想聊的吗?</div>
</div>
</div>
<div class="chat-input">
<input type="text" id="userInput" placeholder="输入消息..." maxlength="100">
<button id="sendBtn" onclick="sendMessage()">发送</button>
</div>
<div class="start-overlay" id="startOverlay">
<div class="start-card">
<div class="start-avatar">🐱</div>
<h2>小狸已就绪!</h2>
<p>你的 AI 小伙伴正在等你聊天~</p>
<button class="start-btn" onclick="startChat()">👉 点击开始聊天</button>
</div>
</div>
</div>
<script>
const messagesDiv = document.getElementById('messages');
const userInput = document.getElementById('userInput');
const sendBtn = document.getElementById('sendBtn');
const sessionId = 'session_' + Math.random().toString(36).substr(2, 9);
function addMessage(text, isUser) {
const div = document.createElement('div');
div.className = `message ${isUser ? 'user' : 'bot'}`;
div.innerHTML = `
${isUser ? '' : '<div class="avatar">🐱</div>'}
<div class="message-content">${escapeHtml(text)}</div>
${isUser ? '<div class="avatar">👤</div>' : ''}
`;
messagesDiv.appendChild(div);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function showTyping() {
const div = document.createElement('div');
div.className = 'message bot';
div.id = 'typing-indicator';
div.innerHTML = `
<div class="avatar">🐱</div>
<div class="message-content">
<div class="typing">
<span></span><span></span><span></span>
</div>
</div>
`;
messagesDiv.appendChild(div);
messagesDiv.scrollTop = messagesDiv.scrollHeight;
}
function hideTyping() {
const typing = document.getElementById('typing-indicator');
if (typing) typing.remove();
}
function escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}
async function sendMessage() {
const text = userInput.value.trim();
if (!text) return;
addMessage(text, true);
userInput.value = '';
sendBtn.disabled = true;
showTyping();
try {
const response = await fetch('/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: text, session_id: sessionId })
});
const data = await response.json();
hideTyping();
addMessage(data.response, false);
} catch (error) {
hideTyping();
addMessage('抱歉,我出错了,请稍后再试~', false);
}
sendBtn.disabled = false;
}
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
function startChat() {
document.getElementById('startOverlay').classList.add('hidden');
userInput.focus();
}
</script>
</body>
</html>
-3
View File
@@ -1,3 +0,0 @@
version https://git-lfs.github.com/spec/v1
oid sha256:c0c0848f74cc7604d41699134a5f34f54d5958779a6653e27973ef495790c29c
size 5267