im unable to get the data drawn to the matplotlib object, can you debug (or find the cause and output working code?)
# main.py
import os
from flask import Flask, request, jsonify, render_template_string
from openai import OpenAI
import json
import numpy as np
from sklearn.decomposition import PCA

app = Flask(__name__)

# Initialize OpenAI client (Ensure you have set the OPENAI_API_KEY environment variable)
client = OpenAI()

def get_related_phrases(string_pair, num_related=50, logs=[]):
    """
    Retrieve related phrases based on the input string pair using OpenAI's GPT-4o-mini model.
    """
    string1, string2 = string_pair
    prompt = (
        f"Generate {num_related} unique and relevant phrases that combine the concepts of '{string1}' and '{string2}'. "
        f"Each phrase should be meaningful and contextually appropriate. Provide them as a comma-separated list."
    )
    
    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are a creative assistant that generates relevant phrases based on given concepts."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=3000,
            temperature=0.7,
        )
        
        # Access the content using attribute access
        phrases_text = response.choices[0].message.content
        logs.append(f"Generated phrases for pair ({string1}, {string2}).")
        # Split phrases by commas and strip whitespace
        phrases = [phrase.strip() for phrase in phrases_text.split(',') if phrase.strip()]
        # Ensure exactly num_related phrases
        return phrases[:num_related]
    except Exception as e:
        logs.append(f"Error generating related phrases: {e}")
        print(f"Error generating related phrases: {e}")
        return []

def get_embedding(text, model="text-embedding-ada-002", logs=[]):
    """
    Retrieve the embedding for a given text using OpenAI's API.
    """
    text = text.replace("\n", " ")
    try:
        response = client.embeddings.create(
            input=[text],
            model=model
        )
        embedding = response.data[0].embedding
        logs.append(f"Retrieved embedding of length {len(embedding)} for text: '{text}'.")
        print(f"Retrieved embedding of length {len(embedding)} for text: '{text}'")  # Debug statement
        return embedding
    except Exception as e:
        logs.append(f"Error retrieving embedding for text '{text}': {e}")
        print(f"Error retrieving embedding for text '{text}': {e}")
        return [0]*1536  # Return a zero vector as fallback

def generate_axis_names(strings, pca_components, logs=[]):
    """
    Generate meaningful axis names using OpenAI's GPT-4o-mini based on the input strings and PCA components.
    """
    string1, string2, string3, string4 = strings
    prompt = (
        f"Given the following four concepts: '{string1}', '{string2}', '{string3}', and '{string4}', "
        f"and the PCA components: {pca_components.tolist()}, provide three meaningful and significant axis names for a 3D plot. "
        f"Each axis name should reflect the underlying data structure and the relationship between the concepts. "
        f"Respond exactly in JSON format as follows:\n"
        "{\n"
        '  "x_axis": "Axis Name 1",\n'
        '  "y_axis": "Axis Name 2",\n'
        '  "z_axis": "Axis Name 3"\n'
        "}"
    )
    
    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are an assistant that creates meaningful axis names based on given concepts and PCA components."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=150,
            temperature=0.3,
        )
        
        axis_names = response.choices[0].message.content
        axis_dict = json.loads(axis_names)
        logs.append("Generated axis names using GPT-4o-mini.")
        return axis_dict
    except Exception as e:
        logs.append(f"Error generating axis names: {e}")
        print(f"Error generating axis names: {e}")
        # Fallback axis names
        return {"x_axis": "Axis 1", "y_axis": "Axis 2", "z_axis": "Axis 3"}

def analyze_data(prompt, logs=[]):
    """
    Analyze the data based on the given prompt.
    """
    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are a data analyst that provides insightful analysis based on provided data points."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=500,
            temperature=0.5,
        )
        analysis = response.choices[0].message.content
        logs.append("Generated analysis using GPT-4o-mini.")
        return analysis
    except Exception as e:
        logs.append(f"Error generating analysis: {e}")
        print(f"Error generating analysis: {e}")
        return "Unable to generate analysis."

@app.route('/')
def index():
    """
    Serve the HTML page for the application.
    """
    html = """
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Interactive 3D Vector Visualizer</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                background-color: #121212; /* Dark background */
                color: #ffffff; /* White text for contrast */
                margin: 0;
                padding: 0;
                display: flex;
                height: 100vh;
                overflow: hidden;
            }
            /* Container for resizable panels */
            .container {
                display: flex;
                width: 100%;
                height: 100%;
            }
            /* Sidebar on the Left */
            .sidebar {
                width: 300px;
                background-color: #1e1e1e;
                padding: 20px;
                box-sizing: border-box;
                overflow-y: auto;
                resize: horizontal;
                min-width: 200px;
                border-right: 2px solid #333333;
            }
            .sidebar h1 {
                color: #aecfff; /* Pastel Aqua Blue */
                text-align: center;
                margin-bottom: 20px;
            }
            .input-box {
                margin-bottom: 15px;
            }
            .input-box label {
                display: block;
                margin-bottom: 5px;
                color: #aecfff; /* Pastel Aqua Blue */
                font-weight: bold;
                text-align: left; /* Align labels to the left */
            }
            .input-box input {
                width: 100%;
                padding: 8px;
                border: none;
                border-radius: 4px;
                font-size: 1em;
                background-color: #2e2e2e;
                color: #ffffff;
            }
            .controls {
                display: flex;
                justify-content: space-between;
                margin-bottom: 15px;
            }
            .num-points {
                display: flex;
                flex-direction: column;
                width: 48%;
            }
            .num-points label {
                color: #aecfff; /* Pastel Aqua Blue */
                font-weight: bold;
                margin-bottom: 5px;
                text-align: left; /* Align labels to the left */
            }
            .num-points .input-container {
                display: flex;
                align-items: center;
                justify-content: flex-start;
                margin-bottom: 5px; /* Add margin for spacing */
            }
            .num-points button {
                padding: 8px;
                border: none;
                border-radius: 4px;
                font-size: 1em;
                cursor: pointer;
                background-color: #aecfff; /* Pastel Aqua Blue */
                color: #000000;
                margin-right: 5px;
            }
            .num-points button:hover {
                background-color: #8fbfd6; /* Darker Pastel Aqua Blue */
            }
            .num-points input {
                width: 60px;
                text-align: center;
                padding: 8px;
                border: none;
                border-radius: 4px;
                background-color: #2e2e2e;
                color: #ffffff;
                font-size: 1em;
                margin-right: 5px;
            }
            /* Removed plot-options from sidebar */
            /* Buttons */
            .submit-button, .fullscreen-button {
                width: 100%;
                padding: 10px;
                margin-top: 10px;
                background-color: #aecfff; /* Pastel Aqua Blue */
                border: none;
                border-radius: 4px;
                cursor: pointer;
                color: #000000;
                font-size: 1em;
                transition: background-color 0.3s;
                font-weight: bold;
            }
            .submit-button:hover, .fullscreen-button:hover {
                background-color: #8fbfd6; /* Darker Pastel Aqua Blue */
            }
            /* Log Area */
            .log-area {
                background-color: #1e1e1e;
                padding: 10px;
                border-radius: 4px;
                margin-top: 20px;
                max-height: 200px;
                overflow-y: auto;
            }
            .log-area h2 {
                color: #aecfff; /* Pastel Aqua Blue */
                text-align: center;
                margin-top: 0;
            }
            .log-area p {
                margin: 5px 0;
                color: #ffffff;
                font-size: 0.9em;
            }
            /* Resizer between sidebar and main-content */
            .resizer1 {
                width: 5px;
                background-color: #333333;
                cursor: ew-resize;
            }
            /* Main Content in the Center */
            .main-content {
                flex-grow: 1;
                display: flex;
                flex-direction: column;
                align-items: center;
                justify-content: center;
                position: relative;
                background-color: #000000;
            }
            /* Top Bar with Action Buttons and Plot Type */
            .top-bar {
                width: 100%;
                background-color: #1e1e1e;
                padding: 10px;
                box-sizing: border-box;
                display: flex;
                justify-content: flex-start;
                gap: 10px;
                position: absolute;
                top: 0;
                left: 0;
            }
            .top-bar button {
                padding: 8px 12px;
                background-color: #aecfff; /* Pastel Aqua Blue */
                border: none;
                border-radius: 4px;
                cursor: pointer;
                color: #000000;
                font-size: 1em;
                transition: background-color 0.3s;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .top-bar button:hover {
                background-color: #8fbfd6; /* Darker Pastel Aqua Blue */
            }
            .top-bar .plot-type-container {
                margin-left: auto;
                display: flex;
                align-items: center;
                gap: 5px;
            }
            .top-bar .plot-type-container label {
                color: #aecfff; /* Pastel Aqua Blue */
                font-weight: bold;
            }
            .top-bar .plot-type-container select {
                padding: 8px;
                border: none;
                border-radius: 4px;
                background-color: #2e2e2e;
                color: #ffffff;
                font-size: 1em;
                cursor: pointer;
            }
            /* Plot Area */
            #result {
                width: 80%;
                height: 80%;
                margin-top: 60px; /* To prevent overlap with top bar */
                background-color: #121212;
                border-radius: 8px;
                box-shadow: 0 0 10px #aecfff;
            }
            /* Resizer between main-content and right-panel */
            .resizer2 {
                width: 5px;
                background-color: #333333;
                cursor: ew-resize;
            }
            /* Right Panel with Legend and Chat */
            .right-panel {
                width: 300px;
                background-color: #1e1e1e;
                padding: 20px;
                box-sizing: border-box;
                overflow-y: auto;
                resize: horizontal;
                min-width: 200px;
                display: flex;
                flex-direction: column;
                gap: 20px;
                border-left: 2px solid #333333;
            }
            /* Tabs */
            .tabs {
                display: flex;
                border-bottom: 1px solid #555555;
            }
            .tab {
                flex: 1;
                padding: 10px 0;
                cursor: pointer;
                background-color: #1e1e1e;
                border: none;
                outline: none;
                transition: background-color 0.3s;
                color: #ffffff;
                font-size: 1em;
                text-align: center;
            }
            .tab:hover, .tab.active {
                background-color: #333333;
                color: #aecfff; /* Pastel Aqua Blue */
            }
            .tab-content {
                display: none;
                flex-grow: 1;
                overflow-y: auto;
            }
            .tab-content.active {
                display: block;
            }
            /* Legend Styling */
            #legend {
                width: 100%;
                background-color: #1e1e1e;
                padding: 10px;
                box-sizing: border-box;
                overflow-y: auto;
                border-radius: 8px;
            }
            /* Dark scrollbar */
            #legend::-webkit-scrollbar {
                width: 8px;
            }
            #legend::-webkit-scrollbar-track {
                background: #1e1e1e; 
                border-radius: 4px;
            }
            #legend::-webkit-scrollbar-thumb {
                background: #555555; 
                border-radius: 4px;
            }
            #legend::-webkit-scrollbar-thumb:hover {
                background: #777777; 
            }
            #legend-list {
                list-style: none; /* Remove bullets */
                padding: 0;
                margin: 0;
            }
            #legend-list li {
                margin-bottom: 5px;
                cursor: pointer;
                padding: 5px;
                border-radius: 4px;
                transition: background-color 0.3s;
                color: #ffffff;
            }
            #legend-list li:hover {
                background-color: #333333;
            }
            .collapsible {
                background-color: #1e1e1e;
                color: #ffffff;
                cursor: pointer;
                padding: 10px;
                width: 100%;
                border: none;
                text-align: left;
                outline: none;
                font-size: 16px;
                border-radius: 4px;
                transition: background-color 0.3s;
            }
            .active, .collapsible:hover {
                background-color: #333333;
            }
            .content {
                padding-left: 15px;
                display: none;
                overflow: hidden;
                background-color: #242424;
                border-radius: 4px;
            }
            .content li {
                padding: 5px;
                margin: 3px 0;
                border-radius: 4px;
                transition: background-color 0.3s;
                color: #dddddd;
                font-size: 14px;
            }
            .content li:hover {
                background-color: #555555;
                color: #ffffff;
            }
            /* Chat Styles */
            .chat-container {
                display: flex;
                flex-direction: column;
                height: 100%;
            }
            .chat-summary {
                background-color: #2e2e2e;
                padding: 10px;
                border-radius: 4px;
                margin-bottom: 10px;
                color: #aecfff; /* Pastel Aqua Blue */
                text-align: left;
            }
            .chat-messages {
                flex-grow: 1;
                background-color: #242424;
                padding: 10px;
                border-radius: 4px;
                overflow-y: auto;
                margin-bottom: 10px;
            }
            .chat-input {
                display: flex;
                align-items: center;
                width: 100%;
            }
            .chat-input input {
                flex-grow: 1;
                padding: 8px;
                border: none;
                border-radius: 4px 0 0 4px;
                font-size: 1em;
                background-color: #2e2e2e;
                color: #ffffff;
            }
            .chat-input button {
                padding: 8px;
                background-color: #aecfff; /* Pastel Aqua Blue */
                border: none;
                border-radius: 0 4px 4px 0;
                cursor: pointer;
                color: white;
                display: flex;
                align-items: center;
                justify-content: center;
            }
            .chat-input button:hover {
                background-color: #8fbfd6; /* Darker Pastel Aqua Blue */
            }
            /* Modal Overlay for Full Screen View */
            .modal {
                display: none; /* Hidden by default */
                position: fixed; /* Stay in place */
                z-index: 1; /* Sit on top */
                padding-top: 60px; /* Location of the box */
                left: 0;
                top: 0;
                width: 100%; /* Full width */
                height: 100%; /* Full height */
                overflow: auto; /* Enable scroll if needed */
                background-color: rgba(0,0,0,0.9); /* Black w/ opacity */
            }
            .close-button {
                position: absolute;
                top: 20px;
                right: 35px;
                color: #ffffff;
                font-size: 40px;
                font-weight: bold;
                transition: color 0.3s;
                cursor: pointer;
            }
            .close-button:hover,
            .close-button:focus {
                color: #aecfff; /* Pastel Aqua Blue */
                text-decoration: none;
                cursor: pointer;
            }
            .modal-content {
                margin: auto;
                display: block;
                width: 80%;
                max-width: 700px;
            }
            @media only screen and (max-width: 700px){
                .modal-content {
                    width: 100%;
                }
            }
        </style>
        <!-- Include Plotly.js -->
        <script src="https://cdn.plot.ly/plotly-latest.min.js"></script>
        <!-- Include FontAwesome for icons -->
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
    </head>
    <body>
        <!-- Loading Spinner with Status -->
        <div class="spinner-overlay" id="spinnerOverlay">
            <div class="spinner"></div>
            <div id="loadingStatus">Initializing...</div>
        </div>
        <div class="container">
            <!-- Sidebar on the Left -->
            <div class="sidebar">
                <h1>3D Vector Inputs</h1>
                <div class="inputs">
                    <div class="input-box">
                        <label for="string1">Input String 1:</label>
                        <input type="text" id="string1" name="string1" placeholder="e.g., financial river bank institute">
                    </div>
                    <div class="input-box">
                        <label for="string2">Input String 2:</label>
                        <input type="text" id="string2" name="string2" placeholder="e.g., river bank place by the river">
                    </div>
                    <div class="input-box">
                        <label for="string3">Input String 3:</label>
                        <input type="text" id="string3" name="string3" placeholder="e.g., sustainability initiatives">
                    </div>
                    <div class="input-box">
                        <label for="string4">Input String 4:</label>
                        <input type="text" id="string4" name="string4" placeholder="e.g., community outreach programs">
                    </div>
                    <div class="controls">
                        <div class="num-points">
                            <label for="numPoints">Data Points</label>
                            <div class="input-container">
                                <button onclick="decrementPoints()" title="Decrease number of data points">-</button>
                                <input type="number" id="numPoints" name="numPoints" value="50" min="50" max="1000" step="50" title="Number of data points">
                                <button onclick="incrementPoints()" title="Increase number of data points">+</button>
                            </div>
                        </div>
                    </div>
                    <!-- Removed plot-options from sidebar -->
                    <button class="submit-button" onclick="submitStrings()" title="Generate and visualize data points">Submit</button>
                    <button class="fullscreen-button" onclick="openModal()" title="View plot in full screen">View Full Screen</button>
                </div>
                <div class="log-area" id="logArea">
                    <h2>Logs</h2>
                    <div id="logs"></div>
                </div>
            </div>
            
            <div class="resizer1"></div>
            
            <!-- Main Content in the Center -->
            <div class="main-content">
                <div class="top-bar">
                    <button onclick="rotateLeft()" title="Rotate left"><i class="fas fa-rotate-left"></i></button>
                    <button onclick="rotateRight()" title="Rotate right"><i class="fas fa-rotate-right"></i></button>
                    <button onclick="zoomIn()" title="Zoom in"><i class="fas fa-search-plus"></i></button>
                    <button onclick="zoomOut()" title="Zoom out"><i class="fas fa-search-minus"></i></button>
                    <button onclick="panUp()" title="Pan up"><i class="fas fa-arrow-up"></i></button>
                    <button onclick="panDown()" title="Pan down"><i class="fas fa-arrow-down"></i></button>
                    <button onclick="changeView()" title="Change view perspective"><i class="fas fa-sync-alt"></i></button>
                    <div class="plot-type-container">
                        <label for="topPlotType">Plot Type:</label>
                        <select id="topPlotType" onchange="changePlotType()">
                            <option value="markers">Markers</option>
                            <option value="lines">Lines</option>
                            <option value="markers+lines">Markers + Lines</option>
                        </select>
                    </div>
                </div>
                <div id="result"></div>
            </div>
            
            <div class="resizer2"></div>
            
            <!-- Right Panel with Legend and Chat -->
            <div class="right-panel">
                <div class="tabs">
                    <button class="tab active" onclick="openTab(event, 'Legend')">Legend</button>
                    <button class="tab" onclick="openTab(event, 'I/O')">I/O</button>
                </div>
                <div id="Legend" class="tab-content active">
                    <div id="legend">
                        <ul id="legend-list"></ul>
                    </div>
                </div>
                <div id="I/O" class="tab-content">
                    <div class="chat-container">
                        <div class="chat-summary" id="chatSummary">
                            <!-- Summary will appear here -->
                        </div>
                        <div class="chat-messages" id="chatMessages">
                            <!-- Chat messages will appear here -->
                        </div>
                        <div class="chat-input">
                            <input type="text" id="chatInput" placeholder="Type your question here...">
                            <button onclick="sendChat()" title="Send"><i class="fas fa-paper-plane"></i></button>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        
        <!-- Modal Overlay for Full Screen View -->
        <div id="myModal" class="modal">
            <span class="close-button" onclick="closeModal()">&times;</span>
            <div class="modal-content">
                <div id="fullResult"></div>
            </div>
        </div>
        
        <script>
            let originalData = null;
            let currentView = 0; // 0: Original, 1: Swap X and Y, 2: Swap X and Z

            // Show spinner with status
            function showSpinner(status) {
                const spinnerOverlay = document.getElementById('spinnerOverlay');
                const loadingStatus = document.getElementById('loadingStatus');
                spinnerOverlay.style.display = 'flex';
                loadingStatus.textContent = status || 'Loading...';
            }

            // Update spinner status
            function updateSpinnerStatus(status) {
                const loadingStatus = document.getElementById('loadingStatus');
                loadingStatus.textContent = status;
            }

            // Hide spinner
            function hideSpinner() {
                document.getElementById('spinnerOverlay').style.display = 'none';
            }

            function appendLog(message) {
                const logDiv = document.getElementById('logs');
                const p = document.createElement('p');
                p.textContent = message;
                logDiv.appendChild(p);
                logDiv.scrollTop = logDiv.scrollHeight;
            }

            function appendLogs(logs) {
                logs.forEach(log => appendLog(log));
            }

            function clearLogs() {
                document.getElementById('logs').innerHTML = '';
            }

            function decrementPoints() {
                const numPointsInput = document.getElementById('numPoints');
                let currentValue = parseInt(numPointsInput.value);
                if (currentValue > 50) { // Step set to 50
                    numPointsInput.value = currentValue - 50;
                } else {
                    numPointsInput.value = 50;
                }
            }

            function incrementPoints() {
                const numPointsInput = document.getElementById('numPoints');
                let currentValue = parseInt(numPointsInput.value);
                if (currentValue < 950) { // Step set to 50
                    numPointsInput.value = currentValue + 50;
                } else {
                    numPointsInput.value = 1000;
                }
            }

            async function submitStrings() {
                const string1 = document.getElementById('string1').value.trim();
                const string2 = document.getElementById('string2').value.trim();
                const string3 = document.getElementById('string3').value.trim();
                const string4 = document.getElementById('string4').value.trim();
                const numPoints = parseInt(document.getElementById('numPoints').value);
                const plotType = document.getElementById('topPlotType').value;

                if (!string1 || !string2 || !string3 || !string4) {
                    alert('Please provide all four input strings.');
                    return;
                }

                if (isNaN(numPoints) || numPoints < 50 || numPoints > 1000) {
                    alert('Please enter a valid number of data points between 50 and 1000.');
                    return;
                }

                showSpinner('Processing your request...');
                clearLogs();
                document.getElementById('chatSummary').innerHTML = '';

                try {
                    const response = await fetch('/compute', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ 
                            string1, 
                            string2, 
                            string3, 
                            string4, 
                            num_points: numPoints 
                        })
                    });

                    if (!response.ok) {
                        const errorData = await response.json();
                        appendLog(`Error: ${errorData.error}`);
                        hideSpinner();
                        return;
                    }

                    const result = await response.json();
                    originalData = result.data; // Assign the plotting data
                    appendLogs(result.logs);

                    // Render the plot in both main view and full screen modal
                    renderPlot(originalData, 'result', plotType);
                    renderPlot(originalData, 'fullResult', plotType);

                    populateLegend(originalData, 'legend-list');

                    // Display the summary
                    if (result.summary) {
                        document.getElementById('chatSummary').innerHTML = `<strong>Summary:</strong> ${result.summary}`;
                    }

                    hideSpinner();
                } catch (error) {
                    console.error('Error:', error);
                    appendLog('An error occurred while processing your request.');
                    hideSpinner();
                }
            }

            function renderPlot(data, elementId, plotType) {
                // Define plot modes
                let mode;
                if (plotType === 'markers') {
                    mode = 'markers';
                } else if (plotType === 'lines') {
                    mode = 'lines';
                } else {
                    mode = 'markers+lines';
                }

                const trace1 = {
                    x: data.x1,
                    y: data.y1,
                    z: data.z1,
                    mode: mode,
                    type: 'scatter3d',
                    marker: {
                        size: 6,
                        color: 'cyan',
                        line: {
                            color: 'white',
                            width: 0.5
                        }
                    },
                    line: {
                        color: 'magenta',
                        width: 1
                    },
                    hoverinfo: 'text',
                    text: data.hover_text1,
                    name: 'Set 1'
                };

                const trace2 = {
                    x: data.x2,
                    y: data.y2,
                    z: data.z2,
                    mode: mode,
                    type: 'scatter3d',
                    marker: {
                        size: 6,
                        color: 'orange',
                        line: {
                            color: 'white',
                            width: 0.5
                        }
                    },
                    line: {
                        color: 'blue',
                        width: 1
                    },
                    hoverinfo: 'text',
                    text: data.hover_text2,
                    name: 'Set 2'
                };

                const plotData = [trace1, trace2];

                const layout = {
                    paper_bgcolor: '#121212',
                    plot_bgcolor: '#121212',
                    scene: {
                        xaxis: { color: 'white', title: data.axis_names.x_axis },
                        yaxis: { color: 'white', title: data.axis_names.y_axis },
                        zaxis: { color: 'white', title: data.axis_names.z_axis },
                        camera: data.camera_eye ? { eye: data.camera_eye } : { eye: {x: 1.75, y: 1.75, z: 1.75} }
                    },
                    margin: { l: 0, r: 20, b: 0, t: 0 }
                };

                Plotly.newPlot(elementId, plotData, layout, {responsive: true, displayModeBar: false});
            }

            function populateLegend(data, legendListId) {
                const legendList = document.getElementById(legendListId);
                legendList.innerHTML = '';

                // Create legend for Set 1
                const set1Title = document.createElement('li');
                set1Title.textContent = data.legend[0];
                set1Title.classList.add('collapsible');
                set1Title.dataset.setIndex = 0;

                const set1Phrases = document.createElement('ul');
                set1Phrases.classList.add('content');

                data.labels1.forEach((phrase, i) => {
                    if (i >= 100) return; // Limit to 100 phrases
                    const phraseItem = document.createElement('li');
                    phraseItem.textContent = phrase;
                    phraseItem.dataset.setIndex = 0;
                    phraseItem.dataset.phraseIndex = i;
                    phraseItem.addEventListener('mouseover', () => highlightTrace(0, i));
                    phraseItem.addEventListener('mouseout', () => resetTraces());
                    set1Phrases.appendChild(phraseItem);
                });

                set1Title.appendChild(set1Phrases);
                legendList.appendChild(set1Title);

                // Create legend for Set 2
                const set2Title = document.createElement('li');
                set2Title.textContent = data.legend[1];
                set2Title.classList.add('collapsible');
                set2Title.dataset.setIndex = 1;

                const set2Phrases = document.createElement('ul');
                set2Phrases.classList.add('content');

                data.labels2.forEach((phrase, i) => {
                    if (i >= 100) return; // Limit to 100 phrases
                    const phraseItem = document.createElement('li');
                    phraseItem.textContent = phrase;
                    phraseItem.dataset.setIndex = 1;
                    phraseItem.dataset.phraseIndex = i;
                    phraseItem.addEventListener('mouseover', () => highlightTrace(1, i));
                    phraseItem.addEventListener('mouseout', () => resetTraces());
                    set2Phrases.appendChild(phraseItem);
                });

                set2Title.appendChild(set2Phrases);
                legendList.appendChild(set2Title);

                // Add event listeners to toggle collapse
                const collapsibles = document.getElementsByClassName("collapsible");
                for (let i = 0; i < collapsibles.length; i++) {
                    collapsibles[i].addEventListener("click", function(event) {
                        // Prevent toggling when clicking on child elements
                        if (event.target !== this) return;
                        this.classList.toggle("active");
                        const content = this.querySelector(".content");
                        if (content.style.display === "block") {
                            content.style.display = "none";
                        } else {
                            content.style.display = "block";
                        }
                    });
                }
            }

            function highlightTrace(setIndex, phraseIndex) {
                if (!originalData) return;
                let traceNumber = setIndex; // Set 0 for Set 1, Set 1 for Set 2

                // Define unique colors and sizes
                const baseColor = setIndex === 0 ? 'cyan' : 'orange';
                const highlightColor = 'red';
                const baseSize = 6;
                const highlightSize = 12;

                // Reset all points to base color and size
                Plotly.restyle('result', {
                    'marker.color': ['cyan', 'orange'],
                    'marker.size': [6, 6]
                }, [0,1]);

                // Highlight the specific point
                const updatedColors = originalData[`x${setIndex+1}`].map((_, i) => i === phraseIndex ? highlightColor : baseColor);
                const updatedSizes = originalData[`x${setIndex+1}`].map((_, i) => i === phraseIndex ? highlightSize : baseSize);

                Plotly.restyle('result', {
                    'marker.color': [updatedColors, setIndex === 0 ? 'orange' : 'cyan'],
                    'marker.size': [updatedSizes, setIndex === 0 ? 6 : 6]
                }, [0,1]);
            }

            function resetTraces() {
                if (!originalData) return;
                const plotElementIds = ['result', 'fullResult'];
                plotElementIds.forEach(elementId => {
                    Plotly.restyle(elementId, {
                        'marker.color': ['cyan', 'orange'],
                        'marker.size': [6, 6],
                        'line.color': ['magenta', 'blue']
                    }, [0,1]);
                });
            }

            function openTab(evt, tabName) {
                const tabContents = document.getElementsByClassName('tab-content');
                for (let content of tabContents) {
                    content.classList.remove('active');
                }
                const tabs = document.getElementsByClassName('tab');
                for (let tab of tabs) {
                    tab.classList.remove('active');
                }
                document.getElementById(tabName).classList.add('active');
                evt.currentTarget.classList.add('active');
            }

            async function sendChat() {
                const userInput = document.getElementById('chatInput').value.trim();
                if (!userInput) return;

                appendChatMessage('You', userInput);
                document.getElementById('chatInput').value = '';

                try {
                    const response = await fetch('/chat', {
                        method: 'POST',
                        headers: { 'Content-Type': 'application/json' },
                        body: JSON.stringify({ 
                            message: userInput, 
                            context: originalData 
                        })
                    });

                    if (!response.ok) {
                        const errorData = await response.json();
                        appendChatMessage('Error', errorData.error);
                        return;
                    }

                    const result = await response.json();
                    appendChatMessage('Assistant', result.reply);
                } catch (error) {
                    console.error('Chat Error:', error);
                    appendChatMessage('Error', 'An error occurred while processing your request.');
                }
            }

            function appendChatMessage(sender, message) {
                const chatMessages = document.getElementById('chatMessages');
                const msgDiv = document.createElement('div');
                msgDiv.innerHTML = `<strong>${sender}:</strong> ${message}`;
                chatMessages.appendChild(msgDiv);
                chatMessages.scrollTop = chatMessages.scrollHeight;
            }

            // Modal Functions
            function openModal() {
                document.getElementById('myModal').style.display = 'block';
                const fullResult = document.getElementById('fullResult');
                const resultContent = document.getElementById('result').innerHTML;
                fullResult.innerHTML = resultContent;
            }

            function closeModal() {
                document.getElementById('myModal').style.display = 'none';
            }
        </script>
    </body>
    </html>
    """
    return render_template_string(html)

@app.route('/compute', methods=['POST'])
def compute():
    """
    Handle computation and return the processed data for plotting.
    Expecting four input strings and the number of data points.
    """
    data = request.json
    string1 = data.get('string1', '').strip()
    string2 = data.get('string2', '').strip()
    string3 = data.get('string3', '').strip()
    string4 = data.get('string4', '').strip()
    num_points = data.get('num_points', 50)

    # Initialize logs
    logs = []

    # Ensure all four strings are provided
    if not string1 or not string2 or not string3 or not string4:
        return jsonify({'error': 'All four input strings must be provided.', 'logs': logs}), 400

    if not isinstance(num_points, int) or num_points < 50 or num_points > 1000:
        return jsonify({'error': 'num_points must be an integer between 50 and 1000.', 'logs': logs}), 400

    try:
        # Prepare datasets
        datasets = []
        colors = ['cyan', 'orange']  # Colors for the two datasets
        labels_group = ['Set 1', 'Set 2']

        # Set 1: string1 and string2
        related_phrases1 = get_related_phrases((string1, string2), num_related=num_points, logs=logs)
        if not related_phrases1:
            return jsonify({'error': 'Failed to generate related phrases for Set 1.', 'logs': logs}), 500
        if len(related_phrases1) > 100:
            related_phrases1 = related_phrases1[:100]
            logs.append('Limited Set 1 phrases to 100 to optimize performance.')
        embeddings1 = [get_embedding(phrase, logs=logs) for phrase in related_phrases1]
        labels1 = related_phrases1

        datasets.append({
            'x1': [emb[0] for emb in embeddings1],
            'y1': [emb[1] for emb in embeddings1],
            'z1': [emb[2] for emb in embeddings1],
            'hover_text1': [f"Content: {phrase}" for phrase in labels1],
            'labels1': labels1
        })

        # Set 2: string3 and string4
        related_phrases2 = get_related_phrases((string3, string4), num_related=num_points, logs=logs)
        if not related_phrases2:
            return jsonify({'error': 'Failed to generate related phrases for Set 2.', 'logs': logs}), 500
        if len(related_phrases2) > 100:
            related_phrases2 = related_phrases2[:100]
            logs.append('Limited Set 2 phrases to 100 to optimize performance.')
        embeddings2 = [get_embedding(phrase, logs=logs) for phrase in related_phrases2]
        labels2 = related_phrases2

        datasets.append({
            'x2': [emb[0] for emb in embeddings2],
            'y2': [emb[1] for emb in embeddings2],
            'z2': [emb[2] for emb in embeddings2],
            'hover_text2': [f"Content: {phrase}" for phrase in labels2],
            'labels2': labels2
        })

        # Combine all data for PCA
        all_embeddings = np.vstack([
            np.column_stack((ds['x1'], ds['y1'], ds['z1'])) for ds in datasets
        ] + [
            np.column_stack((ds['x2'], ds['y2'], ds['z2'])) for ds in datasets
        ])

        # Perform PCA
        pca = PCA(n_components=3)
        reduced_embeddings = pca.fit_transform(all_embeddings)
        logs.append("Performed PCA on combined embeddings.")

        # Generate axis names using LLM
        axis_names = generate_axis_names(
            strings=(string1, string2, string3, string4),
            pca_components=pca.components_,
            logs=logs
        )

        # Assign the reduced embeddings back to datasets
        start = 0
        for dataset in datasets:
            end = start + len(dataset['x1'])
            dataset['x1'] = reduced_embeddings[start:end, 0].tolist()
            dataset['y1'] = reduced_embeddings[start:end, 1].tolist()
            dataset['z1'] = reduced_embeddings[start:end, 2].tolist()
            start = end
        for dataset in datasets:
            end = start + len(dataset['x2'])
            dataset['x2'] = reduced_embeddings[start:end, 0].tolist()
            dataset['y2'] = reduced_embeddings[start:end, 1].tolist()
            dataset['z2'] = reduced_embeddings[start:end, 2].tolist()
            start = end

        # Prepare response data
        response_data = {
            'axis_names': axis_names,
            'x1': datasets[0]['x1'],
            'y1': datasets[0]['y1'],
            'z1': datasets[0]['z1'],
            'hover_text1': datasets[0]['hover_text1'],
            'x2': datasets[1]['x2'],
            'y2': datasets[1]['y2'],
            'z2': datasets[1]['z2'],
            'hover_text2': datasets[1]['hover_text2'],
            'legend': labels_group,
            'labels1': datasets[0]['labels1'],
            'labels2': datasets[1]['labels2'],
            'camera_eye': {  # Store camera position for zoom and rotate
                'x': 1.75,
                'y': 1.75,
                'z': 1.75
            }
        }

        # Generate summary
        prompt = generateSummaryPrompt(response_data)
        summary = analyze_data(prompt, logs)
        response_data['summary'] = summary

        return jsonify({'data': response_data, 'logs': logs})
    except Exception as e:
        logs.append(f"Error during computation: {e}")
        print(f"Error during computation: {e}")  # Debug statement
        return jsonify({'error': 'An internal error occurred. Please try again later.', 'logs': logs}), 500

@app.route('/analyze', methods=['POST'])
def analyze():
    """
    Analyze the data points and return conclusions.
    """
    data = request.json
    prompt = data.get('prompt', '').strip()
    logs = []

    if not prompt:
        return jsonify({'error': 'No prompt provided.'}), 400

    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are a data analyst that provides insightful analysis based on provided data points."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=500,
            temperature=0.5,
        )

        analysis = response.choices[0].message.content
        logs.append("Generated analysis using GPT-4o-mini.")
        return jsonify({'conclusions': analysis, 'logs': logs})
    except Exception as e:
        logs.append(f"Error generating analysis: {e}")
        print(f"Error generating analysis: {e}")
        return jsonify({'error': 'Failed to generate analysis.', 'logs': logs}), 500

@app.route('/chat', methods=['POST'])
def chat():
    """
    Handle chat messages and return responses from the LLM.
    """
    data = request.json
    user_message = data.get('message', '').strip()
    context = data.get('context', {})
    logs = []

    if not user_message:
        return jsonify({'error': 'No message provided.'}), 400

    # Prepare context for the chat
    context_text = ""
    if context:
        context_text += "Current Data Points:\n\nSet 1:\n"
        for i, label in enumerate(context.get('labels1', [])[:100]):
            context_text += f"Point {i+1}: ({context['x1'][i]}, {context['y1'][i]}, {context['z1'][i]}) - {label}\n"
        context_text += "\nSet 2:\n"
        for i, label in enumerate(context.get('labels2', [])[:100]):
            context_text += f"Point {i+1}: ({context['x2'][i]}, {context['y2'][i]}, {context['z2'][i]}) - {label}\n"

    prompt = f"{context_text}\nUser Question: {user_message}\nProvide a detailed and insightful answer based on the data above."

    try:
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=[
                {"role": "system", "content": "You are an assistant that provides detailed and insightful answers based on provided data."},
                {"role": "user", "content": prompt}
            ],
            max_tokens=500,
            temperature=0.5,
        )

        reply = response.choices[0].message.content
        logs.append("Generated chat response using GPT-4o-mini.")
        return jsonify({'reply': reply, 'logs': logs})
    except Exception as e:
        logs.append(f"Error in chat: {e}")
        print(f"Error in chat: {e}")
        return jsonify({'error': 'Failed to generate chat response.', 'logs': logs}), 500

if __name__ == '__main__':
    # Run the Flask app
    app.run(port=5005, debug=True)