const fs = require('fs');
const path = require('path');
const EventEmitter = require('events');
class ConversationEngine extends EventEmitter {
constructor(config = {}) {
super();
this.config = {
maxContextLength: 10,
sessionTimeout: 30 * 60 * 1000,
enablePersonalization: true,
debugMode: false,
...config
};
this.sessions = new Map();
this.intentClassifier = new IntentClassifier();
this.entityExtractor = new EntityExtractor();
this.dialogueManager = new DialogueManager();
this.responseGenerator = new ResponseGenerator();
this.knowledgeBase = new KnowledgeBase();
this.initializeEngine();
}
initializeEngine() {
console.log('🚀 初始化对话引擎...');
this.loadModels();
setInterval(() => this.cleanupSessions(), 5 * 60 * 1000);
console.log('✅ 对话引擎初始化完成');
}
async processMessage(userId, message, sessionId = null) {
try {
const startTime = Date.now();
const session = this.getOrCreateSession(userId, sessionId);
console.log(`\n🔄 处理用户消息: ${userId}`);
console.log(`消息内容: ${message}`);
const preprocessedInput = await this.preprocessInput(message, session);
const nluResult = await this.performNLU(preprocessedInput, session);
const dialogueState = await this.manageDialogue(nluResult, session);
const response = await this.generateResponse(dialogueState, session);
this.updateSession(session, {
userMessage: message,
nluResult,
dialogueState,
response,
timestamp: Date.now()
});
const processingTime = Date.now() - startTime;
this.logConversation(userId, session, processingTime);
this.emit('messageProcessed', {
userId,
sessionId: session.id,
message,
response,
processingTime
});
return {
success: true,
response: response.text,
sessionId: session.id,
metadata: {
intent: nluResult.intent,
confidence: nluResult.confidence,
entities: nluResult.entities,
processingTime
}
};
} catch (error) {
console.error('❌ 消息处理失败:', error);
this.emit('error', {
userId,
message,
error: error.message
});
return {
success: false,
response: '抱歉,我现在无法理解您的消息,请稍后再试。',
error: error.message
};
}
}
getOrCreateSession(userId, sessionId = null) {
const key = sessionId || `${userId}_${Date.now()}`;
if (!this.sessions.has(key)) {
const session = {
id: key,
userId,
createdAt: Date.now(),
lastActiveAt: Date.now(),
context: [],
state: 'active',
userProfile: this.getUserProfile(userId),
dialogueState: {
currentIntent: null,
slots: {},
taskStack: [],
conversationHistory: []
},
metadata: {
messageCount: 0,
averageResponseTime: 0,
satisfactionScore: null
}
};
this.sessions.set(key, session);
console.log(`📝 创建新会话: ${key}`);
}
const session = this.sessions.get(key);
session.lastActiveAt = Date.now();
return session;
}
async preprocessInput(message, session) {
console.log('🔧 预处理用户输入...');
let processed = message.trim().toLowerCase();
processed = await this.correctSpelling(processed);
processed = this.replaceSynonyms(processed);
if (session.context.length > 0) {
processed = this.resolveReferences(processed, session.context);
}
return {
original: message,
processed,
preprocessing: {
cleaned: true,
spellCorrected: processed !== message.trim().toLowerCase(),
synonymsReplaced: true,
referencesResolved: session.context.length > 0
}
};
}
async performNLU(input, session) {
console.log('🧠 执行自然语言理解...');
const intentResult = await this.intentClassifier.classify(
input.processed,
session.context
);
const entities = await this.entityExtractor.extract(
input.processed,
intentResult.intent
);
const confidence = this.calculateConfidence(intentResult, entities);
return {
intent: intentResult.intent,
confidence,
entities,
alternatives: intentResult.alternatives,
processingDetails: {
intentClassification: intentResult,
entityExtraction: entities
}
};
}
async manageDialogue(nluResult, session) {
console.log('💬 管理对话状态...');
const currentState = session.dialogueState;
const newState = await this.dialogueManager.updateState(
currentState,
nluResult,
session.context
);
const action = await this.dialogueManager.decideAction(
newState,
session.userProfile
);
return {
...newState,
nextAction: action,
stateTransition: {
from: currentState.currentIntent,
to: newState.currentIntent,
trigger: nluResult.intent
}
};
}
async generateResponse(dialogueState, session) {
console.log('📝 生成回复...');
const responseContext = {
dialogueState,
userProfile: session.userProfile,
conversationHistory: session.context,
currentTime: new Date()
};
let response;
switch (dialogueState.nextAction.type) {
case 'answer':
response = await this.generateAnswer(dialogueState, responseContext);
break;
case 'clarify':
response = await this.generateClarification(dialogueState, responseContext);
break;
case 'collect_info':
response = await this.generateInfoRequest(dialogueState, responseContext);
break;
case 'recommend':
response = await this.generateRecommendation(dialogueState, responseContext);
break;
default:
response = await this.generateGenericResponse(dialogueState, responseContext);
}
if (this.config.enablePersonalization) {
response = await this.personalizeResponse(response, session.userProfile);
}
return response;
}
async generateAnswer(dialogueState, context) {
const query = dialogueState.slots.query || dialogueState.currentIntent;
const knowledgeResult = await this.knowledgeBase.search(query, {
limit: 3,
threshold: 0.7
});
if (knowledgeResult.results.length > 0) {
const bestAnswer = knowledgeResult.results[0];
return {
text: bestAnswer.content,
type: 'answer',
confidence: bestAnswer.score,
sources: knowledgeResult.results.map(r => r.source),
metadata: {
knowledgeBase: true,
retrievalScore: bestAnswer.score
}
};
}
return await this.responseGenerator.generate({
intent: dialogueState.currentIntent,
context: context.conversationHistory,
userProfile: context.userProfile
});
}
async generateClarification(dialogueState, context) {
const ambiguousEntities = dialogueState.slots.ambiguous || [];
if (ambiguousEntities.length > 0) {
const options = ambiguousEntities.map((entity, index) =>
`${index + 1}. ${entity.value} (${entity.type})`
).join('\n');
return {
text: `我需要确认一下,您指的是:\n${options}\n请选择对应的数字。`,
type: 'clarification',
options: ambiguousEntities,
expectsChoice: true
};
}
return {
text: '抱歉,我没有完全理解您的意思,能否请您再详细说明一下?',
type: 'clarification',
expectsElaboration: true
};
}
updateSession(session, update) {
session.context.push({
userMessage: update.userMessage,
systemResponse: update.response.text,
intent: update.nluResult.intent,
entities: update.nluResult.entities,
timestamp: update.timestamp
});
if (session.context.length > this.config.maxContextLength) {
session.context = session.context.slice(-this.config.maxContextLength);
}
session.dialogueState = update.dialogueState;
session.metadata.messageCount++;
session.metadata.averageResponseTime =
(session.metadata.averageResponseTime * (session.metadata.messageCount - 1) +
(update.timestamp - session.lastActiveAt)) / session.metadata.messageCount;
}
cleanupSessions() {
const now = Date.now();
let cleanedCount = 0;
for (const [sessionId, session] of this.sessions.entries()) {
if (now - session.lastActiveAt > this.config.sessionTimeout) {
this.sessions.delete(sessionId);
cleanedCount++;
}
}
if (cleanedCount > 0) {
console.log(`🧹 清理了 ${cleanedCount} 个过期会话`);
}
}
getSessionStats() {
const activeSessions = this.sessions.size;
const totalMessages = Array.from(this.sessions.values())
.reduce((sum, session) => sum + session.metadata.messageCount, 0);
return {
activeSessions,
totalMessages,
averageMessagesPerSession: activeSessions > 0 ? totalMessages / activeSessions : 0,
memoryUsage: process.memoryUsage()
};
}
exportSessions(format = 'json') {
const data = {
exportTime: new Date().toISOString(),
sessionCount: this.sessions.size,
sessions: Array.from(this.sessions.entries()).map(([id, session]) => ({
id,
...session,
context: session.context.slice(-5)
}))
};
const filename = `conversation_export_${Date.now()}.${format}`;
if (format === 'json') {
fs.writeFileSync(filename, JSON.stringify(data, null, 2));
}
console.log(`📊 会话数据已导出到: ${filename}`);
return filename;
}
}
class IntentClassifier {
constructor() {
this.intents = new Map();
this.loadIntentModels();
}
loadIntentModels() {
const commonIntents = {
greeting: {
patterns: ['你好', 'hello', '嗨', '早上好', '下午好'],
confidence: 0.9
},
question: {
patterns: ['什么是', '如何', '为什么', '怎么样', '?'],
confidence: 0.8
},
request: {
patterns: ['请', '帮我', '我想要', '能否', '可以'],
confidence: 0.85
},
goodbye: {
patterns: ['再见', 'bye', '拜拜', '结束'],
confidence: 0.9
}
};
Object.entries(commonIntents).forEach(([intent, config]) => {
this.intents.set(intent, config);
});
}
async classify(text, context = []) {
const scores = new Map();
for (const [intent, config] of this.intents.entries()) {
let score = 0;
for (const pattern of config.patterns) {
if (text.includes(pattern)) {
score = Math.max(score, config.confidence);
}
}
if (score > 0) {
scores.set(intent, score);
}
}
if (context.length > 0) {
const lastIntent = context[context.length - 1].intent;
if (scores.has(lastIntent)) {
scores.set(lastIntent, scores.get(lastIntent) * 1.1);
}
}
let bestIntent = 'unknown';
let bestScore = 0;
for (const [intent, score] of scores.entries()) {
if (score > bestScore) {
bestIntent = intent;
bestScore = score;
}
}
return {
intent: bestIntent,
confidence: bestScore,
alternatives: Array.from(scores.entries())
.sort((a, b) => b[1] - a[1])
.slice(0, 3)
};
}
}
class EntityExtractor {
constructor() {
this.entityTypes = {
person: /([A-Z][a-z]+\s[A-Z][a-z]+)|([\u4e00-\u9fa5]{2,4})/g,
date: /(\d{4}[-/]\d{1,2}[-/]\d{1,2})|(今天|明天|昨天)/g,
number: /\d+/g,
email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
phone: /(\d{3}[-.]?\d{3}[-.]?\d{4})|(\d{11})/g
};
}
async extract(text, intent = null) {
const entities = [];
for (const [type, pattern] of Object.entries(this.entityTypes)) {
const matches = text.match(pattern);
if (matches) {
matches.forEach(match => {
entities.push({
type,
value: match,
confidence: 0.8,
start: text.indexOf(match),
end: text.indexOf(match) + match.length
});
});
}
}
return entities;
}
}
class DialogueManager {
constructor() {
this.stateTransitions = new Map();
this.initializeTransitions();
}
initializeTransitions() {
this.stateTransitions.set('greeting', {
next: ['question', 'request', 'goodbye'],
action: 'respond_greeting'
});
this.stateTransitions.set('question', {
next: ['question', 'request', 'goodbye'],
action: 'answer_question'
});
this.stateTransitions.set('request', {
next: ['clarify', 'execute', 'question'],
action: 'process_request'
});
}
async updateState(currentState, nluResult, context) {
const newState = { ...currentState };
newState.currentIntent = nluResult.intent;
nluResult.entities.forEach(entity => {
newState.slots[entity.type] = entity.value;
});
newState.conversationHistory.push({
intent: nluResult.intent,
entities: nluResult.entities,
timestamp: Date.now()
});
return newState;
}
async decideAction(state, userProfile) {
const intent = state.currentIntent;
const transition = this.stateTransitions.get(intent);
if (!transition) {
return { type: 'unknown', confidence: 0.5 };
}
switch (intent) {
case 'greeting':
return { type: 'respond', confidence: 0.9 };
case 'question':
return { type: 'answer', confidence: 0.8 };
case 'request':
return this.analyzeRequest(state, userProfile);
default:
return { type: 'clarify', confidence: 0.6 };
}
}
analyzeRequest(state, userProfile) {
const requiredSlots = this.getRequiredSlots(state.currentIntent);
const missingSlots = requiredSlots.filter(slot => !state.slots[slot]);
if (missingSlots.length > 0) {
return {
type: 'collect_info',
confidence: 0.8,
missingSlots
};
}
return { type: 'execute', confidence: 0.9 };
}
getRequiredSlots(intent) {
const slotRequirements = {
book_appointment: ['date', 'time', 'service'],
search_product: ['category', 'price_range'],
make_reservation: ['date', 'time', 'party_size']
};
return slotRequirements[intent] || [];
}
}
class ResponseGenerator {
constructor() {
this.templates = new Map();
this.loadResponseTemplates();
}
loadResponseTemplates() {
const templates = {
greeting: [
'您好!我是您的AI助手,有什么可以帮助您的吗?',
'你好!很高兴为您服务,请问有什么需要帮助的?',
'欢迎!我可以为您提供各种帮助和信息。'
],
goodbye: [
'再见!祝您有美好的一天!',
'感谢您的使用,期待下次为您服务!',
'拜拜!有需要随时找我哦!'
],
unknown: [
'抱歉,我没有完全理解您的意思,能否请您换个方式表达?',
'我需要更多信息来帮助您,请详细说明您的需求。',
'这个问题有点复杂,您能提供更多背景信息吗?'
]
};
Object.entries(templates).forEach(([intent, responses]) => {
this.templates.set(intent, responses);
});
}
async generate(context) {
const { intent, userProfile } = context;
const templates = this.templates.get(intent) || this.templates.get('unknown');
const template = templates[Math.floor(Math.random() * templates.length)];
return {
text: template,
type: 'template',
confidence: 0.7,
metadata: {
template: true,
intent
}
};
}
}
class KnowledgeBase {
constructor() {
this.knowledge = new Map();
this.loadKnowledge();
}
loadKnowledge() {
const basicKnowledge = {
'AI是什么': {
content: '人工智能(AI)是计算机科学的一个分支,致力于创建能够执行通常需要人类智能的任务的系统。',
source: 'knowledge_base',
score: 0.9
},
'Node.js是什么': {
content: 'Node.js是一个基于Chrome V8引擎的JavaScript运行时环境,用于构建快速、可扩展的网络应用程序。',
source: 'knowledge_base',
score: 0.9
}
};
Object.entries(basicKnowledge).forEach(([key, value]) => {
this.knowledge.set(key, value);
});
}
async search(query, options = {}) {
const { limit = 5, threshold = 0.5 } = options;
const results = [];
for (const [key, value] of this.knowledge.entries()) {
if (key.includes(query) || value.content.includes(query)) {
results.push({
key,
...value,
relevanceScore: this.calculateRelevance(query, key, value.content)
});
}
}
const filteredResults = results
.filter(result => result.relevanceScore >= threshold)
.sort((a, b) => b.relevanceScore - a.relevanceScore)
.slice(0, limit);
return {
query,
results: filteredResults,
totalFound: results.length
};
}
calculateRelevance(query, title, content) {
let score = 0;
const queryWords = query.toLowerCase().split(' ');
queryWords.forEach(word => {
if (title.toLowerCase().includes(word)) score += 0.5;
if (content.toLowerCase().includes(word)) score += 0.3;
});
return Math.min(score, 1.0);
}
}
const conversationEngine = new ConversationEngine({
maxContextLength: 10,
enablePersonalization: true,
debugMode: true
});
async function simulateConversation() {
console.log('🎭 开始对话模拟\n');
const userId = 'user_001';
const messages = [
'你好',
'什么是AI?',
'Node.js是什么?',
'谢谢,再见'
];
for (const message of messages) {
console.log(`\n👤 用户: ${message}`);
const result = await conversationEngine.processMessage(userId, message);
if (result.success) {
console.log(`🤖 助手: ${result.response}`);
console.log(`📊 元数据: 意图=${result.metadata.intent}, 置信度=${result.metadata.confidence}`);
} else {
console.log(`❌ 错误: ${result.error}`);
}
}
const stats = conversationEngine.getSessionStats();
console.log('\n📈 会话统计:', stats);
conversationEngine.exportSessions();
}
simulateConversation().catch(console.error);
module.exports = { ConversationEngine, IntentClassifier, EntityExtractor, DialogueManager };