import random
import re
import requests
import json
from datetime import timedelta, datetime
import time

# Dictionary to map tone marks to their replacements
remaining_tone_marks = {
    'a': 'a', 'à': 'a', 'á': 'a', 'ả': 'a', 'ã': 'a', 'ạ': 'a',
    'ă': 'ă', 'ằ': 'ă', 'ắ': 'ă', 'ẳ': 'ă', 'ẵ': 'ă', 'ặ': 'ă',
    'â': 'â', 'ầ': 'â', 'ấ': 'â', 'ẩ': 'â', 'ẫ': 'â', 'ậ': 'â',
    'e': 'e', 'è': 'e', 'é': 'e', 'ẻ': 'e', 'ẽ': 'e', 'ẹ': 'e',
    'ê': 'ê', 'ề': 'ê', 'ế': 'ê', 'ể': 'ê', 'ễ': 'ê', 'ệ': 'ê',
    'i': 'i', 'ì': 'i', 'í': 'i', 'ỉ': 'i', 'ĩ': 'i', 'ị': 'i',
    'o': 'o', 'ò': 'o', 'ó': 'o', 'ỏ': 'o', 'õ': 'o', 'ọ': 'o',
    'ô': 'ô', 'ồ': 'ô', 'ố': 'ô', 'ổ': 'ô', 'ỗ': 'ô', 'ộ': 'ô',
    'ơ': 'ơ', 'ờ': 'ơ', 'ớ': 'ơ', 'ở': 'ơ', 'ỡ': 'ơ', 'ợ': 'ơ',
    'u': 'u', 'ù': 'u', 'ú': 'u', 'ủ': 'u', 'ũ': 'u', 'ụ': 'u',
    'ư': 'ư', 'ừ': 'ư', 'ứ': 'ư', 'ử': 'ư', 'ữ': 'ư', 'ự': 'ư',
    'y': 'y', 'ỳ': 'y', 'ý': 'y', 'ỷ': 'y', 'ỹ': 'y', 'ỵ': 'y',
}

def load_words_from_file(file_path):
    words_set = set()

    try:
        # Read the file with UTF-8 encoding and populate the set with words
        with open(file_path, 'r', encoding='utf-8') as file:
            for line in file:
                # Split the line into words and add to the set
                words_set.update(line.strip().split())
    except FileNotFoundError:
        print(f"Error: The file '{file_path}' was not found.")
    except IOError as e:
        print(f"Error reading the file '{file_path}': {e}")

    return words_set

WORDS_FILE_PATH = r'C:\Users\vaymu\OneDrive\Desktop\qka.txt'
WORDS_SET = load_words_from_file(WORDS_FILE_PATH)

def replace_tone_marks(text):
    # Convert text to lowercase
    text = text.lower()
    
    # Remove numbers and special characters
    text = re.sub(r'[0-9~`!@#$%^&*()_+\-={}\[\]:;"\'<>,.?/|\\“”…‘’]', '', text)
    
    # Replace multiple spaces with a single space and strip leading/trailing spaces
    text = re.sub(r'\s+', ' ', text).strip()
    
    # Replace remaining tone marks with corresponding replacements
    for tone, replacement in remaining_tone_marks.items():
        text = text.replace(tone, replacement)
    
    return text

def check_vietnamese(paragraph, words_set, output_file='non_matches.txt'):
    # Step 1: Clean and normalize the paragraph
    cleaned_paragraph = replace_tone_marks(paragraph)

    # Step 2: Split the cleaned paragraph into words
    words_in_paragraph = cleaned_paragraph.split()

    # Step 3: Identify matching and non-matching words
    matches = [word for word in words_in_paragraph if word in words_set]
    non_matches = [word for word in words_in_paragraph if word not in words_set]

    # Step 4: Write non-matching words to the provided output file
    try:
        with open(output_file, 'w', encoding='utf-8') as file:
            for word in non_matches:
                file.write(f"{word}\n")
    except IOError as e:
        print(f"Error writing to file {output_file}: {e}")
        return

    # Step 5: Calculate match statistics
    total_matches = len(matches)
    total_words = len(words_in_paragraph)
    match_ratio = total_matches / total_words if total_words > 0.7 else 0

    # Step 6: Print results
    # print(f"Match ratio: {match_ratio:.2f}")
    return match_ratio

def levenshtein(seq1, seq2):
    size_x = len(seq1) + 1
    size_y = len(seq2) + 1

    # Create the matrix manually
    matrix = [[0] * size_y for _ in range(size_x)]

    for x in range(size_x):
        matrix[x][0] = x

    for y in range(size_y):
        matrix[0][y] = y

    for x in range(1, size_x):
        for y in range(1, size_y):
            if seq1[x - 1] == seq2[y - 1]:
                matrix[x][y] = min(
                    matrix[x - 1][y] + 1,
                    matrix[x - 1][y - 1],
                    matrix[x][y - 1] + 1
                )
            else:
                matrix[x][y] = min(
                    matrix[x - 1][y] + 1,
                    matrix[x - 1][y - 1] + 1,
                    matrix[x][y - 1] + 1
                )

    return matrix[size_x - 1][size_y - 1]

def parse_transcript(transcript):
    pattern = re.compile(r'(\d+)\s+((\d{2}:\d{2}:\d{2},\d{3}) --> (\d{2}:\d{2}:\d{2},\d{3}))\s+(.*)')
    matches = pattern.findall(transcript)
    
    parsed_data = []
    for match in matches:
        start_time, end_time, text = match[2], match[3], match[4]
        parsed_data.append({
            'start_time': start_time,
            'end_time': end_time,
            'text': text
        })
    
    return parsed_data

def split_into_chunks(parsed_data, chunk_duration_seconds=30):
    chunks = []
    current_chunk = []
    current_chunk_start_time = None
    current_chunk_end_time = None
    
    for entry in parsed_data:
        start_time, end_time, text = entry['start_time'], entry['end_time'], entry['text']
        
        if current_chunk_start_time is None:
            current_chunk_start_time = start_time
        
        current_chunk_end_time = end_time
        current_chunk.append(text)
        
        start_timedelta = timedelta(hours=int(start_time[:2]), minutes=int(start_time[3:5]), seconds=int(start_time[6:8]), milliseconds=int(start_time[9:]))
        end_timedelta = timedelta(hours=int(end_time[:2]), minutes=int(end_time[3:5]), seconds=int(end_time[6:8]), milliseconds=int(end_time[9:]))
        
        if (end_timedelta - timedelta(hours=int(current_chunk_start_time[:2]), minutes=int(current_chunk_start_time[3:5]), seconds=int(current_chunk_start_time[6:8]), milliseconds=int(current_chunk_start_time[9:]))) >= timedelta(seconds=chunk_duration_seconds):
            if not re.search(r'[.!?]$', ' '.join(current_chunk)):
                extended_end_time = (datetime.strptime(end_time, '%H:%M:%S,%f') + timedelta(seconds=30)).strftime('%H:%M:%S,%f')[:-3]
                next_entry = next((e for e in parsed_data if e['start_time'] > end_time and e['start_time'] <= extended_end_time), None)
                if next_entry and re.search(r'[.!?]$', next_entry['text']):
                    current_chunk_end_time = next_entry['end_time']
                    current_chunk.append(next_entry['text'])
                    end_timedelta = timedelta(hours=int(current_chunk_end_time[:2]), minutes=int(current_chunk_end_time[3:5]), seconds=int(current_chunk_end_time[6:8]), milliseconds=int(current_chunk_end_time[9:]))
            
            chunks.append({
                'start_time': current_chunk_start_time,
                'end_time': current_chunk_end_time,
                'text': ' '.join(current_chunk)
            })
            current_chunk = []
            current_chunk_start_time = None
            current_chunk_end_time = None
    
    if current_chunk:
        chunks.append({
            'start_time': current_chunk_start_time,
            'end_time': current_chunk_end_time,
            'text': ' '.join(current_chunk)
        })
    
    if len(chunks) > 1:
        last_chunk = chunks[-1]
        prev_chunk = chunks[-2]
        last_chunk_word_count = len(last_chunk['text'].split())
        prev_chunk_word_count = len(prev_chunk['text'].split())
        
        if last_chunk_word_count <= (3/5) * prev_chunk_word_count:
            merged_text = prev_chunk['text'] + ' ' + last_chunk['text']
            merged_end_time = last_chunk['end_time']
            chunks[-2] = {
                'start_time': prev_chunk['start_time'],
                'end_time': merged_end_time,
                'text': merged_text
            }
            chunks.pop()
    
    if len(chunks) > 1:
        for i in range(1, len(chunks)):
            prev_chunk_text = chunks[i-1]['text']
            current_chunk_text = chunks[i]['text']
            if prev_chunk_text.endswith(current_chunk_text.split()[0]):
                chunks[i-1]['text'] = prev_chunk_text.rsplit(' ', 1)[0]
                chunks[i-1]['end_time'] = chunks[i]['start_time']
                chunks[i]['text'] = prev_chunk_text.rsplit(' ', 1)[1] + ' ' + current_chunk_text
    
    return chunks

def clean_chunks(chunks):
    cleaned_chunks = []
    for chunk in chunks:
        sentences = re.split(r'(?<=[.!?])\s+', chunk['text'])
        cleaned_sentences = []
        for sentence in sentences:
            sentence = re.sub(r'\.(?=\s*$)', '', sentence)
            if len(sentence.split()) > 1:
                cleaned_sentences.append(sentence)
        chunk['text'] = '. '.join(cleaned_sentences)
        if chunk['text']:
            cleaned_chunks.append(chunk)
            # print(cleaned_chunks)
    return cleaned_chunks

def generate_content(api_key, final_prompt, instructions):
    url = f'https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash-002:generateContent?key={api_key}'
    
    headers = {
        'Content-Type': 'application/json;charset=UTF-8',
    }
    
    data = {
        "contents":
            {
                "role": "user",
                "parts": [{"text": final_prompt}]
            }
        ,
        "systemInstruction": {
            "role": "user",
            "parts": [{"text": instructions}]
        },
        "generationConfig": {
            "temperature": 0.3,
            "topK": 30,
            "topP": 0.9,
            "maxOutputTokens": 8192,
            "responseMimeType": "text/plain"
        },
        "safetySettings": [
            {
                "category": "HARM_CATEGORY_HATE_SPEECH",
                "threshold": "BLOCK_NONE"
            },
            {
                "category": "HARM_CATEGORY_HARASSMENT",
                "threshold": "BLOCK_NONE"
            },
            {
                "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
                "threshold": "BLOCK_NONE"
            },
            {
                "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
                "threshold": "BLOCK_NONE"
            }
        ]
    }
    response = requests.post(url, headers=headers, json=data, )
    
    if response.status_code == 200:
        data = response.json()
        
        # print(data)
        content = data['candidates'][0]['content']['parts'][0]['text']
        # print(content)
        return content
    else:
        print("Failed to get a successful response. Status code:", response.status_code)
        print("Response:", response.text)
        return None

# Main execution
api_keys = ["AIzaSyDrPKUyloI2w9vMOI3mdg1hiQngFzJIZpw", 
            "AIzaSyDsArnxR5lJwnSqeKYfTY3mmk3yzvbidD4", 
            "AIzaSyC7E1VDWDr4C-1dJn_ZJcld71FeB5ohD-Y",
            "AIzaSyAnk7cugtt13Y3OXiHZeJ3HYg420u4VR6Y",
            "AIzaSyCzB1jsAPxD82Y7jpFREIO_NifO8m5kWuM"
            ]
            #lehungm88, uyenanhpham3210, anhhongpham3210, vaymuc, phuonglinhpham3210
usage_counts = {}

def select_api_key_and_update_usage(api_keys, usage_counts):
    min_usage = min(usage_counts.get(key, 0) for key in api_keys)
    least_used_keys = [key for key in api_keys if usage_counts.get(key, 0) == min_usage]
    
    selected_key = random.choice(least_used_keys)
    usage_counts[selected_key] = usage_counts.get(selected_key, 0) + 1
    
    return selected_key

def generate_content_with_api_key_rotation(final_prompt, instructions):
    api_key = select_api_key_and_update_usage(api_keys, usage_counts)
    result = generate_content(api_key, final_prompt, instructions)
    
    # Calculate current usage counts
    current_counts = {key: usage_counts.get(key, 0) for key in api_keys}
    print(current_counts)
    
    return result


transcript = """
"""
parsed_data = parse_transcript(transcript)
chunks = split_into_chunks(parsed_data)
cleaned_chunks = clean_chunks(chunks)

previous_chunk_text = ""
previous_content = ""



def check_wrapped_with_triple_asterisks(text):
    return text.startswith('***') and text.endswith('***')

def check_more_than_one_pair_of_triple_asterisks(text):
        return text.count('***') > 2

def check_plagiarism(previous_content, content, similarity_threshold=0.7):
    def clean_text(text):
        return ' '.join(text.split()[:150]).replace(' ', '').replace('\n', '')

    previous_cleaned = clean_text(previous_content)
    compared_content_cleaned = clean_text(content)

    average_length = (len(previous_cleaned) + len(compared_content_cleaned)) / 2
    edit_distance = levenshtein(previous_cleaned, compared_content_cleaned)
    avg_threshold_score = average_length * similarity_threshold

    return edit_distance, avg_threshold_score,  edit_distance <= avg_threshold_score


for i, chunk in enumerate(cleaned_chunks):
    instructions = (
        "You are a Vietnamese professional translator skilled in translating various languages into Vietnamese.\n"
        f"{previous_chunk_text}"
        "Your translation process are outlined as follow:\n"
        "Step 1. Simplify the new content by removing unnecessary words and phrases such as fillers (for example: wow, okay, yeah, oh, yep, blah, um, uh, ah, uhm, uh-oh, etc...) and discourse markers (for example: well, so, like, you know, etc...).\n"
        "Step 2. Correct any spelling or grammatical errors, including correcting any typos in proper names, to enhance clarity and precision.\n"
        "Step 3. Apply adaptation technique in translation to translate the refined, simplified content into Vietnamese, ensuring accuracy and faithfulness to the original meaning.\n"
        "Step 4. Wrap the Vietnamese version in triple asterisks (***). Provide only the Vietnamese version in your response. Exclude any non-Vietnamese version from your response.\n"
        "Step 5. Do not include any extra commentary such as preface, afterword, additional note, or additional explanation in your response.\n"
        "Step 6. Do not reproduce the initial context in your response."
    )
    # print(instructions)
    final_prompt = "Please leverage your initial context and apply your translation process to this new content enclosed within these following triple quotes: " + "'''" + chunk['text'] + "'''"
    # print(final_prompt)

    content = None
    retry_count = 0
    max_retries = 3

    while not content and retry_count < max_retries:
        content = generate_content_with_api_key_rotation(final_prompt, instructions)
        if not content:
            retry_count += 1
            print(f"Retry attempt {retry_count}...")
            time.sleep(5)  # Wait for 5 seconds before retrying

    if not content:
        print("Failed to generate content after 3 attempts. Moving to the next chunk.")
        continue

    if content:
        # Check if the response text is wrapped with triple asterisks
        isWrapped = check_wrapped_with_triple_asterisks(content)
        if isWrapped:
            print("Wrapped with triple asterisks:", isWrapped)

        # Check if the response text contains more than one pair of triple asterisks
        isOnePair = check_more_than_one_pair_of_triple_asterisks(content)
        if isOnePair == False:
            print("More than one pair of triple asterisks:", isOnePair)

        # Check if the response text is Vietnamese or other languages.
        isVietnamese = check_vietnamese(content, WORDS_SET, 'non_matches.txt')
        if isVietnamese > 0.7:
            print('Vietnamese with score more than 0.7 is:', isVietnamese)
        
        print(content)

        # Compare current content with previous content
        if previous_content:
            edit_distance, score, isPlagiarism = check_plagiarism(previous_content,content)
            if isPlagiarism:
                print("\nThe contents are considered plagiarism with", edit_distance, "<", score)
                print("Regenerating...")
                content = generate_content_with_api_key_rotation(final_prompt, instructions)
            else:
                print("\nThe contents are not considered plagiarism with", edit_distance, ">=", score )
        previous_content = content

        # print(content)
        time.sleep(5)
        print("\n")

    # Update previous_chunk_text for the next iteration
    previous_chunk_text = "[[" + "You are provided with the following initial context: " + str(content) + "]]" + ". The initial context, enclosed in these double square brackets, is essential for enhancing both the clarity and accuracy of your translation process.\n"
convert to javascript vanilla google chrome