Json данные не успевают загрузиться исправь это



// Функции активации и их производные
function sigmoid(x) {
    return 1 / (1 + Math.exp(-x));
}

function sigmoidDerivative(x) {
    return x * (1 - x);
}

function relu(x) {
    return x > 0 ? x : 0;
}

function reluDerivative(x) {
    return x > 0 ? 1 : 0;
}

function softmax(arr) {
    const max = Math.max(...arr);
    const exps = arr.map(x => Math.exp(x - max));
    const sum = exps.reduce((a, b) => a + b, 0);
    return exps.map(x => x / sum);
}

// Функция для токенизации предложения с улучшенной предобработкой
function tokenize(sentence) {
    return sentence
        .toLowerCase()
        .replace(/[.,!?]/g, '') // Удаление знаков препинания
        .split(' ')
        .filter(word => word);
}

// Функция для создания TF-IDF векторов
class TfidfVectorizer {
    constructor(vocabulary) {
        this.vocabulary = vocabulary;
        this.idf = new Array(vocabulary.length).fill(0);
    }

    fit(docs) {
        const docCount = docs.length;
        const termDocCounts = new Array(this.vocabulary.length).fill(0);

        docs.forEach(doc => {
            const tokens = new Set(tokenize(doc));
            tokens.forEach(word => {
                let index = this.vocabulary.indexOf(word);
                if (index !== -1) termDocCounts[index]++;
            });
        });

        this.idf = this.vocabulary.map((word, idx) => {
            return Math.log((1 + docCount) / (1 + termDocCounts[idx])) + 1;
        });
    }

    transform(doc) {
        let tf = new Array(this.vocabulary.length).fill(0);
        tokenize(doc).forEach(word => {
            let index = this.vocabulary.indexOf(word);
            if (index !== -1) {
                tf[index]++;
            }
        });
        let tfidf = tf.map((termFreq, idx) => termFreq * this.idf[idx]);
        return tfidf;
    }
}

// Инициализация нейронной сети с дополнительными улучшениями
class NeuralNetwork {
    constructor(input_nodes, hidden_nodes, output_nodes) {
        this.input_nodes = input_nodes;
        this.hidden_nodes = hidden_nodes;
        this.output_nodes = output_nodes;

        // Инициализация весов с использованием нормального распределения
        this.weights_ih = this.initWeights(this.hidden_nodes, this.input_nodes);
        this.weights_ho = this.initWeights(this.output_nodes, this.hidden_nodes);

        // Инициализация смещений
        this.bias_h = new Array(this.hidden_nodes).fill(0).map(() => Math.random() * 2 - 1);
        this.bias_o = new Array(this.output_nodes).fill(0).map(() => Math.random() * 2 - 1);

        // Инициализация скоростей для Momentum
        this.velocity_ih = this.initZeroes(this.hidden_nodes, this.input_nodes);
        this.velocity_ho = this.initZeroes(this.output_nodes, this.hidden_nodes);
    }

    initWeights(rows, cols) {
        // Инициализация весов с небольшими случайными значениями
        return new Array(rows).fill(0).map(() =>
            new Array(cols).fill(0).map(() => Math.random() * 0.01 - 0.005)
        );
    }

    initZeroes(rows, cols) {
        return new Array(rows).fill(0).map(() => new Array(cols).fill(0));
    }

    // Прямое распространение с использованием ReLU для скрытого слоя и Softmax для выходного слоя
    feedforward(input_array) {
        // Вход в скрытый слой
        let hidden = this.weights_ih.map((weights, i) =>
            weights.reduce((sum, w, j) => sum + w * input_array[j], this.bias_h[i])
        ).map(x => relu(x));

        // Выходной слой
        let output = this.weights_ho.map((weights, i) =>
            weights.reduce((sum, w, j) => sum + w * hidden[j], this.bias_o[i])
        );

        // Применение Softmax для нормализации выходных данных
        output = softmax(output);

        return output;
    }

    // Обратное распространение и обучение с использованием Cross-Entropy Loss и Momentum
    train(input_array, target_array, learning_rate = 0.1, momentum = 0.9, lambda = 0.01) {
        // Прямое распространение
        let hidden_inputs = this.weights_ih.map((weights, i) =>
            weights.reduce((sum, w, j) => sum + w * input_array[j], this.bias_h[i])
        );

        let hidden_outputs = hidden_inputs.map(x => relu(x));

        let final_inputs = this.weights_ho.map((weights, i) =>
            weights.reduce((sum, w, j) => sum + w * hidden_outputs[j], this.bias_o[i])
        );

        let final_outputs = softmax(final_inputs);

        // Вычисление ошибок выходного слоя (Cross-Entropy Loss)
        let output_errors = final_outputs.map((output, i) => final_outputs[i] - target_array[i]);

        // Обратное распространение ошибки на скрытый слой
        let hidden_errors = new Array(this.hidden_nodes).fill(0);

        for (let i = 0; i < this.output_nodes; i++) {
            for (let j = 0; j < this.hidden_nodes; j++) {
                hidden_errors[j] += this.weights_ho[i][j] * output_errors[i];
            }
        }

        // Обновление весов скрытого -> выходного слоя
        for (let i = 0; i < this.output_nodes; i++) {
            for (let j = 0; j < this.hidden_nodes; j++) {
                let delta = output_errors[i] * hidden_outputs[j];
                this.velocity_ho[i][j] = momentum * this.velocity_ho[i][j] - learning_rate * delta;
                this.weights_ho[i][j] += this.velocity_ho[i][j];
            }
            // Обновление смещения
            this.bias_o[i] -= learning_rate * output_errors[i];
        }

        // Обновление весов входной -> скрытый слой
        for (let i = 0; i < this.hidden_nodes; i++) {
            let hidden_gradient = hidden_errors[i] * reluDerivative(hidden_inputs[i]);
            for (let j = 0; j < this.input_nodes; j++) {
                let delta = hidden_gradient * input_array[j];
                this.velocity_ih[i][j] = momentum * this.velocity_ih[i][j] - learning_rate * delta;
                this.weights_ih[i][j] += this.velocity_ih[i][j];
            }
            // Обновление смещения
            this.bias_h[i] -= learning_rate * hidden_gradient;
        }
    }
}

// Функция для перемешивания массива (Фишер-Йейтс)
function shuffleArray(array) {
    for (let i = array.length -1; i > 0; i--){
        const j = Math.floor(Math.random() * (i+1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}

const fs = require('fs');

fs.readFile('bd.json', 'utf8', (err, data) => {
    if (err) {
        console.error("Ошибка чтения файла:", err);
        return;
    }
    try {
        const jsonData = JSON.parse(data);
        const training_data = jsonData.map(item => ({
            question: item.question,
            answer: item.answer
        }));
        console.log(training_data);
    } catch (error) {
        console.error("Ошибка парсинга JSON:", error);
    }
});



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

// Создаем соответствие ответов и индексов классов
const answerToIndex = {};
const indexToAnswer = {};
uniqueAnswers.forEach((answer, index) => {
    answerToIndex[answer] = index;
    indexToAnswer[index] = answer;
});

// Создаем словарь для TF-IDF векторизации вопросов
let vocabularySet = new Set();

training_data.forEach(pair => {
    tokenize(pair.question).forEach(word => {
        vocabularySet.add(word);
    });
});
const vocabulary = [...vocabularySet];

// Создание и обучение TF-IDF векторизатора
const vectorizer = new TfidfVectorizer(vocabulary);
const all_questions = training_data.map(pair => pair.question);
vectorizer.fit(all_questions);

// Подготовка данных для обучения
function prepareData(data, vectorizer) {
    let inputs = [];
    let targets = [];
    data.forEach(pair => {
        // Преобразуем вопрос в TF-IDF вектор
        let input = vectorizer.transform(pair.question);
        inputs.push(input);

        // Преобразуем ответ в one-hot вектор класса ответа
        let targetIndex = answerToIndex[pair.answer];
        let target = new Array(uniqueAnswers.length).fill(0);
        target[targetIndex] = 1;
        targets.push(target);
    });
    return { inputs, targets };
}

let prepared = prepareData(training_data, vectorizer);

// Создаем сеть
let nn = new NeuralNetwork(vectorizer.vocabulary.length, 64, uniqueAnswers.length);

// Функция для обучения сети на всей обучающей выборке с мониторингом потерь и точности
function trainNetwork(nn, trainingInputs, trainingOutputs, epochs, learning_rate) {
    for (let epoch = 0; epoch < epochs; epoch++) {
        // Перемешиваем данные для каждой эпохи
        let indices = [...Array(trainingInputs.length).keys()];
        shuffleArray(indices);

        for (let i = 0; i < indices.length; i++) {
            let index = indices[i];
            nn.train(trainingInputs[index], trainingOutputs[index], learning_rate);
        }

        // Периодически выводим прогресс обучения
        if ((epoch + 1) % 50 === 0 || epoch === 0) { // Вывод каждые 100 эпох и первая
            let loss = 0;
            for (let i = 0; i < trainingInputs.length; i++) {
                let output = nn.feedforward(trainingInputs[i]);
                let targetIndex = trainingOutputs[i].indexOf(1);
                // Используем Cross-Entropy Loss
                loss -= Math.log(output[targetIndex] + 1e-15);
            }
            let accuracy = evaluateAccuracy(nn, trainingInputs, trainingOutputs);
            console.log(`Эпоха ${epoch + 1}/${epochs}, Потеря: ${loss.toFixed(4)}, Точность: ${accuracy.toFixed(2)}%`);
        }
    }
}

// Функция для оценки точности модели
function evaluateAccuracy(nn, inputs, outputs) {
    let correct = 0;
    for (let i = 0; i < inputs.length; i++) {
        let prediction = nn.feedforward(inputs[i]);
        let predictedIndex = prediction.indexOf(Math.max(...prediction));
        let actualIndex = outputs[i].indexOf(1);
        if (predictedIndex === actualIndex) {
            correct++;
        }
    }
    return (correct / inputs.length) * 100;
}

// Обучаем сеть
let epochs = 50;
let learning_rate = 0.000015;
trainNetwork(nn, prepared.inputs, prepared.targets, epochs, learning_rate);

// Функция для получения ответа
function getAnswer(question) {
    // Преобразуем вопрос с использованием TF-IDF
    let input = vectorizer.transform(question);

    // Преобразуем в массив чисел
    input = input.map(x => Number(x));

    // Получаем выход сети
    let output = nn.feedforward(input);

    // Определяем индекс ответа с наибольшей вероятностью
    let predictedIndex = output.indexOf(Math.max(...output));

    // Получаем соответствующий ответ
    let answer = indexToAnswer[predictedIndex] || "Извините, я не понял ваш вопрос.";
    return answer;
}

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

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