😎

jsのみのchatbotを作りました。 全文 

2025/03/08に公開

質問内容に応じたbooleanが存在し、回答に応じて、booleanをtrue,flaseする。

yes,noに応じて、質問内容を変化させられる。しなくてもいい。

const questions = [
    {
        id: 'q0',
        text: '新しいチャットを始めますか (yes/no)',
        next: (answer) => answer ? 'q1' : evaluateAnswers()
    },
    {
        id: 'q1',
        text: 'それは鉄道ですか (yes/no)',
        next: (answer) => answer ? 'q2' : evaluateAnswers()
    },
    {
        id: 'q2',
        text: '東京の駅ですか? (yes/no)',
        next: (answer) => evaluateAnswers()
    }
];

最終的に十分な質問が終わったら、判定用関数に通し、結果を出力する。

function evaluateAnswers() {
    const q1 = answers['q1'];
    const q2 = answers['q2'];
    //追加可能


    if (!q1 || !q2) {
        return 'result1'; // 
    }
    return 'result2';
}

この柔軟性の高い条件分岐が自分の工夫ポイントです。

また、URLを入れることが多いと予測されるので、URLを文書内に入れた場合は、それをURL変換する機構を追加した。

別タブでURLを開くので、セキュリティリスクが存在します。
別窓から攻撃される可能性があるということで、
「 aタグ _blank セキュリティ」で検索してください。

一応、

 link.target = '_blank';
link.rel = 'noopener noreferrer'; // セキュリティ対策

とはしてあります。

この前ちょうど、quitaの記事で、URLを改変されていたのがあったので、結構やられるリスクはあるのかなと感じています。気を付けてください。

以下全文


<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        body {
    font-family: Arial, sans-serif;
    background-color: #f4f4f4;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}

.chat-container {
    width: 300px;
    background-color: #fff;
    border-radius: 8px;
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    overflow: hidden;
}

.chat-log {
    height: 300px;
    padding: 10px;
    overflow-y: auto;
    border-bottom: 1px solid #ddd;
}

#user-input {
    width: 100%;
    padding: 10px;
    border: none;
    outline: none;
    box-sizing: border-box;
}
    </style>
</head>
<body>
    <div class="chat-container">
        <div id="chat-log" class="chat-log"></div>
        <input type="text" id="user-input" placeholder="ここに答えを書いてください" onkeypress="handleKeyPress(event)">
    </div>
    <script>
      const chatLog = document.getElementById('chat-log');
const userInput = document.getElementById('user-input');

let answers = {};
let currentQuestion = null;

const questions = [
    {
        id: 'q0',
        text: '新しいチャットを始めますか (yes/no)',
        next: (answer) => answer ? 'q1' : evaluateAnswers()
    },
    {
        id: 'q1',
        text: 'それは鉄道ですか (yes/no)',
        next: (answer) => answer ? 'q2' : evaluateAnswers()
    },
    {
        id: 'q2',
        text: '東京の駅ですか? (yes/no)',
        next: (answer) => evaluateAnswers()
    }
];

const results = {
    result1: 'すみませんが、お応えできるものがありません',
    result2: '東京の駅情報は下記になります。 https://www.jreast.co.jp/map/pdf/map_tokyo.pdf '
};

function displayQuestion(questionId) {
    const question = questions.find(q => q.id === questionId);
    if (question) {
        currentQuestion = question;
        appendMessage('bot', question.text);
    } else {
        const result = results[questionId];
        if (result) {
            appendMessage('bot', result);
        }
        answers = {};//条件の初期化
        displayQuestion('q0');//初期化したときにする質問。お好きなものを
    }
}
/*
function appendMessage(sender, message) {
    const messageElement = document.createElement('div');
    messageElement.classList.add('message', sender);
    messageElement.textContent = message;
    chatLog.appendChild(messageElement);
    
    
    chatLog.scrollTop = chatLog.scrollHeight;
}*/
function appendMessage(sender, message) {
    const messageElement = document.createElement('div');
    messageElement.classList.add('message', sender);
    
    // URLを検出する正規表現(http/httpsから始まり空白までの文字列)
    const urlRegex = /(https?:\/\/[^\s]+)/g;
    
    // メッセージをテキストとURLに分割して処理
    const parts = message.split(urlRegex);
    
    parts.forEach((part, index) => {
        // 奇数番目の要素がURLにマッチした部分
        if (index % 2 === 1) {
            const link = document.createElement('a');
            link.href = part;
            link.textContent = part;
            link.target = '_blank';
            link.rel = 'noopener noreferrer'; // セキュリティ対策
            messageElement.appendChild(link);
        } else {
            // 通常のテキストはテキストノードとして追加
            messageElement.appendChild(document.createTextNode(part));
        }
    });

    chatLog.appendChild(messageElement);
    chatLog.scrollTop = chatLog.scrollHeight;
}

function handleKeyPress(event) {
    if (event.key === 'Enter') {
        const userAnswer = userInput.value.trim().toLowerCase();
        if (userAnswer === 'yes' || userAnswer === 'no') {
            const answer = userAnswer === 'yes';
            answers[currentQuestion.id] = answer;
            userInput.value = '';
            const nextStep = currentQuestion.next(answer);
            if (nextStep) {
                displayQuestion(nextStep);
            } else {
                appendMessage('bot', '質問する内容がなくなりました。');
            }
        } else {
            appendMessage('bot', 'yesかnoで答えてください');
        }
    }
}

function evaluateAnswers() {
    const q1 = answers['q1'];
    const q2 = answers['q2'];
    //追加可能


    if (!q1 || !q2) {
        return 'result1'; // 
    }
    return 'result2';
}

// Start the chatbot with the first question
displayQuestion('q1');//最初にする質問
    </script>
</body>

</html>

Discussion