Use el nodo para hacer un robot de diálogo simple

Use el nodo para hacer un robot de diálogo simple

inserte la descripción de la imagen aquí

Introducir dependencias

const nodejieba = require("nodejieba");
const fs = require('fs');
const readline = require('readline');
const express = require('express');
const app = express();

Preguntas y respuestas sobre almacenamiento

Cree un archivo txt para almacenar preguntas y respuestas programadas.

Como se muestra abajo:

inserte la descripción de la imagen aquí
Interceptación parcial:

你好	你好,有什么可以帮您的吗?
再见	再见,很高兴为您服务!
12312	12312312
12313	12312312

Hacer el directorio accesible

const qaPairs = {
    
    }
const filePath = 'qa_pairs.txt';
// 设置目录文件可访问
app.use(express.static('./'));

establecer interfaz

para consulta y aprendizaje respectivamente

app.get('/QR', (req, res) => {
    
    
    // 获取传来的值
    const question = req.query.question;
    const response = chatbotResponse(question);
    // 跨域
    res.header('Access-Control-Allow-Origin', '*');
    res.send(response);
});

app.get('/QRStudy', (req, res) => {
    
    
    // 获取传来的值
    const question = req.query.question;
    const answer = req.query.answer;
    saveQAPairToFile(question, answer, filePath);
    // 跨域
    res.header('Access-Control-Allow-Origin', '*');
    res.send('success');
});

Guardar preguntas y respuestas en el archivo

// 把问答对写入文件
function saveQAPairToFile(question, answer, filePath) {
    
    
    const qaPairStr = `${
      
      question}\t${
      
      answer}\n`;
    fs.appendFile(filePath, qaPairStr, (err) => {
    
    
        if (err) throw err;
        // 写入完成后读取文件并保存到qaPairs
        loadQAPairsFromFile(filePath);
    });
}

Leer preguntas y respuestas de un archivo

function loadQAPairsFromFile(file) {
    
    
    const rl = readline.createInterface({
    
    
        input: fs.createReadStream(file),
        crlfDelay: Infinity
    });

    rl.on('line', (line) => {
    
    
        const [question, answer] = line.split('\t');
        qaPairs[question] = answer;
    });
}

Haga coincidir la mejor respuesta a través de la tabla del diccionario y el separador de palabras

function findClosestQuestion(userInput) {
    
    
    let closestQuestion = null;
    let maxSimilarity = -1;
    const userInputSet = new Set(nodejieba.cut(userInput));

    for (const question of Object.keys(qaPairs)) {
    
    
        const questionSet = new Set(nodejieba.cut(question));
        const intersection = new Set([...userInputSet].filter(x => questionSet.has(x)));
        const similarity = intersection.size / userInputSet.size;
        if (similarity > maxSimilarity) {
    
    
            maxSimilarity = similarity;
            closestQuestion = question;
        }
    }
    return closestQuestion;
}

function chatbotResponse(userInput) {
    
    
    const closestQuestion = findClosestQuestion(userInput);
    if (qaPairs[closestQuestion]) {
    
    
        switch (qaPairs[closestQuestion]) {
    
    
            case 'mathematical******calculation':
                try {
    
    
                    let expression = userInput.match(/[+\-*/0-9]+/g).join('');
                    let result = eval(expression);
                    return String(result);
                } catch (e) {
    
    
                    return "对不起,我无法理解您的问题。你可以尝试教导我如何回答这个问题。";
                }
            default:
                return qaPairs[closestQuestion];
        }
    } else {
    
    
        return "对不起,我无法理解您的问题。你可以尝试教导我如何回答这个问题。";
    }
}

Lea el contenido de preguntas y respuestas e inicie el servicio

// 读取问答对
loadQAPairsFromFile(filePath);
app.listen(9999, () => {
    
    
    console.log('Server started on port 9999');
});

Interfaz

índice.html

<!DOCTYPE html>
<html>

<head>
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, minimal-ui">
	<script src="./vue.global.js"></script>
</head>
<style>
	body {
    
    
		font-family: Arial, sans-serif;
		margin: 0;
		padding: 0;
		display: flex;
		justify-content: center;
		align-items: center;
		height: 100vh;
		background-color: #f2f2f2;
	}

	.chat-container {
    
    
		width: 100%;
		max-width: 400px;
		background-color: white;
		border-radius: 10px;
		overflow: hidden;
		display: flex;
		flex-direction: column;
		box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
	}

	.chat-header,
	.chat-footer {
    
    
		padding: 20px;
		background-color: #fafafa;
		border-bottom: 1px solid #f2f2f2;
	}

	.chat-header {
    
    
		border-bottom: 1px solid #f2f2f2;
	}

	.chat-content {
    
    
		padding: 20px;
		flex-grow: 1;
		overflow-y: auto;
		max-height: 50vh;
		scroll-behavior: smooth;
	}

	.message {
    
    
		margin-bottom: 20px;
	}

	.my-message {
    
    
		align-self: flex-end;
		background-color: #0084ff;
		color: white;
		padding: 10px;
		border-radius: 10px;
	}

	.their-message {
    
    
		align-self: flex-start;
		background-color: #f2f2f2;
		padding: 10px;
		border-radius: 10px;
	}

	.input-message {
    
    
		flex-grow: 1;
		border: none;
		padding: 10px;
		border-radius: 10px;
		margin-right: 10px;
	}

	.send-button {
    
    
		padding: 10px;
		background-color: #0084ff;
		color: white;
		border: none;
		border-radius: 10px;
		cursor: pointer;
	}

	.modal {
    
    
		display: none;
		position: fixed;
		z-index: 1;
		left: 0;
		top: 0;
		width: 100%;
		height: 100%;
		overflow: auto;
		background-color: rgb(0, 0, 0);
		background-color: rgba(0, 0, 0, 0.4);
	}

	.modal-content {
    
    
		background-color: #fefefe;
		margin: 15% auto;
		padding: 20px;
		border: 1px solid #888;
		width: 80%;
	}

	#feedbackButton {
    
    
		background-color: #0084ff;
		color: white;
		border-radius: 5px;
		border: none;
		align-self: flex-end;
		padding: 5px;
		margin-top: 20px;
	}

	.loading-dots {
    
    
		display: flex;
		justify-content: center;
		padding: 10px 0;
	}

	.dot {
    
    
		display: inline-block;
		width: 10px;
		height: 10px;
		border-radius: 50%;
		margin: 0 5px;
		background-color: white;
		animation: pulse 1s ease-in-out infinite;
	}

	.dot:nth-child(2) {
    
    
		animation-delay: 0.2s;
	}

	.dot:nth-child(3) {
    
    
		animation-delay: 0.4s;
	}

	@keyframes pulse {
    
    
		0% {
    
    
			transform: scale(1);
		}

		50% {
    
    
			transform: scale(1.5);
		}

		100% {
    
    
			transform: scale(1);
		}
	}
</style>

<body>
	<div id="app">
		<div class="chat-container">
			<div class="chat-header">聊天</div>
			<div class="chat-content">
				<div v-for="(item,index) in questionAndAnswer">
					<div v-if="item.question" class="message">
						<div class="my-message">
							{
    
    {
    
    item.question}}
						</div>
					</div>
					<div v-if="machineLoading&&index==questionAndAnswer.length-1" class="message">
						<div class="their-message">
							<div class="loading-dots">
								<span class="dot"></span>
								<span class="dot"></span>
								<span class="dot"></span>
							</div>
						</div>
					</div>
					<div v-if="item.answer" class="message">
						<div class="their-message">
							{
    
    {
    
    item.answer}}
						</div>
					</div>

				</div>
			</div>
			<div class="chat-footer">
				<input type="text" v-model="question" class="input-message" placeholder="输入消息...">
				<button @click="sendMsg" class="send-button">{
    
    {
    
    sendMsgLock?'....':'发送'}}</button>
			</div>
		</div>
		<button id="feedbackButton">教导机器学习新知识</button>
		<div id="feedbackModal" class="modal">
			<div class="modal-content">
				<span id="closeButton">&times;</span>
				<p>碰到以下问题</p>
				<input placeholder="请输入问题" v-model="updateQuestionAndAnswer.question">
				<p>你希望我怎么回答:</p>
				<textarea id="feedbackText" v-model="updateQuestionAndAnswer.answer" placeholder="你希望我怎么回答?" rows="4"
					cols="40"></textarea>
				<div>
					<button @click="submitBtn" id="submitButton">提交</button>
				</div>
			</div>
		</div>
	</div>
</body>
<script>
	const {
    
     createApp } = Vue
	createApp({
    
    
		data() {
    
    
			return {
    
    
				message: 'Hello Vue!',
				questionAndAnswer: [{
    
    
					question: '',
					answer: '你好,你可以问我任何问题,我会尽力回答你的问题。'
				}, {
    
    
					question: '',
					answer: '如果你愿意教我怎么回答,可以点击下面的按钮。你的教导会让我变得更聪明。'
				}],
				question: '',
				updateQuestionAndAnswer: {
    
    
					question: '',
					answer: ''
				},
				machineLoading: false,
				sendMsgLock: false
			}
		},
		methods: {
    
    
			// 是否可以发送消息
			canSendMsg() {
    
    
				return this.sendMsgLock
			},
			sendMsg() {
    
    
				if (this.canSendMsg()) {
    
    
					return
				}
				if (!this.question) {
    
    
					alert('请输入内容')
					return
				}
				this.draw(this.question, '')
				this.requestMeth(`http://106.54.39.111:9999/QR?question=${
      
      this.question}`, (res) => {
    
    
					this.draw('', res)
				})
			},
			// 显示隐藏machineLoading
			showMachineLoading(bool) {
    
    
				this.machineLoading = bool
			},
			// 渲染消息
			draw(question = '', answer = '') {
    
    
				this.sendMsgLock = true
				this.drawText({
    
    
					question,
					answer
				}, () => {
    
    
					this.sendMsgLock = false
					
				},question?true:false)
				
			},
			// 逐条输出内容
			drawText(obj, callback, bool) {
    
    
				let text = obj.answer;
				if (bool) {
    
    
					this.questionAndAnswer.push({
    
    
						question: obj.question,
						answer: obj.answer
					})
					this.scrollToBottom();
					return;
				}
				
				let that = this;
				that.questionAndAnswer.push({
    
    
					question: '',
					answer: ''
				})
				let i = 0;
				let timer = setInterval(() => {
    
    
					if (i < text.length) {
    
    
						that.questionAndAnswer[that.questionAndAnswer.length - 1].answer += text[i];
						i++;
					} else {
    
    
						clearInterval(timer);
						callback();
					}
					this.scrollToBottom();
				}, 100)
			},
			// 发起请求
			requestMeth(url, callback) {
    
    
				let that = this;
				this.showMachineLoading(true);
				this.question = '';
				let xhr = new XMLHttpRequest();
				xhr.open('get', url, true);
				xhr.send();
				xhr.onreadystatechange = function () {
    
    
					if (xhr.readyState == 4 && xhr.status == 200) {
    
    
						that.showMachineLoading(false)
						callback(xhr.responseText)
					}
				}
			},
			// overflow auto 移动到底部
			scrollToBottom() {
    
    
				this.$nextTick(() => {
    
    
					let chatContent = document.querySelector('.chat-content')
					chatContent.scrollTop = chatContent.scrollHeight
				})
			},
			// 提交
			submitBtn() {
    
    
				// 判断输入框是否为空
				if (!this.updateQuestionAndAnswer.question) {
    
    
					alert('我一直认为学习很枯燥,但我听说你可以让学习变得很有趣。你能告诉我你的秘诀吗?')
					return
				}
				if (!this.updateQuestionAndAnswer.answer) {
    
    
					alert('我一直认为学习很枯燥,但我听说你可以让学习变得很有趣。你能告诉我你的秘诀吗?')
					return
				}
				let that = this;
				this.requestMeth(`http://106.54.39.111:9999/QRStudy?question=${
      
      this.updateQuestionAndAnswer.question}&answer=${
      
      this.updateQuestionAndAnswer.answer}`, function (res) {
    
    
					that.draw('', '感谢你教我怎么回答,我现在可以回答更多问题了');
				});
				modal.style.display = "none";
			}
		}
	}).mount('#app')
	var modal = document.getElementById("feedbackModal");
	var btn = document.getElementById("feedbackButton");
	var span = document.getElementById("closeButton");
	btn.onclick = function () {
    
    
		modal.style.display = "block";
	}

	span.onclick = function () {
    
    
		modal.style.display = "none";
	}



	window.onclick = function (event) {
    
    
		if (event.target == modal) {
    
    
			modal.style.display = "none";
		}
	}

</script>

</html>

Este robot de respuesta a preguntas es bastante simple, pero debe aplicarse al modelo de inteligencia artificial para realizar funciones complejas.

Supongo que te gusta

Origin blog.csdn.net/qq_41974199/article/details/130602600
Recomendado
Clasificación