跳到主要内容

智能聊天应用开发

智能聊天应用是AI技术在前端应用中最常见和最实用的场景之一。本文将详细介绍如何从零开始构建一个功能完整、用户体验优秀的智能聊天应用,涵盖架构设计、核心功能实现、UI/UX优化和性能调优等方面。

应用架构设计

整体架构图

核心聊天应用类

// 智能聊天应用主类
class IntelligentChatApp {
constructor(config = {}) {
this.config = {
theme: config.theme || 'light',
language: config.language || 'zh-CN',
autoSave: config.autoSave !== false,
maxHistoryLength: config.maxHistoryLength || 1000,
typingSpeed: config.typingSpeed || 50,
enablePlugins: config.enablePlugins !== false,
...config
};

// 核心组件初始化
this.conversationManager = new ConversationManager(this.config);
this.messageProcessor = new MessageProcessor(this.config);
this.uiManager = new UIManager(this.config);
this.aiService = new AIServiceManager(this.config);
this.pluginManager = new PluginManager(this.config);
this.storageManager = new StorageManager(this.config);

// 状态管理
this.state = {
currentConversation: null,
isTyping: false,
isConnected: true,
userPreferences: {},
activePlugins: new Set()
};

// 事件监听器
this.eventListeners = new Map();

this.initialize();
}

async initialize() {
try {
// 加载用户偏好
await this.loadUserPreferences();

// 初始化UI
await this.uiManager.initialize();

// 加载插件
if (this.config.enablePlugins) {
await this.pluginManager.loadPlugins();
}

// 恢复上次会话
await this.restoreLastSession();

// 设置事件监听
this.setupEventListeners();

console.log('智能聊天应用初始化完成');

} catch (error) {
console.error('应用初始化失败:', error);
this.handleInitializationError(error);
}
}

// 发送消息
async sendMessage(content, options = {}) {
if (!content || !content.trim()) {
throw new Error('消息内容不能为空');
}

const messageId = this.generateMessageId();
const timestamp = Date.now();

// 创建用户消息
const userMessage = {
id: messageId,
role: 'user',
content: content.trim(),
timestamp,
metadata: {
source: options.source || 'user_input',
attachments: options.attachments || [],
context: options.context || {}
}
};

try {
// 添加到当前对话
await this.conversationManager.addMessage(userMessage);

// 更新UI显示用户消息
this.uiManager.displayMessage(userMessage);

// 显示AI正在思考状态
this.setTypingState(true);

// 处理消息并获取AI回复
const aiResponse = await this.processMessage(userMessage, options);

// 创建AI消息
const aiMessage = {
id: this.generateMessageId(),
role: 'assistant',
content: aiResponse.content,
timestamp: Date.now(),
metadata: {
model: aiResponse.model,
provider: aiResponse.provider,
tokens: aiResponse.tokens,
processingTime: aiResponse.processingTime,
confidence: aiResponse.confidence
}
};

// 添加AI回复到对话
await this.conversationManager.addMessage(aiMessage);

// 停止思考状态
this.setTypingState(false);

// 显示AI回复(带打字效果)
await this.uiManager.displayMessageWithTyping(aiMessage);

// 自动保存对话
if (this.config.autoSave) {
await this.saveCurrentConversation();
}

// 触发消息发送完成事件
this.emit('messageSent', { userMessage, aiMessage });

return aiMessage;

} catch (error) {
this.setTypingState(false);

// 创建错误消息
const errorMessage = {
id: this.generateMessageId(),
role: 'system',
content: this.getErrorMessage(error),
timestamp: Date.now(),
metadata: {
error: true,
errorType: error.constructor.name,
originalError: error.message
}
};

await this.conversationManager.addMessage(errorMessage);
this.uiManager.displayMessage(errorMessage);

this.emit('messageError', { error, userMessage });
throw error;
}
}

// 处理消息
async processMessage(userMessage, options = {}) {
// 预处理消息
const processedMessage = await this.messageProcessor.preprocess(userMessage);

// 检查插件处理
if (this.config.enablePlugins) {
const pluginResult = await this.pluginManager.processMessage(processedMessage);
if (pluginResult.handled) {
return pluginResult.response;
}
}

// 构建对话上下文
const context = await this.conversationManager.buildContext({
maxTokens: options.maxContextTokens || 4000,
includeSystemPrompt: true,
includeRecentMessages: true
});

// 调用AI服务
const aiResponse = await this.aiService.generateResponse({
messages: context.messages,
model: options.model || this.config.defaultModel,
temperature: options.temperature || this.config.defaultTemperature,
maxTokens: options.maxTokens || this.config.defaultMaxTokens,
stream: options.stream !== false
});

// 后处理响应
return await this.messageProcessor.postprocess(aiResponse);
}

// 开始新对话
async startNewConversation(title = null) {
const conversation = await this.conversationManager.createConversation({
title: title || this.generateConversationTitle(),
timestamp: Date.now(),
model: this.config.defaultModel,
systemPrompt: this.config.systemPrompt
});

this.state.currentConversation = conversation;
this.uiManager.clearChat();
this.uiManager.updateConversationTitle(conversation.title);

this.emit('conversationStarted', conversation);
return conversation;
}

// 加载历史对话
async loadConversation(conversationId) {
try {
const conversation = await this.conversationManager.loadConversation(conversationId);

if (!conversation) {
throw new Error('对话不存在');
}

this.state.currentConversation = conversation;

// 清空当前聊天界面
this.uiManager.clearChat();

// 显示历史消息
for (const message of conversation.messages) {
this.uiManager.displayMessage(message, { animate: false });
}

this.uiManager.updateConversationTitle(conversation.title);
this.emit('conversationLoaded', conversation);

return conversation;

} catch (error) {
console.error('加载对话失败:', error);
this.uiManager.showError('加载对话失败: ' + error.message);
throw error;
}
}

// 删除对话
async deleteConversation(conversationId) {
try {
await this.conversationManager.deleteConversation(conversationId);

// 如果删除的是当前对话,开始新对话
if (this.state.currentConversation?.id === conversationId) {
await this.startNewConversation();
}

this.emit('conversationDeleted', conversationId);

} catch (error) {
console.error('删除对话失败:', error);
this.uiManager.showError('删除对话失败: ' + error.message);
throw error;
}
}

// 导出对话
async exportConversation(conversationId, format = 'json') {
try {
const conversation = await this.conversationManager.loadConversation(conversationId);

if (!conversation) {
throw new Error('对话不存在');
}

let exportData;

switch (format.toLowerCase()) {
case 'json':
exportData = JSON.stringify(conversation, null, 2);
break;
case 'markdown':
exportData = this.convertToMarkdown(conversation);
break;
case 'txt':
exportData = this.convertToText(conversation);
break;
default:
throw new Error('不支持的导出格式');
}

// 下载文件
this.downloadFile(
exportData,
`conversation_${conversation.title}_${Date.now()}.${format}`,
this.getMimeType(format)
);

this.emit('conversationExported', { conversation, format });

} catch (error) {
console.error('导出对话失败:', error);
this.uiManager.showError('导出对话失败: ' + error.message);
throw error;
}
}

// 设置用户偏好
async setUserPreference(key, value) {
this.state.userPreferences[key] = value;
await this.storageManager.saveUserPreferences(this.state.userPreferences);

// 应用偏好设置
this.applyUserPreference(key, value);

this.emit('preferenceChanged', { key, value });
}

// 应用用户偏好
applyUserPreference(key, value) {
switch (key) {
case 'theme':
this.uiManager.setTheme(value);
break;
case 'language':
this.uiManager.setLanguage(value);
break;
case 'fontSize':
this.uiManager.setFontSize(value);
break;
case 'typingSpeed':
this.config.typingSpeed = value;
break;
case 'autoSave':
this.config.autoSave = value;
break;
}
}

// 启用插件
async enablePlugin(pluginName) {
try {
await this.pluginManager.enablePlugin(pluginName);
this.state.activePlugins.add(pluginName);

this.emit('pluginEnabled', pluginName);

} catch (error) {
console.error('启用插件失败:', error);
throw error;
}
}

// 禁用插件
async disablePlugin(pluginName) {
try {
await this.pluginManager.disablePlugin(pluginName);
this.state.activePlugins.delete(pluginName);

this.emit('pluginDisabled', pluginName);

} catch (error) {
console.error('禁用插件失败:', error);
throw error;
}
}

// 获取应用状态
getState() {
return {
...this.state,
conversations: this.conversationManager.getConversationList(),
availableModels: this.aiService.getAvailableModels(),
availablePlugins: this.pluginManager.getAvailablePlugins(),
config: { ...this.config }
};
}

// 事件监听
on(event, listener) {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, new Set());
}
this.eventListeners.get(event).add(listener);
}

// 移除事件监听
off(event, listener) {
const listeners = this.eventListeners.get(event);
if (listeners) {
listeners.delete(listener);
}
}

// 触发事件
emit(event, data) {
const listeners = this.eventListeners.get(event);
if (listeners) {
for (const listener of listeners) {
try {
listener(data);
} catch (error) {
console.error('事件监听器执行错误:', error);
}
}
}
}

// 辅助方法
generateMessageId() {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

generateConversationTitle() {
const now = new Date();
return `对话 ${now.getFullYear()}-${(now.getMonth() + 1).toString().padStart(2, '0')}-${now.getDate().toString().padStart(2, '0')} ${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}`;
}

setTypingState(isTyping) {
this.state.isTyping = isTyping;
this.uiManager.setTypingIndicator(isTyping);
}

getErrorMessage(error) {
const errorMessages = {
'NetworkError': '网络连接失败,请检查网络设置',
'AuthenticationError': 'API认证失败,请检查密钥配置',
'RateLimitError': '请求频率过高,请稍后再试',
'QuotaExceededError': 'API配额已用完,请检查账户余额',
'ModelNotFoundError': '指定的模型不存在',
'InvalidRequestError': '请求参数无效'
};

return errorMessages[error.constructor.name] || '发生未知错误,请稍后再试';
}

async loadUserPreferences() {
try {
this.state.userPreferences = await this.storageManager.loadUserPreferences() || {};

// 应用所有偏好设置
for (const [key, value] of Object.entries(this.state.userPreferences)) {
this.applyUserPreference(key, value);
}
} catch (error) {
console.warn('加载用户偏好失败:', error);
}
}

async saveCurrentConversation() {
if (this.state.currentConversation) {
await this.conversationManager.saveConversation(this.state.currentConversation);
}
}

async restoreLastSession() {
try {
const lastConversationId = await this.storageManager.getLastConversationId();

if (lastConversationId) {
await this.loadConversation(lastConversationId);
} else {
await this.startNewConversation();
}
} catch (error) {
console.warn('恢复上次会话失败:', error);
await this.startNewConversation();
}
}

setupEventListeners() {
// 监听窗口关闭事件,保存当前状态
window.addEventListener('beforeunload', () => {
if (this.config.autoSave) {
this.saveCurrentConversation();
this.storageManager.saveLastConversationId(this.state.currentConversation?.id);
}
});

// 监听网络状态变化
window.addEventListener('online', () => {
this.state.isConnected = true;
this.uiManager.setConnectionStatus(true);
});

window.addEventListener('offline', () => {
this.state.isConnected = false;
this.uiManager.setConnectionStatus(false);
});
}

handleInitializationError(error) {
console.error('应用初始化失败:', error);

// 显示错误信息给用户
if (this.uiManager) {
this.uiManager.showError('应用初始化失败: ' + error.message);
} else {
alert('应用初始化失败: ' + error.message);
}
}

convertToMarkdown(conversation) {
let markdown = `# ${conversation.title}\n\n`;
markdown += `**创建时间**: ${new Date(conversation.timestamp).toLocaleString()}\n\n`;

for (const message of conversation.messages) {
const role = message.role === 'user' ? '**用户**' : '**AI助手**';
const time = new Date(message.timestamp).toLocaleString();

markdown += `## ${role} (${time})\n\n`;
markdown += `${message.content}\n\n`;
}

return markdown;
}

convertToText(conversation) {
let text = `${conversation.title}\n`;
text += `创建时间: ${new Date(conversation.timestamp).toLocaleString()}\n\n`;

for (const message of conversation.messages) {
const role = message.role === 'user' ? '用户' : 'AI助手';
const time = new Date(message.timestamp).toLocaleString();

text += `[${time}] ${role}: ${message.content}\n\n`;
}

return text;
}

getMimeType(format) {
const mimeTypes = {
'json': 'application/json',
'markdown': 'text/markdown',
'txt': 'text/plain'
};
return mimeTypes[format] || 'text/plain';
}

downloadFile(content, filename, mimeType) {
const blob = new Blob([content], { type: mimeType });
const url = URL.createObjectURL(blob);

const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);

URL.revokeObjectURL(url);
}

// 销毁应用
destroy() {
// 保存当前状态
if (this.config.autoSave) {
this.saveCurrentConversation();
}

// 清理事件监听器
this.eventListeners.clear();

// 销毁各个管理器
this.conversationManager.destroy();
this.messageProcessor.destroy();
this.uiManager.destroy();
this.aiService.destroy();
this.pluginManager.destroy();
this.storageManager.destroy();

console.log('智能聊天应用已销毁');
}
}

插件系统

插件管理器

// 插件管理器
class PluginManager {
constructor(config = {}) {
this.config = config;
this.plugins = new Map();
this.hooks = new Map();
this.eventBus = new EventTarget();
this.pluginStates = new Map();
this.dependencies = new Map();

this.initializeHooks();
}

// 初始化钩子
initializeHooks() {
const defaultHooks = [
'beforeMessageSend',
'afterMessageSend',
'beforeMessageReceive',
'afterMessageReceive',
'beforeConversationCreate',
'afterConversationCreate',
'beforeConversationLoad',
'afterConversationLoad',
'beforeUIRender',
'afterUIRender',
'onError',
'onSettingsChange'
];

defaultHooks.forEach(hook => {
this.hooks.set(hook, []);
});
}

// 注册插件
async registerPlugin(plugin) {
try {
// 验证插件
if (!this.validatePlugin(plugin)) {
throw new Error(`插件验证失败: ${plugin.name}`);
}

// 检查依赖
if (!await this.checkDependencies(plugin)) {
throw new Error(`插件依赖检查失败: ${plugin.name}`);
}

// 初始化插件
if (plugin.initialize) {
await plugin.initialize(this.createPluginContext(plugin));
}

// 注册插件
this.plugins.set(plugin.name, plugin);
this.pluginStates.set(plugin.name, 'active');

// 注册钩子
if (plugin.hooks) {
for (const [hookName, handler] of Object.entries(plugin.hooks)) {
this.addHook(hookName, handler, plugin.name);
}
}

// 注册命令
if (plugin.commands) {
for (const [commandName, handler] of Object.entries(plugin.commands)) {
this.registerCommand(commandName, handler, plugin.name);
}
}

// 触发插件注册事件
this.emit('pluginRegistered', { plugin });

console.log(`插件注册成功: ${plugin.name}`);

} catch (error) {
console.error(`插件注册失败: ${plugin.name}`, error);
throw error;
}
}

// 卸载插件
async unregisterPlugin(pluginName) {
try {
const plugin = this.plugins.get(pluginName);

if (!plugin) {
throw new Error(`插件不存在: ${pluginName}`);
}

// 检查依赖关系
const dependents = this.getDependents(pluginName);
if (dependents.length > 0) {
throw new Error(`无法卸载插件 ${pluginName},以下插件依赖它: ${dependents.join(', ')}`);
}

// 清理插件
if (plugin.cleanup) {
await plugin.cleanup();
}

// 移除钩子
for (const [hookName, handlers] of this.hooks) {
this.hooks.set(hookName, handlers.filter(h => h.pluginName !== pluginName));
}

// 移除插件
this.plugins.delete(pluginName);
this.pluginStates.delete(pluginName);
this.dependencies.delete(pluginName);

// 触发插件卸载事件
this.emit('pluginUnregistered', { pluginName });

console.log(`插件卸载成功: ${pluginName}`);

} catch (error) {
console.error(`插件卸载失败: ${pluginName}`, error);
throw error;
}
}

// 启用插件
async enablePlugin(pluginName) {
try {
const plugin = this.plugins.get(pluginName);

if (!plugin) {
throw new Error(`插件不存在: ${pluginName}`);
}

if (this.pluginStates.get(pluginName) === 'active') {
return; // 已经启用
}

// 检查依赖
if (!await this.checkDependencies(plugin)) {
throw new Error(`插件依赖检查失败: ${pluginName}`);
}

// 启用插件
if (plugin.enable) {
await plugin.enable();
}

this.pluginStates.set(pluginName, 'active');

// 触发插件启用事件
this.emit('pluginEnabled', { pluginName });

console.log(`插件启用成功: ${pluginName}`);

} catch (error) {
console.error(`插件启用失败: ${pluginName}`, error);
throw error;
}
}

// 禁用插件
async disablePlugin(pluginName) {
try {
const plugin = this.plugins.get(pluginName);

if (!plugin) {
throw new Error(`插件不存在: ${pluginName}`);
}

if (this.pluginStates.get(pluginName) === 'disabled') {
return; // 已经禁用
}

// 检查依赖关系
const dependents = this.getActiveDependents(pluginName);
if (dependents.length > 0) {
throw new Error(`无法禁用插件 ${pluginName},以下插件依赖它: ${dependents.join(', ')}`);
}

// 禁用插件
if (plugin.disable) {
await plugin.disable();
}

this.pluginStates.set(pluginName, 'disabled');

// 触发插件禁用事件
this.emit('pluginDisabled', { pluginName });

console.log(`插件禁用成功: ${pluginName}`);

} catch (error) {
console.error(`插件禁用失败: ${pluginName}`, error);
throw error;
}
}

// 添加钩子
addHook(hookName, handler, pluginName) {
if (!this.hooks.has(hookName)) {
this.hooks.set(hookName, []);
}

this.hooks.get(hookName).push({
handler,
pluginName,
priority: handler.priority || 0
});

// 按优先级排序
this.hooks.get(hookName).sort((a, b) => b.priority - a.priority);
}

// 执行钩子
async executeHook(hookName, data = {}) {
const handlers = this.hooks.get(hookName) || [];
let result = data;

for (const { handler, pluginName } of handlers) {
try {
// 检查插件是否启用
if (this.pluginStates.get(pluginName) !== 'active') {
continue;
}

const hookResult = await handler(result, this.createPluginContext(this.plugins.get(pluginName)));

// 如果钩子返回了结果,更新数据
if (hookResult !== undefined) {
result = hookResult;
}

} catch (error) {
console.error(`钩子执行失败: ${hookName} (${pluginName})`, error);

// 触发错误事件
this.emit('hookError', { hookName, pluginName, error });
}
}

return result;
}

// 注册命令
registerCommand(commandName, handler, pluginName) {
if (!this.commands) {
this.commands = new Map();
}

this.commands.set(commandName, {
handler,
pluginName
});
}

// 执行命令
async executeCommand(commandName, args = {}) {
const command = this.commands?.get(commandName);

if (!command) {
throw new Error(`命令不存在: ${commandName}`);
}

// 检查插件是否启用
if (this.pluginStates.get(command.pluginName) !== 'active') {
throw new Error(`插件未启用: ${command.pluginName}`);
}

try {
const plugin = this.plugins.get(command.pluginName);
return await command.handler(args, this.createPluginContext(plugin));
} catch (error) {
console.error(`命令执行失败: ${commandName}`, error);
throw error;
}
}

// 获取插件列表
getPlugins() {
return Array.from(this.plugins.values()).map(plugin => ({
name: plugin.name,
version: plugin.version,
description: plugin.description,
author: plugin.author,
state: this.pluginStates.get(plugin.name),
dependencies: plugin.dependencies || []
}));
}

// 获取插件信息
getPluginInfo(pluginName) {
const plugin = this.plugins.get(pluginName);

if (!plugin) {
return null;
}

return {
name: plugin.name,
version: plugin.version,
description: plugin.description,
author: plugin.author,
state: this.pluginStates.get(pluginName),
dependencies: plugin.dependencies || [],
hooks: Object.keys(plugin.hooks || {}),
commands: Object.keys(plugin.commands || {})
};
}

// 验证插件
validatePlugin(plugin) {
// 检查必需字段
if (!plugin.name || !plugin.version) {
return false;
}

// 检查名称冲突
if (this.plugins.has(plugin.name)) {
return false;
}

// 检查版本格式
if (!/^\d+\.\d+\.\d+$/.test(plugin.version)) {
return false;
}

return true;
}

// 检查依赖
async checkDependencies(plugin) {
if (!plugin.dependencies || plugin.dependencies.length === 0) {
return true;
}

for (const dep of plugin.dependencies) {
const depPlugin = this.plugins.get(dep.name);

if (!depPlugin) {
console.error(`缺少依赖插件: ${dep.name}`);
return false;
}

if (dep.version && !this.isVersionCompatible(depPlugin.version, dep.version)) {
console.error(`依赖插件版本不兼容: ${dep.name} (需要: ${dep.version}, 当前: ${depPlugin.version})`);
return false;
}

if (this.pluginStates.get(dep.name) !== 'active') {
console.error(`依赖插件未启用: ${dep.name}`);
return false;
}
}

return true;
}

// 获取依赖此插件的插件列表
getDependents(pluginName) {
const dependents = [];

for (const [name, plugin] of this.plugins) {
if (plugin.dependencies && plugin.dependencies.some(dep => dep.name === pluginName)) {
dependents.push(name);
}
}

return dependents;
}

// 获取启用状态的依赖插件列表
getActiveDependents(pluginName) {
return this.getDependents(pluginName)
.filter(name => this.pluginStates.get(name) === 'active');
}

// 版本兼容性检查
isVersionCompatible(currentVersion, requiredVersion) {
// 简单的版本比较,实际项目中可以使用更复杂的语义版本比较
const current = currentVersion.split('.').map(Number);
const required = requiredVersion.split('.').map(Number);

for (let i = 0; i < 3; i++) {
if (current[i] > required[i]) return true;
if (current[i] < required[i]) return false;
}

return true;
}

// 创建插件上下文
createPluginContext(plugin) {
return {
plugin,
pluginManager: this,
emit: (event, data) => this.emit(event, { ...data, pluginName: plugin.name }),
executeHook: (hookName, data) => this.executeHook(hookName, data),
executeCommand: (commandName, args) => this.executeCommand(commandName, args),
getPlugin: (name) => this.plugins.get(name),
isPluginActive: (name) => this.pluginStates.get(name) === 'active'
};
}

// 事件发射
emit(eventName, data) {
const event = new CustomEvent(eventName, { detail: data });
this.eventBus.dispatchEvent(event);
}

// 事件监听
on(eventName, handler) {
this.eventBus.addEventListener(eventName, handler);
}

// 移除事件监听
off(eventName, handler) {
this.eventBus.removeEventListener(eventName, handler);
}

// 销毁插件管理器
async destroy() {
// 卸载所有插件
const pluginNames = Array.from(this.plugins.keys());

for (const pluginName of pluginNames) {
try {
await this.unregisterPlugin(pluginName);
} catch (error) {
console.error(`卸载插件失败: ${pluginName}`, error);
}
}

// 清理资源
this.plugins.clear();
this.hooks.clear();
this.pluginStates.clear();
this.dependencies.clear();

if (this.commands) {
this.commands.clear();
}

console.log('插件管理器已销毁');
}
}

// 插件基类
class BasePlugin {
constructor(config = {}) {
this.name = config.name;
this.version = config.version;
this.description = config.description;
this.author = config.author;
this.dependencies = config.dependencies || [];
this.config = config;
}

// 初始化插件
async initialize(context) {
this.context = context;
console.log(`插件初始化: ${this.name}`);
}

// 启用插件
async enable() {
console.log(`插件启用: ${this.name}`);
}

// 禁用插件
async disable() {
console.log(`插件禁用: ${this.name}`);
}

// 清理插件
async cleanup() {
console.log(`插件清理: ${this.name}`);
}
}

示例插件

// 消息统计插件
class MessageStatsPlugin extends BasePlugin {
constructor() {
super({
name: 'message-stats',
version: '1.0.0',
description: '消息统计插件',
author: 'AI Assistant'
});

this.stats = {
totalMessages: 0,
totalTokens: 0,
conversationCount: 0,
averageResponseTime: 0
};

this.responseTimes = [];
}

async initialize(context) {
await super.initialize(context);

// 加载统计数据
await this.loadStats();
}

// 钩子函数
get hooks() {
return {
afterMessageSend: this.onMessageSend.bind(this),
afterMessageReceive: this.onMessageReceive.bind(this),
afterConversationCreate: this.onConversationCreate.bind(this)
};
}

// 命令函数
get commands() {
return {
'stats': this.getStats.bind(this),
'reset-stats': this.resetStats.bind(this)
};
}

// 消息发送后
async onMessageSend(data) {
this.stats.totalMessages++;
this.messageStartTime = Date.now();

await this.saveStats();
return data;
}

// 消息接收后
async onMessageReceive(data) {
if (this.messageStartTime) {
const responseTime = Date.now() - this.messageStartTime;
this.responseTimes.push(responseTime);

// 计算平均响应时间
this.stats.averageResponseTime = this.responseTimes.reduce((a, b) => a + b, 0) / this.responseTimes.length;

// 限制响应时间数组大小
if (this.responseTimes.length > 100) {
this.responseTimes = this.responseTimes.slice(-100);
}
}

if (data.tokens) {
this.stats.totalTokens += data.tokens;
}

await this.saveStats();
return data;
}

// 对话创建后
async onConversationCreate(data) {
this.stats.conversationCount++;
await this.saveStats();
return data;
}

// 获取统计信息
async getStats() {
return {
...this.stats,
averageResponseTime: Math.round(this.stats.averageResponseTime)
};
}

// 重置统计信息
async resetStats() {
this.stats = {
totalMessages: 0,
totalTokens: 0,
conversationCount: 0,
averageResponseTime: 0
};

this.responseTimes = [];
await this.saveStats();

return { message: '统计信息已重置' };
}

// 保存统计数据
async saveStats() {
try {
localStorage.setItem('message-stats', JSON.stringify(this.stats));
} catch (error) {
console.error('保存统计数据失败:', error);
}
}

// 加载统计数据
async loadStats() {
try {
const saved = localStorage.getItem('message-stats');
if (saved) {
this.stats = { ...this.stats, ...JSON.parse(saved) };
}
} catch (error) {
console.error('加载统计数据失败:', error);
}
}
}

// 快捷回复插件
class QuickReplyPlugin extends BasePlugin {
constructor() {
super({
name: 'quick-reply',
version: '1.0.0',
description: '快捷回复插件',
author: 'AI Assistant'
});

this.quickReplies = [
{ text: '你好', shortcut: '/hello' },
{ text: '谢谢', shortcut: '/thanks' },
{ text: '再见', shortcut: '/bye' },
{ text: '请解释一下', shortcut: '/explain' },
{ text: '能给个例子吗?', shortcut: '/example' }
];
}

async initialize(context) {
await super.initialize(context);

// 加载快捷回复
await this.loadQuickReplies();

// 添加UI
this.addQuickReplyUI();
}

// 钩子函数
get hooks() {
return {
beforeMessageSend: this.processShortcuts.bind(this)
};
}

// 命令函数
get commands() {
return {
'add-reply': this.addQuickReply.bind(this),
'remove-reply': this.removeQuickReply.bind(this),
'list-replies': this.listQuickReplies.bind(this)
};
}

// 处理快捷键
async processShortcuts(data) {
if (data.message && data.message.startsWith('/')) {
const shortcut = data.message.trim();
const quickReply = this.quickReplies.find(reply => reply.shortcut === shortcut);

if (quickReply) {
data.message = quickReply.text;
}
}

return data;
}

// 添加快捷回复UI
addQuickReplyUI() {
const container = document.querySelector('.chat-input-container');
if (!container) return;

const quickReplyContainer = document.createElement('div');
quickReplyContainer.className = 'quick-reply-container';
quickReplyContainer.innerHTML = `
<div class="quick-reply-buttons">
${this.quickReplies.map(reply =>
`<button class="quick-reply-btn" data-text="${reply.text}">${reply.shortcut}</button>`
).join('')}
</div>
`;

// 添加样式
const style = document.createElement('style');
style.textContent = `
.quick-reply-container {
margin-bottom: 10px;
}

.quick-reply-buttons {
display: flex;
flex-wrap: wrap;
gap: 5px;
}

.quick-reply-btn {
padding: 5px 10px;
border: 1px solid #ddd;
border-radius: 15px;
background: #f5f5f5;
cursor: pointer;
font-size: 12px;
transition: all 0.2s;
}

.quick-reply-btn:hover {
background: #e0e0e0;
border-color: #ccc;
}
`;

document.head.appendChild(style);
container.parentNode.insertBefore(quickReplyContainer, container);

// 添加点击事件
quickReplyContainer.addEventListener('click', (e) => {
if (e.target.classList.contains('quick-reply-btn')) {
const text = e.target.dataset.text;
const input = document.querySelector('.message-input');
if (input) {
input.value = text;
input.focus();
}
}
});
}

// 添加快捷回复
async addQuickReply(args) {
const { text, shortcut } = args;

if (!text || !shortcut) {
throw new Error('需要提供 text 和 shortcut 参数');
}

if (this.quickReplies.some(reply => reply.shortcut === shortcut)) {
throw new Error('快捷键已存在');
}

this.quickReplies.push({ text, shortcut });
await this.saveQuickReplies();

return { message: '快捷回复添加成功' };
}

// 移除快捷回复
async removeQuickReply(args) {
const { shortcut } = args;

if (!shortcut) {
throw new Error('需要提供 shortcut 参数');
}

const index = this.quickReplies.findIndex(reply => reply.shortcut === shortcut);

if (index === -1) {
throw new Error('快捷键不存在');
}

this.quickReplies.splice(index, 1);
await this.saveQuickReplies();

return { message: '快捷回复移除成功' };
}

// 列出快捷回复
async listQuickReplies() {
return this.quickReplies;
}

// 保存快捷回复
async saveQuickReplies() {
try {
localStorage.setItem('quick-replies', JSON.stringify(this.quickReplies));
} catch (error) {
console.error('保存快捷回复失败:', error);
}
}

// 加载快捷回复
async loadQuickReplies() {
try {
const saved = localStorage.getItem('quick-replies');
if (saved) {
this.quickReplies = JSON.parse(saved);
}
} catch (error) {
console.error('加载快捷回复失败:', error);
}
}

async cleanup() {
// 移除UI
const container = document.querySelector('.quick-reply-container');
if (container) {
container.remove();
}

await super.cleanup();
}
}

完整应用示例

应用初始化

// 智能聊天应用完整示例
class CompleteChatApplication {
constructor(config = {}) {
this.config = {
apiKey: config.apiKey,
storageType: config.storageType || 'localStorage',
theme: config.theme || 'light',
language: config.language || 'zh-CN',
maxConversations: config.maxConversations || 100,
enablePlugins: config.enablePlugins !== false,
...config
};

this.isInitialized = false;
this.components = {};
}

// 初始化应用
async initialize() {
try {
console.log('正在初始化智能聊天应用...');

// 初始化核心组件
await this.initializeComponents();

// 初始化插件系统
if (this.config.enablePlugins) {
await this.initializePlugins();
}

// 初始化UI
await this.initializeUI();

// 加载用户偏好
await this.loadUserPreferences();

// 恢复最后的对话
await this.restoreLastConversation();

this.isInitialized = true;
console.log('智能聊天应用初始化完成');

} catch (error) {
console.error('应用初始化失败:', error);
throw error;
}
}

// 初始化核心组件
async initializeComponents() {
// 初始化AI服务管理器
this.components.aiService = new AIServiceManager({
apiKey: this.config.apiKey,
defaultModel: this.config.defaultModel || 'gpt-3.5-turbo',
timeout: this.config.timeout || 30000
});

// 初始化存储管理器
this.components.storage = new StorageManager({
storageType: this.config.storageType,
maxConversations: this.config.maxConversations,
compressionEnabled: true
});

// 初始化对话管理器
this.components.conversation = new ConversationManager({
storage: this.components.storage,
aiService: this.components.aiService
});

// 初始化消息处理器
this.components.messageProcessor = new MessageProcessor({
maxLength: this.config.maxMessageLength || 4000,
enableFiltering: true
});

// 初始化UI管理器
this.components.ui = new UIManager({
theme: this.config.theme,
language: this.config.language,
container: this.config.container || document.body
});
}

// 初始化插件系统
async initializePlugins() {
this.components.pluginManager = new PluginManager();

// 注册默认插件
const defaultPlugins = [
new MessageStatsPlugin(),
new QuickReplyPlugin()
];

for (const plugin of defaultPlugins) {
try {
await this.components.pluginManager.registerPlugin(plugin);
} catch (error) {
console.warn(`插件注册失败: ${plugin.name}`, error);
}
}
}

// 初始化UI
async initializeUI() {
// 创建UI
await this.components.ui.initialize();

// 绑定事件
this.bindEvents();

// 设置主题
this.components.ui.setTheme(this.config.theme);
}

// 绑定事件
bindEvents() {
// 消息发送事件
this.components.ui.on('messageSend', async (data) => {
await this.handleMessageSend(data.message);
});

// 对话创建事件
this.components.ui.on('conversationCreate', async () => {
await this.createNewConversation();
});

// 对话加载事件
this.components.ui.on('conversationLoad', async (data) => {
await this.loadConversation(data.conversationId);
});

// 对话删除事件
this.components.ui.on('conversationDelete', async (data) => {
await this.deleteConversation(data.conversationId);
});

// 设置变更事件
this.components.ui.on('settingsChange', async (data) => {
await this.handleSettingsChange(data.settings);
});

// 插件命令事件
if (this.components.pluginManager) {
this.components.ui.on('pluginCommand', async (data) => {
await this.executePluginCommand(data.command, data.args);
});
}
}

// 处理消息发送
async handleMessageSend(message) {
try {
// 执行插件钩子:消息发送前
if (this.components.pluginManager) {
const hookData = await this.components.pluginManager.executeHook('beforeMessageSend', {
message,
conversation: this.currentConversation
});
message = hookData.message;
}

// 处理消息
const processedMessage = await this.components.messageProcessor.processMessage(message, 'user');

// 添加用户消息到对话
await this.components.conversation.addMessage(processedMessage);

// 显示用户消息
this.components.ui.addMessage(processedMessage);

// 显示加载状态
this.components.ui.showLoading();

// 执行插件钩子:消息发送后
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('afterMessageSend', {
message: processedMessage,
conversation: this.currentConversation
});
}

// 获取AI回复
const aiResponse = await this.getAIResponse();

// 处理AI回复
const processedResponse = await this.components.messageProcessor.processMessage(aiResponse.content, 'assistant');

// 添加AI回复到对话
await this.components.conversation.addMessage(processedResponse);

// 隐藏加载状态
this.components.ui.hideLoading();

// 显示AI回复
this.components.ui.addMessage(processedResponse, true); // 带打字效果

// 执行插件钩子:消息接收后
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('afterMessageReceive', {
message: processedResponse,
conversation: this.currentConversation,
tokens: aiResponse.tokens
});
}

} catch (error) {
console.error('处理消息发送失败:', error);

// 隐藏加载状态
this.components.ui.hideLoading();

// 显示错误消息
this.components.ui.showError('发送消息失败,请重试');

// 执行插件钩子:错误处理
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('onError', {
error,
context: 'messageSend'
});
}
}
}

// 获取AI回复
async getAIResponse() {
const context = await this.components.conversation.buildContext();

const response = await this.components.aiService.chat({
messages: context.messages,
model: this.config.defaultModel,
temperature: this.config.temperature || 0.7,
maxTokens: this.config.maxTokens || 2000
});

return {
content: response.content,
tokens: response.usage?.total_tokens || 0
};
}

// 创建新对话
async createNewConversation() {
try {
// 执行插件钩子:对话创建前
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('beforeConversationCreate', {});
}

// 创建新对话
this.currentConversation = await this.components.conversation.createConversation();

// 清空UI
this.components.ui.clearMessages();

// 更新对话列表
await this.updateConversationList();

// 执行插件钩子:对话创建后
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('afterConversationCreate', {
conversation: this.currentConversation
});
}

console.log('新对话创建成功:', this.currentConversation.id);

} catch (error) {
console.error('创建新对话失败:', error);
this.components.ui.showError('创建新对话失败');
}
}

// 加载对话
async loadConversation(conversationId) {
try {
// 执行插件钩子:对话加载前
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('beforeConversationLoad', {
conversationId
});
}

// 加载对话
this.currentConversation = await this.components.conversation.loadConversation(conversationId);

if (!this.currentConversation) {
throw new Error('对话不存在');
}

// 清空UI并显示对话消息
this.components.ui.clearMessages();

for (const message of this.currentConversation.messages) {
this.components.ui.addMessage(message);
}

// 保存最后对话ID
await this.components.storage.saveLastConversationId(conversationId);

// 执行插件钩子:对话加载后
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('afterConversationLoad', {
conversation: this.currentConversation
});
}

console.log('对话加载成功:', conversationId);

} catch (error) {
console.error('加载对话失败:', error);
this.components.ui.showError('加载对话失败');
}
}

// 删除对话
async deleteConversation(conversationId) {
try {
await this.components.conversation.deleteConversation(conversationId);

// 如果删除的是当前对话,创建新对话
if (this.currentConversation && this.currentConversation.id === conversationId) {
await this.createNewConversation();
}

// 更新对话列表
await this.updateConversationList();

console.log('对话删除成功:', conversationId);

} catch (error) {
console.error('删除对话失败:', error);
this.components.ui.showError('删除对话失败');
}
}

// 处理设置变更
async handleSettingsChange(settings) {
try {
// 更新配置
Object.assign(this.config, settings);

// 应用主题变更
if (settings.theme) {
this.components.ui.setTheme(settings.theme);
}

// 应用语言变更
if (settings.language) {
this.components.ui.setLanguage(settings.language);
}

// 保存用户偏好
await this.saveUserPreferences();

// 执行插件钩子:设置变更
if (this.components.pluginManager) {
await this.components.pluginManager.executeHook('onSettingsChange', {
settings,
config: this.config
});
}

console.log('设置更新成功');

} catch (error) {
console.error('设置更新失败:', error);
this.components.ui.showError('设置更新失败');
}
}

// 执行插件命令
async executePluginCommand(command, args) {
try {
if (!this.components.pluginManager) {
throw new Error('插件系统未启用');
}

const result = await this.components.pluginManager.executeCommand(command, args);

// 显示命令结果
if (result && result.message) {
this.components.ui.showMessage(result.message);
}

return result;

} catch (error) {
console.error('执行插件命令失败:', error);
this.components.ui.showError(`命令执行失败: ${error.message}`);
}
}

// 更新对话列表
async updateConversationList() {
try {
const conversations = await this.components.storage.getConversationList();
this.components.ui.updateConversationList(conversations);
} catch (error) {
console.error('更新对话列表失败:', error);
}
}

// 保存用户偏好
async saveUserPreferences() {
try {
const preferences = {
theme: this.config.theme,
language: this.config.language,
defaultModel: this.config.defaultModel,
temperature: this.config.temperature,
maxTokens: this.config.maxTokens
};

await this.components.storage.saveUserPreferences(preferences);
} catch (error) {
console.error('保存用户偏好失败:', error);
}
}

// 加载用户偏好
async loadUserPreferences() {
try {
const preferences = await this.components.storage.loadUserPreferences();
Object.assign(this.config, preferences);
} catch (error) {
console.error('加载用户偏好失败:', error);
}
}

// 恢复最后的对话
async restoreLastConversation() {
try {
const lastConversationId = await this.components.storage.getLastConversationId();

if (lastConversationId) {
await this.loadConversation(lastConversationId);
} else {
await this.createNewConversation();
}

// 更新对话列表
await this.updateConversationList();

} catch (error) {
console.error('恢复最后对话失败:', error);
await this.createNewConversation();
}
}

// 导出数据
async exportData() {
try {
return await this.components.storage.exportData();
} catch (error) {
console.error('导出数据失败:', error);
throw error;
}
}

// 导入数据
async importData(data) {
try {
const result = await this.components.storage.importData(data);

// 更新对话列表
await this.updateConversationList();

return result;
} catch (error) {
console.error('导入数据失败:', error);
throw error;
}
}

// 获取应用状态
getStatus() {
return {
initialized: this.isInitialized,
currentConversation: this.currentConversation?.id,
pluginsEnabled: !!this.components.pluginManager,
theme: this.config.theme,
language: this.config.language
};
}

// 销毁应用
async destroy() {
try {
// 保存当前状态
if (this.currentConversation) {
await this.components.storage.saveLastConversationId(this.currentConversation.id);
}

await this.saveUserPreferences();

// 销毁组件
if (this.components.pluginManager) {
await this.components.pluginManager.destroy();
}

if (this.components.ui) {
this.components.ui.destroy();
}

if (this.components.storage) {
this.components.storage.destroy();
}

console.log('智能聊天应用已销毁');

} catch (error) {
console.error('销毁应用失败:', error);
}
}
}

// 应用启动函数
async function startChatApplication(config = {}) {
const app = new CompleteChatApplication(config);

try {
await app.initialize();

// 将应用实例暴露到全局
window.chatApp = app;

console.log('智能聊天应用启动成功');
return app;

} catch (error) {
console.error('智能聊天应用启动失败:', error);
throw error;
}
}

// 使用示例
/*
startChatApplication({
apiKey: 'your-api-key',
theme: 'dark',
language: 'zh-CN',
defaultModel: 'gpt-4',
container: document.getElementById('chat-container')
}).then(app => {
console.log('应用启动成功', app.getStatus());
}).catch(error => {
console.error('应用启动失败', error);
});
*/

最佳实践

性能优化

// 性能优化工具类
class PerformanceOptimizer {
constructor() {
this.debounceTimers = new Map();
this.throttleTimers = new Map();
this.cache = new Map();
this.observers = new Map();
}

// 防抖函数
debounce(key, func, delay = 300) {
if (this.debounceTimers.has(key)) {
clearTimeout(this.debounceTimers.get(key));
}

const timer = setTimeout(() => {
func();
this.debounceTimers.delete(key);
}, delay);

this.debounceTimers.set(key, timer);
}

// 节流函数
throttle(key, func, delay = 100) {
if (this.throttleTimers.has(key)) {
return;
}

func();

const timer = setTimeout(() => {
this.throttleTimers.delete(key);
}, delay);

this.throttleTimers.set(key, timer);
}

// 缓存管理
setCache(key, value, ttl = 300000) { // 默认5分钟
const expiry = Date.now() + ttl;
this.cache.set(key, { value, expiry });
}

getCache(key) {
const item = this.cache.get(key);

if (!item) {
return null;
}

if (Date.now() > item.expiry) {
this.cache.delete(key);
return null;
}

return item.value;
}

// 虚拟滚动
createVirtualScroll(container, items, itemHeight, renderItem) {
const containerHeight = container.clientHeight;
const visibleCount = Math.ceil(containerHeight / itemHeight) + 2;
let scrollTop = 0;

const render = () => {
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = Math.min(startIndex + visibleCount, items.length);

container.innerHTML = '';

// 创建占位符
const topSpacer = document.createElement('div');
topSpacer.style.height = `${startIndex * itemHeight}px`;
container.appendChild(topSpacer);

// 渲染可见项目
for (let i = startIndex; i < endIndex; i++) {
const element = renderItem(items[i], i);
element.style.height = `${itemHeight}px`;
container.appendChild(element);
}

// 创建底部占位符
const bottomSpacer = document.createElement('div');
bottomSpacer.style.height = `${(items.length - endIndex) * itemHeight}px`;
container.appendChild(bottomSpacer);
};

container.addEventListener('scroll', () => {
scrollTop = container.scrollTop;
this.throttle('virtualScroll', render, 16); // 60fps
});

render();
}

// 图片懒加载
lazyLoadImages(selector = 'img[data-src]') {
const images = document.querySelectorAll(selector);

const imageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.removeAttribute('data-src');
imageObserver.unobserve(img);
}
});
});

images.forEach(img => imageObserver.observe(img));
this.observers.set('images', imageObserver);
}

// 内存清理
cleanup() {
// 清理定时器
this.debounceTimers.forEach(timer => clearTimeout(timer));
this.throttleTimers.forEach(timer => clearTimeout(timer));

// 清理缓存
this.cache.clear();

// 清理观察器
this.observers.forEach(observer => observer.disconnect());

// 清理映射
this.debounceTimers.clear();
this.throttleTimers.clear();
this.observers.clear();
}
}

错误处理

// 错误处理工具类
class ErrorHandler {
constructor(config = {}) {
this.config = config;
this.errorLog = [];
this.maxLogSize = config.maxLogSize || 100;

this.setupGlobalErrorHandling();
}

// 设置全局错误处理
setupGlobalErrorHandling() {
// 捕获未处理的Promise拒绝
window.addEventListener('unhandledrejection', (event) => {
this.handleError(event.reason, 'unhandledrejection');
});

// 捕获全局错误
window.addEventListener('error', (event) => {
this.handleError(event.error, 'global');
});
}

// 处理错误
handleError(error, context = 'unknown') {
const errorInfo = {
message: error.message || String(error),
stack: error.stack,
context,
timestamp: new Date().toISOString(),
userAgent: navigator.userAgent,
url: window.location.href
};

// 添加到错误日志
this.addToErrorLog(errorInfo);

// 根据错误类型进行处理
this.processError(errorInfo);

// 上报错误(如果配置了)
if (this.config.reportErrors) {
this.reportError(errorInfo);
}
}

// 添加到错误日志
addToErrorLog(errorInfo) {
this.errorLog.push(errorInfo);

// 限制日志大小
if (this.errorLog.length > this.maxLogSize) {
this.errorLog = this.errorLog.slice(-this.maxLogSize);
}
}

// 处理错误
processError(errorInfo) {
console.error('应用错误:', errorInfo);

// 根据错误类型显示不同的用户提示
if (errorInfo.message.includes('网络')) {
this.showUserMessage('网络连接异常,请检查网络设置', 'warning');
} else if (errorInfo.message.includes('API')) {
this.showUserMessage('服务暂时不可用,请稍后重试', 'error');
} else {
this.showUserMessage('发生了一个错误,我们正在处理中', 'info');
}
}

// 显示用户消息
showUserMessage(message, type = 'info') {
// 创建消息元素
const messageEl = document.createElement('div');
messageEl.className = `error-message error-message-${type}`;
messageEl.textContent = message;

// 添加样式
messageEl.style.cssText = `
position: fixed;
top: 20px;
right: 20px;
padding: 12px 16px;
border-radius: 4px;
color: white;
font-size: 14px;
z-index: 10000;
max-width: 300px;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
animation: slideIn 0.3s ease-out;
`;

// 根据类型设置背景色
const colors = {
info: '#2196F3',
warning: '#FF9800',
error: '#F44336',
success: '#4CAF50'
};

messageEl.style.backgroundColor = colors[type] || colors.info;

// 添加到页面
document.body.appendChild(messageEl);

// 自动移除
setTimeout(() => {
if (messageEl.parentNode) {
messageEl.parentNode.removeChild(messageEl);
}
}, 5000);
}

// 上报错误
async reportError(errorInfo) {
try {
if (!this.config.errorReportUrl) {
return;
}

await fetch(this.config.errorReportUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(errorInfo)
});

} catch (error) {
console.warn('错误上报失败:', error);
}
}

// 获取错误日志
getErrorLog() {
return [...this.errorLog];
}

// 清空错误日志
clearErrorLog() {
this.errorLog = [];
}

// 创建错误边界
createErrorBoundary(component, fallback) {
return {
render: () => {
try {
return component.render();
} catch (error) {
this.handleError(error, 'component');
return fallback ? fallback(error) : '<div>组件加载失败</div>';
}
}
};
}
}

安全实践

// 安全工具类
class SecurityManager {
constructor() {
this.sanitizer = this.createSanitizer();
}

// 创建HTML清理器
createSanitizer() {
const allowedTags = ['p', 'br', 'strong', 'em', 'code', 'pre', 'ul', 'ol', 'li'];
const allowedAttributes = ['class'];

return {
sanitize: (html) => {
// 简单的HTML清理实现
// 实际项目中建议使用DOMPurify等专业库
const div = document.createElement('div');
div.innerHTML = html;

const walker = document.createTreeWalker(
div,
NodeFilter.SHOW_ELEMENT,
null,
false
);

const nodesToRemove = [];
let node;

while (node = walker.nextNode()) {
if (!allowedTags.includes(node.tagName.toLowerCase())) {
nodesToRemove.push(node);
} else {
// 清理属性
const attributes = Array.from(node.attributes);
attributes.forEach(attr => {
if (!allowedAttributes.includes(attr.name)) {
node.removeAttribute(attr.name);
}
});
}
}

nodesToRemove.forEach(node => {
node.parentNode.removeChild(node);
});

return div.innerHTML;
}
};
}

// 清理用户输入
sanitizeInput(input) {
if (typeof input !== 'string') {
return input;
}

// 移除潜在的脚本标签
return input
.replace(/<script[^>]*>.*?<\/script>/gi, '')
.replace(/javascript:/gi, '')
.replace(/on\w+\s*=/gi, '')
.trim();
}

// 清理HTML内容
sanitizeHTML(html) {
return this.sanitizer.sanitize(html);
}

// 验证API密钥格式
validateApiKey(apiKey) {
if (!apiKey || typeof apiKey !== 'string') {
return false;
}

// 基本格式检查
return /^[a-zA-Z0-9\-_]{20,}$/.test(apiKey);
}

// 生成随机ID
generateSecureId() {
const array = new Uint8Array(16);
crypto.getRandomValues(array);
return Array.from(array, byte => byte.toString(16).padStart(2, '0')).join('');
}

// 简单的数据加密(仅用于演示)
encrypt(data, key) {
// 实际项目中应使用更安全的加密算法
const encoded = btoa(JSON.stringify(data));
return btoa(encoded + key);
}

// 简单的数据解密(仅用于演示)
decrypt(encryptedData, key) {
try {
const decoded = atob(encryptedData);
const data = decoded.replace(key, '');
return JSON.parse(atob(data));
} catch (error) {
throw new Error('解密失败');
}
}

// 检查内容安全策略
checkCSP() {
const meta = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
return {
hasCSP: !!meta,
content: meta ? meta.getAttribute('content') : null
};
}

// 验证URL安全性
isUrlSafe(url) {
try {
const urlObj = new URL(url);

// 只允许HTTPS和HTTP协议
if (!['https:', 'http:'].includes(urlObj.protocol)) {
return false;
}

// 检查是否为本地地址
const hostname = urlObj.hostname;
if (['localhost', '127.0.0.1', '0.0.0.0'].includes(hostname)) {
return false;
}

return true;
} catch (error) {
return false;
}
}
}

学习检验

理论问题

  1. 架构设计

    • 智能聊天应用的核心组件有哪些?它们之间如何协作?
    • 为什么需要消息处理系统?它解决了什么问题?
    • 插件系统的设计原理是什么?如何实现插件间的隔离?
  2. 性能优化

    • 在处理大量历史消息时,如何优化UI渲染性能?
    • 如何设计缓存策略来减少API调用次数?
    • 虚拟滚动技术的实现原理是什么?
  3. 数据管理

    • 不同存储方案(localStorage、IndexedDB、内存)的适用场景是什么?
    • 如何设计对话数据的压缩和加密方案?
    • 数据导入导出功能需要考虑哪些安全问题?
  4. 用户体验

    • 如何实现流畅的打字效果?
    • 主题切换功能的技术实现要点是什么?
    • 如何处理网络异常和API错误?

实践练习

初级练习

  1. 基础聊天界面

    // 创建一个简单的聊天界面
    // 要求:
    // - 消息输入框和发送按钮
    // - 消息显示区域
    // - 基本的CSS样式
    // - 支持Enter键发送消息
  2. 消息存储功能

    // 实现消息的本地存储
    // 要求:
    // - 使用localStorage保存消息历史
    // - 页面刷新后能恢复消息
    // - 支持清空历史记录
  3. 主题切换功能

    // 实现明暗主题切换
    // 要求:
    // - 定义明暗两套CSS变量
    // - 实现主题切换按钮
    // - 记住用户的主题偏好

中级练习

  1. AI服务集成

    // 集成OpenAI API
    // 要求:
    // - 实现API调用封装
    // - 处理流式响应
    // - 添加错误处理和重试机制
    // - 实现打字效果显示AI回复
  2. 对话管理系统

    // 实现多对话管理
    // 要求:
    // - 支持创建、删除、重命名对话
    // - 对话列表显示和切换
    // - 对话数据的持久化存储
    // - 对话搜索功能
  3. 消息处理增强

    // 实现高级消息处理
    // 要求:
    // - Markdown渲染支持
    // - 代码高亮显示
    // - 图片和链接预览
    // - 消息编辑和删除功能

高级练习

  1. 插件系统开发

    // 开发一个完整的插件系统
    // 要求:
    // - 插件注册和生命周期管理
    // - 钩子系统实现
    // - 插件间通信机制
    // - 插件配置和设置界面
  2. 性能优化实现

    // 实现性能优化方案
    // 要求:
    // - 虚拟滚动处理大量消息
    // - 图片懒加载
    // - 防抖节流优化
    // - 内存泄漏检测和清理
  3. 高级功能开发

    // 实现高级聊天功能
    // 要求:
    // - 语音输入和播放
    // - 文件上传和预览
    // - 消息引用和回复
    // - 实时协作功能

项目建议

初级项目

  1. 个人AI助手

    • 目标:创建一个简单的个人AI聊天助手
    • 功能:基础对话、消息历史、主题切换
    • 技术栈:HTML/CSS/JavaScript + OpenAI API
    • 学习重点:API集成、基础UI设计、数据存储
  2. 学习伙伴聊天机器人

    • 目标:开发一个帮助学习的AI聊天机器人
    • 功能:问答对话、学习记录、知识点整理
    • 技术栈:React + OpenAI API + localStorage
    • 学习重点:React组件设计、状态管理、用户体验

中级项目

  1. 多模态AI聊天应用

    • 目标:支持文本、图片、语音的综合AI聊天应用
    • 功能:多模态输入、智能回复、媒体处理
    • 技术栈:Vue.js + GPT-4V + Web APIs
    • 学习重点:多模态处理、文件上传、媒体播放
  2. 团队协作AI助手

    • 目标:为团队协作设计的AI聊天工具
    • 功能:多用户支持、权限管理、数据同步
    • 技术栈:React + Node.js + WebSocket + MongoDB
    • 学习重点:实时通信、用户管理、数据同步
  3. 智能客服系统

    • 目标:企业级智能客服聊天系统
    • 功能:自动回复、人工转接、数据分析
    • 技术栈:Angular + Express.js + Redis + PostgreSQL
    • 学习重点:企业级架构、性能优化、数据分析

高级项目

  1. AI驱动的内容创作平台

    • 目标:集成多种AI能力的内容创作工具
    • 功能:文本生成、图片创作、视频编辑、协作编辑
    • 技术栈:Next.js + FastAPI + PostgreSQL + Redis + Docker
    • 学习重点:微服务架构、AI模型集成、实时协作
  2. 智能教育平台

    • 目标:个性化AI教育聊天平台
    • 功能:自适应学习、进度跟踪、智能推荐、多语言支持
    • 技术栈:React + Python + TensorFlow + Kubernetes
    • 学习重点:机器学习、个性化推荐、云原生部署
  3. 企业级AI工作台

    • 目标:集成多种AI工具的企业工作平台
    • 功能:多AI模型支持、工作流自动化、数据分析、权限管理
    • 技术栈:微前端 + 微服务 + Kubernetes + 多种AI服务
    • 学习重点:企业级架构、系统集成、DevOps

延伸阅读

技术文档

  1. 前端框架

  2. AI服务API

  3. JavaScript AI库

学习资源

  1. 在线课程

  2. 技术博客

  3. 开源项目

工具和库

  1. 开发工具

    • Vite - 现代前端构建工具
    • Webpack - 模块打包工具
    • ESLint - JavaScript代码检查工具
  2. UI组件库

  3. 状态管理

社区和论坛

  1. 技术社区

  2. 中文社区

    • 掘金 - 中文技术社区
    • 思否 - 中文编程问答
    • V2EX - 创意工作者社区

通过本文的学习,你应该掌握了智能聊天应用开发的完整技术栈和最佳实践。从基础的UI设计到高级的插件系统,从性能优化到安全实践,这些知识将帮助你构建出专业级的AI聊天应用。

记住,优秀的AI应用不仅需要强大的技术实现,更需要良好的用户体验设计。在开发过程中,始终以用户为中心,持续优化和改进你的应用。

对话管理器

// 对话管理器
class ConversationManager {
constructor(config = {}) {
this.config = config;
this.conversations = new Map();
this.currentConversation = null;
this.maxConversations = config.maxConversations || 100;
this.maxMessagesPerConversation = config.maxMessagesPerConversation || 1000;

this.storageManager = new StorageManager(config);
this.contextBuilder = new ContextBuilder(config);
}

// 创建新对话
async createConversation(options = {}) {
const conversation = {
id: this.generateConversationId(),
title: options.title || '新对话',
timestamp: options.timestamp || Date.now(),
lastUpdated: Date.now(),
messages: [],
metadata: {
model: options.model || 'gpt-3.5-turbo',
systemPrompt: options.systemPrompt || '',
temperature: options.temperature || 0.7,
maxTokens: options.maxTokens || 2048,
totalTokens: 0,
messageCount: 0,
...options.metadata
},
settings: {
autoTitle: options.autoTitle !== false,
saveHistory: options.saveHistory !== false,
enablePlugins: options.enablePlugins !== false,
...options.settings
}
};

// 添加系统提示消息(如果有)
if (conversation.metadata.systemPrompt) {
const systemMessage = {
id: this.generateMessageId(),
role: 'system',
content: conversation.metadata.systemPrompt,
timestamp: Date.now(),
metadata: { hidden: true }
};
conversation.messages.push(systemMessage);
}

this.conversations.set(conversation.id, conversation);
this.currentConversation = conversation;

// 保存到存储
await this.saveConversation(conversation);

// 清理旧对话(如果超过限制)
await this.cleanupOldConversations();

return conversation;
}

// 加载对话
async loadConversation(conversationId) {
// 先从内存中查找
let conversation = this.conversations.get(conversationId);

if (!conversation) {
// 从存储中加载
conversation = await this.storageManager.loadConversation(conversationId);

if (conversation) {
this.conversations.set(conversationId, conversation);
}
}

if (conversation) {
this.currentConversation = conversation;
}

return conversation;
}

// 保存对话
async saveConversation(conversation) {
conversation.lastUpdated = Date.now();

// 更新内存中的对话
this.conversations.set(conversation.id, conversation);

// 保存到存储
await this.storageManager.saveConversation(conversation);
}

// 删除对话
async deleteConversation(conversationId) {
// 从内存中删除
this.conversations.delete(conversationId);

// 从存储中删除
await this.storageManager.deleteConversation(conversationId);

// 如果删除的是当前对话,清空当前对话
if (this.currentConversation?.id === conversationId) {
this.currentConversation = null;
}
}

// 添加消息到对话
async addMessage(message, conversationId = null) {
const conversation = conversationId
? await this.loadConversation(conversationId)
: this.currentConversation;

if (!conversation) {
throw new Error('没有活动的对话');
}

// 检查消息数量限制
if (conversation.messages.length >= this.maxMessagesPerConversation) {
// 删除最旧的非系统消息
const oldestNonSystemIndex = conversation.messages.findIndex(
msg => msg.role !== 'system'
);
if (oldestNonSystemIndex !== -1) {
conversation.messages.splice(oldestNonSystemIndex, 1);
}
}

// 添加消息
conversation.messages.push(message);
conversation.metadata.messageCount = conversation.messages.length;

// 更新token统计(如果有)
if (message.metadata?.tokens) {
conversation.metadata.totalTokens += message.metadata.tokens;
}

// 自动生成标题(如果是第一条用户消息且启用了自动标题)
if (conversation.settings.autoTitle &&
message.role === 'user' &&
conversation.messages.filter(m => m.role === 'user').length === 1) {
conversation.title = await this.generateConversationTitle(message.content);
}

// 保存对话
await this.saveConversation(conversation);

return message;
}

// 构建对话上下文
async buildContext(options = {}) {
const conversation = this.currentConversation;
if (!conversation) {
throw new Error('没有活动的对话');
}

return await this.contextBuilder.buildContext(conversation, options);
}

// 获取对话列表
getConversationList() {
return Array.from(this.conversations.values())
.sort((a, b) => b.lastUpdated - a.lastUpdated)
.map(conv => ({
id: conv.id,
title: conv.title,
timestamp: conv.timestamp,
lastUpdated: conv.lastUpdated,
messageCount: conv.metadata.messageCount,
totalTokens: conv.metadata.totalTokens
}));
}

// 搜索对话
async searchConversations(query, options = {}) {
const results = [];
const searchTerms = query.toLowerCase().split(' ');

for (const conversation of this.conversations.values()) {
let score = 0;

// 搜索标题
const titleMatch = searchTerms.every(term =>
conversation.title.toLowerCase().includes(term)
);
if (titleMatch) score += 10;

// 搜索消息内容
for (const message of conversation.messages) {
if (message.role === 'system') continue;

const contentMatch = searchTerms.some(term =>
message.content.toLowerCase().includes(term)
);
if (contentMatch) score += 1;
}

if (score > 0) {
results.push({
conversation: {
id: conversation.id,
title: conversation.title,
timestamp: conversation.timestamp,
lastUpdated: conversation.lastUpdated
},
score
});
}
}

// 按分数排序
results.sort((a, b) => b.score - a.score);

// 限制结果数量
const limit = options.limit || 20;
return results.slice(0, limit);
}

// 导出对话数据
async exportConversations(conversationIds = null) {
const conversationsToExport = conversationIds
? conversationIds.map(id => this.conversations.get(id)).filter(Boolean)
: Array.from(this.conversations.values());

return {
exportDate: new Date().toISOString(),
version: '1.0',
conversations: conversationsToExport
};
}

// 导入对话数据
async importConversations(exportData) {
if (!exportData.conversations || !Array.isArray(exportData.conversations)) {
throw new Error('无效的导入数据格式');
}

const importedCount = 0;

for (const conversation of exportData.conversations) {
try {
// 生成新的ID避免冲突
const newConversation = {
...conversation,
id: this.generateConversationId(),
timestamp: Date.now(),
lastUpdated: Date.now()
};

// 为所有消息生成新ID
newConversation.messages = conversation.messages.map(msg => ({
...msg,
id: this.generateMessageId()
}));

await this.saveConversation(newConversation);
importedCount++;

} catch (error) {
console.warn('导入对话失败:', conversation.title, error);
}
}

return { importedCount, totalCount: exportData.conversations.length };
}

// 清理旧对话
async cleanupOldConversations() {
const conversations = Array.from(this.conversations.values())
.sort((a, b) => b.lastUpdated - a.lastUpdated);

if (conversations.length > this.maxConversations) {
const conversationsToDelete = conversations.slice(this.maxConversations);

for (const conversation of conversationsToDelete) {
await this.deleteConversation(conversation.id);
}
}
}

// 生成对话标题
async generateConversationTitle(firstMessage) {
try {
// 使用AI生成简洁的标题
const prompt = `请为以下对话生成一个简洁的标题(不超过20个字符):\n\n${firstMessage}`;

// 这里应该调用AI服务,简化实现
const words = firstMessage.split(' ').slice(0, 5).join(' ');
return words.length > 20 ? words.substring(0, 17) + '...' : words;

} catch (error) {
console.warn('生成对话标题失败:', error);
return firstMessage.substring(0, 20) + (firstMessage.length > 20 ? '...' : '');
}
}

// 辅助方法
generateConversationId() {
return `conv_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

generateMessageId() {
return `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
}

destroy() {
this.conversations.clear();
this.currentConversation = null;
}
}

上下文构建器

// 上下文构建器
class ContextBuilder {
constructor(config = {}) {
this.config = config;
this.maxContextTokens = config.maxContextTokens || 4000;
this.systemPromptTokens = config.systemPromptTokens || 500;
}

// 构建对话上下文
async buildContext(conversation, options = {}) {
const maxTokens = options.maxTokens || this.maxContextTokens;
const includeSystemPrompt = options.includeSystemPrompt !== false;
const includeRecentMessages = options.includeRecentMessages !== false;

const context = {
messages: [],
totalTokens: 0,
truncated: false,
metadata: {
conversationId: conversation.id,
buildTime: Date.now(),
strategy: 'recent_first'
}
};

// 添加系统提示
if (includeSystemPrompt) {
const systemMessage = conversation.messages.find(msg => msg.role === 'system');
if (systemMessage) {
context.messages.push(this.formatMessage(systemMessage));
context.totalTokens += this.estimateTokens(systemMessage.content);
}
}

if (includeRecentMessages) {
// 获取非系统消息
const nonSystemMessages = conversation.messages.filter(msg => msg.role !== 'system');

// 从最新消息开始,逐步添加到上下文中
const recentMessages = [];
let currentTokens = context.totalTokens;

for (let i = nonSystemMessages.length - 1; i >= 0; i--) {
const message = nonSystemMessages[i];
const messageTokens = this.estimateTokens(message.content);

if (currentTokens + messageTokens > maxTokens) {
context.truncated = true;
break;
}

recentMessages.unshift(this.formatMessage(message));
currentTokens += messageTokens;
}

context.messages.push(...recentMessages);
context.totalTokens = currentTokens;
}

return context;
}

// 智能上下文构建(保留重要消息)
async buildSmartContext(conversation, options = {}) {
const maxTokens = options.maxTokens || this.maxContextTokens;
const importanceThreshold = options.importanceThreshold || 0.5;

// 分析消息重要性
const messagesWithImportance = await this.analyzeMessageImportance(conversation.messages);

// 按重要性和时间排序
const sortedMessages = messagesWithImportance
.filter(msg => msg.role !== 'system')
.sort((a, b) => {
// 首先按重要性排序,然后按时间排序
if (Math.abs(a.importance - b.importance) > 0.1) {
return b.importance - a.importance;
}
return b.timestamp - a.timestamp;
});

const context = {
messages: [],
totalTokens: 0,
truncated: false,
metadata: {
conversationId: conversation.id,
buildTime: Date.now(),
strategy: 'importance_based'
}
};

// 添加系统提示
const systemMessage = conversation.messages.find(msg => msg.role === 'system');
if (systemMessage) {
context.messages.push(this.formatMessage(systemMessage));
context.totalTokens += this.estimateTokens(systemMessage.content);
}

// 添加重要消息
for (const message of sortedMessages) {
const messageTokens = this.estimateTokens(message.content);

if (context.totalTokens + messageTokens > maxTokens) {
context.truncated = true;
break;
}

if (message.importance >= importanceThreshold) {
context.messages.push(this.formatMessage(message));
context.totalTokens += messageTokens;
}
}

// 按时间顺序重新排列消息(除了系统消息)
const systemMessages = context.messages.filter(msg => msg.role === 'system');
const otherMessages = context.messages
.filter(msg => msg.role !== 'system')
.sort((a, b) => a.timestamp - b.timestamp);

context.messages = [...systemMessages, ...otherMessages];

return context;
}

// 分析消息重要性
async analyzeMessageImportance(messages) {
return messages.map(message => {
let importance = 0.5; // 基础重要性

// 根据消息长度调整重要性
const length = message.content.length;
if (length > 200) importance += 0.1;
if (length > 500) importance += 0.1;

// 根据消息类型调整重要性
if (message.role === 'system') importance = 1.0;
if (message.role === 'user') importance += 0.1;

// 根据关键词调整重要性
const importantKeywords = ['重要', '关键', '问题', '错误', '帮助', '解决'];
const keywordCount = importantKeywords.filter(keyword =>
message.content.includes(keyword)
).length;
importance += keywordCount * 0.05;

// 根据时间调整重要性(最近的消息更重要)
const age = Date.now() - message.timestamp;
const ageHours = age / (1000 * 60 * 60);
if (ageHours < 1) importance += 0.2;
else if (ageHours < 24) importance += 0.1;

return {
...message,
importance: Math.min(1.0, importance)
};
});
}

// 格式化消息
formatMessage(message) {
return {
role: message.role,
content: message.content,
timestamp: message.timestamp
};
}

// 估算token数量
estimateTokens(text) {
// 简单估算:1 token ≈ 4 字符(英文)或 1.5 字符(中文)
const chineseChars = (text.match(/[\u4e00-\u9fff]/g) || []).length;
const otherChars = text.length - chineseChars;

return Math.ceil(chineseChars / 1.5 + otherChars / 4);
}
}

消息处理系统

消息处理器

// 消息处理器
class MessageProcessor {
constructor(config = {}) {
this.config = config;
this.filters = new Map();
this.transformers = new Map();
this.validators = new Map();

this.setupDefaultProcessors();
}

// 预处理消息
async preprocess(message) {
let processedMessage = { ...message };

// 验证消息
await this.validateMessage(processedMessage);

// 应用过滤器
for (const [name, filter] of this.filters) {
if (filter.enabled) {
processedMessage = await filter.process(processedMessage);
}
}

// 应用转换器
for (const [name, transformer] of this.transformers) {
if (transformer.enabled) {
processedMessage = await transformer.process(processedMessage);
}
}

return processedMessage;
}

// 后处理AI响应
async postprocess(aiResponse) {
let processedResponse = { ...aiResponse };

// 内容清理
processedResponse.content = this.cleanContent(processedResponse.content);

// 格式化处理
processedResponse.content = this.formatContent(processedResponse.content);

// 安全检查
processedResponse = await this.securityCheck(processedResponse);

return processedResponse;
}

// 验证消息
async validateMessage(message) {
// 检查必需字段
if (!message.content || typeof message.content !== 'string') {
throw new Error('消息内容无效');
}

// 检查内容长度
if (message.content.length > this.config.maxMessageLength || 10000) {
throw new Error('消息内容过长');
}

// 检查内容是否为空
if (!message.content.trim()) {
throw new Error('消息内容不能为空');
}

// 应用自定义验证器
for (const [name, validator] of this.validators) {
if (validator.enabled) {
await validator.validate(message);
}
}
}

// 清理内容
cleanContent(content) {
// 移除多余的空白字符
content = content.replace(/\s+/g, ' ').trim();

// 移除潜在的恶意脚本
content = content.replace(/<script[^>]*>[\s\S]*?<\/script>/gi, '');
content = content.replace(/javascript:/gi, '');
content = content.replace(/on\w+\s*=/gi, '');

return content;
}

// 格式化内容
formatContent(content) {
// 处理代码块
content = this.formatCodeBlocks(content);

// 处理链接
content = this.formatLinks(content);

// 处理列表
content = this.formatLists(content);

return content;
}

// 格式化代码块
formatCodeBlocks(content) {
// 处理行内代码
content = content.replace(/`([^`]+)`/g, '<code>$1</code>');

// 处理代码块
content = content.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
const language = lang || 'text';
return `<pre><code class="language-${language}">${this.escapeHtml(code.trim())}</code></pre>`;
});

return content;
}

// 格式化链接
formatLinks(content) {
const urlRegex = /(https?:\/\/[^\s]+)/g;
return content.replace(urlRegex, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
}

// 格式化列表
formatLists(content) {
// 处理无序列表
content = content.replace(/^\s*[-*+]\s+(.+)$/gm, '<li>$1</li>');
content = content.replace(/(<li>.*<\/li>)/s, '<ul>$1</ul>');

// 处理有序列表
content = content.replace(/^\s*\d+\.\s+(.+)$/gm, '<li>$1</li>');

return content;
}

// 安全检查
async securityCheck(response) {
// 检查敏感信息
const sensitivePatterns = [
/\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/, // 信用卡号
/\b\d{3}-\d{2}-\d{4}\b/, // 社会安全号
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b/ // 邮箱地址
];

for (const pattern of sensitivePatterns) {
if (pattern.test(response.content)) {
console.warn('检测到潜在敏感信息');
// 可以选择脱敏或警告用户
}
}

return response;
}

// 转义HTML
escapeHtml(text) {
const div = document.createElement('div');
div.textContent = text;
return div.innerHTML;
}

// 设置默认处理器
setupDefaultProcessors() {
// 垃圾信息过滤器
this.addFilter('spam', {
enabled: true,
process: async (message) => {
const spamKeywords = ['广告', '推广', '赚钱', '点击链接'];
const hasSpam = spamKeywords.some(keyword =>
message.content.toLowerCase().includes(keyword)
);

if (hasSpam) {
console.warn('检测到潜在垃圾信息');
}

return message;
}
});

// 内容长度限制器
this.addTransformer('length_limiter', {
enabled: true,
process: async (message) => {
const maxLength = this.config.maxMessageLength || 10000;
if (message.content.length > maxLength) {
message.content = message.content.substring(0, maxLength) + '...';
message.metadata = message.metadata || {};
message.metadata.truncated = true;
}
return message;
}
});

// 基础验证器
this.addValidator('basic', {
enabled: true,
validate: async (message) => {
if (!message.role || !['user', 'assistant', 'system'].includes(message.role)) {
throw new Error('无效的消息角色');
}
}
});
}

// 添加过滤器
addFilter(name, filter) {
this.filters.set(name, filter);
}

// 添加转换器
addTransformer(name, transformer) {
this.transformers.set(name, transformer);
}

// 添加验证器
addValidator(name, validator) {
this.validators.set(name, validator);
}

// 移除处理器
removeFilter(name) {
this.filters.delete(name);
}

removeTransformer(name) {
this.transformers.delete(name);
}

removeValidator(name) {
this.validators.delete(name);
}

// 启用/禁用处理器
enableFilter(name) {
const filter = this.filters.get(name);
if (filter) filter.enabled = true;
}

disableFilter(name) {
const filter = this.filters.get(name);
if (filter) filter.enabled = false;
}

destroy() {
this.filters.clear();
this.transformers.clear();
this.validators.clear();
}
}

UI管理系统

UI管理器

// UI管理器
class UIManager {
constructor(config = {}) {
this.config = config;
this.theme = config.theme || 'light';
this.language = config.language || 'zh-CN';
this.fontSize = config.fontSize || 'medium';

this.elements = {};
this.eventListeners = new Map();
this.animationQueue = [];
this.isAnimating = false;

this.initializeElements();
this.setupEventListeners();
this.applyTheme();
}

// 初始化UI元素
initializeElements() {
// 创建主容器
this.elements.container = this.createElement('div', {
id: 'chat-container',
className: 'chat-container'
});

// 创建头部
this.elements.header = this.createElement('div', {
className: 'chat-header'
});

// 创建标题
this.elements.title = this.createElement('h1', {
className: 'chat-title',
textContent: '智能助手'
});

// 创建状态指示器
this.elements.status = this.createElement('div', {
className: 'chat-status'
});

// 创建消息容器
this.elements.messagesContainer = this.createElement('div', {
className: 'messages-container'
});

// 创建消息列表
this.elements.messagesList = this.createElement('div', {
className: 'messages-list'
});

// 创建输入区域
this.elements.inputArea = this.createElement('div', {
className: 'input-area'
});

// 创建输入框
this.elements.input = this.createElement('textarea', {
className: 'message-input',
placeholder: '输入您的消息...',
rows: 1
});

// 创建发送按钮
this.elements.sendButton = this.createElement('button', {
className: 'send-button',
textContent: '发送'
});

// 创建打字指示器
this.elements.typingIndicator = this.createElement('div', {
className: 'typing-indicator',
innerHTML: '<span></span><span></span><span></span>'
});

// 组装UI结构
this.assembleUI();
}

// 组装UI结构
assembleUI() {
// 组装头部
this.elements.header.appendChild(this.elements.title);
this.elements.header.appendChild(this.elements.status);

// 组装消息区域
this.elements.messagesContainer.appendChild(this.elements.messagesList);
this.elements.messagesContainer.appendChild(this.elements.typingIndicator);

// 组装输入区域
this.elements.inputArea.appendChild(this.elements.input);
this.elements.inputArea.appendChild(this.elements.sendButton);

// 组装主容器
this.elements.container.appendChild(this.elements.header);
this.elements.container.appendChild(this.elements.messagesContainer);
this.elements.container.appendChild(this.elements.inputArea);

// 添加到页面
document.body.appendChild(this.elements.container);
}

// 显示消息
displayMessage(message, options = {}) {
const messageElement = this.createMessageElement(message);

if (options.animate !== false) {
this.animateMessageIn(messageElement);
}

this.elements.messagesList.appendChild(messageElement);
this.scrollToBottom();

return messageElement;
}

// 带打字效果显示消息
async displayMessageWithTyping(message, options = {}) {
const messageElement = this.createMessageElement({
...message,
content: ''
});

this.elements.messagesList.appendChild(messageElement);
this.scrollToBottom();

// 打字效果
await this.typeMessage(messageElement, message.content, options.typingSpeed);

return messageElement;
}

// 创建消息元素
createMessageElement(message) {
const messageDiv = this.createElement('div', {
className: `message message-${message.role}`,
'data-message-id': message.id
});

// 创建消息头部
const messageHeader = this.createElement('div', {
className: 'message-header'
});

// 创建角色标签
const roleLabel = this.createElement('span', {
className: 'message-role',
textContent: this.getRoleLabel(message.role)
});

// 创建时间戳
const timestamp = this.createElement('span', {
className: 'message-timestamp',
textContent: this.formatTimestamp(message.timestamp)
});

messageHeader.appendChild(roleLabel);
messageHeader.appendChild(timestamp);

// 创建消息内容
const messageContent = this.createElement('div', {
className: 'message-content',
innerHTML: this.formatMessageContent(message.content)
});

// 创建消息操作
const messageActions = this.createMessageActions(message);

messageDiv.appendChild(messageHeader);
messageDiv.appendChild(messageContent);
messageDiv.appendChild(messageActions);

return messageDiv;
}

// 创建消息操作按钮
createMessageActions(message) {
const actionsDiv = this.createElement('div', {
className: 'message-actions'
});

// 复制按钮
const copyButton = this.createElement('button', {
className: 'action-button copy-button',
title: '复制消息',
innerHTML: '📋'
});

copyButton.addEventListener('click', () => {
this.copyMessage(message);
});

// 重新生成按钮(仅对AI消息)
if (message.role === 'assistant') {
const regenerateButton = this.createElement('button', {
className: 'action-button regenerate-button',
title: '重新生成',
innerHTML: '🔄'
});

regenerateButton.addEventListener('click', () => {
this.emit('regenerateMessage', message);
});

actionsDiv.appendChild(regenerateButton);
}

actionsDiv.appendChild(copyButton);

return actionsDiv;
}

// 打字效果
async typeMessage(messageElement, content, speed = null) {
const typingSpeed = speed || this.config.typingSpeed || 50;
const contentElement = messageElement.querySelector('.message-content');

let currentIndex = 0;
const formattedContent = this.formatMessageContent(content);

return new Promise((resolve) => {
const typeInterval = setInterval(() => {
if (currentIndex < content.length) {
const partialContent = content.substring(0, currentIndex + 1);
contentElement.innerHTML = this.formatMessageContent(partialContent);
currentIndex++;
this.scrollToBottom();
} else {
clearInterval(typeInterval);
contentElement.innerHTML = formattedContent;
resolve();
}
}, typingSpeed);
});
}

// 设置打字指示器
setTypingIndicator(isTyping) {
if (isTyping) {
this.elements.typingIndicator.style.display = 'flex';
this.scrollToBottom();
} else {
this.elements.typingIndicator.style.display = 'none';
}
}

// 清空聊天
clearChat() {
this.elements.messagesList.innerHTML = '';
}

// 更新对话标题
updateConversationTitle(title) {
this.elements.title.textContent = title;
}

// 设置连接状态
setConnectionStatus(isConnected) {
const statusText = isConnected ? '已连接' : '连接断开';
const statusClass = isConnected ? 'connected' : 'disconnected';

this.elements.status.textContent = statusText;
this.elements.status.className = `chat-status ${statusClass}`;
}

// 显示错误信息
showError(message) {
const errorElement = this.createElement('div', {
className: 'error-message',
textContent: message
});

this.elements.messagesContainer.appendChild(errorElement);

// 3秒后自动移除
setTimeout(() => {
if (errorElement.parentNode) {
errorElement.parentNode.removeChild(errorElement);
}
}, 3000);
}

// 设置主题
setTheme(theme) {
this.theme = theme;
this.elements.container.setAttribute('data-theme', theme);
this.applyTheme();
}

// 应用主题
applyTheme() {
const themes = {
light: {
'--bg-color': '#ffffff',
'--text-color': '#333333',
'--border-color': '#e0e0e0',
'--user-bg': '#007bff',
'--assistant-bg': '#f8f9fa'
},
dark: {
'--bg-color': '#1a1a1a',
'--text-color': '#ffffff',
'--border-color': '#333333',
'--user-bg': '#0056b3',
'--assistant-bg': '#2d2d2d'
}
};

const themeVars = themes[this.theme] || themes.light;

for (const [property, value] of Object.entries(themeVars)) {
document.documentElement.style.setProperty(property, value);
}
}

// 设置语言
setLanguage(language) {
this.language = language;
this.updateUITexts();
}

// 更新UI文本
updateUITexts() {
const texts = {
'zh-CN': {
placeholder: '输入您的消息...',
send: '发送',
connected: '已连接',
disconnected: '连接断开'
},
'en-US': {
placeholder: 'Type your message...',
send: 'Send',
connected: 'Connected',
disconnected: 'Disconnected'
}
};

const currentTexts = texts[this.language] || texts['zh-CN'];

this.elements.input.placeholder = currentTexts.placeholder;
this.elements.sendButton.textContent = currentTexts.send;
}

// 设置字体大小
setFontSize(size) {
this.fontSize = size;
this.elements.container.setAttribute('data-font-size', size);
}

// 辅助方法
createElement(tag, attributes = {}) {
const element = document.createElement(tag);

for (const [key, value] of Object.entries(attributes)) {
if (key === 'textContent' || key === 'innerHTML') {
element[key] = value;
} else {
element.setAttribute(key, value);
}
}

return element;
}

getRoleLabel(role) {
const labels = {
user: '用户',
assistant: 'AI助手',
system: '系统'
};
return labels[role] || role;
}

formatTimestamp(timestamp) {
const date = new Date(timestamp);
return date.toLocaleTimeString();
}

formatMessageContent(content) {
// 这里可以集成markdown解析器或其他格式化工具
return content.replace(/\n/g, '<br>');
}

copyMessage(message) {
navigator.clipboard.writeText(message.content).then(() => {
this.showNotification('消息已复制到剪贴板');
}).catch(err => {
console.error('复制失败:', err);
});
}

showNotification(message) {
const notification = this.createElement('div', {
className: 'notification',
textContent: message
});

document.body.appendChild(notification);

setTimeout(() => {
notification.classList.add('show');
}, 10);

setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 300);
}, 2000);
}

scrollToBottom() {
this.elements.messagesContainer.scrollTop = this.elements.messagesContainer.scrollHeight;
}

animateMessageIn(messageElement) {
messageElement.style.opacity = '0';
messageElement.style.transform = 'translateY(20px)';

setTimeout(() => {
messageElement.style.transition = 'opacity 0.3s ease, transform 0.3s ease';
messageElement.style.opacity = '1';
messageElement.style.transform = 'translateY(0)';
}, 10);
}

setupEventListeners() {
// 发送按钮点击事件
this.elements.sendButton.addEventListener('click', () => {
this.handleSendMessage();
});

// 输入框回车事件
this.elements.input.addEventListener('keydown', (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault();
this.handleSendMessage();
}
});

// 输入框自动调整高度
this.elements.input.addEventListener('input', () => {
this.autoResizeTextarea();
});
}

handleSendMessage() {
const content = this.elements.input.value.trim();
if (content) {
this.emit('sendMessage', content);
this.elements.input.value = '';
this.autoResizeTextarea();
}
}

autoResizeTextarea() {
const textarea = this.elements.input;
textarea.style.height = 'auto';
textarea.style.height = Math.min(textarea.scrollHeight, 120) + 'px';
}

// 事件系统
on(event, listener) {
if (!this.eventListeners.has(event)) {
this.eventListeners.set(event, new Set());
}
this.eventListeners.get(event).add(listener);
}

emit(event, data) {
const listeners = this.eventListeners.get(event);
if (listeners) {
for (const listener of listeners) {
try {
listener(data);
} catch (error) {
console.error('UI事件监听器执行错误:', error);
}
}
}
}

async initialize() {
// 加载CSS样式
await this.loadStyles();

// 初始化完成
console.log('UI管理器初始化完成');
}

async loadStyles() {
const styles = `
.chat-container {
display: flex;
flex-direction: column;
height: 100vh;
max-width: 800px;
margin: 0 auto;
border: 1px solid var(--border-color);
border-radius: 8px;
overflow: hidden;
background-color: var(--bg-color);
color: var(--text-color);
}

.chat-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid var(--border-color);
background-color: var(--bg-color);
}

.messages-container {
flex: 1;
overflow-y: auto;
padding: 1rem;
}

.message {
margin-bottom: 1rem;
padding: 0.75rem;
border-radius: 8px;
max-width: 80%;
}

.message-user {
background-color: var(--user-bg);
color: white;
margin-left: auto;
}

.message-assistant {
background-color: var(--assistant-bg);
}

.input-area {
display: flex;
padding: 1rem;
border-top: 1px solid var(--border-color);
gap: 0.5rem;
}

.message-input {
flex: 1;
padding: 0.75rem;
border: 1px solid var(--border-color);
border-radius: 4px;
resize: none;
font-family: inherit;
}

.send-button {
padding: 0.75rem 1.5rem;
background-color: var(--user-bg);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}

.typing-indicator {
display: none;
align-items: center;
gap: 4px;
padding: 0.5rem;
}

.typing-indicator span {
width: 8px;
height: 8px;
border-radius: 50%;
background-color: #999;
animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) {
animation-delay: 0.2s;
}

.typing-indicator span:nth-child(3) {
animation-delay: 0.4s;
}

@keyframes typing {
0%, 60%, 100% {
transform: translateY(0);
}
30% {
transform: translateY(-10px);
}
}
`;

const styleElement = document.createElement('style');
styleElement.textContent = styles;
document.head.appendChild(styleElement);
}

destroy() {
// 移除事件监听器
this.eventListeners.clear();

// 移除DOM元素
if (this.elements.container && this.elements.container.parentNode) {
this.elements.container.parentNode.removeChild(this.elements.container);
}

console.log('UI管理器已销毁');
}
}

存储管理系统

存储管理器

// 存储管理器
class StorageManager {
constructor(config = {}) {
this.config = config;
this.storageType = config.storageType || 'localStorage';
this.encryptionKey = config.encryptionKey;
this.compressionEnabled = config.compressionEnabled !== false;

this.storage = this.initializeStorage();
this.cache = new Map();
this.syncQueue = [];
this.isSyncing = false;
}

// 初始化存储
initializeStorage() {
switch (this.storageType) {
case 'localStorage':
return new LocalStorageAdapter();
case 'indexedDB':
return new IndexedDBAdapter(this.config);
case 'memory':
return new MemoryStorageAdapter();
default:
return new LocalStorageAdapter();
}
}

// 保存对话
async saveConversation(conversation) {
try {
const key = `conversation_${conversation.id}`;
const data = await this.prepareDataForStorage(conversation);

await this.storage.setItem(key, data);

// 更新缓存
this.cache.set(key, conversation);

// 更新对话索引
await this.updateConversationIndex(conversation);

console.log('对话保存成功:', conversation.id);

} catch (error) {
console.error('保存对话失败:', error);
throw error;
}
}

// 加载对话
async loadConversation(conversationId) {
try {
const key = `conversation_${conversationId}`;

// 先从缓存中查找
if (this.cache.has(key)) {
return this.cache.get(key);
}

// 从存储中加载
const data = await this.storage.getItem(key);

if (!data) {
return null;
}

const conversation = await this.parseDataFromStorage(data);

// 更新缓存
this.cache.set(key, conversation);

return conversation;

} catch (error) {
console.error('加载对话失败:', error);
throw error;
}
}

// 删除对话
async deleteConversation(conversationId) {
try {
const key = `conversation_${conversationId}`;

// 从存储中删除
await this.storage.removeItem(key);

// 从缓存中删除
this.cache.delete(key);

// 更新对话索引
await this.removeFromConversationIndex(conversationId);

console.log('对话删除成功:', conversationId);

} catch (error) {
console.error('删除对话失败:', error);
throw error;
}
}

// 获取对话列表
async getConversationList() {
try {
const index = await this.storage.getItem('conversation_index') || [];
return index.sort((a, b) => b.lastUpdated - a.lastUpdated);
} catch (error) {
console.error('获取对话列表失败:', error);
return [];
}
}

// 保存用户偏好
async saveUserPreferences(preferences) {
try {
const data = await this.prepareDataForStorage(preferences);
await this.storage.setItem('user_preferences', data);

console.log('用户偏好保存成功');

} catch (error) {
console.error('保存用户偏好失败:', error);
throw error;
}
}

// 加载用户偏好
async loadUserPreferences() {
try {
const data = await this.storage.getItem('user_preferences');

if (!data) {
return {};
}

return await this.parseDataFromStorage(data);

} catch (error) {
console.error('加载用户偏好失败:', error);
return {};
}
}

// 保存最后对话ID
async saveLastConversationId(conversationId) {
try {
await this.storage.setItem('last_conversation_id', conversationId);
} catch (error) {
console.error('保存最后对话ID失败:', error);
}
}

// 获取最后对话ID
async getLastConversationId() {
try {
return await this.storage.getItem('last_conversation_id');
} catch (error) {
console.error('获取最后对话ID失败:', error);
return null;
}
}

// 清空所有数据
async clearAllData() {
try {
await this.storage.clear();
this.cache.clear();

console.log('所有数据已清空');

} catch (error) {
console.error('清空数据失败:', error);
throw error;
}
}

// 导出数据
async exportData() {
try {
const conversations = [];
const conversationList = await this.getConversationList();

for (const item of conversationList) {
const conversation = await this.loadConversation(item.id);
if (conversation) {
conversations.push(conversation);
}
}

const preferences = await this.loadUserPreferences();

return {
version: '1.0',
exportDate: new Date().toISOString(),
conversations,
preferences
};

} catch (error) {
console.error('导出数据失败:', error);
throw error;
}
}

// 导入数据
async importData(exportData) {
try {
if (!exportData.conversations || !Array.isArray(exportData.conversations)) {
throw new Error('无效的导入数据格式');
}

let importedCount = 0;

// 导入对话
for (const conversation of exportData.conversations) {
try {
await this.saveConversation(conversation);
importedCount++;
} catch (error) {
console.warn('导入对话失败:', conversation.title, error);
}
}

// 导入用户偏好
if (exportData.preferences) {
await this.saveUserPreferences(exportData.preferences);
}

console.log(`数据导入完成,成功导入 ${importedCount} 个对话`);

return { importedCount, totalCount: exportData.conversations.length };

} catch (error) {
console.error('导入数据失败:', error);
throw error;
}
}

// 获取存储使用情况
async getStorageUsage() {
try {
const usage = await this.storage.getUsage();

return {
used: usage.used || 0,
total: usage.total || 0,
percentage: usage.total ? (usage.used / usage.total * 100).toFixed(2) : 0,
conversationCount: (await this.getConversationList()).length
};

} catch (error) {
console.error('获取存储使用情况失败:', error);
return { used: 0, total: 0, percentage: 0, conversationCount: 0 };
}
}

// 清理过期数据
async cleanupExpiredData(maxAge = 30 * 24 * 60 * 60 * 1000) { // 默认30天
try {
const conversationList = await this.getConversationList();
const now = Date.now();
let cleanedCount = 0;

for (const item of conversationList) {
if (now - item.lastUpdated > maxAge) {
await this.deleteConversation(item.id);
cleanedCount++;
}
}

console.log(`清理完成,删除了 ${cleanedCount} 个过期对话`);

return cleanedCount;

} catch (error) {
console.error('清理过期数据失败:', error);
throw error;
}
}

// 更新对话索引
async updateConversationIndex(conversation) {
try {
let index = await this.storage.getItem('conversation_index') || [];

// 查找现有项目
const existingIndex = index.findIndex(item => item.id === conversation.id);

const indexItem = {
id: conversation.id,
title: conversation.title,
timestamp: conversation.timestamp,
lastUpdated: conversation.lastUpdated,
messageCount: conversation.metadata.messageCount,
totalTokens: conversation.metadata.totalTokens
};

if (existingIndex !== -1) {
index[existingIndex] = indexItem;
} else {
index.push(indexItem);
}

// 限制索引大小
if (index.length > this.config.maxConversations || 100) {
index = index.sort((a, b) => b.lastUpdated - a.lastUpdated)
.slice(0, this.config.maxConversations || 100);
}

await this.storage.setItem('conversation_index', index);

} catch (error) {
console.error('更新对话索引失败:', error);
}
}

// 从对话索引中移除
async removeFromConversationIndex(conversationId) {
try {
let index = await this.storage.getItem('conversation_index') || [];
index = index.filter(item => item.id !== conversationId);
await this.storage.setItem('conversation_index', index);
} catch (error) {
console.error('从对话索引中移除失败:', error);
}
}

// 准备数据用于存储
async prepareDataForStorage(data) {
let processedData = JSON.stringify(data);

// 压缩数据
if (this.compressionEnabled) {
processedData = await this.compressData(processedData);
}

// 加密数据
if (this.encryptionKey) {
processedData = await this.encryptData(processedData);
}

return processedData;
}

// 从存储中解析数据
async parseDataFromStorage(data) {
let processedData = data;

// 解密数据
if (this.encryptionKey) {
processedData = await this.decryptData(processedData);
}

// 解压缩数据
if (this.compressionEnabled) {
processedData = await this.decompressData(processedData);
}

return JSON.parse(processedData);
}

// 压缩数据
async compressData(data) {
// 简单的压缩实现,实际项目中可以使用更高效的压缩算法
return btoa(data);
}

// 解压缩数据
async decompressData(data) {
return atob(data);
}

// 加密数据
async encryptData(data) {
// 简单的加密实现,实际项目中应使用更安全的加密算法
return btoa(data);
}

// 解密数据
async decryptData(data) {
return atob(data);
}

destroy() {
this.cache.clear();
this.syncQueue = [];
console.log('存储管理器已销毁');
}
}

// LocalStorage适配器
class LocalStorageAdapter {
async getItem(key) {
try {
const item = localStorage.getItem(key);
return item ? JSON.parse(item) : null;
} catch (error) {
console.error('LocalStorage getItem 失败:', error);
return null;
}
}

async setItem(key, value) {
try {
localStorage.setItem(key, JSON.stringify(value));
} catch (error) {
console.error('LocalStorage setItem 失败:', error);
throw error;
}
}

async removeItem(key) {
try {
localStorage.removeItem(key);
} catch (error) {
console.error('LocalStorage removeItem 失败:', error);
throw error;
}
}

async clear() {
try {
localStorage.clear();
} catch (error) {
console.error('LocalStorage clear 失败:', error);
throw error;
}
}

async getUsage() {
try {
let used = 0;
for (let key in localStorage) {
if (localStorage.hasOwnProperty(key)) {
used += localStorage[key].length + key.length;
}
}

return {
used: used,
total: 5 * 1024 * 1024 // 5MB 估算
};
} catch (error) {
return { used: 0, total: 0 };
}
}
}

// IndexedDB适配器
class IndexedDBAdapter {
constructor(config = {}) {
this.dbName = config.dbName || 'ChatAppDB';
this.version = config.dbVersion || 1;
this.db = null;
}

async init() {
if (this.db) return this.db;

return new Promise((resolve, reject) => {
const request = indexedDB.open(this.dbName, this.version);

request.onerror = () => reject(request.error);
request.onsuccess = () => {
this.db = request.result;
resolve(this.db);
};

request.onupgradeneeded = (event) => {
const db = event.target.result;

if (!db.objectStoreNames.contains('data')) {
db.createObjectStore('data', { keyPath: 'key' });
}
};
});
}

async getItem(key) {
await this.init();

return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['data'], 'readonly');
const store = transaction.objectStore('data');
const request = store.get(key);

request.onerror = () => reject(request.error);
request.onsuccess = () => {
const result = request.result;
resolve(result ? result.value : null);
};
});
}

async setItem(key, value) {
await this.init();

return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['data'], 'readwrite');
const store = transaction.objectStore('data');
const request = store.put({ key, value });

request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}

async removeItem(key) {
await this.init();

return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['data'], 'readwrite');
const store = transaction.objectStore('data');
const request = store.delete(key);

request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}

async clear() {
await this.init();

return new Promise((resolve, reject) => {
const transaction = this.db.transaction(['data'], 'readwrite');
const store = transaction.objectStore('data');
const request = store.clear();

request.onerror = () => reject(request.error);
request.onsuccess = () => resolve();
});
}

async getUsage() {
try {
const estimate = await navigator.storage.estimate();
return {
used: estimate.usage || 0,
total: estimate.quota || 0
};
} catch (error) {
return { used: 0, total: 0 };
}
}
}

// 内存存储适配器
class MemoryStorageAdapter {
constructor() {
this.data = new Map();
}

async getItem(key) {
return this.data.get(key) || null;
}

async setItem(key, value) {
this.data.set(key, value);
}

async removeItem(key) {
this.data.delete(key);
}

async clear() {
this.data.clear();
}

async getUsage() {
let used = 0;
for (const [key, value] of this.data) {
used += JSON.stringify(key).length + JSON.stringify(value).length;
}

return {
used: used,
total: Infinity
};
}
}