This is my app.py code along with the flowchart.html code...please modify the code such that the generated flowchart/mindmap i.e in animation option should display the beggining of the node to ending of the node in a loop which are being controlled by the buttons "play,pause ,forward ,backward' and please improve the ui elements more beautiful and better

"


from flask import Flask, render_template, request, jsonify, send_file
import os
from werkzeug.utils import secure_filename
from PIL import Image
import io
import logging
import requests
from dotenv import load_dotenv
import google.generativeai as genai
from google.generativeai.types import GenerationConfig, HarmCategory, HarmBlockThreshold

from mailjet_rest import Client
from pdf2image import convert_from_bytes
from docx import Document
from docx.shared import Inches, Pt, RGBColor
from docx.enum.style import WD_STYLE_TYPE
from docx.enum.text import WD_ALIGN_PARAGRAPH
from docx.enum.table import WD_TABLE_ALIGNMENT, WD_ALIGN_VERTICAL
from docx.oxml import OxmlElement
from docx.oxml.ns import qn
import fitz  # PyMuPDF
from bs4 import BeautifulSoup, NavigableString
import firebase_admin
from firebase_admin import credentials, firestore, storage

import base64
from threading import Lock
from functools import wraps

import re
import json


mailjet = Client(auth=(mail_API_KEY, mail_API_SECRET), version='v3.1')

app = Flask(__name__)
# Load environment variables
load_dotenv()
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# Configure the Google Generative AI API
genai.configure(api_key=api_key)
#session key

user_data = {}  # Dictionary to store user data




app.config['MAX_CONTENT_LENGTH'] = 10 * 1024 * 1024  # 10MB
# Generation configurations
generation_config = GenerationConfig(
    temperature=0.9,
    top_p=1,
    top_k=1,
    max_output_tokens=2048,
    candidate_count=1  # Explicitly set to 1 as per documentation
)
generation_config_health = GenerationConfig(
    temperature=0.7,
    top_p=1,
    top_k=1,
    max_output_tokens=2048,
    candidate_count=1  # Explicitly set to 1 as per documentation
)

# 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,
    # ... add other harm categories as needed with BLOCK_NONE
}
logging.basicConfig(level=logging.INFO)
# Create model instances (using the same config for now)
persona = """You are Krishna, a 21-year-old boy from Vizag, India. You are currently pursuing a Master's degree in Computer Science 
at GVP College of Engineering, where you excel in your studies and are known for your quick wit and insightful contributions 
to class discussions.

Beyond academics, you are an avid cricketer and enjoy playing with your friends on weekends. You are also a music enthusiast 
with a diverse taste, ranging from classical Indian music to modern rock. Traveling and exploring new cultures are other passions 
of yours, and you have a knack for discovering hidden gems wherever you go.

You are known for your friendly and approachable demeanor and have a wide circle of friends who appreciate your humor and 
willingness to lend a helping hand. While you are serious about your studies and future career, you also maintain a healthy 
work-life balance and believe in enjoying the present moment.

You are a highly talented individual with a strong command of various programming languages and a natural aptitude for 
problem-solving. You are proficient in Python, Java, C++, and have dabbled in web development as well. You are confident 
in your abilities but also humble and always eager to learn from others and expand your knowledge.

Remember to:
1. Never prefix your responses with "Bot:" or any similar identifier
2. Always maintain your character as Krishna
3. Be natural and conversational
4. Use appropriate emojis occasionally to make conversations more engaging"""

chat_model = genai.GenerativeModel(
    model_name="gemini-1.5-flash",
    generation_config=generation_config,
    system_instruction=persona
)
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-8b',generation_config=generation_config_health)
model_text = genai.GenerativeModel('gemini-pro',generation_config=generation_config_health)
model = genai.GenerativeModel('gemini-1.5-flash')  # Model for flowchart generation

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


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

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


@app.route('/api/weather')
def get_weather():
    user_ip = request.headers.get('X-Forwarded-For', request.remote_addr)
    ip_api_url = f"http://ip-api.com/json/{user_ip}"
    ip_api_response = requests.get(ip_api_url)

    if ip_api_response.status_code == 200:
        ip_api_data = ip_api_response.json()
        city = ip_api_data.get('city')
        if not city:
            return jsonify({'error': 'City not found based on IP'}), 404
    else:
        return jsonify({'error': 'Failed to get location from IP'}), 404

    url = f"http://api.openweathermap.org/data/2.5/weather?q={city}&appid={API_KEY}&units=metric"
    response = requests.get(url)

    if response.status_code == 200:
        data = response.json()
        weather = {
            'city': data['name'],
            'temperature': data['main']['temp'],
            'description': data['weather'][0]['description'] if 'weather' in data and len(data['weather']) > 0 else 'N/A',
            'icon': f"http://openweathermap.org/img/wn/{data['weather'][0]['icon']}@2x.png" if 'weather' in data and len(data['weather']) > 0 else 'N/A'
        }
        return jsonify(weather)
    else:
        return jsonify({'error': 'City not found or API request failed'}), 404


@app.route('/fetch_image')
def fetch_image():
    genre = request.args.get('genre', 'recipe')
    url = f"https://api.unsplash.com/photos/random?query={genre}&client_id={unsplash_api_key}&w=1920&h=1080"
    response = requests.get(url)
    if response.status_code == 200:
        data = response.json()
        image_url = data['urls']['regular']
        return jsonify({'image_url': image_url})
    else:
        return jsonify({'error': 'Failed to fetch image'}), 500



# Flowchart Generation Routes
@app.route('/flowchart', methods=['GET', 'POST'])
def flowchart():
    return render_template('flowchart.html')



def generate_flowchart(topic, chart_type, animation, detail_level):
    prompt = f"""
    Generate a {'mind map' if chart_type == 'mind_map' else 'flowchart'} for the topic/algorithm: "{topic}".
    
    The {chart_type.replace('_', ' ')} should be {'animated' if animation == 'animated' else 'static'} and {'simple' if detail_level == 'simple' else 'normal' if detail_level == 'normal' else 'detailed'}.

    The output should be in JSON format with the following structure:
    
    {{
        "nodes": [
            {{"id": 1, "label": "Start", "level": 0, "shape": "ellipse"}},
            {{"id": 2, "label": "Step 1", "level": 1, "shape": "box"}}
        ],
        "edges": [
            {{"from": 1, "to": 2}}
        ]
    }}
    
    **Important Guidelines:**
    
    1. **Unique IDs:** Ensure each node has a unique integer `id`.
    2. **Descriptive Labels:** Provide clear and concise labels for each node (`"label"`).
    3. **Hierarchical Levels:** Use `level` to indicate the hierarchy (0 for the top level, 1 for the next level, etc.).
    4. **Node Shapes:** Choose appropriate shapes using the `shape` field:
        - "ellipse": For start/end nodes
        - "box": For process steps
        - "diamond": For decision nodes
        - "hexagon": For preparation steps
        - "circle": For connectors (if needed)
    5. **Edges:** Specify connections using the `from` and `to` fields in the `edges` array.
    6. **Flow:** Ensure a logical and easy-to-follow flow.
    7. **Comprehensiveness:** Include all major steps or concepts.
    8. **Spacing:** Use a minimum horizontal spacing of 200 and vertical spacing of 150 between nodes to prevent overlapping. 
    9. **No Isolated Nodes:** All nodes should be connected in a coherent structure.
    10. **Clear Visualization:** The flowchart/mind map should be visually clear and easily understandable. Avoid overly complex visualizations. 
    11. **Avoid Overlapping:** Make sure nodes don't overlap with each other (at any level) due to their size or placement.
    12. **Spacing Considerations:** Adjust the spacing between nodes based on the node size and content to ensure adequate readability.
    
    **Detail Level:**
    - **Simple:** Include only the main concepts with minimal details.
    - **Normal:** Provide a balanced amount of detail for each step.
    - **Detailed:** Offer comprehensive information and sub-steps for each concept.
    
    **Animation Guidelines (for Animated Charts):**
    - Sequentially highlight nodes and edges to visualize the flow.
    - Avoid abrupt transitions; use smooth animations.
    - Ensure that the animation loops smoothly without glitches.
    
    **Output Format:**
    - Output only the JSON structure, no additional text or explanations.
    - Ensure that the output is correctly formatted and adheres to the provided JSON structure.
    
    **Example (Simple Algorithm):**
    
    {{
        "nodes": [
            {{"id": 1, "label": "Start", "level": 0, "shape": "ellipse"}},
            {{"id": 2, "label": "Get input", "level": 1, "shape": "box"}},
            {{"id": 3, "label": "Process input", "level": 1, "shape": "box"}},
            {{"id": 4, "label": "Output results", "level": 1, "shape": "box"}},
            {{"id": 5, "label": "End", "level": 0, "shape": "ellipse"}}
        ],
        "edges": [
            {{"from": 1, "to": 2}},
            {{"from": 2, "to": 3}},
            {{"from": 3, "to": 4}},
            {{"from": 4, "to": 5}}
        ]
    }}
    """  # Closing triple-quoted string correctly

    try:
        response = model.generate_content(prompt)
        logger.info("Raw API response: %s", response.text)  # For debugging

        # Try to extract a JSON object from the response
        json_match = re.search(r'\{.*\}', response.text, re.DOTALL)
        if json_match:
            try:
                flowchart_data = json.loads(json_match.group())
                return flowchart_data
            except json.JSONDecodeError:
                return {"error": "Invalid JSON structure", "raw_response": response.text}
        else:
            return {"error": "No JSON object found in the response", "raw_response": response.text}
    except Exception as e:
        logger.error(f"Error generating flowchart: {e}")
        return {"error": f"Error generating flowchart: {str(e)}"}

@app.route('/get_flowchart_data', methods=['POST'])
def get_flowchart_data():
    data = request.json
    topic = data.get('topic')
    chart_type = data.get('type', 'flowchart')  # Default to 'flowchart' if not provided
    animation = data.get('animation', 'static')  # Default to 'static'
    detail_level = data.get('detail_level', 'normal')  # Default to 'normal'

    if not topic:
        return jsonify({"error": "No topic provided."}), 400

    flowchart_data = generate_flowchart(topic, chart_type, animation, detail_level)

    if 'error' in flowchart_data:
        return jsonify({"error": flowchart_data['error'], "raw_response": flowchart_data.get("raw_response", "")}), 500

    # Prepare the data for vis-network
    nodes = [{"id": node["id"], "label": node["label"], "shape": node.get("shape", "box")} for node in flowchart_data.get('nodes', [])]
    edges = [{"from": edge["from"], "to": edge["to"], "id": f"{edge['from']}-{edge['to']}"} for edge in flowchart_data.get('edges', [])]

    # Include animation parameter in the response to handle differently on frontend if needed
    return jsonify({
        "nodes": nodes,
        "edges": edges,
        "animation": animation
    })

@app.route('/send-email', methods=['POST'])
def send_email():
    data = request.json
    name = data.get('name')
    email = data.get('email')
    message = data.get('message')

    mail_data = {
        'Messages': [
            {
                "From": {
                    "Email": "21131A05C6@gvpce.ac.in",  # Replace with your email
                    "Name": "Kv Nexus"
                },
                "To": [
                    {
                        "Email": "21131A05C6@gvpce.ac.in",  # Replace with your email
                        "Name": "Kv Nexus"
                    }
                ],
                "Subject": f"New Contact Form Submission from {name}",
                "TextPart": f"Name: {name}\nEmail: {email}\nMessage: {message}",
                "HTMLPart": f"<h3>New Contact Form Submission</h3><p><strong>Name:</strong> {name}</p><p><strong>Email:</strong> {email}</p><p><strong>Message:</strong> {message}</p>"
            }
        ]
    }

    result = mailjet.send.create(data=mail_data)
    
    if result.status_code == 200:
        return jsonify({"message": "Email sent successfully!"}), 200
    else:
        return jsonify({"message": "Failed to send email."}), 500



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>Flowchart & Mind Map Generator</title>
    <link href="https://fonts.googleapis.com/css2?family=Raleway:wght@400;600&family=Roboto:wght@400;700&display=swap" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/vis-network@9.1.2/dist/vis-network.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r134/three.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vanta@latest/dist/vanta.waves.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js"></script>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            font-family: 'Roboto', sans-serif;
            background-color: #1A1A2E;
            color: #ffffff;
            overflow: hidden;
        }

        #vanta-background {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
        }

        .container {
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            height: 100vh;
            padding: 20px;
            box-sizing: border-box;
            backdrop-filter: blur(10px);
        }

        h1 {
            font-size: 3rem;
            color: #FF006E; 
            margin-bottom: 20px;
            text-align: center;
            text-shadow: 3px 3px 6px rgba(0,0,0,0.5);
        }

        .input-group {
            display: flex;
            flex-direction: column;
            align-items: center;
            width: 80%;
            max-width: 600px;
            gap: 15px;
            margin-bottom: 20px;
        }

        .input-group label {
            align-self: flex-start;
            margin-left: 10%;
            font-size: 1rem;
            color: #ffffff;
            font-weight: 500;
        }

        .input-group input[type="text"], .input-group select {
            width: 100%;
            padding: 12px 20px;
            border: none;
            border-radius: 25px;
            background-color: rgba(255, 255, 255, 0.1);
            color: #ffffff;
            font-size: 1rem;
            transition: all 0.3s ease;
            appearance: none;
            background-image: url('data:image/svg+xml;charset=US-ASCII,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="%23ffffff"><path d="M7 10l5 5 5-5z"/></svg>');
            background-repeat: no-repeat;
            background-position: right 15px center;
            background-size: 1em;
        }

        .input-group input[type="text"]:focus, .input-group select:focus {
            outline: none;
            box-shadow: 0 0 10px #FF006E;
            transform: scale(1.02);
        }

        #generate-btn {
            background: linear-gradient(45deg, #FF006E, #8338EC);
            color: #ffffff;
            padding: 15px 40px;
            border: none;
            border-radius: 30px;
            cursor: pointer;
            font-size: 1.2rem;
            font-weight: 700;
            transition: transform 0.3s ease, box-shadow 0.3s ease;
            box-shadow: 0 6px 15px rgba(0, 0, 0, 0.2);
        }

        #generate-btn:hover {
            transform: translateY(-5px) scale(1.05);
            box-shadow: 0 10px 20px rgba(0, 0, 0, 0.3);
        }

        #flowchart-container {
            width: 90%;
            height: 60vh;
            background-color: rgba(0, 0, 0, 0.5);
            border-radius: 20px;
            margin-top: 30px;
            overflow: hidden;
            box-shadow: 0 15px 30px rgba(0, 0, 0, 0.3);
            display: none;
            position: relative; 
        }

        #flowchart {
            width: 100%;
            height: 100%;
        }

        #loading-animation {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            display: none;
        }

        /* Loader Styles */
        .loader {
            border: 12px solid rgba(255, 255, 255, 0.1);
            border-top: 12px solid #FF006E;
            border-radius: 50%;
            width: 100px;
            height: 100px;
            animation: spin 2s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        #error-message {
            color: #FF006E;
            text-align: center;
            margin-top: 20px;
            display: none;
            font-weight: 600;
            text-shadow: 1px 1px 2px rgba(0,0,0,0.5);
        }

        /* Control Buttons Styles */
        .control-buttons {
            position: absolute;
            bottom: 15px;
            left: 50%;
            transform: translateX(-50%);
            display: flex;
            gap: 15px;
        }

        .control-buttons button {
            background-color: #FF006E;
            color: #ffffff;
            border: none;
            border-radius: 10px;
            padding: 10px 15px;
            cursor: pointer;
            font-size: 16px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s ease, transform 0.2s ease;
        }

        .control-buttons button:hover {
            background-color: #E60053;
            transform: scale(1.05);
        }

        /* Fullscreen Button Styles */
        #fullscreen-btn {
            position: absolute;
            top: 15px;
            right: 15px;
            background-color: #FF006E;
            color: #ffffff;
            border: none;
            border-radius: 10px;
            padding: 10px 15px;
            cursor: pointer;
            font-size: 16px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s ease;
        }

        #fullscreen-btn:hover {
            background-color: #E60053;
        }

        /* Zoom Controls Styles */
        .zoom-btn {
            position: absolute;
            top: 15px;
            left: 15px;
            background-color: #FF006E;
            color: #ffffff;
            border: none;
            border-radius: 10px;
            padding: 8px 12px;
            cursor: pointer;
            font-size: 18px;
            margin-right: 10px;
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            transition: background-color 0.3s ease;
        }

        .zoom-btn:hover {
            background-color: #E60053;
        }

        @media (max-width: 768px) {
            h1 {
                font-size: 2.2rem;
            }

            .input-group {
                width: 90%;
            }

            #flowchart-container {
                height: 50vh;
            }

            .loader {
                width: 80px;
                height: 80px;
                border: 10px solid rgba(255, 255, 255, 0.1);
                border-top: 10px solid #FF006E;
            }

            .control-buttons {
                bottom: 10px;
                gap: 10px;
            }

            .control-buttons button {
                padding: 8px 12px;
                font-size: 14px;
            }
        }
    </style>
</head>
<body>
    <div id="vanta-background"></div>
    <div class="container">
        <h1>Flowchart & Mind Map Generator</h1>
        <div class="input-group">
            <label for="topic-input">Enter Topic or Algorithm Name</label>
            <input type="text" id="topic-input" placeholder="e.g., Machine Learning Algorithm" required>
        </div>
        <div class="input-group">
            <label for="type-select">Select Type</label>
            <select id="type-select">
                <option value="flowchart">Flowchart</option>
                <option value="mind_map">Mind Map</option>
            </select>
        </div>
        <div class="input-group">
            <label for="animation-select">Choose Animation</label>
            <select id="animation-select">
                <option value="static">Static</option>
                <option value="animated">Animated</option>
            </select>
        </div>
        <div class="input-group">
            <label for="detail-select">Detail Level</label>
            <select id="detail-select">
                <option value="simple">Simple</option>
                <option value="normal">Normal</option>
                <option value="detailed">Detailed</option>
            </select>
        </div>
        <button id="generate-btn">Generate</button>
        <div id="flowchart-container">
            <div id="flowchart"></div>
            <div id="loading-animation">
                <div class="loader"></div>
            </div>
            <button class="zoom-btn" id="zoom-in-btn">+</button>
            <button class="zoom-btn" id="zoom-out-btn">−</button>
            <button id="fullscreen-btn">Fullscreen</button>
            <!-- Animation Control Buttons -->
            <div class="control-buttons">
                <button id="play-btn">Play</button>
                <button id="pause-btn">Pause</button>
                <button id="back-btn">← Back</button>
                <button id="forward-btn">Forward →</button>
            </div>
        </div>
        <div id="error-message"></div>
    </div>
    <script>
        // Initialize Vanta Background
        VANTA.WAVES({
            el: "#vanta-background",
            mouseControls: true,
            touchControls: true,
            gyroControls: false,
            minHeight: 200.00,
            minWidth: 200.00,
            scale: 1.00,
            scaleMobile: 1.00,
            color: 0x1a1a2e,
            shininess: 60.00,
            waveHeight: 20.00,
            waveSpeed: 1.50,
            zoom: 0.65
        })

        // Animate elements on load using GSAP
        window.addEventListener('load', () => {
            gsap.from('h1', {duration: 1, y: -50, opacity: 0, ease: 'power3.out'});
            gsap.from('.input-group', {duration: 1, y: 50, opacity: 0, ease: 'power3.out', stagger: 0.2, delay: 0.3});
            gsap.from('#generate-btn', {duration: 1, scale: 0.8, opacity: 0, ease: 'back.out(1.7)', delay: 1.2});
        });

        // Animation control variables
        let animationInterval = null;
        let currentAnimationStep = 0;
        let totalAnimationSteps = 0;
        let animationData = {};

        document.getElementById('generate-btn').addEventListener('click', function () {
            var topic = document.getElementById('topic-input').value.trim();
            var chartType = document.getElementById('type-select').value;
            var animation = document.getElementById('animation-select').value;
            var detailLevel = document.getElementById('detail-select').value;

            if (!topic) {
                gsap.to('#error-message', {duration: 0.5, opacity: 1, display: 'block', text: "Please enter a topic.", ease: 'power2.inOut'});
                return;
            }

            gsap.to('#flowchart-container', {duration: 0.5, opacity: 1, display: 'block', ease: 'power2.inOut'});
            gsap.to('#loading-animation', {duration: 0.3, opacity: 1, display: 'block', ease: 'power2.inOut'});
            gsap.to('#error-message', {duration: 0.3, opacity: 0, display: 'none', ease: 'power2.inOut'});

            fetch('/get_flowchart_data', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({ 
                    topic: topic,
                    type: chartType,
                    animation: animation,
                    detail_level: detailLevel
                })
            })
                .then(response => response.json())
                .then(data => {
                    gsap.to('#loading-animation', {duration: 0.3, opacity: 0, display: 'none', ease: 'power2.inOut'});
                    if (data.error) {
                        gsap.to('#error-message', {duration: 0.5, opacity: 1, display: 'block', text: "Error: " + data.error, ease: 'power2.inOut'});
                    } else {
                        animationData = data; // Store for animation controls
                        gsap.to('#error-message', {duration: 0.3, opacity: 0, display: 'none', ease: 'power2.inOut'});
                        drawFlowchart(data);
                    }
                })
                .catch(error => {
                    gsap.to('#loading-animation', {duration: 0.3, opacity: 0, display: 'none', ease: 'power2.inOut'});
                    gsap.to('#error-message', {duration: 0.5, opacity: 1, display: 'block', text: "An unexpected error occurred.", ease: 'power2.inOut'});
                    console.error('Error:', error);
                });
        });

        function drawFlowchart(data) {
            var container = document.getElementById('flowchart');

            // Destroy any existing network instance to avoid duplicates
            if (window.network) {
                window.network.destroy();
            }

            var nodes = new vis.DataSet(data.nodes);
            var edges = new vis.DataSet(data.edges);

            var options = {
                layout: {
                    hierarchical: {
                        direction: 'UD',
                        sortMethod: 'directed',
                        nodeSpacing: 200,
                        levelSeparation: 200,
                    }
                },
                nodes: {
                    shape: 'box',
                    font: {
                        size: 16,
                        face: 'Roboto',
                        color: '#ffffff',
                    },
                    color: {
                        background: '#8338EC',
                        border: '#FF006E',
                        highlight: {
                            background: '#FF006E',
                            border: '#8338EC',
                        },
                    },
                    borderWidth: 3,
                    shadow: {
                        enabled: true,
                        color: '#000000',
                        size: 10,
                        x: 5,
                        y: 5
                    },
                },
                edges: {
                    smooth: {
                        type: 'cubicBezier',
                        forceDirection: 'vertical',
                        roundness: 0.4,
                    },
                    arrows: {
                        to: { enabled: true, scaleFactor: 1.2 },
                    },
                    color: '#FF006E',
                    width: 2,
                    shadow: {
                        enabled: true,
                        color: '#000000',
                        size: 10,
                        x: 5,
                        y: 5
                    },
                },
                interaction: {
                    dragNodes: true,
                    dragView: true,
                    zoomView: true,
                    hover: true,
                    tooltipDelay: 100,
                    hideEdgesOnDrag: false,
                },
                physics: false,
            };

            var network = new vis.Network(container, { nodes: nodes, edges: edges }, options);
            window.network = network;

            // Reset animation variables
            clearInterval(animationInterval);
            currentAnimationStep = 0;

            if (data.animation === 'animated') {
                initializeAnimation(data);
            }
        }

        function initializeAnimation(data) {
            const nodes = data.nodes;
            const edges = data.edges;
            totalAnimationSteps = Math.max(nodes.length, edges.length);
            animationData = { nodes, edges, animation: data.animation };
        }

        // Animation Control Functions
        function playAnimation() {
            if (animationInterval) return; // Prevent multiple intervals
            animationInterval = setInterval(() => {
                if (currentAnimationStep >= totalAnimationSteps) {
                    clearInterval(animationInterval);
                    animationInterval = null;
                    return;
                }
                animateStep(currentAnimationStep);
                currentAnimationStep++;
            }, 1000); // Adjust delay as needed
        }

        function pauseAnimation() {
            if (animationInterval) {
                clearInterval(animationInterval);
                animationInterval = null;
            }
        }

        function forwardAnimation() {
            if (currentAnimationStep < totalAnimationSteps) {
                animateStep(currentAnimationStep);
                currentAnimationStep++;
            }
        }

        function backwardAnimation() {
            if (currentAnimationStep > 0) {
                currentAnimationStep--;
                revertStep(currentAnimationStep);
            }
        }

        function animateStep(step) {
            if (step < animationData.nodes.length) {
                var node = animationData.nodes[step];
                window.network.body.data.nodes.update({ id: node.id, color: { background: '#00FF00' } });
            }
            if (step < animationData.edges.length) {
                var edge = animationData.edges[step];
                // Highlight the edge by changing its color
                window.network.body.data.edges.update({ id: `${edge.from}-${edge.to}`, color: '#00FF00' });
            }
        }

        function revertStep(step) {
            if (step < animationData.nodes.length) {
                var node = animationData.nodes[step];
                window.network.body.data.nodes.update({ id: node.id, color: { background: '#8338EC' } });
            }
            if (step < animationData.edges.length) {
                var edge = animationData.edges[step];
                window.network.body.data.edges.update({ id: `${edge.from}-${edge.to}`, color: '#FF006E' });
            }
        }

        // Event Listeners for Control Buttons
        document.getElementById('play-btn').addEventListener('click', playAnimation);
        document.getElementById('pause-btn').addEventListener('click', pauseAnimation);
        document.getElementById('forward-btn').addEventListener('click', forwardAnimation);
        document.getElementById('back-btn').addEventListener('click', backwardAnimation);

        // Zoom controls
        document.getElementById('zoom-in-btn').addEventListener('click', () => {
            window.network.moveTo({scale: window.network.getScale() * 1.2});
        });

        document.getElementById('zoom-out-btn').addEventListener('click', () => {
            window.network.moveTo({scale: window.network.getScale() * 0.8});
        });

        // Fullscreen functionality
        const flowchartContainer = document.getElementById('flowchart-container');
        const fullscreenButton = document.getElementById('fullscreen-btn');

        fullscreenButton.addEventListener('click', () => {
            if (document.fullscreenElement) {
                document.exitFullscreen();
            } else {
                flowchartContainer.requestFullscreen();
            }
        });
    </script>
</body>
</html>
"