diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c69b11e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+app.log
\ No newline at end of file
diff --git a/__pycache__/main.cpython-313.pyc b/__pycache__/main.cpython-313.pyc
new file mode 100644
index 0000000..5b3788c
Binary files /dev/null and b/__pycache__/main.cpython-313.pyc differ
diff --git a/main.py b/main.py
index 0dacccd..1b17bf0 100644
--- a/main.py
+++ b/main.py
@@ -1,26 +1,65 @@
#All Rights Reserved John Salguero
#Starts the backend to my Youtube stream
+import json
+import asyncio
+import logging
from problem_generator import generate_problem
from steps_generator import generate_steps
from sympy import init_printing, sympify
-import time
-import json
+from fastapi import FastAPI, WebSocket, WebSocketDisconnect
-#define the entry point to the programs
-def main():
- init_printing(order='lex')
- count = -1
- no_problem = True
-
- problem = generate_problem()
- problem["steps"] = generate_steps(problem);
+logging.basicConfig(
+ level=logging.INFO,
+ format="%(asctime)s [%(levelname)s] %(message)s",
+ handlers=[
+ logging.FileHandler("app.log"),
+ logging.StreamHandler() # prints to console
+ ]
+)
+log = logging.getLogger(__name__)
- no_problem = check_solution(problem["steps"][-1]["after"], problem["solution"])
- if no_problem:
- with open("www/data/data.json", "w") as f:
- json.dump(problem, f)
+app = FastAPI()
+
+clients = []
+
+@app.websocket("/ws")
+async def websocket_endpoint(ws: WebSocket):
+ await ws.accept()
+ clients.append(ws)
+
+ try:
+ while True:
+ data = json.loads(await ws.receive_text())
+
+ log.info(f"Received from browser: {data}")
+
+ if data.get("type") == "query_problem":
+ problem = generate_problem_message()
+ await ws.send_text(json.dumps(problem))
+
+ except WebSocketDisconnect:
+ log.info("Client disconnected")
+ except Exception as e:
+ log.error(f"Unexpected error: {e}")
+ finally:
+ if ws in clients:
+ clients.remove(ws)
+
+# example loop
+def generate_problem_message():
+ problem_solved = False
+ problem = {}
+ while not problem_solved:
+ problem["type"] = "generated_problem"
+ problem["data"] = generate_problem()
+ problem["data"]["steps"] = generate_steps(problem["data"]);
+ problem_solved = check_solution(problem["data"]["steps"][-1]["after"], problem["data"]["solution"])
+ if not problem_solved:
+ log.warning(f"issue with problem: {problem}")
+
+ return problem
def check_solution(got, solution):
values = set([sympify(r.split("=")[1].strip()) for r in got.split(",")])
@@ -53,8 +92,4 @@ def is_iterable(obj):
iter(obj)
return True
except TypeError:
- return False
-
-#Starts the program
-if __name__ == "__main__":
- main()
\ No newline at end of file
+ return False
\ No newline at end of file
diff --git a/www/data/data.json b/www/data/data.json
deleted file mode 100644
index 43d4989..0000000
--- a/www/data/data.json
+++ /dev/null
@@ -1 +0,0 @@
-{"type": "two_sides", "problem": "-4*x - 3 = x + 32", "solution": -7, "steps": [{"before": "-4*x - 3 = x + 32", "after": "-5*x - 3 = 32", "step": "Subtract x from both sides", "rule": "Subtraction Property of Equality"}, {"before": "-5*x - 3 = 32", "after": "-5*x = 35", "step": "Add 3 to both sides", "rule": "Addition Property of Equality"}, {"before": "-5*x = 35", "after": "x = -7", "step": "Divide both sides by -5", "rule": "Division Property of Equality"}]}
\ No newline at end of file
diff --git a/www/overlay.html b/www/overlay.html
index 140c2b1..187503f 100644
--- a/www/overlay.html
+++ b/www/overlay.html
@@ -2,7 +2,7 @@
-
+
@@ -10,7 +10,8 @@
Loading...
-
-
+
+
+
\ No newline at end of file
diff --git a/www/problem.js b/www/problem.js
deleted file mode 100644
index 0308ecb..0000000
--- a/www/problem.js
+++ /dev/null
@@ -1,79 +0,0 @@
-let state = "problem"; // problem | steps | done
-let stepIndex = 0;
-let currentData = null;
-
-// Load the data to draw
-async function loadData() {
- const res = await fetch("data/data.json");
- currentData = await res.json();
-
- state = "problem";
- stepIndex = 0;
-
- render();
-}
-
-function render() {
- if (!currentData) return;
-
- const problemEl = document.getElementById("problem");
- const stepsEl = document.getElementById("steps");
-
- if (state === "problem") {
- problemEl.innerHTML = `\\(${currentData.problem}\\)`;
- stepsEl.innerHTML = "";
- }
-
- if (state === "step") {
- problemEl.innerHTML = `\\(${currentData.problem}\\)`;
-
- let html = "";
- for (let i = 0; i <= stepIndex; i++) {
- const s = currentData.steps[i];
- html += `
-
-
\\(${s.before}\\)
-
${s.step}
-
\\(${s.after}\\)
-
-
- `;
- }
-
- stepsEl.innerHTML = html;
- }
-
- MathJax.typesetPromise();
-}
-
-function startSequence() {
- // 1. show problem
- state = "problem";
- render();
-
- setTimeout(() => {
- state = "step";
- stepIndex = 0;
- render();
-
- let interval = setInterval(() => {
- stepIndex++;
-
- render();
-
- if (stepIndex >= currentData.steps.length - 1) {
- clearInterval(interval);
-
- setTimeout(() => {
- loadData(); // next problem
- }, 3000);
- }
- }, 2000); // time between steps
-
- }, 4000); // thinking time before reveal
-}
-
-loadData().then(() => {
- startSequence();
-});
-
diff --git a/www/background.js b/www/scripts/background.js
similarity index 100%
rename from www/background.js
rename to www/scripts/background.js
diff --git a/www/scripts/problem.js b/www/scripts/problem.js
new file mode 100644
index 0000000..3b2d947
--- /dev/null
+++ b/www/scripts/problem.js
@@ -0,0 +1,50 @@
+let state = "problem"; // problem | steps | done
+
+function showProblem() {
+ const problemEl = document.getElementById("problem");
+ const stepsEl = document.getElementById("steps");
+
+ problemEl.innerHTML = `\\(${problemData.problem}\\)`;
+ stepsEl.innerHTML = "";
+
+ MathJax.typesetPromise();
+}
+
+function startSequence() {
+ setTimeout(() => {
+ showNextStep();
+ }, 3000); // thinking time
+}
+
+function showNextStep() {
+ const stepsEl = document.getElementById("steps");
+
+ if (stepIndex >= problemData.steps.length) {
+ // finished → request next problem
+ setTimeout(() => {
+ requestNextProblem();
+ }, 3000);
+
+ return;
+ }
+
+ const s = problemData.steps[stepIndex];
+
+ const html = `
+
+
\\(${s.before}\\)
+
${s.step}
+
\\(${s.after}\\)
+
+
+ `;
+
+ stepsEl.innerHTML += html;
+
+ MathJax.typesetPromise();
+
+ stepIndex++;
+
+ setTimeout(showNextStep, 2000); // time between steps
+}
+
diff --git a/www/scripts/web_sockets.js b/www/scripts/web_sockets.js
new file mode 100644
index 0000000..e46101a
--- /dev/null
+++ b/www/scripts/web_sockets.js
@@ -0,0 +1,31 @@
+const socket = new WebSocket("ws://localhost:8000/ws");
+let problemData = null;
+let stepIndex = 0;
+
+socket.onopen = () => {
+ console.log("Connected to server");
+
+ socket.send(JSON.stringify({
+ type: "query_problem"
+ }));
+};
+
+socket.onmessage = (event) => {
+ const msg = JSON.parse(event.data);
+
+ if (msg.type === "generated_problem") {
+ problemData = msg.data;
+ stepIndex = 0;
+
+ showProblem();
+
+ // start animation sequence
+ startSequence();
+ }
+};
+
+function requestNextProblem() {
+ socket.send(JSON.stringify({
+ type: "query_problem"
+ }));
+}
\ No newline at end of file
diff --git a/www/styles.css b/www/style/styles.css
similarity index 100%
rename from www/styles.css
rename to www/style/styles.css