после обучения сохраняет обученную модель , если модель уже есть то можно вводить свои вопросы вот код const fs = require('fs').promises;
const natural = require('natural');
const brain = require('brain.js');

// Создаем токенизатор и стеммер
const tokenizer = new natural.WordTokenizer();
const stemmer = natural.PorterStemmerRu; // Для русского языка

// Функция токенизации и стемминга
function tokenizeAndStem(text) {
    const tokens = tokenizer.tokenize(text.toLowerCase());
    return tokens.map(token => stemmer.stem(token));
}

// Основная часть программы
(async () => {
    try {
        const data = await fs.readFile('bd.json', 'utf8');
        const jsonData = JSON.parse(data);

        const training_data = jsonData.map(item => ({
            question: item.question,
            answer: item.answer
        }));

        // Создаем список уникальных ответов
        const uniqueAnswers = [...new Set(training_data.map(pair => pair.answer))];

        const answerToIndex = {};
        const indexToAnswer = {};
        uniqueAnswers.forEach((answer, index) => {
            answerToIndex[answer] = index;
            indexToAnswer[index] = answer;
        });

        // Обрабатываем все вопросы и собираем словарь терминов
        let vocabularySet = new Set();
        training_data.forEach(pair => {
            const processedQuestion = tokenizeAndStem(pair.question);
            processedQuestion.forEach(term => {
                vocabularySet.add(term);
            });
        });

        const vocabulary = Array.from(vocabularySet);

        // Создаем отображение термина в индекс
        const termToIndex = {};
        vocabulary.forEach((term, index) => {
            termToIndex[term] = index;
        });

        // Вычисляем IDF для каждого термина
        const idfValues = {};
        const totalDocuments = training_data.length;
        vocabulary.forEach(term => {
            let docsWithTerm = 0;
            training_data.forEach(pair => {
                const tokens = tokenizeAndStem(pair.question);
                if (tokens.includes(term)) {
                    docsWithTerm++;
                }
            });
            idfValues[term] = Math.log(totalDocuments / (1 + docsWithTerm));
        });

        // Подготавливаем данные для обучения нейронной сети
        const trainingSet = training_data.map((pair) => {
            const processedQuestion = tokenizeAndStem(pair.question);
            const tfValues = {};

            // Вычисляем TF для текущего документа
            processedQuestion.forEach(term => {
                if (!tfValues[term]) {
                    tfValues[term] = 0;
                }
                tfValues[term] += 1;
            });

            // Формируем TF-IDF вектор
            const tfidfVector = new Array(vocabulary.length).fill(0);
            Object.keys(tfValues).forEach(term => {
                const termIndex = termToIndex[term];
                if (termIndex !== undefined) {
                    const tf = tfValues[term] / processedQuestion.length; // Относительный TF
                    const idf = idfValues[term];
                    tfidfVector[termIndex] = tf * idf;
                }
            });

            const output = {};
            output[answerToIndex[pair.answer]] = 1;

            return {
                input: tfidfVector,
                output: output
            };
        });

        // Определяем параметры нейронной сети
        const config = {
            hiddenLayers: [64], // Слои скрытых нейронов
            activation: 'relu', // Функция активации
            learningRate: 0.01
        };

        const net = new brain.NeuralNetwork(config);

        // Тренируем нейронную сеть
        console.log('Начало обучения нейронной сети...');
        net.train(trainingSet, {
            iterations: 2000,
            log: true,
            logPeriod: 100,
            errorThresh: 0.005
        });
        console.log('Обучение завершено.');

        // Функция для получения ответа на вопрос
        function getAnswer(question) {
            const processedQuestion = tokenizeAndStem(question);
            const tfValues = {};

            processedQuestion.forEach(term => {
                if (!tfValues[term]) {
                    tfValues[term] = 0;
                }
                tfValues[term] += 1;
            });

            const tfidfVector = new Array(vocabulary.length).fill(0);
            Object.keys(tfValues).forEach(term => {
                const termIndex = termToIndex[term];
                if (termIndex !== undefined) {
                    const tf = tfValues[term] / processedQuestion.length;
                    const idf = idfValues[term] || Math.log(totalDocuments / (1 + 1)); // Если терм не встречался ранее
                    tfidfVector[termIndex] = tf * idf;
                }
            });

            const output = net.run(tfidfVector);
            const predictedIndex = Object.keys(output).reduce((a, b) => output[a] > output[b] ? a : b);
            const answer = indexToAnswer[predictedIndex] || "Извините, я не понял ваш вопрос.";
            return answer;
        }

        // Тестовые вопросы
        const test_questions = [
            "привет",
            "как дела",
            "что тебя зовут",
            "как тебя зовут",
            "рад тебя видеть",
            "пока",
            "до свидания",
            "добрый день",
            "приветствую",
            "до встречи",
            "как твои дела",
            "что за фигня",
            "спасибо",
            "пожалуйста",
            "как работает твой мозг",
            "расскажи шутку",
            "что ты умеешь",
            "сколько тебе лет",
            "где ты находишься",
            "расскажи анекдот"
        ];

        test_questions.forEach(q => {
            let ans = getAnswer(q);
            console.log(`Вопрос: "${q}" => Ответ: "${ans}"`);
        });

    } catch (error) {
        console.error("Ошибка:", error);
    }
})();