this is my app.py code along with the document_summarisation.html code...in the generated document i am getting the words "LIST_ITEM" ,"IMAGE" and "*ITALIC","BOLD" and symbols like "_" and "__" ,"*"...please fix it ...also fix any issues in it *
"
from flask import Flask, render_template, request, jsonify, send_file
import google.generativeai as genai
from dotenv import load_dotenv
import os
from werkzeug.utils import secure_filename
from PIL import Image
import PIL
import io
from io import BytesIO
import logging
from langdetect import detect
import requests
from requests import get
from google.generativeai.types import GenerationConfig 
from markdown import markdown
from google.generativeai.types import GenerationConfig, HarmCategory, HarmBlockThreshold
import re
import json
from mailjet_rest import Client
from pdf2image import convert_from_bytes
from docx import Document
from docx.shared import Inches
import tempfile
import PyPDF2
import base64
from docx import Document
from docx.shared import Inches, Pt
from docx.enum.style import WD_STYLE_TYPE
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.shared import RGBColor
import fitz  # PyMuPDF

app = Flask(__name__)

# Load environment variables
load_dotenv()
mail_API_KEY = os.environ.get("mail_API_KEY")
mail_API_SECRET = os.environ.get("mail_API_SECRET")
mailjet = Client(auth=(mail_API_KEY, mail_API_SECRET), version='v3.1')
api_key = ""
unsplash_api_key = os.getenv('UNSPLASH_API_KEY')
API_KEY = os.getenv('OPENWEATHERMAP_API_KEY')

# Set up logging
logging.basicConfig(level=logging.INFO)

# Configure the Google Generative AI API
genai.configure(api_key=api_key)

# Session key
user_data = {}  # Dictionary to store user data

import os
import uuid
import time
from threading import Lock
from flask import Flask, render_template, request, jsonify, send_file
from werkzeug.utils import secure_filename
from PIL import Image
import io
import logging
import base64
import fitz  # PyMuPDF
# Firebase imports
import firebase_admin
from firebase_admin import credentials, firestore, storage

# Initialize Firebase
cred = credentials.Certificate('C:\\Users\\vamsi\\Downloads\\KV-Nexus-main (9)\\KV-Nexus-main\\V1 copy 18\\key2.json')
firebase_admin.initialize_app(cred, {
    'storageBucket': 'xxxxx'
})
db = firestore.client()
bucket = storage.bucket()
# Generation configurations
generation_config = GenerationConfig(
    temperature=0.9,
    top_p=1,
    top_k=1,
    max_output_tokens=2048,
    candidate_count=1
)
generation_config_health = GenerationConfig(
    temperature=0.7,
    top_p=1,
    top_k=1,
    max_output_tokens=512,
    candidate_count=1
)

# Safety Settings
safety_settings = {
    HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_NONE,
    HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_NONE,
    HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_NONE,
    HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_NONE,
}

# Create model instances
chat_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
chef_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
story_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
psychology_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
code_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
algorithm_model = genai.GenerativeModel("gemini-1.5-flash", generation_config=generation_config)
model_vision = genai.GenerativeModel('gemini-1.5-flash', generation_config=generation_config_health)
model_text = genai.GenerativeModel('gemini-pro', generation_config=generation_config_health)
model = genai.GenerativeModel('gemini-1.5-flash')

@app.route('/')
def index():
    return render_template('index.html')



def format_response(response_text):
    """Formats the response text for display."""
    lines = [line.strip() for line in response_text.split('\n') if line.strip()]
    formatted_text = '<br>'.join(lines)
    return formatted_text

# ... [Other route handlers remain unchanged] ...
import os
import uuid
import time
import json
from threading import Lock

from flask import Flask, render_template, request, jsonify, send_file
import google.generativeai as genai
from dotenv import load_dotenv
from werkzeug.utils import secure_filename
from PIL import Image
import io
import logging
import base64
import fitz  # PyMuPDF

# Import for persistent storage
from tinydb import TinyDB, Query


# Document summarizer with improved formatting
import tempfile
import time
from threading import Lock
from docx.enum.text import WD_ALIGN_PARAGRAPH, WD_BREAK
from docx.enum.table import WD_ALIGN_VERTICAL

# Rate limiting parameters
REQUEST_LIMIT = 15  # Adjust as needed
TIME_WINDOW = 60
request_count = 0
last_request_time = 0
rate_limit_lock = Lock()


def process_pdf_in_batches(file):
    """Processes PDF in batches to avoid exceeding Vercel's time limit"""
    pdf_document = fitz.open(stream=file.read(), filetype="pdf")
    total_pages = len(pdf_document)
    all_summaries = []
    batch_size = 1  # Process one page at a time

    for i in range(0, total_pages, batch_size):
        batch_texts = []
        batch_images = []
        for page_num in range(i, min(i + batch_size, total_pages)):
            page = pdf_document[page_num]
            text = page.get_text("text")
            batch_texts.append(text)

            # Image processing
            image_list = page.get_images(full=True)
            for img_index, img in enumerate(image_list):
                xref = img[0]
                base_image = pdf_document.extract_image(xref)
                image_bytes = base_image["image"]
                img = Image.open(io.BytesIO(image_bytes))
                batch_images.append(img)  # Directly append PIL Image

        batch_summary = generate_summary(batch_texts, batch_images)
        all_summaries.append(batch_summary)
        time.sleep(1)  # Adjust sleep based on response time

    final_summary = "\n\n".join(all_summaries)
    return final_summary, total_pages
from functools import wraps
def rate_limited(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        global request_count, last_request_time
        with rate_limit_lock:
            current_time = time.time()
            if current_time - last_request_time > TIME_WINDOW:
                request_count = 0
                last_request_time = current_time

            request_count += 1
            if request_count > REQUEST_LIMIT:
                remaining_time = TIME_WINDOW - (current_time - last_request_time)
                return jsonify({'error': f'Rate limit exceeded. Please try again in {int(remaining_time)} seconds.'}), 429

            last_request_time = current_time
        return func(*args, **kwargs)

    return wrapper

@app.route('/document_summarizer', methods=['GET', 'POST'])
def document_summarizer():
    return render_template('document_summarizer.html')

def process_pdf(file):
    pdf_document = fitz.open(stream=file.read(), filetype="pdf")
    images = []
    texts = []

    for page_num in range(len(pdf_document)):
        page = pdf_document[page_num]
        # Extract text
        text = page.get_text()
        texts.append(text)

        # Extract images
        image_list = page.get_images(full=True)
        for img_index, img in enumerate(image_list):
            xref = img[0]
            base_image = pdf_document.extract_image(xref)
            image_bytes = base_image["image"]
            # Convert to base64
            image_base64 = base64.b64encode(image_bytes).decode('utf-8')
            images.append(image_base64)

    return texts, images

@app.route('/process_pdf', methods=['POST'])
@rate_limited
def process_pdf_endpoint():
    data = request.get_json()
    pdf_id = data.get('pdf_id')
    if not pdf_id:
        return jsonify({'error': 'No PDF ID provided.'}), 400

    # Retrieve processing status from Firestore
    doc_ref = db.collection('pdf_processes').document(pdf_id)
    doc = doc_ref.get()
    if not doc.exists:
        return jsonify({'error': 'Invalid PDF ID.'}), 400
    result = doc.to_dict()

    try:
        blob = bucket.blob(f'pdfs/{pdf_id}.pdf')
        if not blob.exists():
            return jsonify({'error': 'File not found.'}), 404

        pdf_bytes = blob.download_as_bytes()
        pdf_document = fitz.open(stream=pdf_bytes, filetype="pdf")
        total_pages = result.get('total_pages', len(pdf_document))

        current_page = result['current_page']
        summary = result['summary']

        start_time = time.time()

        # Process pages until time limit is reached
        while current_page < total_pages and (time.time() - start_time) < 8:
            page = pdf_document[current_page]
            text = page.get_text()
            images = []

            # Extract images
            image_list = page.get_images(full=True)
            for img_index, img in enumerate(image_list):
                xref = img[0]
                base_image = pdf_document.extract_image(xref)
                image_bytes = base_image["image"]
                image_base64 = base64.b64encode(image_bytes).decode('utf-8')
                images.append(image_base64)

            # Generate summary for the page
            page_summary = generate_summary([text], images)
            summary += page_summary + '\n\n'

            current_page += 1
            # Update the processing status in Firestore
            doc_ref.update({'current_page': current_page, 'summary': summary})

        pdf_document.close()

        if current_page >= total_pages:
            # Processing complete
            doc_ref.update({'status': 'completed'})
            # Optionally delete the PDF from storage
            blob.delete()
            return jsonify({'status': 'completed'}), 200
        else:
            # Processing not complete
            return jsonify({'status': 'processing', 'current_page': current_page, 'total_pages': total_pages}), 200

    except Exception as e:
        return jsonify({'error': str(e)}), 500

def generate_summary(texts, images):
    # Modified prompt to encourage better formatting
    prompt = [
    """Summarize the following text, incorporating details from any included images.
    Ensure that the summary is well-structured with clear headings and subheadings.
    Use the following formatting guidelines:

    - Use 'TITLE: [Your Title]' for main sections.
    - Use 'SUBTITLE: [Your Subtitle]' for subsections.
    - For emphasis, use 'BOLD:[Your Text]' to make the text bold.
    - For important points, use 'ITALIC:[Your Text]' to italicize the text.
    - For lists, use 'LIST_ITEM: [Your List Item]' at the start of each item.
    - For tables, present data in a structured format using 'TABLE_START', 'TABLE_ROW', and 'TABLE_END' tags.

    **Please avoid using asterisks (*) or other symbols for formatting. Use only the specified formatting markers.**

    Example:

    TITLE: Introduction
    SUBTITLE: Background
    BOLD: This is an important concept.
    ITALIC: Note this subtle point.
    LIST_ITEM: First point
    LIST_ITEM: Second point
    TABLE_START
    TABLE_ROW: Column1 | Column2 | Column3
    TABLE_ROW: Data1 | Data2 | Data3
    TABLE_END

    Use simple and easy English. Keep the summary concise but informative.
    """,
    "\n".join(texts)
]

    for img in images:
        prompt.append(img)
        
    try:
        response = model_vision.generate_content(prompt, safety_settings=safety_settings)
        return response.text
    except Exception as e:
        print(f"Error in Gemini API call: {e}")
        return f"Error summarizing: {e}"

# ... [Imports and other code remain unchanged] ...

def create_word_document(summary):
    doc = Document()
    
    # Define and customize styles
    styles = doc.styles
    
    # Title style
    title_style = styles.add_style('CustomTitle', WD_STYLE_TYPE.PARAGRAPH)
    title_style.font.name = 'Calibri Light'
    title_style.font.size = Pt(26)
    title_style.font.bold = True
    title_style.font.color.rgb = RGBColor(31, 56, 100)  # Dark blue
    title_style.paragraph_format.space_before = Pt(24)
    title_style.paragraph_format.space_after = Pt(12)
    title_style.paragraph_format.keep_with_next = True

    # Subtitle style
    subtitle_style = styles.add_style('CustomSubtitle', WD_STYLE_TYPE.PARAGRAPH)
    subtitle_style.font.name = 'Calibri'
    subtitle_style.font.size = Pt(18)
    subtitle_style.font.bold = True
    subtitle_style.font.color.rgb = RGBColor(54, 95, 145)  # Medium blue
    subtitle_style.paragraph_format.space_before = Pt(18)
    subtitle_style.paragraph_format.space_after = Pt(6)
    subtitle_style.paragraph_format.keep_with_next = True

    # Normal text style
    normal_style = styles.add_style('CustomNormal', WD_STYLE_TYPE.PARAGRAPH)
    normal_style.font.name = 'Calibri'
    normal_style.font.size = Pt(12)
    normal_style.paragraph_format.space_after = Pt(8)
    normal_style.paragraph_format.line_spacing = 1.15

    # List item style
    list_style = styles.add_style('CustomList', WD_STYLE_TYPE.PARAGRAPH)
    list_style.font.name = 'Calibri'
    list_style.font.size = Pt(12)
    list_style.paragraph_format.left_indent = Inches(0.25)
    list_style.paragraph_format.first_line_indent = Inches(-0.25)
    list_style.paragraph_format.space_after = Pt(4)
    list_style.paragraph_format.line_spacing = 1.15

    # Process the summary
    paragraphs = summary.split('\n')
    in_table = False
    table_rows = []
    
    # Function to process inline formatting
    def process_text_line(paragraph, text, default_style=None):
        import re
        # Pattern to match **bold**, *italic*
        pattern = re.compile(r'\*\*(.*?)\*\*|\*(.*?)\*')
        last_end = 0
        for match in pattern.finditer(text):
            start, end = match.span()
            # Text before the match
            if start > last_end:
                run = paragraph.add_run(text[last_end:start])
                if default_style == 'bold':
                    run.bold = True
                elif default_style == 'italic':
                    run.italic = True
            # Matched text
            if match.group(1):  # Bold text
                run = paragraph.add_run(match.group(1))
                run.bold = True
                if default_style == 'bold':
                    run.bold = True
                elif default_style == 'italic':
                    run.italic = True
            elif match.group(2):  # Italic text
                run = paragraph.add_run(match.group(2))
                run.italic = True
                if default_style == 'bold':
                    run.bold = True
                elif default_style == 'italic':
                    run.italic = True
            last_end = end
        # Text after the last match
        if last_end < len(text):
            run = paragraph.add_run(text[last_end:])
            if default_style == 'bold':
                run.bold = True
            elif default_style == 'italic':
                run.italic = True

    for para in paragraphs:
        para = para.strip()
    
        if para.startswith('TITLE:'):
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomTitle')
            process_text_line(p, para[6:].strip())
            p.alignment = WD_ALIGN_PARAGRAPH.CENTER
    
        elif para.startswith('SUBTITLE:'):
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomSubtitle')
            process_text_line(p, para[9:].strip())
    
        elif para.startswith('BOLD:'):
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomNormal')
            process_text_line(p, para[5:].strip(), default_style='bold')
    
        elif para.startswith('ITALIC:'):
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomNormal')
            process_text_line(p, para[7:].strip(), default_style='italic')
    
        elif para.startswith('LIST_ITEM:'):
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomList')
            run = p.add_run('• ')
            run.font.size = Pt(10)
            process_text_line(p, para[10:].strip())
    
        elif para.startswith('TABLE_START'):
            in_table = True
            table_rows = []
    
        elif para.startswith('TABLE_ROW:'):
            in_table = True
            row_data = [cell.strip() for cell in para[10:].split('|')]
            table_rows.append(row_data)
    
        elif para.startswith('TABLE_END'):
            add_table_to_document(doc, table_rows)
            table_rows = []
            in_table = False
    
        elif para:
            if in_table:
                add_table_to_document(doc, table_rows)
                table_rows = []
                in_table = False
            p = doc.add_paragraph('', style='CustomNormal')
            process_text_line(p, para.strip())
    
    if in_table:
        add_table_to_document(doc, table_rows)
    
    # Add page borders
    set_page_border(doc)
    
    # Set up the document layout
    section = doc.sections[0]
    section.page_height = Inches(11)
    section.page_width = Inches(8.5)
    section.left_margin = Inches(1)
    section.right_margin = Inches(1)
    section.top_margin = Inches(1)
    section.bottom_margin = Inches(1)
    
    docx_buffer = io.BytesIO()
    doc.save(docx_buffer)
    docx_buffer.seek(0)
    return docx_buffer

# ... [Rest of the code remains unchanged] ...
def add_table_to_document(doc, rows):
    if not rows:
        return
    table = doc.add_table(rows=len(rows), cols=len(rows[0]))
    table.style = 'Light List Accent 1'  # Choose a more visually appealing style

    # Set column widths and alignment
    widths = [Inches(2.0)] * len(rows[0])  # Adjust column widths as needed
    for row_idx, row in enumerate(rows):
        for col_idx, cell_text in enumerate(row):
            cell = table.cell(row_idx, col_idx)
            cell.text = cell_text
            cell.width = widths[col_idx]
            cell.vertical_alignment = WD_ALIGN_VERTICAL.CENTER
            cell.paragraphs[0].alignment = WD_ALIGN_PARAGRAPH.CENTER

    # Make the header row bold and with background color
    hdr_cells = table.rows[0].cells
    for cell in hdr_cells:
        for paragraph in cell.paragraphs:
            for run in paragraph.runs:
                run.font.bold = True
        shading_elm = OxmlElement('w:shd')
        shading_elm.set(qn('w:fill'), 'D9E1F2')  # Light blue background
        cell._tc.get_or_add_tcPr().append(shading_elm)

    table.allow_autofit = True
    doc.add_paragraph()  # Add space after table

def set_page_border(doc):
    """
    Adds a wider double border to every page of the document.
    """
    for section in doc.sections:
        sectPr = section._sectPr
        pgBorders = OxmlElement('w:pgBorders')
        pgBorders.set(qn('w:offsetFrom'), 'page')
        for border_position in ('top', 'left', 'bottom', 'right'):
            border_el = OxmlElement(f'w:{border_position}')
            border_el.set(qn('w:val'), 'double')
            border_el.set(qn('w:sz'), '24')  # Adjusted border width
            border_el.set(qn('w:space'), '24')
            border_el.set(qn('w:color'), '5B9BD5')  # Blue border color
            pgBorders.append(border_el)
        sectPr.append(pgBorders)

@app.route('/upload', methods=['POST'])
@rate_limited
def upload_file():
    if 'file' not in request.files:
        return jsonify({'error': 'No file part'}), 400
    file = request.files['file']
    if file.filename == '':
        return jsonify({'error': 'No selected file'}), 400

    if file and file.filename.endswith('.pdf'):
        try:
            # Generate a unique PDF ID
            pdf_id = str(uuid.uuid4())

            # Upload the PDF to Firebase Storage
            blob = bucket.blob(f'pdfs/{pdf_id}.pdf')
            blob.upload_from_file(file)

            # Get the total number of pages
            pdf_document = fitz.open(stream=blob.download_as_bytes(), filetype="pdf")
            total_pages = len(pdf_document)
            pdf_document.close()

            # Initialize processing status in Firestore
            db.collection('pdf_processes').document(pdf_id).set({
                'status': 'processing',
                'current_page': 0,
                'total_pages': total_pages,
                'summary': '',
                'timestamp': firestore.SERVER_TIMESTAMP
            })

            return jsonify({'pdf_id': pdf_id}), 200
        except Exception as e:
            return jsonify({'error': str(e)}), 500
    else:
        return jsonify({'error': 'Invalid file type. Please upload a PDF.'}), 400
# ... [Other route handlers remain unchanged] ...
@app.route('/check_status', methods=['GET'])
def check_status():
    pdf_id = request.args.get('pdf_id')
    if not pdf_id:
        return jsonify({'error': 'No PDF ID provided.'}), 400

    # Retrieve processing status from Firestore
    doc_ref = db.collection('pdf_processes').document(pdf_id)
    doc = doc_ref.get()
    if not doc.exists:
        return jsonify({'error': 'Invalid PDF ID.'}), 400
    result = doc.to_dict()

    status = result.get('status', 'processing')
    if status == 'completed':
        # Create word document
        summary = result['summary']
        docx_buffer = create_word_document(summary)
        # Encode the docx file to base64
        docx_base64 = base64.b64encode(docx_buffer.getvalue()).decode('utf-8')
        return jsonify({
            'status': 'completed',
            'docx': docx_base64,
            'total_pages': result.get('total_pages', 0),
            'processing_time': 'N/A'  # Optionally calculate processing time
        }), 200
    else:
        return jsonify({
            'status': 'processing',
            'current_page': result.get('current_page', 0),
            'total_pages': result.get('total_pages', 0)
        }), 200

# ... [Include the rest of your functions like create_word_document, generate_summary, etc.] ...

# Test upload to Cloud Storage

if __name__ == '__main__':
    app.run(debug=True)
"
"
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PDF Summarizer</title>
    <link href="https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400;500;700&family=Roboto:wght@300;400;500;700&family=Dancing+Script:wght@600&family=Kaushan+Script&display=swap" rel="stylesheet" />
    <link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet" />
    <link href="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.css" rel="stylesheet" />
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js" defer></script>
    <script src="https://cdn.jsdelivr.net/particles.js/2.0.0/particles.min.js"></script>
    <script src="https://unpkg.com/typewriter-effect@latest/dist/core.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.5.1/dist/confetti.browser.min.js"></script>
    <style>
        body {
            font-family: 'Montserrat', sans-serif;
            background-image: url('https://images.stockcake.com/public/4/e/f/4ef87898-2e97-4e79-8da4-9a82a2288fed/enchanted-nighttime-reading-stockcake.jpg'); 
            background-size: cover;
            background-repeat: no-repeat;
            background-attachment: fixed;
        }
        .glass-effect {
            background: rgba(255, 255, 255, 0.15);
            backdrop-filter: blur(10px);
            -webkit-backdrop-filter: blur(10px);
            border: 1px solid rgba(255, 255, 255, 0.2);
            box-shadow: 0 8px 32px 0 rgba(31, 38, 135, 0.37);
        }
        .animate-fade-in {
            opacity: 0;
            animation: fadeIn 0.5s ease-in forwards;
        }
        @keyframes fadeIn {
            to {
                opacity: 1;
            }
        }
        .loader {
            border-top-color: #3498db;
            animation: spinner 1s linear infinite;
        }
        @keyframes spinner {
            to {
                transform: rotate(360deg);
            }
        }
        .animated-bg {
            background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
            background-size: 400% 400%;
            animation: gradientBG 15s ease infinite;
        }
        @keyframes gradientBG {
            0% {
                background-position: 0% 50%;
            }
            50% {
                background-position: 100% 50%;
            }
            100% {
                background-position: 0% 50%;
            }
        }
        .hover-effect {
            transition: all 0.3s ease;
        }
        .hover-effect:hover {
            transform: translateY(-5px);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.2);
        }
        @media (max-width: 768px) {
            .flex-container {
                flex-direction: column;
            }
            .quote-container {
                width: 100%;
                margin-bottom: 2rem;
            }
            .main-content {
                width: 100%;
                padding-left: 0;
            }
            #title {
                font-size: 3rem;
            }
            .file-upload-label {
                height: 12rem;
            }
        }
    </style>
</head>
<body class="min-h-screen flex items-center justify-center p-4"> 
    <div id="particles-js" class="absolute inset-0"></div>
    <div class="bg-white bg-opacity-50 rounded-2xl shadow-2xl w-full max-w-6xl p-4 sm:p-8 animate-fade-in flex flex-container glass-effect relative z-10">
        <!-- Quote of the Day -->
        <div class="quote-container w-full sm:w-1/3 p-6 rounded-2xl text-white flex flex-col items-center justify-center animated-bg mb-4 sm:mb-0" data-aos="fade-right">
            <h2 class="text-3xl sm:text-4xl font-bold mb-4" style="font-family: 'Kaushan Script', cursive;">Quote of the Day</h2>
            <p id="quote" class="text-xl sm:text-2xl text-center"></p>
        </div>
        <!-- Main Content -->
        <div class="main-content w-full sm:w-2/3 sm:pl-8">
            <!-- Header -->
            <div class="text-center mb-8" data-aos="zoom-in">
                <h1 id="title" class="text-4xl sm:text-6xl font-extrabold bg-clip-text text-transparent bg-gradient-to-r from-blue-600 to-teal-400">
                    PDF Summarizer
                </h1>
                <p class="text-green-700 mt-4 text-lg">
                    Quickly generate summaries of your PDF documents
                </p>
            </div>

            <!-- Upload Form -->
            <form id="upload-form" class="space-y-6" enctype="multipart/form-data">
                <!-- File Upload -->
                <div class="flex items-center justify-center w-full" data-aos="fade-up">
                    <label for="file" class="file-upload-label relative flex flex-col items-center justify-center w-full h-48 sm:h-64 border-4 border-dashed rounded-2xl cursor-pointer bg-white hover:bg-gray-50 transition duration-500 ease-in-out transform hover:scale-105 glass-effect">
                        <div class="flex flex-col items-center justify-center">
                            <i class="fas fa-cloud-upload-alt text-5xl sm:text-7xl text-blue-500 mb-4 animate-bounce"></i>
                            <p class="mb-2 text-base sm:text-lg text-gray-700 text-center">
                                <span class="font-semibold">Click to upload</span>
                                or drag and drop
                            </p>
                            <p class="text-sm text-gray-500">
                                PDF files only (Max 10MB)
                            </p>
                        </div>
                        <input id="file" name="file" type="file" class="absolute inset-0 opacity-0 cursor-pointer" accept=".pdf"/>
                    </label>
                </div>

                <!-- File Preview -->
                <div id="file-preview" class="hidden bg-gray-50 p-4 rounded-lg border border-gray-200 glass-effect" data-aos="fade-up">
                    <h3 class="font-semibold text-gray-700 mb-2">
                        Selected File:
                    </h3>
                    <div class="flex items-center">
                        <i class="far fa-file-pdf text-red-500 text-2xl mr-2"></i>
                        <span id="file-name" class="text-gray-800"></span>
                    </div>
                </div>

                <!-- Submit Button -->
                <button type="submit" class="w-full bg-gradient-to-r from-purple-500 to-pink-500 text-white py-4 px-6 rounded-xl font-bold shadow-lg hover:from-purple-600 hover:to-pink-600 transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-105 focus:outline-none focus:ring-4 focus:ring-purple-200 hover-effect" data-aos="zoom-in-up">
                    Summarize PDF
                </button>
            </form>

            <!-- Loading Indicator -->
            <div id="loading" class="hidden mt-8 flex flex-col items-center" data-aos="fade-up">
                <div class="loader ease-linear rounded-full border-8 border-t-8 border-gray-200 h-16 w-16 mb-4"></div>
                <p class="text-lg font-medium text-gray-700 mb-2">
                    Processing your PDF, please wait...
                </p>
                <p class="text-sm text-gray-600">
                    Processing large PDFs may take several minutes
                </p>
                <p id="progress-text" class="text-sm text-gray-600 mt-2"></p>
            </div>

            <!-- Result Section -->
            <div id="result" class="hidden mt-8 animate-fade-in" data-aos="fade-up">
                <h2 class="text-3xl font-semibold mb-4 text-gray-800">
                    Your Summary is Ready!
                </h2>
                <div class="mb-4">
                    <p class="text-lg text-gray-700">
                        Total pages processed: <span id="total-pages" class="font-semibold">0</span>
                    </p>
                    <p class="text-lg text-gray-700">
                        Processing time: <span id="processing-time" class="font-semibold">0</span> seconds
                    </p>
                </div>
                <button id="download-button" class="inline-flex items-center bg-green-500 text-white py-3 px-6 rounded-xl font-semibold shadow-lg hover:bg-green-600 transition duration-500 ease-in-out transform hover:-translate-y-1 hover:scale-105 focus:outline-none focus:ring-4 focus:ring-green-200 hover-effect">
                    <i class="fas fa-download mr-2"></i> Download Summary
                </button>
            </div>
        </div>
    </div>
    <!-- AOS JS -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/aos/2.3.4/aos.js"></script>
    <!-- Initialize AOS -->
    <script>
        AOS.init({
            duration: 1000,
            once: true,
        });
    </script>
    <script>
        const form = document.getElementById('upload-form');
        const fileUpload = document.getElementById('file');
        const filePreview = document.getElementById('file-preview');
        const fileName = document.getElementById('file-name');
        const loading = document.getElementById('loading');
        const result = document.getElementById('result');
        const downloadButton = document.getElementById('download-button');
        const quoteElement = document.getElementById('quote');
        const progressText = document.getElementById('progress-text');

        // Random Fonts and Colors
        const fonts = [
            'Dancing Script',
            'Kaushan Script',
            'Montserrat',
            'Roboto',
            'Courier New',
            'Georgia',
            'Times New Roman',
        ];
        const colors = [
            '#ff6b6b',
            '#feca57',
            '#48dbfb',
            '#1dd1a1',
            '#5f27cd',
            '#222f3e',
            '#ee5253',
            '#0abde3',
            '#10ac84',
            '#341f97',
        ];

        // Apply Random Font and Color to Quote
        function styleQuote() {
            const randomFont =
                fonts[Math.floor(Math.random() * fonts.length)];
            const randomColor =
                colors[Math.floor(Math.random() * colors.length)];
            quoteElement.style.fontFamily = randomFont;
            quoteElement.style.color = randomColor;
            gsap.from(quoteElement, {
                opacity: 0,
                y: -20,
                duration: 1,
                ease: "bounce.out",
            });
        }

        // Fetch Quote from Server
        async function fetchQuote() {
            try {
                const response = await fetch('/quote');
                if (response.ok) {
                    const data = await response.json();
                    quoteElement.textContent = `${data.quote}`;
                    styleQuote();
                } else {
                    quoteElement.textContent =
                        'Error fetching quote. Please try again later.';
                }
            } catch (error) {
                quoteElement.textContent =
                    'Error fetching quote. Please try again later.';
            }
        }

        // Load Quote on Page Load
        window.addEventListener('load', fetchQuote);

        // File Upload Preview
        fileUpload.addEventListener('change', (e) => {
            const file = e.target.files[0];
            if (file) {
                fileName.textContent = file.name;
                filePreview.classList.remove('hidden');
                gsap.from(filePreview, {
                    opacity: 0,
                    y: -20,
                    duration: 0.5,
                });
            }
        });

        // Form Submission
        form.addEventListener('submit', async (e) => {
            e.preventDefault();
            const formData = new FormData(form);
        
            // Show loading
            form.classList.add('hidden');
            loading.classList.remove('hidden');
            progressText.textContent = 'Uploading file...';
        
            try {
                // Upload the file and get pdf_id
                const response = await fetch('/upload', {
                    method: 'POST',
                    body: formData,
                });
        
                if (response.ok) {
                    const data = await response.json();
                    const pdfId = data.pdf_id;
    
                    // Start processing the PDF
                    progressText.textContent = 'Processing your PDF...';
                    await processPdf(pdfId);
                } else {
                    throw new Error('Upload failed');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred. Please try again or upload a smaller PDF file.');
                loading.classList.add('hidden');
                form.classList.remove('hidden');
            }
        });
        
        async function processingLoop(pdfId) {
            try {
                const response = await fetch('/process_pdf', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({pdf_id: pdfId}),
                });
    
                if (response.ok) {
                    const data = await response.json();
                    if (data.status === 'completed') {
                        await checkStatus(pdfId);
                    } else if (data.status === 'processing') {
                        progressText.textContent = `Processed ${data.current_page} of ${data.total_pages} pages...`;
                        // Poll again after a short delay
                        setTimeout(() => processingLoop(pdfId), 1000);
                    } else {
                        throw new Error(data.error || 'Processing failed');
                    }
                } else {
                    throw new Error('Processing failed');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred during processing. Please try again later.');
                loading.classList.add('hidden');
                form.classList.remove('hidden');
            }
        }

        // Process PDF
        async function processPdf(pdfId) {
            try {
                // First, check the status
                const statusResponse = await fetch(`/check_status?pdf_id=${pdfId}`);
                if (statusResponse.ok) {
                    const statusData = await statusResponse.json();
                    if (statusData.status === 'completed') {
                        // If already completed, proceed to download
                        await checkStatus(pdfId);
                    } else {
                        // Start the processing loop
                        await processingLoop(pdfId);
                    }
                } else {
                    throw new Error('Failed to check initial status.');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred during processing. Please try again later.');
                loading.classList.add('hidden');
                form.classList.remove('hidden');
            }
        }

        // Check Status and Download
        async function checkStatus(pdfId) {
            try {
                const response = await fetch(`/check_status?pdf_id=${pdfId}`);
                if (response.ok) {
                    const data = await response.json();
                    if (data.status === 'completed') {
                        // Hide loading and show result
                        loading.classList.add('hidden');
                        result.classList.remove('hidden');
                        triggerConfetti();
    
                        // Update UI with processing details
                        document.getElementById('total-pages').textContent = data.total_pages;
                        document.getElementById('processing-time').textContent = data.processing_time || 'N/A';
    
                        // Create blob from base64 data
                        const binaryData = atob(data.docx);
                        const array = new Uint8Array(binaryData.length);
                        for (let i = 0; i < binaryData.length; i++) {
                            array[i] = binaryData.charCodeAt(i);
                        }
                        const blob = new Blob([array], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
                        const url = window.URL.createObjectURL(blob);
    
                        // Set up download button
                        downloadButton.addEventListener('click', () => {
                            const link = document.createElement('a');
                            link.href = url;
                            link.download = 'summary.docx';
                            document.body.appendChild(link);
                            link.click();
                            document.body.removeChild(link);
                        });
                    } else if (data.status === 'processing') {
                        // Update progress text
                        progressText.textContent = `Processed ${data.current_page} of ${data.total_pages} pages...`;
                        // Poll for status again
                        setTimeout(() => checkStatus(pdfId), 1000);
                    } else {
                        throw new Error(data.error || 'Unknown status');
                    }
                } else {
                    throw new Error('Failed to check status');
                }
            } catch (error) {
                console.error('Error:', error);
                alert('An error occurred while checking the status. Please try again later.');
                loading.classList.add('hidden');
                form.classList.remove('hidden');
            }
        }

        // Particle effect
        particlesJS("particles-js", {
            particles: {
                number: { value: 80, density: { enable: true, value_area: 800 } },
                color: { value: "#ffffff" },
                shape: { type: "circle", stroke: { width: 0, color: "#000000" }, polygon: { nb_sides: 5 } },
                opacity: { value: 0.5, random: false, anim: { enable: false, speed: 1, opacity_min: 0.1, sync: false } },
                size: { value: 3, random: true, anim: { enable: false, speed: 40, size_min: 0.1, sync: false } },
                line_linked: { enable: true, distance: 150, color: "#ffffff", opacity: 0.4, width: 1 },
                move: { enable: true, speed: 6, direction: "none", random: false, straight: false, out_mode: "out", bounce: false, attract: { enable: false, rotateX: 600, rotateY: 1200 } }
            },
            interactivity: {
                detect_on: "canvas",
                events: { onhover: { enable: true, mode: "repulse" }, onclick: { enable: true, mode: "push" }, resize: true },
                modes: { grab: { distance: 400, line_linked: { opacity: 1 } }, bubble: { distance: 400, size: 40, duration: 2, opacity: 8, speed: 3 }, repulse: { distance: 200, duration: 0.4 }, push: { particles_nb: 4 }, remove: { particles_nb: 2 } }
            },
            retina_detect: true
        });

        // Typewriter effect for the title
        const titleElement = document.getElementById('title');
        new Typewriter(titleElement, {
            strings: ['PDF Summarizer'],
            autoStart: true,
            loop: true,
            delay: 75,
            deleteSpeed: 50,
        });

        // Confetti effect on successful upload
        function triggerConfetti() {
            confetti({
                particleCount: 100,
                spread: 70,
                origin: { y: 0.6 }
            });
        }

        // Add smooth scrolling to all links
        document.querySelectorAll('a[href^="#"]').forEach(anchor => {
            anchor.addEventListener('click', function (e) {
                e.preventDefault();

                document.querySelector(this.getAttribute('href')).scrollIntoView({
                    behavior: 'smooth'
                });
            });
        });

        // Parallax effect removed (we're using a fixed background image)

        // Add hover effect to buttons
        const buttons = document.querySelectorAll('button, a');
        buttons.forEach(button => {
            button.addEventListener('mouseenter', () => {
                gsap.to(button, { scale: 1.05, duration: 0.3 });
            });
            button.addEventListener('mouseleave', () => {
                gsap.to(button, { scale: 1, duration: 0.3 });
            });
        });

        // Add a subtle animation to the quote section
        gsap.to('.animated-bg', {
            backgroundPosition: '100% 50%',
            duration: 10,
            repeat: -1,
            yoyo: true,
            ease: 'power1.inOut'
        });
    </script>
</body>
</html>
"