Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Mathematical Insight Tutor</title> | |
<!-- Bootstrap CSS --> | |
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"> | |
<!-- Font Awesome Icons --> | |
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0-beta3/css/all.min.css" rel="stylesheet"> | |
<style> | |
body { | |
background-color: #f4f6f9; | |
} | |
.card-header { | |
background-color: #007bff; | |
color: white; | |
} | |
.nav-pills .nav-link.active { | |
background-color: #007bff; | |
} | |
.result-container { | |
background-color: white; | |
border-radius: 8px; | |
padding: 20px; | |
margin-top: 20px; | |
box-shadow: 0 4px 6px rgba(0,0,0,0.1); | |
max-height: 400px; | |
overflow-y: auto; | |
} | |
.typing-indicator { | |
display: none; | |
color: #007bff; | |
font-style: italic; | |
} | |
.markdown-content code { | |
background-color: #f4f4f4; | |
padding: 2px 4px; | |
border-radius: 4px; | |
} | |
.markdown-content pre { | |
background-color: #f4f4f4; | |
padding: 10px; | |
border-radius: 4px; | |
overflow-x: auto; | |
} | |
</style> | |
<!-- KaTeX CSS for styling --> | |
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css"> | |
</head> | |
<body> | |
<div class="container mt-5"> | |
<div class="row justify-content-center"> | |
<div class="col-md-10"> | |
<div class="card shadow-lg"> | |
<div class="card-header text-center"> | |
<h2 class="mb-0"> | |
<i class="fas fa-calculator me-2"></i>Mathematical Insight Tutor | |
</h2> | |
</div> | |
<div class="card-body"> | |
<!-- Navigation Tabs --> | |
<ul class="nav nav-pills nav-fill mb-4" id="mathTabs" role="tablist"> | |
<li class="nav-item" role="presentation"> | |
<button class="nav-link active" id="solve-tab" data-bs-toggle="tab" data-bs-target="#solve" type="button" role="tab"> | |
<i class="fas fa-calculator me-2"></i>Solve Problem | |
</button> | |
</li> | |
<li class="nav-item" role="presentation"> | |
<button class="nav-link" id="hint-tab" data-bs-toggle="tab" data-bs-target="#hint" type="button" role="tab"> | |
<i class="fas fa-lightbulb me-2"></i>Generate Hint | |
</button> | |
</li> | |
<li class="nav-item" role="presentation"> | |
<button class="nav-link" id="verify-tab" data-bs-toggle="tab" data-bs-target="#verify" type="button" role="tab"> | |
<i class="fas fa-check-circle me-2"></i>Verify Solution | |
</button> | |
</li> | |
<li class="nav-item" role="presentation"> | |
<button class="nav-link" id="generate-tab" data-bs-toggle="tab" data-bs-target="#generate" type="button" role="tab"> | |
<i class="fas fa-file-alt me-2"></i>Practice Question | |
</button> | |
</li> | |
<li class="nav-item" role="presentation"> | |
<button class="nav-link" id="explain-tab" data-bs-toggle="tab" data-bs-target="#explain" type="button" role="tab"> | |
<i class="fas fa-chalkboard-teacher me-2"></i>Explain Concept | |
</button> | |
</li> | |
</ul> | |
<!-- Tab Content --> | |
<div class="tab-content" id="mathTabsContent"> | |
<!-- Solve Problem Tab --> | |
<div class="tab-pane fade show active" id="solve" role="tabpanel"> | |
<form id="solveForm" class="math-form" data-endpoint="solve"> | |
<div class="mb-3"> | |
<label for="solveProblem" class="form-label">Enter Math Problem</label> | |
<input type="text" class="form-control" id="solveProblem" name="problem" | |
placeholder="e.g., Solve for x: 2x + 5 = 15" required> | |
</div> | |
<div class="mb-3"> | |
<label for="solveDifficulty" class="form-label">Difficulty Level</label> | |
<select class="form-select" id="solveDifficulty" name="difficulty" required> | |
<option value="">Select Difficulty</option> | |
<option>Beginner</option> | |
<option>Intermediate</option> | |
<option>Advanced</option> | |
</select> | |
</div> | |
<button type="submit" class="btn btn-primary"> | |
<i class="fas fa-play me-2"></i>Solve Problem | |
</button> | |
</form> | |
</div> | |
<!-- Hint Tab --> | |
<div class="tab-pane fade" id="hint" role="tabpanel"> | |
<form id="hintForm" class="math-form" data-endpoint="hint"> | |
<div class="mb-3"> | |
<label for="hintProblem" class="form-label">Enter Math Problem for Hint</label> | |
<input type="text" class="form-control" id="hintProblem" name="problem" | |
placeholder="e.g., Solve for x: 2x + 5 = 15" required> | |
</div> | |
<div class="mb-3"> | |
<label for="hintDifficulty" class="form-label">Difficulty Level</label> | |
<select class="form-select" id="hintDifficulty" name="difficulty" required> | |
<option value="">Select Difficulty</option> | |
<option>Beginner</option> | |
<option>Intermediate</option> | |
<option>Advanced</option> | |
</select> | |
</div> | |
<button type="submit" class="btn btn-primary"> | |
<i class="fas fa-lightbulb me-2"></i>Generate Hint | |
</button> | |
</form> | |
</div> | |
<!-- Verify Solution Tab --> | |
<div class="tab-pane fade" id="verify" role="tabpanel"> | |
<form id="verifyForm" class="math-form" data-endpoint="verify"> | |
<div class="mb-3"> | |
<label for="verifyProblem" class="form-label">Enter Math Problem</label> | |
<input type="text" class="form-control" id="verifyProblem" name="problem" | |
placeholder="e.g., Solve for x: 2x + 5 = 15" required> | |
</div> | |
<div class="mb-3"> | |
<label for="verifySolution" class="form-label">Enter Your Solution</label> | |
<input type="text" class="form-control" id="verifySolution" name="solution" | |
placeholder="e.g., x = 5" required> | |
</div> | |
<button type="submit" class="btn btn-primary"> | |
<i class="fas fa-check-circle me-2"></i>Verify Solution | |
</button> | |
</form> | |
</div> | |
<!-- Generate Practice Question Tab --> | |
<div class="tab-pane fade" id="generate" role="tabpanel"> | |
<form id="generateForm" class="math-form" data-endpoint="generate"> | |
<div class="mb-3"> | |
<label for="generateTopic" class="form-label">Enter Math Topic</label> | |
<input type="text" class="form-control" id="generateTopic" name="topic" | |
placeholder="e.g., Algebra, Calculus" required> | |
</div> | |
<div class="mb-3"> | |
<label for="generateDifficulty" class="form-label">Difficulty Level</label> | |
<select class="form-select" id="generateDifficulty" name="difficulty" required> | |
<option value="">Select Difficulty</option> | |
<option>Beginner</option> | |
<option>Intermediate</option> | |
<option>Advanced</option> | |
</select> | |
</div> | |
<button type="submit" class="btn btn-primary"> | |
<i class="fas fa-file-alt me-2"></i>Generate Practice Question | |
</button> | |
</form> | |
</div> | |
<!-- Explain Concept Tab --> | |
<div class="tab-pane fade" id="explain" role="tabpanel"> | |
<form id="explainForm" class="math-form" data-endpoint="explain"> | |
<div class="mb-3"> | |
<label for="explainProblem" class="form-label">Enter Math Problem</label> | |
<input type="text" class="form-control" id="explainProblem" name="problem" | |
placeholder="e.g., Solve for x: 2x + 5 = 15" required> | |
</div> | |
<div class="mb-3"> | |
<label for="explainDifficulty" class="form-label">Difficulty Level</label> | |
<select class="form-select" id="explainDifficulty" name="difficulty" required> | |
<option value="">Select Difficulty</option> | |
<option>Beginner</option> | |
<option>Intermediate</option> | |
<option>Advanced</option> | |
</select> | |
</div> | |
<button type="submit" class="btn btn-primary"> | |
<i class="fas fa-chalkboard-teacher me-2"></i>Explain Concept | |
</button> | |
</form> | |
</div> | |
</div> | |
<!-- Result Container --> | |
<div class="result-container mt-4"> | |
<div class="typing-indicator" id="typingIndicator"> | |
<i class="fas fa-spinner fa-spin me-2"></i>Generating response... | |
</div> | |
<div id="resultContent" class="markdown-content"></div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Bootstrap JS and Popper --> | |
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.6/dist/umd/popper.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.min.js"></script> | |
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script> | |
<!-- KaTeX JS for rendering --> | |
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js"></script> | |
<!-- Auto-render extension --> | |
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js"></script> | |
<script> | |
function preprocessLatex(text) { | |
// Convert block math `[ ... ]` to `\[ ... \]` | |
text = text.replace(/\[([^\[\]]+)\]/g, '\\[$1\\]'); | |
// Convert inline math `( ... )` to `\( ... \)` | |
text = text.replace(/\(([^\(\)]+)\)/g, '\\($1\\)'); | |
return text; | |
} | |
document.addEventListener('DOMContentLoaded', () => { | |
// WebSocket connection management | |
let socket = null; | |
// Function to handle WebSocket connection and streaming | |
function handleWebSocketStream(endpoint, formData) { | |
// Close any existing socket | |
if (socket) { | |
socket.close(); | |
} | |
// Get DOM elements | |
const resultContent = document.getElementById('resultContent'); | |
const typingIndicator = document.getElementById('typingIndicator'); | |
// Reset result container | |
resultContent.innerHTML = ''; | |
typingIndicator.style.display = 'block'; | |
// Establish WebSocket connection | |
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'; | |
socket = new WebSocket(`${protocol}//${window.location.host}/ws/${endpoint}`); | |
socket.onopen = () => { | |
// Send form data through WebSocket | |
socket.send(JSON.stringify(formData)); | |
}; | |
socket.onmessage = (event) => { | |
const data = JSON.parse(event.data); | |
if (data.chunk) { | |
resultContent.innerHTML += data.chunk; | |
} | |
if (data.complete) { | |
const htmlChunk = marked.parse(resultContent.innerHTML); | |
const preProcLatex=preprocessLatex(htmlChunk); | |
// Append streaming chunks as HTML | |
resultContent.innerHTML = preProcLatex; | |
renderMathInElement(resultContent, { | |
delimiters: [ | |
{ left: "\\(", right: "\\)", display: false }, | |
{ left: "\\[", right: "\\]", display: true }, | |
{ left: "$$", right: "$$", display: true }, | |
{ left: "$", right: "$", display: false } | |
] | |
}); | |
// Streaming complete | |
typingIndicator.style.display = 'none'; | |
socket.close(); | |
} | |
if (data.error) { | |
// Handle errors | |
resultContent.innerHTML = `Error: ${data.error}`; | |
typingIndicator.style.display = 'none'; | |
socket.close(); | |
} | |
}; | |
socket.onerror = (error) => { | |
console.error('WebSocket Error:', error); | |
resultContent.innerHTML = 'WebSocket connection error'; | |
typingIndicator.style.display = 'none'; | |
}; | |
} | |
// Attach submit event to all math forms | |
const forms = document.querySelectorAll('.math-form'); | |
forms.forEach(form => { | |
form.addEventListener('submit', (e) => { | |
e.preventDefault(); | |
// Get the WebSocket endpoint from the form's data attribute | |
const endpoint = form.dataset.endpoint; | |
// Prepare form data | |
const formData = Object.fromEntries(new FormData(form)); | |
// Initiate WebSocket streaming | |
handleWebSocketStream(endpoint, formData); | |
}); | |
}); | |
}); | |
</script> | |
</body> | |
</html> | |