Update app.py
Browse files
app.py
CHANGED
|
@@ -103,126 +103,102 @@ def search_image(query):
|
|
| 103 |
|
| 104 |
return duckduckgo_search_api(query)
|
| 105 |
|
| 106 |
-
# Graph plotting function -
|
| 107 |
def execute_plotting_code(code_snippet):
|
| 108 |
"""Execute plotting code in a safe environment."""
|
| 109 |
try:
|
| 110 |
-
# Clear any existing plots
|
| 111 |
plt.close('all')
|
| 112 |
|
| 113 |
-
# Create a
|
| 114 |
-
fig
|
| 115 |
|
| 116 |
-
#
|
| 117 |
-
plt.style.use('seaborn-v0_8-darkgrid')
|
| 118 |
-
|
| 119 |
-
# Prepare execution environment with ALL necessary imports
|
| 120 |
namespace = {
|
| 121 |
'plt': plt,
|
| 122 |
'np': np,
|
| 123 |
-
'ax': ax,
|
| 124 |
'fig': fig,
|
| 125 |
-
'
|
| 126 |
-
'
|
| 127 |
}
|
| 128 |
|
| 129 |
# Clean the code
|
| 130 |
cleaned_code = code_snippet.strip()
|
| 131 |
|
| 132 |
-
#
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
|
| 135 |
-
|
| 136 |
-
has_plot = any(keyword in cleaned_code.lower() for keyword in [
|
| 137 |
-
'plt.plot', 'ax.plot', 'plt.scatter', 'ax.scatter',
|
| 138 |
-
'plt.bar', 'ax.bar', 'plt.hist', 'ax.hist'
|
| 139 |
-
])
|
| 140 |
|
| 141 |
-
# If no plotting command, add sample data
|
| 142 |
if not has_plot:
|
| 143 |
-
|
|
|
|
| 144 |
cleaned_code += 'x = np.linspace(0, 10, 100)\n'
|
| 145 |
cleaned_code += 'y = np.sin(x)\n'
|
| 146 |
-
cleaned_code += '
|
| 147 |
-
cleaned_code += 'ax.set_xlabel("X (units)", fontsize=12)\n'
|
| 148 |
-
cleaned_code += 'ax.set_ylabel("Y (units)", fontsize=12)\n'
|
| 149 |
-
cleaned_code += 'ax.set_title("Physics Graph", fontsize=14)\n'
|
| 150 |
-
|
| 151 |
-
# Execute the code
|
| 152 |
-
exec(cleaned_code, namespace)
|
| 153 |
|
| 154 |
-
#
|
| 155 |
-
|
|
|
|
| 156 |
|
| 157 |
-
#
|
| 158 |
-
|
| 159 |
-
|
| 160 |
-
|
| 161 |
-
|
| 162 |
-
|
| 163 |
-
|
| 164 |
-
|
|
|
|
| 165 |
|
| 166 |
-
#
|
| 167 |
-
|
| 168 |
|
| 169 |
-
#
|
| 170 |
-
|
| 171 |
-
if labels:
|
| 172 |
-
ax.legend()
|
| 173 |
-
|
| 174 |
-
# Ensure there's data on the plot
|
| 175 |
-
if len(ax.lines) == 0 and len(ax.collections) == 0 and len(ax.patches) == 0:
|
| 176 |
-
# No data plotted, add sample data
|
| 177 |
-
x = np.linspace(0, 10, 100)
|
| 178 |
-
y = np.sin(x)
|
| 179 |
-
ax.plot(x, y, 'r--', linewidth=2, label='Sample: sin(x)')
|
| 180 |
-
ax.set_xlabel('X (sample)', fontsize=12)
|
| 181 |
-
ax.set_ylabel('Y (sample)', fontsize=12)
|
| 182 |
-
ax.set_title('Sample Graph (No data provided)', fontsize=14)
|
| 183 |
-
ax.legend()
|
| 184 |
-
st.warning("⚠️ No data found in graph code. Displaying sample graph.")
|
| 185 |
|
| 186 |
-
#
|
| 187 |
-
plt.
|
| 188 |
|
| 189 |
-
# Display the plot
|
| 190 |
st.pyplot(fig)
|
| 191 |
|
| 192 |
# Close the figure
|
| 193 |
plt.close(fig)
|
| 194 |
|
|
|
|
|
|
|
| 195 |
except Exception as e:
|
| 196 |
-
st.error(f"Graph Error: {str(e)[:
|
| 197 |
|
| 198 |
-
#
|
| 199 |
try:
|
| 200 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 201 |
-
|
| 202 |
-
|
| 203 |
-
|
| 204 |
-
|
| 205 |
-
|
| 206 |
-
|
| 207 |
-
|
| 208 |
-
ax.plot(x, y1, 'b-', linewidth=2, label='sin(x)')
|
| 209 |
-
ax.plot(x, y2, 'r--', linewidth=2, label='cos(x)')
|
| 210 |
-
ax.set_xlabel('Angle (radians)', fontsize=12)
|
| 211 |
-
ax.set_ylabel('Value', fontsize=12)
|
| 212 |
-
ax.set_title('Trigonometric Functions (Fallback)', fontsize=14)
|
| 213 |
-
ax.grid(True, linestyle='--', alpha=0.6, color='gray')
|
| 214 |
ax.legend()
|
| 215 |
-
ax.axhline(y=0, color='k', linestyle='-', alpha=0.3)
|
| 216 |
-
ax.axvline(x=0, color='k', linestyle='-', alpha=0.3)
|
| 217 |
-
|
| 218 |
-
plt.tight_layout()
|
| 219 |
st.pyplot(fig)
|
| 220 |
plt.close(fig)
|
| 221 |
-
|
| 222 |
-
st.info("Displayed fallback graph. The AI's code may need adjustment.")
|
| 223 |
except:
|
| 224 |
st.error("⚠️ Could not generate any graph.")
|
| 225 |
-
|
|
|
|
| 226 |
# Display message function
|
| 227 |
def display_message(role, content, enable_voice=False):
|
| 228 |
"""Display chat message with all features."""
|
|
@@ -355,6 +331,16 @@ When asked to create a graph, you MUST write COMPLETE, EXECUTABLE Python code th
|
|
| 355 |
6. Adds grid: plt.grid(True, linestyle='--', alpha=0.6)
|
| 356 |
7. Adds legend if needed: plt.legend()
|
| 357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
**EXAMPLE OF GOOD GRAPH CODE:**
|
| 359 |
import matplotlib.pyplot as plt
|
| 360 |
import numpy as np
|
|
|
|
| 103 |
|
| 104 |
return duckduckgo_search_api(query)
|
| 105 |
|
| 106 |
+
# Graph plotting function - REORDERED AND FIXED
|
| 107 |
def execute_plotting_code(code_snippet):
|
| 108 |
"""Execute plotting code in a safe environment."""
|
| 109 |
try:
|
| 110 |
+
# Clear any existing plots FIRST
|
| 111 |
plt.close('all')
|
| 112 |
|
| 113 |
+
# Create a fresh figure
|
| 114 |
+
fig = plt.figure(figsize=(10, 6))
|
| 115 |
|
| 116 |
+
# Create execution namespace with ALL required imports
|
|
|
|
|
|
|
|
|
|
| 117 |
namespace = {
|
| 118 |
'plt': plt,
|
| 119 |
'np': np,
|
|
|
|
| 120 |
'fig': fig,
|
| 121 |
+
'ax': None,
|
| 122 |
+
'math': __import__('math')
|
| 123 |
}
|
| 124 |
|
| 125 |
# Clean the code
|
| 126 |
cleaned_code = code_snippet.strip()
|
| 127 |
|
| 128 |
+
# CRITICAL FIX: Ensure imports are at the top
|
| 129 |
+
if 'import matplotlib' not in cleaned_code:
|
| 130 |
+
cleaned_code = 'import matplotlib.pyplot as plt\nimport numpy as np\n' + cleaned_code
|
| 131 |
+
|
| 132 |
+
# CRITICAL FIX: Ensure plt.figure or plt.subplots is called
|
| 133 |
+
if 'plt.figure' not in cleaned_code and 'plt.subplots' not in cleaned_code:
|
| 134 |
+
cleaned_code = cleaned_code.replace('import matplotlib.pyplot as plt',
|
| 135 |
+
'import matplotlib.pyplot as plt\nplt.figure(figsize=(10, 6))')
|
| 136 |
+
|
| 137 |
+
# CRITICAL FIX: Check if there's actual plotting
|
| 138 |
+
plot_keywords = ['plt.plot(', 'ax.plot(', 'plt.scatter(', 'ax.scatter(',
|
| 139 |
+
'plt.bar(', 'ax.bar(', 'plt.hist(', 'ax.hist(']
|
| 140 |
|
| 141 |
+
has_plot = any(keyword in cleaned_code for keyword in plot_keywords)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 142 |
|
|
|
|
| 143 |
if not has_plot:
|
| 144 |
+
# Add a sample plot
|
| 145 |
+
cleaned_code += '\n\n# Adding sample plot since no plotting command was found\n'
|
| 146 |
cleaned_code += 'x = np.linspace(0, 10, 100)\n'
|
| 147 |
cleaned_code += 'y = np.sin(x)\n'
|
| 148 |
+
cleaned_code += 'plt.plot(x, y, "b-", linewidth=2, label="sin(x)")\n'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 149 |
|
| 150 |
+
# CRITICAL FIX: Ensure plt.show() is NOT in the code (Streamlit handles this)
|
| 151 |
+
cleaned_code = cleaned_code.replace('plt.show()', '')
|
| 152 |
+
cleaned_code = cleaned_code.replace('plt.show', '')
|
| 153 |
|
| 154 |
+
# Add labels if missing
|
| 155 |
+
if 'plt.xlabel' not in cleaned_code:
|
| 156 |
+
cleaned_code += '\nplt.xlabel("X-axis", fontsize=12)'
|
| 157 |
+
if 'plt.ylabel' not in cleaned_code:
|
| 158 |
+
cleaned_code += '\nplt.ylabel("Y-axis", fontsize=12)'
|
| 159 |
+
if 'plt.title' not in cleaned_code:
|
| 160 |
+
cleaned_code += '\nplt.title("Physics Graph", fontsize=14)'
|
| 161 |
+
if 'plt.grid' not in cleaned_code:
|
| 162 |
+
cleaned_code += '\nplt.grid(True, linestyle="--", alpha=0.6)'
|
| 163 |
|
| 164 |
+
# DEBUG: Print the code being executed
|
| 165 |
+
# print("DEBUG - Executing code:\n", cleaned_code[:200])
|
| 166 |
|
| 167 |
+
# EXECUTE THE CODE
|
| 168 |
+
exec(cleaned_code, namespace)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 169 |
|
| 170 |
+
# Get current figure
|
| 171 |
+
fig = plt.gcf()
|
| 172 |
|
| 173 |
+
# Display the plot IMMEDIATELY
|
| 174 |
st.pyplot(fig)
|
| 175 |
|
| 176 |
# Close the figure
|
| 177 |
plt.close(fig)
|
| 178 |
|
| 179 |
+
return True
|
| 180 |
+
|
| 181 |
except Exception as e:
|
| 182 |
+
st.error(f"❌ Graph Error: {str(e)[:100]}")
|
| 183 |
|
| 184 |
+
# Create a SIMPLE guaranteed plot
|
| 185 |
try:
|
| 186 |
fig, ax = plt.subplots(figsize=(10, 6))
|
| 187 |
+
x = np.linspace(0, 10, 100)
|
| 188 |
+
y = x**2 # Simple quadratic
|
| 189 |
+
ax.plot(x, y, 'b-', linewidth=2, label='y = x²')
|
| 190 |
+
ax.set_xlabel('X', fontsize=12)
|
| 191 |
+
ax.set_ylabel('Y', fontsize=12)
|
| 192 |
+
ax.set_title('Sample Graph (Code had issues)', fontsize=14)
|
| 193 |
+
ax.grid(True, linestyle='--', alpha=0.6)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 194 |
ax.legend()
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
st.pyplot(fig)
|
| 196 |
plt.close(fig)
|
| 197 |
+
st.warning("Displayed sample graph. The AI's code may need adjustment.")
|
|
|
|
| 198 |
except:
|
| 199 |
st.error("⚠️ Could not generate any graph.")
|
| 200 |
+
|
| 201 |
+
return False
|
| 202 |
# Display message function
|
| 203 |
def display_message(role, content, enable_voice=False):
|
| 204 |
"""Display chat message with all features."""
|
|
|
|
| 331 |
6. Adds grid: plt.grid(True, linestyle='--', alpha=0.6)
|
| 332 |
7. Adds legend if needed: plt.legend()
|
| 333 |
|
| 334 |
+
**IMPORTANT GRAPH RULES:**
|
| 335 |
+
- You MUST include ACTUAL DATA in your graph code
|
| 336 |
+
- Example of BAD code (won't show graph):
|
| 337 |
+
```python
|
| 338 |
+
import matplotlib.pyplot as plt
|
| 339 |
+
plt.figure(figsize=(10, 6))
|
| 340 |
+
# Missing actual plot() command!
|
| 341 |
+
plt.show()
|
| 342 |
+
|
| 343 |
+
|
| 344 |
**EXAMPLE OF GOOD GRAPH CODE:**
|
| 345 |
import matplotlib.pyplot as plt
|
| 346 |
import numpy as np
|