исправь ошикби
const tf = require('@tensorflow/tfjs-node');
const fs = require('fs').promises;
const readlineSync = require('readline-sync');
const natural = require('natural');
const stopword = require('stopword');

async function loadData() {
    try {
        const data = await fs.readFile('bd.json', 'utf8');
        return JSON.parse(data);
    } catch (error) {
        console.error('Ошибка при загрузке данных:', error);
        throw error;
    }
}

function preprocessText(text) {
    const tokenizer = new natural.WordTokenizer();
    const lemmatizer = new natural.PorterStemmerRu(); // Замените на подходящий лемматизатор для русского языка
    let tokens = tokenizer.tokenize(text.toLowerCase());
    tokens = stopword.removeStopwords(tokens, stopword.ru);
    tokens = tokens.map(token => lemmatizer.stem(token));
    return tokens;
}

function createWordIndex(allTokens) {
    const uniqueTokens = [...new Set(allTokens)];
    const wordIndex = {};
    uniqueTokens.forEach((word, index) => {
        wordIndex[word] = index + 2; // +2 для резервирования индексов 0 (паддинг) и 1 (неизвестное слово)
    });
    return wordIndex;
}

function vectorizeQuestions(questions, wordIndex, maxLength) {
    return questions.map(tokens => {
        const vector = tokens.map(word => wordIndex[word] || 1); // 1 для неизвестных слов
        // Добавляем паддинг до maxLength
        if (vector.length < maxLength) {
            return vector.concat(Array(maxLength - vector.length).fill(0));
        } else {
            return vector.slice(0, maxLength);
        }
    });
}

async function trainModel(data) {
    const tokenizer = new natural.WordTokenizer();
    const lemmatizer = new natural.PorterStemmerRu(); // Замените на подходящий лемматизатор для русского языка
    const questionsTokens = data.map(item => preprocessText(item.question));
    const allTokens = questionsTokens.flat();
    const wordIndex = createWordIndex(allTokens);

    const maxLength = Math.max(...questionsTokens.map(tokens => tokens.length));

    const X_data = vectorizeQuestions(questionsTokens, wordIndex, maxLength);
    const X = tf.tensor2d(X_data);

    const Y_data = data.map((_, index) => index);
    const Y = tf.tensor1d(Y_data, 'int32');
    const Y_oneHot = tf.oneHot(Y, data.length);

    const model = tf.sequential();
    model.add(tf.layers.embedding({
        inputDim: Object.keys(wordIndex).length + 2,
        outputDim: 128,
        inputLength: maxLength
    }));
    model.add(tf.layers.lstm({ units: 64, returnSequences: false }));
    model.add(tf.layers.dropout({ rate: 0.5 }));
    model.add(tf.layers.dense({ units: data.length, activation: 'softmax' }));

    model.compile({
        optimizer: tf.train.adam(),
        loss: 'categoricalCrossentropy',
        metrics: ['accuracy']
    });

    await model.fit(X, Y_oneHot, {
        epochs: 50,
        batchSize: 8,
        validationSplit: 0.2,
        callbacks: {
            onEpochEnd: async (epoch, logs) => {
                console.log(`Эпоха ${epoch + 1}: потеря = ${logs.loss}, точность = ${logs.acc}`);
            }
        }
    });

    return { model, wordIndex, maxLength };
}

function predictAnswer(model, wordIndex, inputQuestion, data, maxLength) {
    const tokens = preprocessText(inputQuestion);
    const inputVector = vectorizeQuestions([tokens], wordIndex, maxLength)[0];
    const inputTensor = tf.tensor2d([inputVector]);

    const prediction = model.predict(inputTensor);
    const predictedIndex = prediction.argMax(1).dataSync()[0];

    return data[predictedIndex].answer;
}

async function main() {
    try {
        const data = await loadData();
        const { model, wordIndex, maxLength } = await trainModel(data);

        while (true) {
            const inputQuestion = readlineSync.question('Введите вопрос (или "exit" для выхода): ');
            if (inputQuestion.toLowerCase() === 'exit') {
                break;
            }
            const answer = predictAnswer(model, wordIndex, inputQuestion, data, maxLength);
            console.log('Ответ:', answer);
        }
    } catch (error) {
        console.error('Ошибка в главной функции:', error);
    }
}

main();