## 完整代码实现
### 后端代码 (app.py)
```python
import os
import json
import uuid
import requests
from datetime import datetime
from flask import Flask, render_template, request, jsonify
from dotenv import load_dotenv
# 加载环境变量
load_dotenv()
app = Flask(__name__)
# 文件路径配置
USER_DATA_FILE = 'data/users.json'
INTERACTION_DATA_FILE = 'data/interactions/{user_id}.json'
KNOWLEDGE_GRAPH_FILE = 'data/knowledge_graphs/{topic}.json'
# 确保数据目录存在
os.makedirs('data/users', exist_ok=True)
os.makedirs('data/interactions', exist_ok=True)
os.makedirs('data/knowledge_graphs', exist_ok=True)
# DeepSeek API 配置
DEEPSEEK_API_KEY = os.getenv('DEEPSEEK_API_KEY')
DEEPSEEK_API_URL = "https://api.deepseek.com/v1/chat/completions"
# 主页路由
@app.route('/')
def home():
return render_template('index.html')
# 用户认证路由
@app.route('/auth', methods=['POST'])
def auth():
action = request.json.get('action')
username = request.json.get('username')
password = request.json.get('password')
email = request.json.get('email', '')
if action == 'login':
return login_user(username, password)
elif action == 'register':
return register_user(username, password, email)
else:
return jsonify({'success': False, 'message': '无效操作'})
def login_user(username, password):
try:
with open(USER_DATA_FILE, 'r') as f:
users = json.load(f)
for user in users:
if user['username'] == username and user['password'] == password:
# 创建用户会话
session_id = str(uuid.uuid4())
user['session_id'] = session_id
user['last_login'] = datetime.now().isoformat()
# 更新用户数据
with open(USER_DATA_FILE, 'w') as f:
json.dump(users, f, indent=2)
return jsonify({
'success': True,
'session_id': session_id,
'user': {
'id': user['id'],
'username': username,
'email': user['email'],
'learning_style': user.get('learning_style', 'visual'),
'interests': user.get('interests', ['科技'])
}
})
return jsonify({'success': False, 'message': '用户名或密码错误'})
except Exception as e:
return jsonify({'success': False, 'message': f'登录失败: {str(e)}'})
def register_user(username, password, email):
try:
# 创建或加载用户数据
if os.path.exists(USER_DATA_FILE):
with open(USER_DATA_FILE, 'r') as f:
users = json.load(f)
else:
users = []
# 检查用户名是否已存在
if any(user['username'] == username for user in users):
return jsonify({'success': False, 'message': '用户名已存在'})
# 创建新用户
new_user = {
'id': str(uuid.uuid4()),
'username': username,
'password': password,
'email': email,
'created_at': datetime.now().isoformat(),
'learning_style': 'balanced', # 默认学习风格
'interests': ['科技', '教育'], # 默认兴趣
'knowledge_level': 'intermediate' # 默认知识水平
}
users.append(new_user)
with open(USER_DATA_FILE, 'w') as f:
json.dump(users, f, indent=2)
return jsonify({'success': True, 'message': '注册成功'})
except Exception as e:
return jsonify({'success': False, 'message': f'注册失败: {str(e)}'})
# 核心AI对话功能
@app.route('/conversation', methods=['POST'])
def conversation():
session_id = request.headers.get('X-Session-ID')
user_query = request.json.get('query')
context = request.json.get('context', [])
if not session_id:
return jsonify({'success': False, 'message': '缺少会话ID'})
# 获取用户信息
user = get_user_by_session(session_id)
if not user:
return jsonify({'success': False, 'message': '用户未认证'})
# 构建对话历史
full_context = [
{"role": "system", "content": build_system_prompt(user)},
*context[-5:], # 保留最近5轮对话
{"role": "user", "content": user_query}
]
# 调用DeepSeek API
response = call_deepseek_api(full_context)
if not response:
return jsonify({'success': False, 'message': 'AI服务不可用'})
ai_reply = response['choices'][0]['message']['content']
# 保存交互记录
save_interaction(user['id'], user_query, ai_reply)
# 生成后续问题建议
suggestions = generate_suggestions(ai_reply)
# 情感分析
emotion = analyze_emotion(user_query)
return jsonify({
'success': True,
'reply': ai_reply,
'suggestions': suggestions,
'emotion': emotion,
'context': full_context
})
def build_system_prompt(user):
return f"""
你是一位名为EduPal的AI学习伴侣,当前用户信息如下:
- 用户名: {user['username']}
- 学习风格: {user['learning_style']}
- 知识水平: {user['knowledge_level']}
- 兴趣领域: {', '.join(user['interests'])}
请根据用户的学习风格和知识水平调整回答方式,融入其兴趣领域的知识。
回答应简洁(100-200字),使用{user['learning_style']}学习风格。
在适当的时候使用比喻、实例和可视化描述。
"""
def call_deepseek_api(messages):
headers = {
"Authorization": f"Bearer {DEEPSEEK_API_KEY}",
"Content-Type": "application/json"
}
payload = {
"model": "deepseek-chat",
"messages": messages,
"temperature": 0.7,
"max_tokens": 500,
"top_p": 0.9
}
try:
response = requests.post(DEEPSEEK_API_URL, headers=headers, json=payload, timeout=30)
return response.json()
except Exception as e:
print(f"API调用失败: {str(e)}")
return None
def generate_suggestions(ai_reply):
"""生成后续问题建议"""
prompt = f"""
基于以下回复内容,生成3个用户可能继续问的问题:
{ai_reply}
要求:
1. 问题要自然且相关
2. 每个问题不超过10个字
3. 返回JSON格式: {{"suggestions": ["问题1", "问题2", "问题3"]}}
"""
response = call_deepseek_api([
{"role": "user", "content": prompt}
])
if response:
try:
return json.loads(response['choices'][0]['message']['content'])['suggestions']
except:
return ["还想了解什么?", "需要进一步解释吗?", "还有其他问题吗?"]
return []
def analyze_emotion(text):
"""分析用户情绪"""
prompt = f"""
分析以下文本的情感倾向:
"{text}"
返回JSON格式:{{"emotion": "positive/negative/neutral", "intensity": 0-10}}
"""
response = call_deepseek_api([
{"role": "user", "content": prompt}
])
if response:
try:
return json.loads(response['choices'][0]['message']['content'])
except:
return {"emotion": "neutral", "intensity": 5}
return {"emotion": "neutral", "intensity": 5}
# 知识图谱功能
@app.route('/knowledge-graph', methods=['POST'])
def generate_knowledge_graph():
session_id = request.headers.get('X-Session-ID')
topic = request.json.get('topic')
if not session_id:
return jsonify({'success': False, 'message': '缺少会话ID'})
user = get_user_by_session(session_id)
if not user:
return jsonify({'success': False, 'message': '用户未认证'})
# 检查是否有缓存
graph_file = KNOWLEDGE_GRAPH_FILE.format(topic=topic)
if os.path.exists(graph_file):
with open(graph_file, 'r') as f:
return jsonify({'success': True, 'graph': json.load(f)})
# 生成知识图谱
prompt = f"""
为以下主题创建知识图谱:
{topic}
要求:
1. 包含5-7个核心概念
2. 显示概念之间的关系
3. 使用Mermaid语法格式
4. 返回JSON格式: {{"mermaid": "graph TD\nA-->B\n..."}}
"""
response = call_deepseek_api([
{"role": "user", "content": prompt}
])
if not response:
return jsonify({'success': False, 'message': '生成失败'})
try:
graph_data = json.loads(response['choices'][0]['message']['content'])
with open(graph_file, 'w') as f:
json.dump(graph_data, f)
return jsonify({'success': True, 'graph': graph_data})
except:
return jsonify({'success': False, 'message': '解析失败'})
# 学习报告功能
@app.route('/learning-report', methods=['GET'])
def generate_learning_report():
session_id = request.headers.get('X-Session-ID')
if not session_id:
return jsonify({'success': False, 'message': '缺少会话ID'})
user = get_user_by_session(session_id)
if not user:
return jsonify({'success': False, 'message': '用户未认证'})
# 加载用户交互历史
interactions = load_interactions(user['id'])
# 生成学习报告
prompt = f"""
基于以下学习交互记录生成学习报告:
{json.dumps(interactions[-10:], ensure_ascii=False)}
报告要求:
1. 总结学习轨迹
2. 分析知识掌握情况
3. 识别优势领域
4. 提出改进建议
5. 推荐后续学习主题
返回JSON格式:
{{
"summary": "总体总结",
"progress": {{
"strengths": ["优势1", "优势2"],
"weaknesses": ["待改进领域1", "待改进领域2"]
}},
"recommendations": {{
"resources": ["推荐资源1", "推荐资源2"],
"topics": ["推荐主题1", "推荐主题2"]
}}
}}
"""
response = call_deepseek_api([
{"role": "user", "content": prompt}
])
if not response:
return jsonify({'success': False, 'message': '生成失败'})
try:
report = json.loads(response['choices'][0]['message']['content'])
return jsonify({'success': True, 'report': report})
except:
return jsonify({'success': False, 'message': '解析失败'})
# 情感支持功能
@app.route('/emotional-support', methods=['POST'])
def emotional_support():
session_id = request.headers.get('X-Session-ID')
message = request.json.get('message')
if not session_id:
return jsonify({'success': False, 'message': '缺少会话ID'})
user = get_user_by_session(session_id)
if not user:
return jsonify({'success': False, 'message': '用户未认证'})
# 情感分析
emotion = analyze_emotion(message)
# 生成支持性回复
prompt = f"""
用户情绪状态: {emotion['emotion']} (强度: {emotion['intensity']}/10)
用户留言: "{message}"
请生成:
1. 情感认可
2. 建设性建议
3. 鼓励性结语
保持温暖、支持性的语气,不超过150字。
"""
response = call_deepseek_api([
{"role": "user", "content": prompt}
])
if not response:
return jsonify({'success': False, 'message': '生成失败'})
return jsonify({
'success': True,
'reply': response['choices'][0]['message']['content'],
'emotion': emotion
})
# 辅助函数
def get_user_by_session(session_id):
if not os.path.exists(USER_DATA_FILE):
return None
with open(USER_DATA_FILE, 'r') as f:
users = json.load(f)
for user in users:
if user.get('session_id') == session_id:
return user
return None
def save_interaction(user_id, query, reply):
interaction_file = INTERACTION_DATA_FILE.format(user_id=user_id)
# 创建或加载交互记录
if os.path.exists(interaction_file):
with open(interaction_file, 'r') as f:
interactions = json.load(f)
else:
interactions = []
# 添加新记录
interactions.append({
"timestamp": datetime.now().isoformat(),
"query": query,
"reply": reply
})
with open(interaction_file, 'w') as f:
json.dump(interactions, f, indent=2)
def load_interactions(user_id):
interaction_file = INTERACTION_DATA_FILE.format(user_id=user_id)
if os.path.exists(interaction_file):
with open(interaction_file, 'r') as f:
return json.load(f)
return []
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000, debug=True)
```
### 前端核心代码 (index.html)
```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>EduPal - AI学习伴侣</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.132.2/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/mermaid@9.1.3/dist/mermaid.min.js"></script>
<style>
:root {
--primary: #4361ee;
--secondary: #3f37c9;
--accent: #4895ef;
--light: #f8f9fa;
--dark: #212529;
--success: #4cc9f0;
--danger: #f72585;
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
min-height: 100vh;
margin: 0;
padding: 0;
color: var(--dark);
}
.container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 15px 0;
border-bottom: 1px solid rgba(0,0,0,0.1);
}
.logo {
display: flex;
align-items: center;
gap: 10px;
}
.logo h1 {
margin: 0;
color: var(--primary);
}
.user-section {
display: flex;
align-items: center;
gap: 15px;
}
.avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: var(--accent);
display: flex;
align-items: center;
justify-content: center;
color: white;
font-weight: bold;
}
.main-content {
display: grid;
grid-template-columns: 1fr 350px;
gap: 25px;
margin-top: 25px;
}
.chat-container {
background: white;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
overflow: hidden;
display: flex;
flex-direction: column;
height: 75vh;
}
.chat-header {
padding: 15px 20px;
background: var(--primary);
color: white;
}
.messages {
flex: 1;
overflow-y: auto;
padding: 20px;
display: flex;
flex-direction: column;
gap: 15px;
}
.message {
max-width: 80%;
padding: 12px 18px;
border-radius: 18px;
line-height: 1.5;
}
.user-message {
align-self: flex-end;
background: var(--primary);
color: white;
border-bottom-right-radius: 5px;
}
.ai-message {
align-self: flex-start;
background: #eef2ff;
color: var(--dark);
border-bottom-left-radius: 5px;
}
.input-area {
display: flex;
padding: 15px;
border-top: 1px solid #eee;
gap: 10px;
}
.input-area input {
flex: 1;
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 25px;
font-size: 16px;
}
.input-area button {
background: var(--primary);
color: white;
border: none;
border-radius: 25px;
padding: 12px 25px;
cursor: pointer;
font-weight: 600;
}
.suggestions {
display: flex;
gap: 10px;
padding: 0 15px 15px;
flex-wrap: wrap;
}
.suggestion {
background: #edf2ff;
color: var(--primary);
border-radius: 20px;
padding: 8px 15px;
font-size: 14px;
cursor: pointer;
transition: all 0.2s;
}
.suggestion:hover {
background: #dbe4ff;
}
.sidebar {
display: flex;
flex-direction: column;
gap: 25px;
}
.card {
background: white;
border-radius: 15px;
box-shadow: 0 5px 15px rgba(0,0,0,0.08);
padding: 20px;
}
.card h2 {
margin-top: 0;
color: var(--secondary);
font-size: 1.3rem;
}
#knowledge-graph {
height: 300px;
background: #f8f9fa;
border-radius: 10px;
margin: 15px 0;
overflow: auto;
}
.emotion-indicator {
display: flex;
align-items: center;
gap: 10px;
margin: 10px 0;
}
.emotion-bar {
flex: 1;
height: 8px;
background: #e9ecef;
border-radius: 4px;
overflow: hidden;
}
.emotion-fill {
height: 100%;
background: var(--accent);
border-radius: 4px;
}
.avatar-3d {
height: 200px;
background: #f8f9fa;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
color: #6c757d;
}
.report-section {
margin-top: 15px;
}
.strength-item, .weakness-item {
display: flex;
align-items: center;
gap: 8px;
margin: 8px 0;
}
.strength-item::before {
content: "✓";
color: var(--success);
}
.weakness-item::before {
content: "!";
color: var(--danger);
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.5);
z-index: 1000;
justify-content: center;
align-items: center;
}
.modal-content {
background: white;
border-radius: 15px;
width: 90%;
max-width: 500px;
max-height: 90vh;
overflow-y: auto;
padding: 25px;
}
.auth-form {
display: flex;
flex-direction: column;
gap: 15px;
}
.auth-form input {
padding: 12px 15px;
border: 1px solid #ddd;
border-radius: 8px;
font-size: 16px;
}
.auth-form button {
background: var(--primary);
color: white;
border: none;
border-radius: 8px;
padding: 12px;
cursor: pointer;
font-weight: 600;
font-size: 16px;
}
.tabs {
display: flex;
margin-bottom: 20px;
}
.tab {
flex: 1;
text-align: center;
padding: 12px;
background: #e9ecef;
cursor: pointer;
}
.tab.active {
background: var(--primary);
color: white;
}
.tab:first-child {
border-radius: 8px 0 0 8px;
}
.tab:last-child {
border-radius: 0 8px 8px 0;
}
</style>
</head>
<body>
<div class="container">
<header>
<div class="logo">
<h1>EduPal</h1>
<span>AI学习伴侣</span>
</div>
<div class="user-section">
<div class="avatar" id="user-avatar">U</div>
<button id="auth-btn">登录/注册</button>
</div>
</header>
<main class="main-content">
<div class="chat-container">
<div class="chat-header">
<h2>与EduPal对话</h2>
</div>
<div class="messages" id="messages">
<div class="message ai-message">
你好!我是EduPal,你的AI学习伴侣。我可以帮助你学习新知识、解答问题,还能根据你的学习风格个性化教学。你想了解什么?
</div>
</div>
<div class="suggestions" id="suggestions">
<div class="suggestion">推荐一个学习计划</div>
<div class="suggestion">解释量子计算</div>
<div class="suggestion">如何提高学习效率?</div>
</div>
<div class="input-area">
<input type="text" id="user-input" placeholder="输入你的问题...">
<button id="send-btn">发送</button>
</div>
</div>
<div class="sidebar">
<div class="card">
<h2>3D学习助手</h2>
<div class="avatar-3d" id="avatar-3d">
<canvas id="avatar-canvas"></canvas>
</div>
<div class="emotion-indicator">
<span>情绪状态:</span>
<div class="emotion-bar">
<div class="emotion-fill" id="emotion-fill" style="width: 50%"></div>
</div>
<span id="emotion-label">中立</span>
</div>
</div>
<div class="card">
<h2>知识图谱</h2>
<div id="knowledge-graph"></div>
<button id="generate-graph-btn" style="width:100%">生成当前主题图谱</button>
</div>
<div class="card">
<h2>学习报告</h2>
<div id="report-summary">暂无报告数据</div>
<button id="generate-report-btn" style="width:100%; margin-top:15px">生成学习报告</button>
</div>
</div>
</main>
</div>
<!-- 认证模态框 -->
<div class="modal" id="auth-modal">
<div class="modal-content">
<div class="tabs">
<div class="tab active" data-tab="login">登录</div>
<div class="tab" data-tab="register">注册</div>
</div>
<form class="auth-form" id="login-form">
<input type="text" id="login-username" placeholder="用户名" required>
<input type="password" id="login-password" placeholder="密码" required>
<button type="submit">登录</button>
</form>
<form class="auth-form" id="register-form" style="display:none">
<input type="text" id="register-username" placeholder="用户名" required>
<input type="email" id="register-email" placeholder="邮箱" required>
<input type="password" id="register-password" placeholder="密码" required>
<input type="password" id="register-confirm" placeholder="确认密码" required>
<button type="submit">注册</button>
</form>
</div>
</div>
<script>
// 全局状态
let sessionId = null;
let currentUser = null;
let conversationContext = [];
// DOM元素
const authModal = document.getElementById('auth-modal');
const authBtn = document.getElementById('auth-btn');
const loginForm = document.getElementById('login-form');
const registerForm = document.getElementById('register-form');
const tabs = document.querySelectorAll('.tab');
const messagesContainer = document.getElementById('messages');
const userInput = document.getElementById('user-input');
const sendBtn = document.getElementById('send-btn');
const suggestionsContainer = document.getElementById('suggestions');
const knowledgeGraphContainer = document.getElementById('knowledge-graph');
const generateGraphBtn = document.getElementById('generate-graph-btn');
const emotionFill = document.getElementById('emotion-fill');
const emotionLabel = document.getElementById('emotion-label');
const reportSummary = document.getElementById('report-summary');
const generateReportBtn = document.getElementById('generate-report-btn');
// 初始化3D头像
function init3DAvatar() {
const canvas = document.getElementById('avatar-canvas');
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(75, canvas.clientWidth / canvas.clientHeight, 0.1, 1000);
const renderer = new THREE.WebGLRenderer({ canvas, alpha: true });
renderer.setSize(canvas.clientWidth, canvas.clientHeight);
// 创建基础几何体
const geometry = new THREE.SphereGeometry(1, 32, 32);
const material = new THREE.MeshBasicMaterial({ color: 0x4361ee });
const sphere = new THREE.Mesh(geometry, material);
scene.add(sphere);
camera.position.z = 3;
// 动画循环
function animate() {
requestAnimationFrame(animate);
sphere.rotation.x += 0.01;
sphere.rotation.y += 0.01;
renderer.render(scene, camera);
}
animate();
}
// 初始化Mermaid
mermaid.initialize({
startOnLoad: true,
theme: 'neutral',
securityLevel: 'loose'
});
// 显示认证模态框
authBtn.addEventListener('click', () => {
authModal.style.display = 'flex';
});
// 切换登录/注册标签
tabs.forEach(tab => {
tab.addEventListener('click', () => {
tabs.forEach(t => t.classList.remove('active'));
tab.classList.add('active');
if (tab.dataset.tab === 'login') {
loginForm.style.display = 'flex';
registerForm.style.display = 'none';
} else {
loginForm.style.display = 'none';
registerForm.style.display = 'flex';
}
});
});
// 登录处理
loginForm.addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('login-username').value;
const password = document.getElementById('login-password').value;
const response = await fetch('/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'login',
username,
password
})
});
const data = await response.json();
if (data.success) {
sessionId = data.session_id;
currentUser = data.user;
document.getElementById('user-avatar').textContent = currentUser.username.charAt(0).toUpperCase();
authModal.style.display = 'none';
// 添加欢迎消息
addMessage(`欢迎回来,${currentUser.username}!今天想学习什么?`, 'ai');
} else {
alert(data.message);
}
});
// 注册处理
registerForm.addEventListener('submit', async (e) => {
e.preventDefault();
const username = document.getElementById('register-username').value;
const email = document.getElementById('register-email').value;
const password = document.getElementById('register-password').value;
const confirm = document.getElementById('register-confirm').value;
if (password !== confirm) {
alert('两次输入的密码不一致');
return;
}
const response = await fetch('/auth', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
action: 'register',
username,
password,
})
});
const data = await response.json();
if (data.success) {
alert('注册成功!请登录');
tabs[0].click();
} else {
alert(data.message);
}
});
// 发送消息
sendBtn.addEventListener('click', sendMessage);
userInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') sendMessage();
});
// 建议点击
suggestionsContainer.addEventListener('click', (e) => {
if (e.target.classList.contains('suggestion')) {
userInput.value = e.target.textContent;
sendMessage();
}
});
// 生成知识图谱
generateGraphBtn.addEventListener('click', async () => {
if (!currentUser) {
alert('请先登录');
return;
}
const lastUserMessage = conversationContext
.filter(msg => msg.role === 'user')
.pop()?.content;
if (!lastUserMessage) {
alert('请先进行对话');
return;
}
const response = await fetch('/knowledge-graph', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Session-ID': sessionId
},
body: JSON.stringify({ topic: lastUserMessage })
});
const data = await response.json();
if (data.success) {
knowledgeGraphContainer.innerHTML = '';
const graphDiv = document.createElement('div');
graphDiv.className = 'mermaid';
graphDiv.textContent = data.graph.mermaid;
knowledgeGraphContainer.appendChild(graphDiv);
mermaid.init(undefined, graphDiv);
} else {
alert('生成失败: ' + data.message);
}
});
// 生成学习报告
generateReportBtn.addEventListener('click', async () => {
if (!currentUser) {
alert('请先登录');
return;
}
const response = await fetch('/learning-report', {
method: 'GET',
headers: { 'X-Session-ID': sessionId }
});
const data = await response.json();
if (data.success) {
const report = data.report;
let html = `
<h3>学习总结</h3>
<p>${report.summary}</p>
<h3>学习进度</h3>
<div class="report-section">
<h4>优势领域</h4>
${report.progress.strengths.map(s => `<div class="strength-item">${s}</div>`).join('')}
<h4>待改进领域</h4>
${report.progress.weaknesses.map(w => `<div class="weakness-item">${w}</div>`).join('')}
</div>
<h3>学习建议</h3>
<div class="report-section">
<h4>推荐资源</h4>
<ul>${report.recommendations.resources.map(r => `<li>${r}</li>`).join('')}</ul>
<h4>推荐主题</h4>
<ul>${report.recommendations.topics.map(t => `<li>${t}</li>`).join('')}</ul>
</div>
`;
reportSummary.innerHTML = html;
} else {
alert('生成失败: ' + data.message);
}
});
// 添加消息到对话框
function addMessage(text, sender) {
const messageDiv = document.createElement('div');
messageDiv.className = `message ${sender}-message`;
messageDiv.textContent = text;
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// 发送消息
async function sendMessage() {
const message = userInput.value.trim();
if (!message) return;
if (!currentUser) {
alert('请先登录');
return;
}
// 添加用户消息
addMessage(message, 'user');
userInput.value = '';
// 添加到上下文
conversationContext.push({ role: 'user', content: message });
// 发送到后端
const response = await fetch('/conversation', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Session-ID': sessionId
},
body: JSON.stringify({
query: message,
context: conversationContext
})
});
const data = await response.json();
if (data.success) {
// 添加AI回复
addMessage(data.reply, 'ai');
// 更新上下文
conversationContext = data.context;
// 更新建议
updateSuggestions(data.suggestions);
// 更新情绪状态
updateEmotion(data.emotion);
} else {
addMessage('抱歉,我暂时无法回答这个问题。请稍后再试。', 'ai');
}
}
// 更新建议
function updateSuggestions(suggestions) {
suggestionsContainer.innerHTML = '';
suggestions.forEach(suggestion => {
const div = document.createElement('div');
div.className = 'suggestion';
div.textContent = suggestion;
suggestionsContainer.appendChild(div);
});
}
// 更新情绪状态
function updateEmotion(emotion) {
const intensity = emotion.intensity;
emotionFill.style.width = `${intensity * 10}%`;
let label = '';
if (emotion.emotion === 'positive') {
label = `积极 (${intensity}/10)`;
emotionFill.style.backgroundColor = '#4ade80';
} else if (emotion.emotion === 'negative') {
label = `消极 (${intensity}/10)`;
emotionFill.style.backgroundColor = '#f87171';
} else {
label = `中立 (${intensity}/10)`;
emotionFill.style.backgroundColor = '#60a5fa';
}
emotionLabel.textContent = label;
}
// 初始化
window.addEventListener('load', () => {
init3DAvatar();
});
</script>
</body>
</html>
```
### 环境文件 (.env)
```
DEEPSEEK_API_KEY=your_api_key_here
```
---
## 项目策划书:EduPal - AI学习伴侣
### 1. 项目概述
**项目名称**:EduPal
**项目定位**:基于大模型的个性化AI学习伴侣系统
**核心创新**:融合情感智能与知识图谱的学习体验
**目标用户**:中学生、大学生及终身学习者
**技术栈**:
- 后端:Python/Flask
- 前端:HTML5/CSS3/JavaScript + Three.js
- AI模型:DeepSeek API
- 可视化:Mermaid.js
### 2. 核心功能设计
#### 2.1 智能学习伴侣
- **个性化学习路径**:基于用户画像动态调整教学内容
- **情境感知对话**:记忆对话历史,保持对话连贯性
- **智能追问建议**:AI生成后续学习问题
- **多模态解释**:结合文本、图表、可视化解释复杂概念
#### 2.2 情感智能支持
- **情绪识别系统**:分析用户文本情感倾向与强度
- **共情式回应**:生成温暖、支持性的回复
- **学习状态监测**:识别学习挫折并提供鼓励
#### 2.3 知识图谱系统
- **动态知识图谱**:自动生成学科概念关系图
- **交互式探索**:点击节点获取详细解释
- **知识关联发现**:揭示跨学科知识连接
#### 2.4 学习分析报告
- **学习轨迹可视化**:展示知识掌握进度
- **优势领域识别**:突出用户擅长领域
- **个性化建议**:推荐学习资源和改进方向
### 3. 技术创新点
#### 3.1 动态用户画像系统
```mermaid
graph LR
A[用户交互] --> B[行为分析]
B --> C[知识水平评估]
B --> D[学习风格识别]
B --> E[兴趣领域挖掘]
C --> F[个性化回复]
D --> F
E --> F
```
#### 3.2 情感智能引擎
- **情感分析模型**:基于文本的情感分类与强度量化
- **CBT(认知行为疗法)融合**:在回复中融入心理学原理
- **情绪可视化**:实时情绪状态仪表盘
#### 3.3 知识图谱生成技术
- **概念提取算法**:自动识别核心知识点
- **关系推理引擎**:建立概念间的逻辑联系
- **跨学科连接**:发现不同领域的知识关联
### 4. 系统架构
#### 4.1 技术架构
```mermaid
graph TD
A[前端界面] --> B[Flask API网关]
B --> C[用户管理系统]
B --> D[对话引擎]
B --> E[知识图谱生成]
B --> F[学习分析模块]
C --> G[用户数据存储]
D --> H[DeepSeek API]
E --> H
F --> G
```
#### 4.2 数据流设计
```mermaid
sequenceDiagram
用户->>前端: 发起请求
前端->>后端: API调用
后端->>AI模型: 请求处理
AI模型->>后端: 返回结果
后端->>前端: 响应数据
前端->>用户: 展示结果
前端->>后端: 用户反馈
后端->>AI模型: 模型优化
```
### 5. 实现计划
| 阶段 | 时间 | 主要任务 | 交付物 |
|------|------|----------|--------|
| 1. 基础框架 | 第1周 | 用户系统搭建、API接口设计 | 可运行的原型系统 |
| 2. 核心AI | 第2周 | 对话引擎、情感分析模块 | 智能对话功能 |
| 3. 知识可视化 | 第3周 | 知识图谱生成、3D虚拟形象 | 交互式学习界面 |
| 4. 优化部署 | 第4周 | 性能优化、云端部署 | 可上线应用 |
### 6. 创新亮点
1. **情感智能融合**
业内首个将情感分析深度融入教育场景的AI系统
2. **动态知识图谱**
实时生成个性化知识结构图,辅助构建知识体系
3. **成长陪伴模式**
从单纯答疑进化为学习旅程的全程伴侣
4. **多模态交互**
结合3D虚拟形象、知识图谱和自然语言对话
### 7. 预期成果
1. **功能完备的Web应用**
- 个性化学习对话系统
- 情感支持模块
- 知识图谱可视化
- 学习分析报告
2. **技术文档**
- 系统架构设计
- API文档
- 部署指南
3. **演示材料**
- 产品演示视频
- 用户测试报告
- 创新点说明文档
### 8. 部署方案
```bash
# 部署步骤
1. 安装依赖
pip install flask python-dotenv requests
2. 设置环境变量
echo "DEEPSEEK_API_KEY=your_api_key" > .env
3. 启动服务
python app.py
4. 配置生产环境
gunicorn -w 4 -b 0.0.0.0:5000 app:app
```
### 9. 项目优势
1. **教育普惠性**:降低个性化教育门槛
2. **情感连接**:解决传统AI冷漠问题
3. **知识结构化**:帮助构建系统知识体系
4. **可扩展性**:支持多学科知识领域
5. **用户粘性**:成长陪伴式学习体验
---
## 下一步建议
1. **申请DeepSeek API Key**:替换.env文件中的API密钥
2. **部署测试环境**:使用Vercel或Render部署前端
3. **丰富学科知识库**:添加特定领域的学习资料
4. **开发移动应用**:基于Flutter开发跨平台APP
5. **接入更多AI服务**:集成多模态模型支持图像解释
