compendious commited on
Commit
e6f5f64
·
verified ·
1 Parent(s): 6042735

Upload folder using huggingface_hub

Browse files
Dockerfile CHANGED
@@ -1,7 +1,14 @@
 
1
  FROM python:3.10-slim
 
 
2
  WORKDIR /code
 
3
  COPY requirements.txt .
4
  RUN pip install --no-cache-dir -r requirements.txt
 
 
5
  COPY . .
6
- # We run from /code so that 'frontend/' and 'models/' are visible to app.py
 
7
  CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "7860"]
 
1
+ # Python 3.10 (slim) as base
2
  FROM python:3.10-slim
3
+
4
+ # THhis is the working directory of the container
5
  WORKDIR /code
6
+
7
  COPY requirements.txt .
8
  RUN pip install --no-cache-dir -r requirements.txt
9
+
10
+ # Copy the entire application code into the container
11
  COPY . .
12
+
13
+ # Run the FastAPI application using uvicorn on all interfaces at port 7860
14
  CMD ["uvicorn", "backend.app:app", "--host", "0.0.0.0", "--port", "7860"]
LICENSE CHANGED
@@ -1,3 +1,5 @@
 
 
1
  © 2026 intelligent-username
2
 
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
@@ -5,3 +7,4 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
5
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
 
7
  THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 
1
+ # MIT License
2
+
3
  © 2026 intelligent-username
4
 
5
  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 
7
  The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
 
9
  THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10
+
README.md CHANGED
@@ -6,19 +6,24 @@ colorTo: gray
6
  sdk: docker
7
  app_port: 7860
8
  ---
 
9
  # Optical Character Recognition
10
 
11
  ![Demonstration](https://varak.dev/host/EMNIST-OCR-DEMO.webp)
12
 
13
  Use the tool live [here](https://ocr.varak.dev).
14
 
15
- This is an optical character recognition (OCR) tool that extracts characters from drawings. Using basic JS/HTML, we create a canvas to draw on, convert the drawing toa usable 28x28 pixel format, and send to the backend for prediction. In the backend, we use FastAPI to handle requests, with the only routes being `/` for the home page and `/predict` for predictions. The prediction route uses a pre-trained CNN model that is able to recognize all English characters and digits. For more details on the architecture, the dataset, and training process, check out [this writeup](https://github.com/intelligent-username/CNN/tree/main/char), which presents the simpler of two models trained for my writeup on CNNs (this one). For a better understanding of CNNs in general, check out this [broader writeup](https://github.com/intelligent-username/CNN).
 
 
 
 
16
 
17
  ## Usage
18
 
19
  Once again, the tool is hosted [here](https://ocr.varak.dev) for easy access.
20
 
21
- Draw the character you want to recognize on the left canvas. The right canvas will display the top-k predictions, where k can be adjusted using the slider below it. The slider is capped at 15 since, after 15, all of the predictions are basically at 0% probability.
22
 
23
  To run this project locally, take the following steps:
24
 
@@ -35,8 +40,8 @@ cd OCR
35
 
36
  ```bash
37
  python -m venv OCR-env
38
- OCR-env\Scripts\activate # On Windows
39
- source OCR-env/bin/activate # On macOS/Linux
40
  pip install -r requirements.txt
41
  ```
42
 
 
6
  sdk: docker
7
  app_port: 7860
8
  ---
9
+
10
  # Optical Character Recognition
11
 
12
  ![Demonstration](https://varak.dev/host/EMNIST-OCR-DEMO.webp)
13
 
14
  Use the tool live [here](https://ocr.varak.dev).
15
 
16
+ This is an optical character recognition (OCR) tool that extracts characters from drawings. It's made with FastAPI for the backend, vanilla JS/HTML for the frontend, and the model was trained using PyTorch.
17
+
18
+ The project creates a canvas to draw on, converts the drawing to a usable 28x28 pixel format, and sends it to the backend for prediction.
19
+
20
+ The only two routes for the backend are `/` for the home page and `/predict` for prediction API. The prediction route recognizes all English characters and digits. For more details on the architecture, the dataset, and training process, check out [this writeup](https://github.com/intelligent-username/CNN/tree/main/char), which presents the simpler of two models trained for my [writeup on CNNs](https://github.com/intelligent-username/CNN).
21
 
22
  ## Usage
23
 
24
  Once again, the tool is hosted [here](https://ocr.varak.dev) for easy access.
25
 
26
+ Draw the character you want to recognize on the left canvas. The right canvas will display the top-k predictions, where k can be adjusted using the slider below it. The slider is capped at 15 since, after 15, all of the predictions are basically guaranteed to be at 0% probability.
27
 
28
  To run this project locally, take the following steps:
29
 
 
40
 
41
  ```bash
42
  python -m venv OCR-env
43
+ OCR-env\Scripts\activate # On Windows
44
+ source OCR-env/bin/activate # On mac/Linux
45
  pip install -r requirements.txt
46
  ```
47
 
backend/__init__.py CHANGED
@@ -1 +1 @@
1
- # Just for Docker
 
1
+ # Modularize
backend/app.py CHANGED
@@ -1,6 +1,7 @@
1
  import torch as t
2
  import asyncio
3
  import os
 
4
 
5
  from backend.utils import predict_image
6
  from backend.model import EMNIST_VGG
@@ -54,8 +55,6 @@ if not os.path.exists(MODEL_PATH):
54
  # This downloads the file and returns the local path
55
  downloaded_path = hf_hub_download(repo_id=REPO_ID, filename=FILENAME)
56
 
57
- # Optional: Move it to your backend folder so your existing load logic works
58
- import shutil
59
  shutil.copy(downloaded_path, MODEL_PATH)
60
  print(f"Weights secured at {MODEL_PATH}")
61
 
 
1
  import torch as t
2
  import asyncio
3
  import os
4
+ import shutil
5
 
6
  from backend.utils import predict_image
7
  from backend.model import EMNIST_VGG
 
55
  # This downloads the file and returns the local path
56
  downloaded_path = hf_hub_download(repo_id=REPO_ID, filename=FILENAME)
57
 
 
 
58
  shutil.copy(downloaded_path, MODEL_PATH)
59
  print(f"Weights secured at {MODEL_PATH}")
60
 
backend/model.py CHANGED
@@ -1,12 +1,13 @@
1
  """
2
  VGG-style CNN for EMNIST character classification.
3
- See the README for a better description.
4
  """
5
 
6
  # The .pth file (weights) for this model will be downloaded from HuggingFace by app.py
7
  # It's hosted at https://huggingface.co/compendious/EMNIST-OCR-WEIGHTS/
8
  # The file is EMNIST_CNN.pth
9
- # Go here to download directly: https://huggingface.co/compendious/EMNIST-OCR-WEIGHTS/resolve/main/EMNIST_CNN.pth?download=true
 
10
 
11
  import torch
12
  import torch.nn as nn
 
1
  """
2
  VGG-style CNN for EMNIST character classification.
3
+ See the README for a more detailed description.
4
  """
5
 
6
  # The .pth file (weights) for this model will be downloaded from HuggingFace by app.py
7
  # It's hosted at https://huggingface.co/compendious/EMNIST-OCR-WEIGHTS/
8
  # The file is EMNIST_CNN.pth
9
+ # Go here to download directly:
10
+ # https://huggingface.co/compendious/EMNIST-OCR-WEIGHTS/resolve/main/EMNIST_CNN.pth?download=true
11
 
12
  import torch
13
  import torch.nn as nn
backend/utils.py CHANGED
@@ -4,6 +4,19 @@ import numpy as np
4
  MAX_CLASSES = 15
5
 
6
  def predict_image(image: list[float], model, device, top_k: int = 10) -> dict:
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  # RESHAPE
8
  # Input comes in as flat 784 list -> (1 batch, 1 channel, 28 height, 28 width)
9
  x = t.tensor(image, dtype=t.float32).view(1, 1, 28, 28)
 
4
  MAX_CLASSES = 15
5
 
6
  def predict_image(image: list[float], model, device, top_k: int = 10) -> dict:
7
+ """
8
+ Docstring for predict_image
9
+
10
+ :param image: Description
11
+ :type image: list[float]
12
+ :param model: Description
13
+ :param device: Description
14
+ :param top_k: Description
15
+ :type top_k: int
16
+ :return: Description
17
+ :rtype: dict
18
+ """
19
+
20
  # RESHAPE
21
  # Input comes in as flat 784 list -> (1 batch, 1 channel, 28 height, 28 width)
22
  x = t.tensor(image, dtype=t.float32).view(1, 1, 28, 28)
frontend/helpers/Sanitizer.js CHANGED
@@ -1,3 +1,8 @@
 
 
 
 
 
1
  const blockSize = 15; // 420 / 28 = 15
2
 
3
  // Input Processor
 
1
+ // Take Canvas input (left)
2
+ // Convert 420x420 to 28x28
3
+ // Then convert to Binary
4
+ // So it can be sent to the API
5
+
6
  const blockSize = 15; // 420 / 28 = 15
7
 
8
  // Input Processor
frontend/helpers/barGraphs.js CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  function drawPredictionGraph(canvas, predictions) {
2
  const ctx = canvas.getContext("2d");
3
  const w = canvas.width;
 
1
+ // Take response from API
2
+ // Draw final output
3
+
4
  function drawPredictionGraph(canvas, predictions) {
5
  const ctx = canvas.getContext("2d");
6
  const w = canvas.width;
frontend/helpers/footer.js CHANGED
@@ -1,3 +1,5 @@
 
 
1
  function initFooter() {
2
  const footer = document.createElement('footer');
3
  footer.className = 'footer';
 
1
+ // Just the footer w/ basic info
2
+
3
  function initFooter() {
4
  const footer = document.createElement('footer');
5
  footer.className = 'footer';
frontend/helpers/kSlider.js CHANGED
@@ -1,7 +1,10 @@
 
 
1
  const slider = document.getElementById("k-slider");
2
  const output = document.getElementById("k-value");
3
 
4
  // Initialize w/ default
 
5
  output.textContent = slider.value;
6
 
7
  // Update number instantly on drag
 
1
+ // top-k bar chart display slider
2
+
3
  const slider = document.getElementById("k-slider");
4
  const output = document.getElementById("k-value");
5
 
6
  // Initialize w/ default
7
+ // 10 rn
8
  output.textContent = slider.value;
9
 
10
  // Update number instantly on drag
frontend/index.html CHANGED
@@ -2,7 +2,7 @@
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
- <title>EMNIST OCR Canvas</title>
6
  <link rel="stylesheet" href="/static/style.css" />
7
  </head>
8
  <body>
 
2
  <html lang="en">
3
  <head>
4
  <meta charset="UTF-8" />
5
+ <title>EMNIST OCR Canvases</title>
6
  <link rel="stylesheet" href="/static/style.css" />
7
  </head>
8
  <body>
frontend/main.js CHANGED
@@ -1,4 +1,4 @@
1
- // main.js is just for putting everything together quickly and simply. Don't grow into a monolith or complicate the project.
2
 
3
  const canvas = document.getElementById("draw-canvas");
4
  // Use willReadFrequently to optimize repeated getImageData readbacks
 
1
+
2
 
3
  const canvas = document.getElementById("draw-canvas");
4
  // Use willReadFrequently to optimize repeated getImageData readbacks
frontend/style.css CHANGED
@@ -1,3 +1,5 @@
 
 
1
  body {
2
  font-family: 'Consolas', 'Courier New', monospace;
3
  margin: 0;
 
1
+ /* Each style is basically just for 1 element */
2
+
3
  body {
4
  font-family: 'Consolas', 'Courier New', monospace;
5
  margin: 0;
requirements.txt CHANGED
@@ -1,9 +1,15 @@
1
- fastapi
2
- uvicorn
3
- aiofiles
4
- torch --index-url https://download.pytorch.org/whl/cpu
5
- torchvision --index-url https://download.pytorch.org/whl/cpu
6
- numpy
7
- pydantic
8
 
9
- huggingface-hub
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ --extra-index-url https://download.pytorch.org/whl/cpu
 
 
 
 
 
 
2
 
3
+ # ML
4
+ torch==2.5.1
5
+ torchvision==0.20.1
6
+ numpy==1.26.4
7
+
8
+ # Frameworx
9
+ fastapi==0.115.6
10
+ pydantic==2.10.3
11
+ uvicorn==0.34.0
12
+ aiofiles==24.1.0
13
+
14
+ # Utilz
15
+ huggingface-hub==0.27.0