-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Include working MathJax server in docker image (#258)
## Summary of changes - Include MathJax server deps (Node and JS libs) in docker image ( Resolves #256 ) - Corrected bug in parsing JSON data in `tex2mml` endpoint ( Resolves #257 ) - Update `docker-compose.img2mml.yml` to include networked MathJax and unified REST API for latex2mml + img2mml services (w/ examples in Python) - Update development environment setup instructions - mml response is now xml (avoids funky escapes previously encountered)
- Loading branch information
1 parent
085e0b4
commit 04eb5ee
Showing
15 changed files
with
262 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,37 @@ | ||
# Docker Compose file for the img2mml service | ||
version: "3" | ||
services: | ||
img2mml: | ||
image: lumai/askem-skema-img2mml:local | ||
eq2mml: | ||
#image: lumai/askem-skema-py:latest | ||
# ... or to build locally: | ||
image: lumai/askem-skema-eq2mml:local | ||
build: | ||
context: . | ||
dockerfile: Dockerfile.skema-py | ||
depends_on: | ||
# FIXME: add `condition: service_healthy` and healthcheck | ||
- mathjax | ||
# open browser to http://localhost:8000/docs | ||
entrypoint: uvicorn skema.img2mml.img2mml:app --host=0.0.0.0 --port 8000 | ||
entrypoint: uvicorn skema.img2mml.eq2mml:app --host=0.0.0.0 --port 8000 | ||
ports: | ||
- "8000:8000" # Change port mapping appropriately before deploying. | ||
environment: | ||
- "SKEMA_MATHJAX_HOST=mathjax" | ||
- "SKEMA_MATHJAX_PORT=8031" | ||
# example cmd: curl -X POST http://0.0.0.0:8031/tex2mml \ | ||
# -H "Content-Type: application/json" \ | ||
# -d '{"tex_src": "E = mc^{2}"}' | ||
mathjax: | ||
#image: lumai/askem-skema-py:latest | ||
# ... or to build locally: | ||
image: lumai/askem-skema-mathjax:local | ||
build: | ||
context: . | ||
dockerfile: Dockerfile.skema-py | ||
environment: | ||
- "SKEMA_MATHJAX_HOST=0.0.0.0" | ||
- "SKEMA_MATHJAX_PORT=8031" | ||
ports: | ||
- "8031:8031" | ||
working_dir: /app/skema/img2mml/data_generation | ||
entrypoint: ["npm", "start"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from typing import Text | ||
from pathlib import Path | ||
import base64 | ||
|
||
# NOTE: generate additional images with https://latex2png.com/ | ||
|
||
def _img2b64(img_name: Text) -> bytes: | ||
p = Path(__file__).parent / "images" / img_name | ||
with p.open("rb") as infile: | ||
img_bytes = infile.read() | ||
return base64.b64encode(img_bytes).decode("utf-8") | ||
|
||
img_b64_bayes_transparent = _img2b64("bayes-rule-transparent.png") | ||
img_b64_bayes_white_bg = _img2b64("bayes-rule-white-bg.png") |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
node_modules/ | ||
package-lock.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"name": "mathjax-server", | ||
"version": "1.0.0", | ||
"description": "", | ||
"main": "mathjax_server.js", | ||
"scripts": { | ||
"start": "node mathjax_server.js", | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
}, | ||
"keywords": [], | ||
"author": "", | ||
"license": "Apache 2.0", | ||
"dependencies": { | ||
"express": "^4.18.2", | ||
"lodash": "^4.17.21", | ||
"mathjax-node": "^2.1.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
# -*- coding: utf-8 -*- | ||
""" | ||
Convert the LaTeX equation to the corresponding presentation MathML using the MathJAX service. | ||
Please run the following command to initialize the MathJAX service: | ||
node data_generation/mathjax_server.js | ||
""" | ||
|
||
from typing import Text, Union | ||
from typing_extensions import Annotated | ||
from fastapi import FastAPI, Body, File, Response, Request, Query | ||
from skema.img2mml.api import (get_mathml_from_bytes, get_mathml_from_latex) | ||
from skema.data.eq2mml import img_b64_bayes_white_bg | ||
from pydantic import BaseModel, Field | ||
import base64 | ||
|
||
EquationQueryParameter = Annotated[ | ||
Text, | ||
Query( | ||
examples={ | ||
"simple": { | ||
"summary": "A familiar equation", | ||
"description": "A simple equation (mass-energy equivalence)", | ||
"value": "E = mc^{2}", | ||
}, | ||
"complex": { | ||
"summary": "A more feature-rich equation (Bayes' rule)", | ||
"description": "A equation drawing on latex features", | ||
"value": "\\frac{P(\\textrm{a } | \\textrm{ b}) \\times P(\\textrm{b})}{P(\\textrm{a})}", | ||
} | ||
}, | ||
), | ||
] | ||
|
||
ImageBytes = Annotated[ | ||
bytes, | ||
File( | ||
description="bytes of a PNG of an equation", | ||
# examples={ | ||
# "bayes-rule": { | ||
# "summary": "PNG of Bayes' rule", | ||
# "description": "PNG of Bayes' rule", | ||
# "value": str(img_path_bayes_rule_eqn), | ||
# } | ||
# }, | ||
), | ||
] | ||
|
||
class LatexEquation(BaseModel): | ||
tex_src: Text = Field(title="LaTeX equation", description="The LaTeX equation to process") | ||
class Config: | ||
schema_extra = { | ||
"example": { | ||
"tex_src": "E = mc^{c}", | ||
} | ||
} | ||
|
||
|
||
app = FastAPI() | ||
|
||
def process_latex_equation(eqn: Text) -> Response: | ||
"""Helper function used by both GET and POST LaTeX equation processing endpoints""" | ||
res = get_mathml_from_latex(eqn) | ||
return Response(content=res, media_type="application/xml") | ||
|
||
# FIXME: have this test the mathjax endpoint (and perhaps check the pt model loaded) | ||
@app.get("/healthcheck", summary="Ping endpoint to test health of service", response_model=Text, status_code=200) | ||
def healthcheck(): | ||
return "The eq2mml service is running." | ||
|
||
@app.post("/image/mml", summary="Get MathML representation of an equation image") | ||
async def post_image_to_mathml(data: ImageBytes) -> Response: | ||
""" | ||
Endpoint for generating MathML from an input image. | ||
### Python example | ||
``` | ||
import requests | ||
files = { | ||
"data": open("bayes-rule-white-bg.png", "rb"), | ||
} | ||
r = requests.post("http://0.0.0.0:8000/image/mml", files=files) | ||
print(r.text) | ||
""" | ||
# convert bytes of png image to tensor | ||
res = get_mathml_from_bytes(data) | ||
print(res) | ||
print(type(res)) | ||
return Response(content=res, media_type="application/xml") | ||
|
||
@app.post("/image/base64/mml", summary="Get MathML representation of an equation image") | ||
async def post_b64image_to_mathml(request: Request) -> Response: | ||
""" | ||
Endpoint for generating MathML from an input image. | ||
### Python example | ||
``` | ||
from pathlib import Path | ||
import base64 | ||
import requests | ||
url = "http://0.0.0.0:8000/image/base64/mml" | ||
with Path("bayes-rule-white-bg.png").open("rb") as infile: | ||
img_bytes = infile.read() | ||
img_b64 = base64.b64encode(img_bytes).decode("utf-8") | ||
r = requests.post(url, data=img_b64) | ||
print(r.text) | ||
""" | ||
img_b64 = await request.body() | ||
img_bytes = base64.b64decode(img_b64) | ||
# convert bytes of png image to tensor | ||
res = get_mathml_from_bytes(img_bytes) | ||
return Response(content=res, media_type="application/xml") | ||
|
||
@app.get("/latex/mml", summary="Get MathML representation of a LaTeX equation") | ||
async def get_tex_to_mathml(tex_src: EquationQueryParameter) -> Response: | ||
""" | ||
GET endpoint for generating MathML from an input LaTeX equation. | ||
### Python example | ||
``` | ||
import requests | ||
r = requests.get("http://0.0.0.0:8000/latex/mml", params={"tex_src":"E = mc^{c}"}) | ||
print(r.text) | ||
""" | ||
return process_latex_equation(tex_src) | ||
|
||
@app.post("/latex/mml", summary="Get MathML representation of a LaTeX equation") | ||
async def post_tex_to_mathml(eqn: LatexEquation) -> Response: | ||
""" | ||
Endpoint for generating MathML from an input LaTeX equation. | ||
### Python example | ||
``` | ||
import requests | ||
r = requests.post("http://0.0.0.0:8000/latex/mml", json={"tex_src":"E = mc^{c}"}) | ||
print(r.text) | ||
""" | ||
# convert latex string to presentation mathml | ||
return process_latex_equation(eqn.tex_src) |
Oops, something went wrong.