643 lines
26 KiB
Python
643 lines
26 KiB
Python
"""
|
|
Sistema de Panel LaTeX para la Calculadora MAV CAS Híbrida
|
|
"""
|
|
from PySide6.QtWidgets import (
|
|
QWidget, QVBoxLayout, QHBoxLayout, QLabel, QFrame, QTextBrowser
|
|
)
|
|
from PySide6.QtCore import Qt, QTimer
|
|
from PySide6.QtGui import QFont
|
|
from PySide6.QtWebEngineWidgets import QWebEngineView
|
|
import logging
|
|
from typing import List, Dict, Optional
|
|
from .evaluation import EvaluationResult
|
|
from .mathjax_manager import MathJaxManager
|
|
import sympy
|
|
|
|
|
|
class LatexPanel(QWidget):
|
|
"""Panel LaTeX con WebEngine o fallback a HTML"""
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.equations = []
|
|
self._webview_available = False
|
|
self._mathjax_ready = False
|
|
self._pending_equations = []
|
|
self._parent_calculator = parent
|
|
self._webview_initialized = False
|
|
self._mathjax_timeout_count = 0
|
|
self._max_mathjax_timeout = 20 # 10 segundos (20 * 500ms)
|
|
|
|
# Manager de MathJax local
|
|
self.mathjax_manager = MathJaxManager()
|
|
|
|
self._setup_ui()
|
|
|
|
# Timer para verificar si MathJax está listo (inicializado bajo demanda)
|
|
self._mathjax_check_timer = None
|
|
|
|
def _setup_ui(self):
|
|
"""Configura la UI del panel"""
|
|
layout = QVBoxLayout(self)
|
|
layout.setContentsMargins(0, 0, 0, 0)
|
|
|
|
# Header
|
|
header = QFrame()
|
|
header.setFixedHeight(30)
|
|
header.setStyleSheet("background-color: #1a1a1a; border-bottom: 1px solid #3c3c3c;")
|
|
header_layout = QHBoxLayout(header)
|
|
header_layout.setContentsMargins(10, 0, 10, 0)
|
|
|
|
title = QLabel("📐 Ecuaciones LaTeX")
|
|
title.setStyleSheet("color: #80c7f7; font-weight: bold;")
|
|
header_layout.addWidget(title)
|
|
header_layout.addStretch()
|
|
|
|
layout.addWidget(header)
|
|
|
|
# Intentar crear WebEngineView
|
|
try:
|
|
self.webview = QWebEngineView()
|
|
self.webview.setContextMenuPolicy(Qt.NoContextMenu)
|
|
self._setup_webview()
|
|
layout.addWidget(self.webview)
|
|
self._webview_available = True
|
|
logging.debug("✅ WebEngineView disponible para LaTeX")
|
|
except Exception as e:
|
|
logging.warning(f"⚠️ WebEngineView no disponible: {e}")
|
|
# Fallback a QTextBrowser
|
|
self.text_browser = QTextBrowser()
|
|
self.text_browser.setOpenExternalLinks(False)
|
|
self._setup_text_browser()
|
|
layout.addWidget(self.text_browser)
|
|
self._webview_available = False
|
|
|
|
def _setup_webview(self):
|
|
"""Configura WebEngineView con MathJax (inicialización perezosa)"""
|
|
# No cargar HTML inmediatamente para optimizar tiempo de inicio
|
|
pass
|
|
|
|
def _setup_text_browser(self):
|
|
"""Configura el browser de texto como fallback"""
|
|
self.text_browser.setStyleSheet("""
|
|
QTextBrowser {
|
|
background-color: #1a1a1a;
|
|
color: #d4d4d4;
|
|
border: none;
|
|
font-family: 'Consolas';
|
|
font-size: 11px;
|
|
padding: 10px;
|
|
}
|
|
""")
|
|
self.text_browser.setHtml("""
|
|
<style>
|
|
body {
|
|
background-color: #1a1a1a;
|
|
color: #d4d4d4;
|
|
font-family: 'Consolas';
|
|
padding: 10px;
|
|
}
|
|
.equation {
|
|
margin: 10px 0;
|
|
padding: 10px;
|
|
background: #2d2d2d;
|
|
border-left: 3px solid #80c7f7;
|
|
border-radius: 3px;
|
|
}
|
|
.comment { border-left-color: #6a9955; }
|
|
.assignment { border-left-color: #dcdcaa; }
|
|
</style>
|
|
<div style="text-align: center; margin-top: 50px; color: #808080;">
|
|
📐 Panel de Ecuaciones<br>
|
|
<small>Las ecuaciones aparecerán aquí</small>
|
|
</div>
|
|
""")
|
|
|
|
def _generate_mathjax_html(self):
|
|
"""Genera HTML base con MathJax configurado para SVG (local o CDN)"""
|
|
# Obtener URL de MathJax (local si está disponible, CDN como fallback)
|
|
mathjax_url = self.mathjax_manager.get_mathjax_url()
|
|
|
|
return f"""<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
|
|
<script>
|
|
// Intentar cargar MathJax local primero, luego CDN como fallback
|
|
window.mathjaxLoadAttempts = 0;
|
|
window.mathJaxReady = false;
|
|
|
|
function loadMathJax(url, isFallback = false) {{
|
|
return new Promise((resolve, reject) => {{
|
|
const script = document.createElement('script');
|
|
script.id = 'MathJax-script';
|
|
script.async = true;
|
|
script.src = url;
|
|
|
|
script.onload = () => {{
|
|
console.log('MathJax cargado desde:', url);
|
|
resolve();
|
|
}};
|
|
|
|
script.onerror = () => {{
|
|
console.error('Error cargando MathJax desde:', url);
|
|
reject(new Error('MathJax load failed'));
|
|
}};
|
|
|
|
document.head.appendChild(script);
|
|
}});
|
|
}}
|
|
|
|
// Configuración de MathJax
|
|
window.MathJax = {{
|
|
tex: {{
|
|
inlineMath: [['$', '$'], ['\\\\(', '\\\\)']],
|
|
displayMath: [['$$', '$$'], ['\\\\[', '\\\\]']],
|
|
processEscapes: true
|
|
}},
|
|
svg: {{
|
|
scale: 0.9,
|
|
minScale: 0.5,
|
|
fontCache: 'global'
|
|
}},
|
|
startup: {{
|
|
ready: function () {{
|
|
MathJax.startup.defaultReady();
|
|
window.mathJaxReady = true;
|
|
console.log('MathJax SVG completamente listo');
|
|
}}
|
|
}}
|
|
}};
|
|
|
|
// Intentar cargar MathJax local, luego CDN
|
|
loadMathJax('{mathjax_url}').catch(() => {{
|
|
console.log('Fallback a CDN de MathJax...');
|
|
return loadMathJax('https://cdn.jsdelivr.net/npm/mathjax@3.2.2/es5/tex-svg.js', true);
|
|
}}).catch(() => {{
|
|
console.error('No se pudo cargar MathJax desde ninguna fuente');
|
|
// Marcar como listo para mostrar contenido sin renderizado
|
|
setTimeout(() => {{
|
|
window.mathJaxReady = true;
|
|
console.log('Modo fallback activado - sin renderizado LaTeX');
|
|
}}, 2000);
|
|
}});
|
|
</script>
|
|
<style>
|
|
body {{
|
|
background-color: #1a1a1a;
|
|
color: #d4d4d4;
|
|
font-family: 'Segoe UI', Arial, sans-serif;
|
|
margin: 0;
|
|
padding: 8px;
|
|
line-height: 1.2;
|
|
}}
|
|
.equation-block {{
|
|
background: rgba(45, 45, 48, 0.8);
|
|
border-left: 3px solid;
|
|
margin: 4px 0;
|
|
padding: 6px 12px;
|
|
border-radius: 4px;
|
|
transition: all 0.1s ease;
|
|
}}
|
|
.equation-block:hover {{
|
|
background: rgba(45, 45, 48, 0.9);
|
|
}}
|
|
.comment {{ border-left-color: #6a9955; }}
|
|
.assignment {{ border-left-color: #dcdcaa; }}
|
|
.equation {{ border-left-color: #c586c0; }}
|
|
.symbolic {{ border-left-color: #9cdcfe; }}
|
|
|
|
.math-content {{
|
|
margin: 2px 0;
|
|
font-size: 14px;
|
|
}}
|
|
|
|
.comment-text {{
|
|
font-style: italic;
|
|
color: #6a9955;
|
|
font-size: 12px;
|
|
margin: 0;
|
|
}}
|
|
|
|
.info-message {{
|
|
text-align: center;
|
|
padding: 20px;
|
|
color: #666;
|
|
font-size: 12px;
|
|
}}
|
|
|
|
/* Optimizaciones para SVG rendering */
|
|
mjx-container[jax="SVG"] {{
|
|
margin: 2px 0 !important;
|
|
}}
|
|
|
|
mjx-container[jax="SVG"] svg {{
|
|
vertical-align: middle;
|
|
}}
|
|
|
|
mjx-container[jax="SVG"] svg text {{
|
|
fill: #d4d4d4 !important;
|
|
}}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div id="equations-container">
|
|
<div class="info-message">
|
|
Panel de Ecuaciones LaTeX (SVG)
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
function addEquation(type, content) {{
|
|
try {{
|
|
var container = document.getElementById('equations-container');
|
|
if (!container) {{
|
|
console.error('Container no encontrado');
|
|
return;
|
|
}}
|
|
|
|
// Limpiar mensaje inicial si existe
|
|
var infoMsg = container.querySelector('.info-message');
|
|
if (infoMsg) infoMsg.remove();
|
|
|
|
var equation = document.createElement('div');
|
|
equation.className = 'equation-block ' + type;
|
|
|
|
var mathContent = document.createElement('div');
|
|
mathContent.className = 'math-content';
|
|
|
|
if (type === 'comment') {{
|
|
mathContent.className = 'comment-text';
|
|
mathContent.textContent = content;
|
|
console.log('Comentario agregado:', content);
|
|
}} else {{
|
|
mathContent.innerHTML = '$$' + content + '$$';
|
|
console.log('Ecuación agregada:', content);
|
|
}}
|
|
|
|
equation.appendChild(mathContent);
|
|
container.appendChild(equation);
|
|
|
|
// Re-renderizar MathJax solo si está listo
|
|
if (window.MathJax && window.mathJaxReady && type !== 'comment') {{
|
|
console.log('Renderizando con MathJax...');
|
|
MathJax.typesetPromise([equation]).then(() => {{
|
|
console.log('Ecuación renderizada exitosamente');
|
|
}}).catch(function(err) {{
|
|
console.error('Error renderizando con MathJax:', err);
|
|
// Mostrar como texto plano si falla
|
|
mathContent.innerHTML = content;
|
|
}});
|
|
}} else if (type !== 'comment') {{
|
|
console.log('MathJax no listo, mostrando como texto:', window.mathJaxReady);
|
|
// Mostrar como texto plano si MathJax no está listo
|
|
mathContent.innerHTML = content;
|
|
}}
|
|
|
|
}} catch (e) {{
|
|
console.error('Error en addEquation:', e);
|
|
}}
|
|
}}
|
|
|
|
function clearEquations() {{
|
|
try {{
|
|
var container = document.getElementById('equations-container');
|
|
if (container) {{
|
|
container.innerHTML = '<div class="info-message">Panel de Ecuaciones LaTeX (SVG)</div>';
|
|
console.log('Ecuaciones limpiadas');
|
|
}}
|
|
}} catch (e) {{
|
|
console.error('Error en clearEquations:', e);
|
|
}}
|
|
}}
|
|
|
|
// Función para notificar que está listo para renderizar
|
|
function triggerInitialRender() {{
|
|
try {{
|
|
console.log('Verificando estado MathJax:', window.mathJaxReady);
|
|
if (window.mathJaxReady) {{
|
|
console.log('MathJax SVG listo para renderizado inicial');
|
|
return true;
|
|
}}
|
|
return false;
|
|
}} catch (e) {{
|
|
console.error('Error en triggerInitialRender:', e);
|
|
return false;
|
|
}}
|
|
}}
|
|
|
|
// Monitor de estado para debug
|
|
setInterval(() => {{
|
|
if (window.mathJaxReady) {{
|
|
console.log('🎯 MathJax listo detectado');
|
|
}}
|
|
}}, 3000);
|
|
</script>
|
|
</body>
|
|
</html>"""
|
|
|
|
def _ensure_webview_initialized(self):
|
|
"""Inicializa WebEngine bajo demanda para optimizar tiempo de carga"""
|
|
if self._webview_initialized:
|
|
return
|
|
|
|
try:
|
|
if hasattr(self, 'webview') and self._webview_available:
|
|
html_content = self._generate_mathjax_html()
|
|
self.webview.setHtml(html_content)
|
|
|
|
# Inicializar timer de verificación MathJax
|
|
if self._mathjax_check_timer is None:
|
|
self._mathjax_check_timer = QTimer()
|
|
self._mathjax_check_timer.timeout.connect(self._check_mathjax_ready)
|
|
self._mathjax_check_timer.start(500) # Verificar cada 500ms
|
|
|
|
self._webview_initialized = True
|
|
logging.debug("✅ WebEngine LaTeX inicializado bajo demanda")
|
|
except Exception as e:
|
|
logging.error(f"Error inicializando WebEngine: {e}")
|
|
|
|
def _check_mathjax_ready(self):
|
|
"""Verifica si MathJax está listo y renderiza ecuaciones pendientes"""
|
|
if not self._webview_available:
|
|
return
|
|
|
|
# Verificar múltiples condiciones de MathJax
|
|
js_check = """
|
|
(function() {
|
|
try {
|
|
// Verificar si window.mathJaxReady está definido
|
|
if (window.mathJaxReady === true) return true;
|
|
|
|
// Verificar si MathJax está disponible y listo
|
|
if (window.MathJax && window.MathJax.startup && window.MathJax.startup.document && window.MathJax.startup.document.state() >= 8) {
|
|
window.mathJaxReady = true;
|
|
return true;
|
|
}
|
|
|
|
// Verificar si existen las funciones necesarias
|
|
if (typeof addEquation === 'function' && typeof clearEquations === 'function') {
|
|
window.mathJaxReady = true;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
} catch(e) {
|
|
console.error('Error verificando MathJax:', e);
|
|
return false;
|
|
}
|
|
})();
|
|
"""
|
|
|
|
self.webview.page().runJavaScript(js_check, self._on_mathjax_ready_check)
|
|
|
|
def _on_mathjax_ready_check(self, ready):
|
|
"""Callback cuando se verifica el estado de MathJax"""
|
|
logging.debug(f"🔍 MathJax ready check: {ready}")
|
|
|
|
if ready and not self._mathjax_ready:
|
|
self._mathjax_ready = True
|
|
self._mathjax_check_timer.stop()
|
|
logging.debug(f"✅ MathJax listo, procesando {len(self._pending_equations)} ecuaciones pendientes")
|
|
|
|
# Renderizar ecuaciones pendientes
|
|
for eq in self._pending_equations:
|
|
self._add_equation_to_webview(eq['type'], eq['content'])
|
|
logging.debug(f"📊 Ecuación agregada al WebView: {eq['type']}")
|
|
self._pending_equations.clear()
|
|
|
|
# Trigger initial render si hay un calculador padre
|
|
if self._parent_calculator and hasattr(self._parent_calculator, '_trigger_initial_latex_render'):
|
|
self._parent_calculator._trigger_initial_latex_render()
|
|
elif not ready:
|
|
self._mathjax_timeout_count += 1
|
|
if self._mathjax_timeout_count >= self._max_mathjax_timeout:
|
|
# Timeout alcanzado, forzar como listo para mostrar contenido en texto plano
|
|
logging.warning("⚠️ MathJax timeout - cambiando a modo fallback")
|
|
self._mathjax_ready = True
|
|
self._mathjax_check_timer.stop()
|
|
|
|
# Procesar ecuaciones pendientes como texto plano
|
|
for eq in self._pending_equations:
|
|
self._add_equation_as_text(eq['type'], eq['content'])
|
|
self._pending_equations.clear()
|
|
else:
|
|
logging.debug(f"⏳ MathJax aún no está listo ({self._mathjax_timeout_count}/{self._max_mathjax_timeout}), continuando verificación...")
|
|
|
|
def _add_equation_to_webview(self, eq_type: str, content: str):
|
|
"""Añade una ecuación directamente al webview"""
|
|
if self._webview_available:
|
|
escaped_content = content.replace('\\', '\\\\').replace("'", "\\'").replace('"', '\\"')
|
|
js_code = f"addEquation('{eq_type}', '{escaped_content}');"
|
|
self.webview.page().runJavaScript(js_code)
|
|
|
|
def _add_equation_as_text(self, eq_type: str, content: str):
|
|
"""Añade una ecuación como texto plano cuando MathJax falla"""
|
|
if self._webview_available:
|
|
escaped_content = content.replace('\\', '\\\\').replace("'", "\\'").replace('"', '\\"')
|
|
# Agregar ecuación como texto plano sin MathJax
|
|
js_code = f"""
|
|
var container = document.getElementById('equations-container');
|
|
if (container) {{
|
|
var equation = document.createElement('div');
|
|
equation.className = 'equation-block {eq_type}';
|
|
equation.innerHTML = '<div class="math-content" style="font-family: monospace;">{escaped_content}</div>';
|
|
container.appendChild(equation);
|
|
}}
|
|
"""
|
|
self.webview.page().runJavaScript(js_code)
|
|
|
|
def add_equation(self, eq_type: str, content: str):
|
|
"""Añade una ecuación al panel"""
|
|
self.equations.append({'type': eq_type, 'content': content})
|
|
|
|
if self._webview_available:
|
|
# Inicializar WebEngine bajo demanda
|
|
self._ensure_webview_initialized()
|
|
|
|
if self._mathjax_ready:
|
|
# MathJax está listo, renderizar inmediatamente
|
|
self._add_equation_to_webview(eq_type, content)
|
|
else:
|
|
# MathJax no está listo, guardar para después
|
|
self._pending_equations.append({'type': eq_type, 'content': content})
|
|
else:
|
|
# Actualizar HTML en text browser
|
|
self._update_text_browser()
|
|
|
|
def clear_equations(self):
|
|
"""Limpia todas las ecuaciones"""
|
|
self.equations.clear()
|
|
self._pending_equations.clear()
|
|
|
|
if self._webview_available and self._webview_initialized:
|
|
# Usar JavaScript para limpiar dinámicamente si MathJax está listo
|
|
if self._mathjax_ready:
|
|
self.webview.page().runJavaScript("clearEquations();")
|
|
else:
|
|
# Si MathJax no está listo, recargar HTML base limpio
|
|
html_content = self._generate_mathjax_html()
|
|
self.webview.setHtml(html_content)
|
|
elif hasattr(self, 'text_browser'):
|
|
# Para fallback o WebEngine no inicializado, solo si text_browser existe
|
|
self._setup_text_browser() # Reset al estado inicial
|
|
|
|
def _update_text_browser(self):
|
|
"""Actualiza el contenido del text browser (fallback)"""
|
|
# Verificar que text_browser existe antes de usarlo
|
|
if not hasattr(self, 'text_browser'):
|
|
return
|
|
|
|
html_parts = ["""
|
|
<style>
|
|
body {
|
|
background-color: #1a1a1a;
|
|
color: #d4d4d4;
|
|
font-family: 'Consolas';
|
|
margin: 0;
|
|
padding: 8px;
|
|
line-height: 1.2;
|
|
}
|
|
.equation {
|
|
margin: 4px 0;
|
|
padding: 6px 12px;
|
|
background: rgba(45, 45, 48, 0.8);
|
|
border-left: 3px solid #80c7f7;
|
|
border-radius: 4px;
|
|
font-size: 12px;
|
|
}
|
|
.comment {
|
|
border-left-color: #6a9955;
|
|
font-style: italic;
|
|
color: #6a9955;
|
|
font-size: 11px;
|
|
}
|
|
.assignment { border-left-color: #dcdcaa; }
|
|
.equation-type { border-left-color: #c586c0; }
|
|
.symbolic { border-left-color: #9cdcfe; }
|
|
code {
|
|
font-family: 'Consolas';
|
|
font-size: 11px;
|
|
color: #d4d4d4;
|
|
}
|
|
</style>
|
|
"""]
|
|
|
|
for eq in self.equations:
|
|
eq_type = eq['type']
|
|
content = eq['content']
|
|
css_class = eq_type
|
|
|
|
if eq_type == 'comment':
|
|
html_parts.append(f'<div class="equation {css_class}">{content}</div>')
|
|
else:
|
|
# Para ecuaciones matemáticas, mostrar en formato de código
|
|
html_parts.append(f'<div class="equation {css_class}"><code>{content}</code></div>')
|
|
|
|
self.text_browser.setHtml(''.join(html_parts))
|
|
|
|
|
|
class LatexProcessor:
|
|
"""Procesador de contenido LaTeX"""
|
|
|
|
@staticmethod
|
|
def generate_complete_latex_content(result: EvaluationResult) -> str:
|
|
"""Genera contenido LaTeX completo incluyendo toda la información del output"""
|
|
try:
|
|
# Para comentarios, usar el texto directamente
|
|
if result.result_type == "comment":
|
|
return result.output or ""
|
|
|
|
latex_parts = []
|
|
|
|
# PARTE 1: Contenido principal (con LaTeX de SymPy si es posible)
|
|
main_content = ""
|
|
if result.actual_result_object is not None:
|
|
try:
|
|
# Verificar si es una ecuación Eq()
|
|
if hasattr(result.actual_result_object, 'func') and result.actual_result_object.func.__name__ == 'Equality':
|
|
# Es una ecuación, convertir a formato var = valor
|
|
lhs = result.actual_result_object.lhs
|
|
rhs = result.actual_result_object.rhs
|
|
lhs_latex = sympy.latex(lhs)
|
|
rhs_latex = sympy.latex(rhs)
|
|
main_content = f"{lhs_latex} = {rhs_latex}"
|
|
else:
|
|
# Intentar generar LaTeX de SymPy para el objeto matemático
|
|
main_content = sympy.latex(result.actual_result_object)
|
|
|
|
# Para asignaciones, el resultado ya viene formateado
|
|
if result.is_assignment and not main_content:
|
|
# Extraer del output ya formateado
|
|
main_content = result.output.split(" ≈")[0] if " ≈" in result.output else result.output
|
|
|
|
except Exception:
|
|
# Si falla el LaTeX de SymPy, usar el output textual
|
|
main_content = result.output or ""
|
|
else:
|
|
main_content = result.output or ""
|
|
|
|
latex_parts.append(main_content)
|
|
|
|
# PARTE 2: Aproximación numérica (si está disponible en el output)
|
|
if result.output and "≈" in result.output:
|
|
approx_parts = result.output.split("≈", 1)
|
|
if len(approx_parts) == 2:
|
|
approx_value = approx_parts[1].strip()
|
|
# Extraer solo la parte numérica antes del indicador de tipo
|
|
if ";" in approx_value:
|
|
approx_value = approx_value.split(";")[0].strip()
|
|
|
|
# La aproximación ya viene en formato var = valor, mantenerla así
|
|
latex_parts.append(f"\\approx {approx_value}")
|
|
|
|
# PARTE 3: Indicador de tipo (si está en el output)
|
|
if result.output and "[" in result.output and "]" in result.output:
|
|
# Extraer el indicador de tipo (ej: [=], [Equality], etc.)
|
|
parts = result.output.split("[")
|
|
if len(parts) >= 2:
|
|
type_part = "[" + parts[-1] # Tomar el último indicador
|
|
if "]" in type_part:
|
|
type_indicator = type_part.split("]")[0] + "]"
|
|
latex_parts.append(f"\\quad \\text{{{type_indicator}}}")
|
|
|
|
# Combinar todas las partes
|
|
complete_latex = " ".join(latex_parts)
|
|
|
|
# Limpiar caracteres problemáticos para MathJax
|
|
complete_latex = complete_latex.replace("__", "_{").replace("**", "^")
|
|
|
|
# Agregar llaves de cierre para subíndices
|
|
import re
|
|
complete_latex = re.sub(r'_\{(\w+)', r'_{\1}', complete_latex)
|
|
|
|
return complete_latex
|
|
|
|
except Exception as e:
|
|
logging.error(f"Error generando LaTeX completo: {e}")
|
|
# Fallback al output original
|
|
return result.output or ""
|
|
|
|
@staticmethod
|
|
def should_add_to_latex(result: EvaluationResult) -> tuple[bool, str]:
|
|
"""Determina si un resultado debe agregarse al panel LaTeX y qué tipo usar"""
|
|
try:
|
|
if result.result_type == "comment":
|
|
return True, "comment"
|
|
elif result.is_assignment:
|
|
return True, "assignment"
|
|
elif result.is_equation:
|
|
return True, "equation"
|
|
elif result.success and result.output:
|
|
# Agregar si tiene contenido matemático
|
|
math_indicators = ['=', '+', '-', '*', '/', '^', 'sqrt', 'sin', 'cos', 'tan', 'log', 'exp']
|
|
if any(indicator in result.output for indicator in math_indicators):
|
|
return True, "symbolic"
|
|
elif result.actual_result_object is not None and isinstance(result.actual_result_object, sympy.Basic):
|
|
return True, "symbolic"
|
|
|
|
return False, ""
|
|
|
|
except Exception:
|
|
return False, "" |