File size: 6,820 Bytes
c93a8ee
b357fbc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c93a8ee
b357fbc
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import streamlit as st
import numpy as np
import matplotlib.pyplot as plt
import sympy as sp
from sympy.parsing.sympy_parser import parse_expr
from sympy.utilities.lambdify import lambdify
import io
import os
import base64
from datetime import datetime
from transformers import AutoModelForSeq2SeqLM, AutoTokenizer

# Create required directories
os.makedirs("uploads", exist_ok=True)

# Page config
st.set_page_config(page_title="Equation2Graph", page_icon="πŸ“ˆ", layout="wide")

# Session state
if 'history' not in st.session_state:
    st.session_state.history = []

# Initialize NLP model
@st.cache_resource
def load_nlp_model():
    try:
        tokenizer = AutoTokenizer.from_pretrained("t5-small")
        model = AutoModelForSeq2SeqLM.from_pretrained("t5-small")
        return tokenizer, model
    except Exception as e:
        st.warning(f"⚠ AI model could not be loaded: {str(e)}. Falling back to basic equation parsing.")
        return None, None

# Load models
tokenizer, model = load_nlp_model()

def convert_nl_to_equation(nl_input):
    """Convert natural language to equation using AI model or fallback to basic parsing"""
    if tokenizer and model:
        try:
            inputs = tokenizer.encode(nl_input, return_tensors="pt", truncation=True)
            outputs = model.generate(inputs, max_length=50)
            return tokenizer.decode(outputs[0], skip_special_tokens=True)
        except Exception as e:
            st.error(f"Error in AI conversion: {str(e)}")
            return basic_nl_to_equation(nl_input)
    else:
        return basic_nl_to_equation(nl_input)

def basic_nl_to_equation(text):
    """Basic natural language to equation conversion"""
    # Define basic math terms
    terms = {
        'squared': '^2',
        'cubed': '^3',
        'plus': '+',
        'minus': '-',
        'times': '*',
        'multiply by': '*',
        'divided by': '/',
        'over': '/',
        'to the power of': '^',
        'sin of': 'sin(',
        'cos of': 'cos(',
        'tan of': 'tan(',
        'exponential of': 'exp(',
        'log of': 'log(',
        'absolute value of': 'abs('
    }
    
    # Normalize text
    text = text.lower().strip()
    
    # Replace terms
    for term, symbol in terms.items():
        text = text.replace(term, symbol)
    
    # Clean up the equation
    text = text.replace(' ', '')
    if text.count('(') > text.count(')'):
        text += ')'  # Close any unclosed parentheses
        
    # Remove any invalid characters
    text = ''.join(c for c in text if c.isalnum() or c in '+-*/^().')
    return text

def parse_and_validate_equation(equation_str):
    try:
        equation_str = equation_str.replace('^', '')
        expr = parse_expr(equation_str)
        x = sp.Symbol('x')
        f = lambdify(x, expr, modules=['numpy'])
        return f, expr
    except Exception as e:
        st.error(f"Error parsing equation: {str(e)}")
        return None, None

def plot_equation(f, expr, x_range=(-10, 10), points=1000):
    try:
        fig, ax = plt.subplots(figsize=(10, 6))
        x = np.linspace(x_range[0], x_range[1], points)
        y = f(x)
        ax.plot(x, y, '-b', label=str(expr))
        ax.grid(True, alpha=0.3)
        ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
        ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
        ax.set_xlabel('x')
        ax.set_ylabel('y')
        ax.set_title(f'Graph of {str(expr)}')
        ax.legend()
        return fig
    except Exception as e:
        st.error(f"Error plotting equation: {str(e)}")
        return None

def get_download_link(fig):
    buf = io.BytesIO()
    fig.savefig(buf, format='png', bbox_inches='tight')
    buf.seek(0)
    b64 = base64.b64encode(buf.read()).decode()
    return f'<a href="data:image/png;base64,{b64}" download="equation_plot.png">πŸ“₯ Download Plot</a>'

# Header
st.title("πŸ“ˆ Equation2Graph")
st.markdown("Visualize mathematical equations instantly, from symbolic or natural language input!")

# Columns
col1, col2 = st.columns([2, 1])

with col1:
    # Natural language input
    st.subheader("πŸ—£ Describe your equation (optional)")
    nl_input = st.text_input(
        "Enter your equation in plain English:",
        placeholder="e.g., the square of x plus two times x plus one"
    )
    
    equation = ""
    if nl_input:
        equation = convert_nl_to_equation(nl_input)
        if equation:
            st.success(f"Converted to equation: {equation}")
        else:
            st.error("Failed to convert input")

    # Direct equation input (fallback or primary)
    equation = st.text_input(
        "Or enter your equation directly:",
        value=equation,
        placeholder="e.g., x^2 + 2*x + 1"
    )

    # Plot settings
    with st.expander("βš™ Plot Settings"):
        col_a, col_b = st.columns(2)
        with col_a:
            x_min = st.number_input("X-axis minimum", value=-10.0)
        with col_b:
            x_max = st.number_input("X-axis maximum", value=10.0)
        points = st.slider("Number of points", 100, 2000, 1000)

    # Process and plot
    if equation:
        f, expr = parse_and_validate_equation(equation)
        if f and expr:
            fig = plot_equation(f, expr, (x_min, x_max), points)
            if fig:
                st.pyplot(fig)
                st.markdown(get_download_link(fig), unsafe_allow_html=True)
                if equation not in [h['equation'] for h in st.session_state.history]:
                    st.session_state.history.append({
                        'equation': equation,
                        'timestamp': datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    })

with col2:
    st.subheader("πŸ“š Example Equations")
    examples = [
        "x^2 + 2*x + 1",
        "sin(x) + cos(x)",
        "exp(-x^2)",
        "x^3 - 4*x",
        "tan(x)",
        "log(abs(x))"
    ]
    for ex in examples:
        if st.button(ex):
            st.experimental_set_query_params(equation=ex)

    st.subheader("πŸ“– Recent Equations")
    for item in reversed(st.session_state.history[-5:]):
        st.text(f"{item['equation']}")
        st.caption(f"Plotted on: {item['timestamp']}")

with st.expander("β„Ή How to use Equation2Graph"):
    st.markdown("""
    ### Instructions:
    1. Describe or type your equation
    2. The graph updates automatically
    3. Adjust plot settings if needed
    4. Download the graph as PNG

    ### Natural Language Support:
    - Try: "the square of x plus two times x"
    - You can still type equations like: x^2 + 2*x

    ### Supported Math Functions:
    - Basic: +, -, *, /, ^
    - Trig: sin(x), cos(x), tan(x)
    - Exponential/log: exp(x), log(x)
    """)

# Footer
st.markdown("---")
st.markdown("Equation2Graph | Now with 🧠 AI-powered equation parser | Made by webwhiz")