Add providers:

https://raw.githubusercontent.com/xtekky/gpt4free/refs/heads/main/docs/client.md
https://raw.githubusercontent.com/xtekky/gpt4free/refs/heads/main/docs/legacy.md

```
import wolframalpha
from g4f.client import Client as GPTClient
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import time
from functools import lru_cache
import random
import re
import numpy as np
from scipy import stats
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
import logging
import json
import os
from concurrent.futures import ThreadPoolExecutor
import requests
from PIL import Image
from io import BytesIO
import sys  # Added for log file opening on non-Windows systems
from g4f.Provider import Bixin123

# ------------------------- Configuration -------------------------
CONFIG_FILE = 'config.json'

default_config = {
    "WOLFRAM_APP_ID": 'JG3W9R-WPRHXR7ULG',
    "GPT_MODEL": 'gpt-4-turbo',
    "MAX_DEPTH": 20,
    "PRECISION": 100,
    "GPT_MAX_TOKENS": 6000,  # Increased to accommodate advanced reasoning
    "GPT_TOKENS_PER_MESSAGE": 2048,  # Increased per message tokens
    "DEBUG_MODE": False  # New configuration for debug mode
}

def load_config():
    if not os.path.exists(CONFIG_FILE):
        with open(CONFIG_FILE, 'w') as f:
            json.dump(default_config, f, indent=4)
        return default_config.copy()
    else:
        with open(CONFIG_FILE, 'r') as f:
            return json.load(f)

def save_config(config):
    with open(CONFIG_FILE, 'w') as f:
        json.dump(config, f, indent=4)

config = load_config()

# ------------------------- Logging Setup -------------------------
LOG_FILE = 'math_solver.log'

logging.basicConfig(
    filename=LOG_FILE,
    filemode='a',
    format='%(asctime)s - %(levelname)s - %(message)s',
    level=logging.DEBUG if config.get("DEBUG_MODE", False) else logging.INFO
)

# Console handler for real-time debugging
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG if config.get("DEBUG_MODE", False) else logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
logging.getLogger().addHandler(console_handler)

# ------------------------- Initialize Clients -------------------------
try:
    wolfram_client = wolframalpha.Client(config["WOLFRAM_APP_ID"])
    logging.info("WolframAlpha client initialized successfully.")
except Exception as e:
    logging.error(f"Failed to initialize WolframAlpha client: {e}")
    wolfram_client = None

try:
    gpt_client = GPTClient()
    logging.info("GPT client initialized successfully.")
except Exception as e:
    logging.error(f"Failed to initialize GPT client: {e}")
    gpt_client = None

# ------------------------- Global Variables -------------------------
history = []

executor = ThreadPoolExecutor(max_workers=5)  # For managing threads efficiently

# ------------------------- Utility Functions -------------------------

@lru_cache(maxsize=256)
def evaluate_expression(expression):
    # Utilize WolframAlpha and GPT to evaluate expressions
    logging.debug(f"Evaluating expression: '{expression}'.")
    analytical_result, confidence, mean_conf, std_conf = query_wolframalpha(expression)
    gpt_result = query_gpt(f"Provide an advanced mathematical evaluation for the following expression: {expression}", suggestion=analytical_result)
    combined_result = f"**WolframAlpha Evaluation:**\n{analytical_result}\n\n**GPT Evaluation:**\n{gpt_result}"
    logging.debug("Evaluation completed using WolframAlpha and GPT.")
    return combined_result

def high_precision_calculation(expression, precision=config.get("PRECISION", 100)):
    # High precision calculations via WolframAlpha
    logging.debug(f"High precision calculation requested for '{expression}' with precision {precision}.")
    try:
        res = wolfram_client.query(f"High precision calculation of {expression} with {precision} digits")
        high_prec_result = next(res.results).text
        logging.debug(f"High precision result: {high_prec_result}")
        return high_prec_result
    except StopIteration:
        logging.warning("No results returned from WolframAlpha for high precision calculation.")
        return "WolframAlpha could not perform high precision calculation."
    except Exception as e:
        logging.error(f"Error in high precision calculation '{expression}': {e}")
        return f"Error performing high precision calculation: {e}"

def estimate_confidence(depth, accuracy, complexity, iterations):
    base_confidence = 0.5 + (depth * 0.05) + (accuracy * 0.2) - (complexity * 0.02) + (iterations * 0.01)
    confidence = round(min(max(base_confidence, 0.0), 1.0), 2)
    logging.debug(f"Estimated confidence: {confidence} (Depth: {depth}, Accuracy: {accuracy}, Complexity: {complexity}, Iterations: {iterations})")
    return confidence

def calculate_complexity(expression):
    # Simplified estimation based on length and operators
    try:
        complexity = len(expression) + expression.count('^') + expression.count('*') + expression.count('/')
        logging.debug(f"Calculated complexity for '{expression}': {complexity}")
        return complexity
    except Exception as e:
        logging.error(f"Error calculating complexity for '{expression}': {e}")
        return 15  # Default complexity if estimation fails

# ------------------------- Advanced Depth Calculation and Handler -------------------------

def dynamic_depth_adjustment(confidence, current_depth, max_depth):
    """
    Dynamically adjust the depth based on confidence levels.
    """
    if confidence < 0.7 and current_depth < max_depth:
        return current_depth + 1
    return current_depth

def advanced_depth_system(problem, max_depth=config.get("MAX_DEPTH", 20), max_iterations=10):
    best_result = None
    best_confidence = 0.0
    results = []

    for depth in range(1, max_depth + 1):
        for iteration in range(1, max_iterations + 1):
            time.sleep(0.05 * depth * random.random())  # Reduced sleep for performance
                
            refined_problem = refine_problem(problem, depth)
            potential_solution = f"{refined_problem} (Depth {depth}, Iteration {iteration})"
            accuracy = (depth * 0.05 + iteration * 0.02) * random.uniform(0.9, 1.1)
            complexity = calculate_complexity(problem)
            confidence = estimate_confidence(depth, accuracy, complexity, iteration)

            results.append((potential_solution, confidence))

            if confidence > best_confidence:
                best_result = potential_solution
                best_confidence = confidence

            if confidence > 0.95:
                logging.debug(f"Confidence threshold met at depth {depth}, iteration {iteration}.")
                break

        # Dynamic depth adjustment based on current best confidence
        if best_confidence > 0.9:
            logging.debug(f"Dynamic depth adjustment: Breaking early at depth {depth} due to high confidence.")
            break

    confidences = [r[1] for r in results]
    mean_confidence = np.mean(confidences) if confidences else 0.0
    std_confidence = np.std(confidences) if confidences else 0.0
    
    if len(confidences) > 1:
        z_scores = stats.zscore(confidences)
        outliers = np.abs(z_scores) > 2
    else:
        outliers = [False]
    
    filtered_results = [r for r, is_outlier in zip(results, outliers) if not is_outlier]

    if filtered_results:
        best_result, best_confidence = max(filtered_results, key=lambda x: x[1])
        logging.debug("Filtered outliers and selected the best result.")
    else:
        logging.debug("No filtered results available; using initial best result.")

    return best_result, best_confidence, mean_confidence, std_confidence

def refine_problem(problem, depth):
    # Simplified refinement by rephrasing based on depth
    try:
        refined = f"{problem} (Refinement Depth: {depth})"
        logging.debug(f"Refined problem at depth {depth}: {refined}")
        return refined
    except Exception as e:
        logging.error(f"Error refining problem '{problem}' at depth {depth}: {e}")
        return problem

# ------------------------- Advanced Self-Correction Specialty -------------------------

def self_correct_response(original_response):
    """
    Uses GPT to analyze and correct its own response for potential errors or improvements.
    """
    logging.debug("Initiating self-correction process.")
    correction_prompt = f"""Analyze the following response for any potential errors, inconsistencies, or areas that can be improved. Provide a revised version if necessary.

Response:
{original_response}

Revised Response:
"""
    corrected_response = query_gpt(correction_prompt)
    logging.debug("Self-correction process completed.")
    return corrected_response

# ------------------------- Advanced Scoping-Tuning Analyzation AI Method -------------------------

def scoping_tuning_analysis(problem, response):
    """
    Analyzes the response and dynamically adjusts the scope and focus of the problem-solving approach.
    """
    logging.debug("Starting scoping-tuning analysis.")
    analysis_prompt = f"""Given the problem and the initial response below, analyze the adequacy and thoroughness of the solution. Suggest any adjustments to the problem scope or focus areas that could enhance the solution's accuracy and completeness.

Problem:
{problem}

Initial Response:
{response}

Analysis and Suggestions:
"""
    analysis = query_gpt(analysis_prompt)
    logging.debug("Scoping-tuning analysis completed.")
    return analysis

# ------------------------- Translator and Query Functions -------------------------

def advanced_auto_translate_to_wolfram(query):
    query = query.lower()
    
    translation_map = {
        'solve': 'compute',
        'find': 'determine',
        'calculate': 'evaluate',
        'simplify': 'simplify the expression',
        'integrate': 'calculate the integral of',
        'differentiate': 'calculate the derivative of',
        'derivative': 'differentiate',
        'integral': 'integrate',
        'limit': 'evaluate the limit of',
        'roots': 'determine the roots of the equation',
        'factor': 'factorize',
        'expand': 'expand the expression',
        'series': 'find the series expansion of',
        'approximate': 'find a numerical approximation of',
        'solve system': 'solve the system of equations',
        'optimize': 'find the optimal value of',
    }
    
    for key, value in translation_map.items():
        query = query.replace(key, value)
    
    logging.debug(f"Translated query to WolframAlpha: {query}")
    return query

def query_wolframalpha(query, max_depth=config.get("MAX_DEPTH", 20)):
    if not wolfram_client:
        logging.error("WolframAlpha client is not initialized.")
        return "WolframAlpha client is not available.", 0.0, 0.0, 0.0

    translated_query = advanced_auto_translate_to_wolfram(query)
    best_result = "WolframAlpha could not find an answer."
    best_confidence = 0.0
    analytical_result = "Could not perform analytical analysis."
    mean_confidence = std_confidence = 0.0

    try:
        res = wolfram_client.query(translated_query + ' explain step by step')
        wolfram_output = next(res.results).text
        logging.debug(f"WolframAlpha output: {wolfram_output}")
        best_result, best_confidence, mean_confidence, std_confidence = advanced_depth_system(wolfram_output, max_depth=max_depth)
        analytical_result = wolfram_to_analytical(best_result)
        logging.info("Queried WolframAlpha successfully.")
    except StopIteration:
        logging.warning("No results returned from WolframAlpha.")
    except Exception as e:
        logging.error(f"Error querying WolframAlpha: {e}")

    return analytical_result, best_confidence, mean_confidence, std_confidence

def wolfram_to_analytical(wolfram_result):
    steps = wolfram_result.split('\n')
    analytical_steps = []

    for step in steps:
        step = re.sub(r'\d+(\.\d+)?', 'x', step)
        step = step.replace('Solve[', 'Solve the equation: ')
        step = step.replace('Integrate[', 'Integrate the function: ')
        step = step.replace('Differentiate[', 'Differentiate the function: ')
        analytical_steps.append(step)

    analytical_steps.extend([
        "To solve this problem analytically:",
        "1. **Identify the problem type** (e.g., algebraic, calculus, etc.).",
        "2. **Choose appropriate mathematical techniques** based on the problem type.",
        "3. **Apply relevant theorems or formulas** to set up the problem.",
        "4. **Simplify and solve step by step**, ensuring each step logically follows from the previous one.",
        "5. **Verify the solution** by substituting it back into the original equation or checking against known results.",
        "6. **Interpret the results** within the context of the original problem to provide meaningful conclusions."
    ])

    analytical = "\n".join(analytical_steps)
    logging.debug("Converted WolframAlpha result to analytical steps.")
    return analytical

# ------------------------- GPT Query Functions -------------------------

def query_gpt(message, suggestion=None):
    if not gpt_client:
        logging.error("GPT client is not initialized.")
        return "GPT client is not available."
    
    prompt = generate_custom_prompt(message, suggestion)
    logging.debug(f"GPT Prompt: {prompt}")

    try:
        response = gpt_client.chat.completions.create(
            model=config.get("GPT_MODEL", "gpt-4"),
            messages=[{"role": "user", "content": prompt}],
            max_tokens=config.get("GPT_TOKENS_PER_MESSAGE", 2048)
        )
        result = response.choices[0].message.content
        logging.debug(f"GPT Response: {result}")
        return result
    except Exception as e:
        logging.error(f"Error querying GPT: {e}")
        return "GPT could not generate a solution."

def generate_custom_prompt(user_input: str, suggestion: str = None) -> str:
    # Advanced Chain-of-Thought Specialization
    base_prompt = f"""You are an advanced mathematical reasoning AI with specialized Chain-of-Thought capabilities. Your task is to provide a comprehensive solution to the following problem, including detailed explanations, multiple approaches, and rigorous proofs where applicable.
    
Problem: {user_input}

Your solution should include the following sections:

1. **Problem Analysis**: Thoroughly understand and decompose the problem. Identify key mathematical concepts involved.
2. **Approach Selection**: Decide on the most effective mathematical methods and techniques to tackle the problem.
3. **Detailed Step-by-Step Solution**: Execute the chosen methods systematically, providing clear and logical explanations for each step.
4. **Verification and Validation**: Confirm the accuracy of each step and the final solution. Check for alternative solutions or potential errors.
5. **Comprehensive Proof**: If applicable, supply a formal proof supporting the solution, ensuring all mathematical justifications are sound.
6. **Alternative Methods**: Present other viable methods to solve the problem, highlighting their advantages or different perspectives.

Ensure that each section is clearly marked and well-organized. If there are ambiguities or assumptions made to solve the problem, explicitly state them in the **Problem Analysis** section.
"""

    # Append analytical suggestion from WolframAlpha if available
    if suggestion:
        base_prompt += f"\n\n**Analytical Suggestion from WolframAlpha:**\n{suggestion}\n\n"
    else:
        base_prompt += "\n\n**Analytical Suggestion from WolframAlpha:**\nNo analytical approach available. Please proceed with your own method.\n\n"

    logging.debug("Generated custom prompt for GPT with advanced Chain-of-Thought specialization.")
    return base_prompt

# ------------------------- Step-by-Step and Proof Functions -------------------------

def show_step_by_step_solution(problem):
    # Utilize GPT to generate step-by-step solution
    logging.debug("Generating step-by-step solution using GPT.")
    step_prompt = f"Provide a detailed, step-by-step solution to the following problem:\n\n{problem}"
    step_solution = query_gpt(step_prompt)
    return step_solution

def advanced_proof_techniques(problem):
    # Utilize GPT to generate comprehensive proofs
    logging.debug("Generating advanced proof using GPT.")
    proof_prompt = f"Provide a comprehensive mathematical proof for the solution to the following problem:\n\n{problem}"
    proof = query_gpt(proof_prompt)
    return proof

# ------------------------- Plotting Function -------------------------

def plot_expression(expression):
    try:
        # Utilize WolframAlpha to get a plot image
        logging.debug(f"Attempting to plot expression: '{expression}'.")
        plot_query = f"plot {expression}"
        res = wolfram_client.query(plot_query)
        
        # Extract image URL from WolframAlpha's response
        plot_pod = None
        for pod in res.pods:
            if pod.title.lower() in ['plot', 'graph', 'graphic']:
                plot_pod = pod
                break
        
        if not plot_pod:
            logging.warning("No plot available from WolframAlpha for the given expression.")
            return "WolframAlpha could not generate a plot for the given expression."

        plot_subpod = plot_pod.subpods[0]
        plot_url = plot_subpod.img.src
        logging.debug(f"Retrieved plot URL from WolframAlpha: {plot_url}")
        
        # Download the plot image
        response = requests.get(plot_url)
        img = Image.open(BytesIO(response.content))
        fig, ax = plt.subplots(figsize=(5, 4))
        ax.imshow(img)
        ax.axis('off')  # Hide axes
        logging.debug("Plot downloaded and prepared for display.")
        return fig
    except StopIteration:
        logging.warning("No plot available from WolframAlpha for the given expression.")
        return "WolframAlpha could not generate a plot for the given expression."
    except Exception as e:
        logging.error(f"Error plotting expression '{expression}': {e}")
        return f"Error plotting expression: {e}"

# ------------------------- Chatbot Function with Advanced Features -------------------------

def chatbot(message):
    wolfram_result, wolfram_confidence, mean_conf, std_conf = query_wolframalpha(message)

    gpt_result = query_gpt(message, suggestion=wolfram_result)
    gpt_result, gpt_confidence, gpt_mean_conf, gpt_std_conf = advanced_depth_system(gpt_result)

    # Combine results from WolframAlpha and GPT
    combined_response = f"**Analytical Approach:**\n{wolfram_result}\n\n**GPT Solution:**\n{gpt_result}"

    # Apply Advanced Self-Correction
    corrected_response = self_correct_response(combined_response)

    # Apply Advanced Scoping-Tuning Analysis
    scoping_analysis = scoping_tuning_analysis(message, corrected_response)

    # Final combined result with self-correction and scoping-tuning analysis
    final_result = f"{corrected_response}\n\n**Scoping-Tuning Analysis:**\n{scoping_analysis}\n\n**Proof and Verification:**\n{advanced_proof_techniques(message)}"

    confidence = max(wolfram_confidence, gpt_confidence)
    mean_confidence = (mean_conf + gpt_mean_conf) / 2
    std_confidence = (std_conf + gpt_std_conf) / 2

    history.append((message, final_result, confidence, mean_confidence, std_confidence))
    logging.info("Chatbot response generated successfully with advanced features.")
    return final_result, confidence, mean_confidence, std_confidence

# ------------------------- GUI Functions -------------------------

def on_submit():
    user_input = entry.get().strip()
    if not user_input:
        messagebox.showwarning("Input Error", "Please enter a math problem.")
        return
    submit_button.config(state="disabled")
    progress_bar.pack(fill=tk.X, padx=10, pady=(0,10))
    progress_bar.start()
    executor.submit(process_input, user_input)

def process_input(user_input):
    try:
        update_status("Processing...")
        response, confidence, mean_conf, std_conf = chatbot(user_input)
        result_text.delete(1.0, tk.END)
        result_text.insert(tk.END, f"**Solution:**\n{response}\n\n**Confidence:** {confidence}\n**Mean Confidence:** {mean_conf:.2f}\n**Std Confidence:** {std_conf:.2f}")

        step_by_step_solution = show_step_by_step_solution(user_input)
        if step_by_step_solution:
            result_text.insert(tk.END, f"\n\n**Detailed Steps:**\n{step_by_step_solution}")

        # Plotting
        fig = plot_expression(user_input)
        if isinstance(fig, plt.Figure):
            # Clear previous plots
            for widget in result_frame.winfo_children():
                if isinstance(widget, FigureCanvasTkAgg):
                    widget.get_tk_widget().destroy()
            plot_canvas = FigureCanvasTkAgg(fig, master=result_frame)
            plot_canvas.draw()
            plot_canvas.get_tk_widget().pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        else:
            result_text.insert(tk.END, f"\n\n{fig}")

        confidence_label.config(text=f"Confidence: {confidence}")
        update_status("Done.")
    except Exception as e:
        logging.error(f"Error processing input '{user_input}': {e}")
        messagebox.showerror("Processing Error", f"An error occurred: {e}")
    finally:
        progress_bar.stop()
        progress_bar.pack_forget()
        submit_button.config(state="normal")

def on_history():
    history_window = tk.Toplevel(root)
    history_window.title("Calculation History")

    history_frame = ttk.Frame(history_window, padding="10")
    history_frame.pack(fill=tk.BOTH, expand=True)

    title_label = ttk.Label(history_frame, text="Calculation History", font=("Helvetica", 14, "bold"))
    title_label.pack(pady=(0, 10))

    history_text = tk.Text(history_frame, height=20, width=80, wrap=tk.WORD)
    history_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    scroll_bar = ttk.Scrollbar(history_frame, orient=tk.VERTICAL, command=history_text.yview)
    scroll_bar.pack(side=tk.RIGHT, fill=tk.Y)
    history_text.config(yscrollcommand=scroll_bar.set)

    for i, (query, result, confidence, mean_conf, std_conf) in enumerate(history, 1):
        history_text.insert(tk.END, f"{i}. **Problem:** {query}\n**Result:**\n{result}\n**Confidence:** {confidence}, **Mean Confidence:** {mean_conf:.2f}, **Std Confidence:** {std_conf:.2f}\n\n")

    history_window.update_idletasks()
    history_window.minsize(history_text.winfo_width() + 50, history_text.winfo_height() + 100)

def on_save_history():
    if not history:
        messagebox.showinfo("No History", "There is no history to save.")
        return
    file_path = filedialog.asksaveasfilename(defaultextension=".txt", filetypes=[("Text Files", "*.txt")])
    if file_path:
        try:
            with open(file_path, 'w') as f:
                for i, (query, result, confidence, mean_conf, std_conf) in enumerate(history, 1):
                    f.write(f"{i}. Problem: {query}\nResult:\n{result}\nConfidence: {confidence}, Mean: {mean_conf:.2f}, Std: {std_conf:.2f}\n\n")
            messagebox.showinfo("Success", "History saved successfully.")
            logging.info(f"History saved to '{file_path}'.")
        except Exception as e:
            logging.error(f"Error saving history to '{file_path}': {e}")
            messagebox.showerror("Save Error", f"Failed to save history: {e}")

def on_load_config():
    config_window = tk.Toplevel(root)
    config_window.title("Configuration Settings")

    config_frame = ttk.Frame(config_window, padding="10")
    config_frame.pack(fill=tk.BOTH, expand=True)

    labels = [
        "WolframAlpha App ID:",
        "GPT Model:",
        "Max Depth:",
        "Precision:",
        "GPT Max Tokens:",
        "GPT Tokens Per Message:",
        "Debug Mode (True/False):"
    ]
    keys = list(default_config.keys())
    entries = []

    for idx, key in enumerate(keys):
        label = ttk.Label(config_frame, text=labels[idx])
        label.grid(row=idx, column=0, padx=5, pady=5, sticky=tk.E)
        entry = ttk.Entry(config_frame, width=40)
        entry.grid(row=idx, column=1, padx=5, pady=5)
        entry.insert(0, str(config.get(key, default_config[key])))
        entries.append(entry)

    def save_settings():
        new_config = {}
        for key, entry in zip(keys, entries):
            new_config[key] = entry.get().strip()
        
        # Validate and convert numerical values
        try:
            new_config["MAX_DEPTH"] = int(new_config["MAX_DEPTH"])
            new_config["PRECISION"] = int(new_config["PRECISION"])
            new_config["GPT_MAX_TOKENS"] = int(new_config["GPT_MAX_TOKENS"])
            new_config["GPT_TOKENS_PER_MESSAGE"] = int(new_config["GPT_TOKENS_PER_MESSAGE"])
            new_config["DEBUG_MODE"] = new_config["DEBUG_MODE"].lower() in ['true', '1', 'yes']
        except ValueError:
            messagebox.showerror("Invalid Input", "Please enter valid numerical values for Max Depth, Precision, GPT Max Tokens, and GPT Tokens Per Message, and a valid boolean for Debug Mode.")
            return
        
        # Update global config
        config.update(new_config)
        save_config(config)
        
        # Update logging level based on debug mode
        if config["DEBUG_MODE"]:
            logging.getLogger().setLevel(logging.DEBUG)
            console_handler.setLevel(logging.DEBUG)
            logging.debug("Debug mode enabled.")
        else:
            logging.getLogger().setLevel(logging.INFO)
            console_handler.setLevel(logging.INFO)
            logging.info("Debug mode disabled.")
        
        # Reinitialize WolframAlpha client with new App ID if changed
        global wolfram_client
        try:
            wolfram_client = wolframalpha.Client(config["WOLFRAM_APP_ID"])
            logging.info("WolframAlpha client re-initialized successfully with new App ID.")
        except Exception as e:
            logging.error(f"Failed to re-initialize WolframAlpha client: {e}")
            wolfram_client = None
        
        messagebox.showinfo("Success", "Configuration updated successfully.")
        config_window.destroy()
        logging.info("Configuration settings updated by user.")
    
    save_button = ttk.Button(config_frame, text="Save", command=save_settings)
    save_button.grid(row=len(keys), column=0, columnspan=2, pady=10)

def on_exit():
    if messagebox.askokcancel("Exit", "Do you really want to exit?"):
        executor.shutdown(wait=False)
        root.destroy()

def update_status(message):
    status_var.set(message)
    root.update_idletasks()

# ------------------------- Log Viewing Function -------------------------
def open_log_file():
    try:
        if os.name == 'nt':  # For Windows
            os.startfile(LOG_FILE)
        elif os.name == 'posix':  # For macOS and Linux
            import subprocess
            opener = "open" if sys.platform == "darwin" else "xdg-open"
            subprocess.call([opener, LOG_FILE])
        logging.debug("Opened log file.")
    except Exception as e:
        logging.error(f"Failed to open log file: {e}")
        messagebox.showerror("Error", f"Could not open log file: {e}")

# ------------------------- Main Application -------------------------

root = tk.Tk()
root.title("Advanced Math Solver with Chain-of-Thought Specialization")
root.protocol("WM_DELETE_WINDOW", on_exit)

# Style Configuration
style = ttk.Style()
style.theme_use("clam")

# Menu Bar
menubar = tk.Menu(root)
settings_menu = tk.Menu(menubar, tearoff=0)
settings_menu.add_command(label="Configuration", command=on_load_config)
settings_menu.add_separator()
settings_menu.add_command(label="Exit", command=on_exit)
menubar.add_cascade(label="Settings", menu=settings_menu)

history_menu = tk.Menu(menubar, tearoff=0)
history_menu.add_command(label="View History", command=on_history)
history_menu.add_command(label="Save History", command=on_save_history)
menubar.add_cascade(label="History", menu=history_menu)

debug_menu = tk.Menu(menubar, tearoff=0)  # New debug menu
debug_menu.add_command(label="View Logs", command=lambda: open_log_file())
menubar.add_cascade(label="Debug", menu=debug_menu)

root.config(menu=menubar)

# Entry Frame
entry_frame = ttk.Frame(root, padding="10")
entry_frame.pack(fill=tk.X)

entry_label = ttk.Label(entry_frame, text="Enter Math Problem:")
entry_label.pack(side=tk.LEFT, padx=(0,5))

entry = ttk.Entry(entry_frame, width=50)
entry.pack(side=tk.LEFT, fill=tk.X, expand=True, padx=(0,5))
entry.bind('<Return>', lambda event: on_submit())

submit_button = ttk.Button(entry_frame, text="Submit", command=on_submit)
submit_button.pack(side=tk.LEFT, padx=(5,0))

# Progress Bar
progress_bar = ttk.Progressbar(root, mode='indeterminate')

# Result Frame
result_frame = ttk.Frame(root, padding="10")
result_frame.pack(fill=tk.BOTH, expand=True)

result_text = tk.Text(result_frame, height=15, wrap=tk.WORD)
result_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

result_scroll_bar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=result_text.yview)
result_scroll_bar.pack(side=tk.RIGHT, fill=tk.Y)
result_text.config(yscrollcommand=result_scroll_bar.set)

# Confidence Frame
confidence_frame = ttk.Frame(root, padding="10")
confidence_frame.pack(fill=tk.X)

confidence_label = ttk.Label(confidence_frame, text="Confidence: N/A", font=("Helvetica", 12))
confidence_label.pack()

# Status Bar
status_var = tk.StringVar()
status_var.set("Ready")
status_bar = ttk.Label(root, textvariable=status_var, relief=tk.SUNKEN, anchor='w')
status_bar.pack(fill=tk.X, side=tk.BOTTOM)

# ------------------------- Run Application -------------------------

root.mainloop()