chenpei d0dc94e36d feat: 将弹幕功能替换为AI聊天助手
新功能:
- 创建AI聊天助手组件(AIChatWidget)
- 支持文字+图片多模态对话
- 集成Gemini AI API
- 支持图片编辑和内容生成
- 实时对话历史管理
- 优雅的UI设计,支持黑夜模式

技术实现:
- 后端API代理Gemini API(/api/ai-chat)
- 支持最多5张图片上传
- 流式响应处理
- 对话历史管理
- Base64图片处理

配置:
- 在.env中添加Gemini API配置
- GEMINI_API_KEY
- GEMINI_API_BASE_URL
- GEMINI_MODEL

替换原弹幕功能,提供更强大的AI助手体验!
2025-10-27 17:45:37 +08:00

109 lines
2.6 KiB
JavaScript
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const dotenv = require('dotenv');
const bcrypt = require('bcryptjs');
dotenv.config();
// JWT密钥,应该存储在环境变量中
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key-should-be-in-env';
const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '7d';
/**
* 生成密码哈希
* @param {string} password - 原始密码
* @returns {Object} - 包含哈希密码和盐值
*/
function hashPassword(password) {
const salt = crypto.randomBytes(16).toString('hex');
const hash = crypto
.pbkdf2Sync(password, salt, 10000, 64, 'sha512')
.toString('hex');
return { hash, salt };
}
/**
* 验证密码
* @param {string} plainPassword - 明文密码
* @param {string} hashedPassword - 哈希密码
* @returns {Promise<boolean>} - 密码是否匹配
*/
const verifyPassword = async (plainPassword, hashedPassword) => {
try {
if (!plainPassword || !hashedPassword) {
throw new Error('密码验证失败:缺少必要参数');
}
const isMatch = await bcrypt.compare(plainPassword, hashedPassword);
return isMatch;
} catch (error) {
console.error('密码验证错误:', error);
throw error;
}
};
/**
* 生成JWT令牌
* @param {Object} payload - 令牌载荷
* @returns {string} - JWT令牌
*/
const generateToken = (payload) => {
try {
if (!payload || !payload._id) {
throw new Error('生成令牌失败:缺少必要参数');
}
const token = jwt.sign(
payload,
process.env.JWT_SECRET || 'your-secret-key',
{ expiresIn: '7d' }
);
return token;
} catch (error) {
console.error('生成令牌错误:', error);
throw error;
}
};
/**
* 验证JWT令牌
* @param {string} token - JWT令牌
* @returns {Object} - 解码后的载荷
*/
const verifyToken = (token) => {
try {
if (!token) {
throw new Error('验证令牌失败:缺少令牌');
}
const decoded = jwt.verify(token, process.env.JWT_SECRET || 'your-secret-key');
return decoded;
} catch (error) {
console.error('验证令牌错误:', error);
throw error;
}
};
/**
* 从请求中提取令牌
* @param {Object} req - Express请求对象
* @returns {string|null} - JWT令牌或null
*/
function extractTokenFromRequest(req) {
if (req.headers.authorization && req.headers.authorization.startsWith('Bearer ')) {
return req.headers.authorization.substring(7);
}
if (req.cookies && req.cookies.token) {
return req.cookies.token;
}
return null;
}
module.exports = {
hashPassword,
verifyPassword,
generateToken,
verifyToken,
extractTokenFromRequest
};