import numpy as np
from keras.models import Model
from keras.layers import Input, LSTM, Bidirectional, Concatenate, Dot,Embedding,Activation,Dense
from keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

# Define hyperparameters
max_sequence_length = 100
embedding_dim = 100
latent_dim = 256

# Load train, validate, and test data from text files
with open('D:/PHD Papers/scientific translation/GPT/First Code BiLSTM/NewResult/Train.txt', 'r', encoding='utf-8') as f:
    train_data = f.read().splitlines()
with open('D:/PHD Papers/scientific translation/GPT/First Code BiLSTM/NewResult/Validate.txt', 'r', encoding='utf-8') as f:
    validate_data = f.read().splitlines()
with open('D:/PHD Papers/scientific translation/GPT/First Code BiLSTM/NewResult/Test.txt', 'r', encoding='utf-8') as f:
    test_data = f.read().splitlines()

# Tokenize sentences and convert them into numerical representations
tokenizer_en = Tokenizer()
tokenizer_en.fit_on_texts(train_data)
train_data_en = tokenizer_en.texts_to_sequences(train_data)
train_data_en = pad_sequences(train_data_en, maxlen=max_sequence_length)

tokenizer_ar = Tokenizer()
tokenizer_ar.fit_on_texts(train_data)
train_data_ar = tokenizer_ar.texts_to_sequences(train_data)
train_data_ar = pad_sequences(train_data_ar, maxlen=max_sequence_length)

# Define encoder inputs and LSTM layer
encoder_inputs = Input(shape=(max_sequence_length,))
encoder_embedding = Embedding(len(tokenizer_en.word_index) + 1, embedding_dim)(encoder_inputs)
encoder_lstm = Bidirectional(LSTM(latent_dim, return_sequences=True))(encoder_embedding)

# Define decoder inputs and LSTM layer
decoder_inputs = Input(shape=(max_sequence_length,))
decoder_embedding = Embedding(len(tokenizer_ar.word_index) + 1, embedding_dim)(decoder_inputs)
decoder_lstm = Bidirectional(LSTM(latent_dim, return_sequences=True))(decoder_embedding)

# Apply attention mechanism
attention = Dot(axes=[2, 2])([decoder_lstm, encoder_lstm])
attention = Activation('softmax')(attention)
context = Dot(axes=[2, 1])([attention, encoder_lstm])
decoder_combined_context = Concatenate(axis=-1)([context, decoder_lstm])

# Define decoder output layer
decoder_dense = Dense(len(tokenizer_ar.word_index) + 1, activation='softmax')
decoder_outputs = decoder_dense(decoder_combined_context)

# Define the model
model = Model([encoder_inputs, decoder_inputs], decoder_outputs)
model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
model.summary()

# Train the model
model.fit([train_data_en, train_data_ar], np.expand_dims(train_data_ar, -1), batch_size=64, epochs=10,
          validation_split=0.2)

# Use test data to evaluate the model
with open('D:/PHD Papers/scientific translation/GPT/First Code BiLSTM/NewResult/Test.txt', 'r', encoding='utf-8') as f:
    test_data = f.read().splitlines()

test_data_en = tokenizer_en.texts_to_sequences(test_data)
test_data_en = pad_sequences(test_data_en, maxlen=max_sequence_length)

predicted_arabic = model.predict(test_data_en)
decoded_arabic = tokenizer_ar.sequences_to_texts(np.argmax(predicted_arabic, axis=-1))

# Print example prediction translation from test data
print("English sentence: ", test_data[0])
print("Predicted Arabic sentence: ", decoded_arabic[0])