LexTechA commited on
Commit
30f0c4b
Β·
verified Β·
1 Parent(s): f1f87f1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +40 -9
app.py CHANGED
@@ -6,8 +6,9 @@ import secrets
6
  import logging
7
  import numpy as np
8
  from contextlib import asynccontextmanager
 
9
 
10
- from fastapi import FastAPI, HTTPException, Security, Depends
11
  from fastapi.security.api_key import APIKeyHeader
12
  from fastapi.middleware.cors import CORSMiddleware
13
  from pydantic import BaseModel
@@ -17,7 +18,11 @@ import onnxruntime as rt
17
 
18
  from utils.tokenizer_base import Tokenizer
19
 
20
- logging.basicConfig(level=logging.INFO)
 
 
 
 
21
  logger = logging.getLogger(__name__)
22
 
23
  # ── Config ────────────────────────────────────────────────────────────────────
@@ -30,9 +35,9 @@ ORT_INTRA_THREADS = int(os.getenv("ORT_INTRA_THREADS", "1"))
30
  ORT_INTER_THREADS = int(os.getenv("ORT_INTER_THREADS", "1"))
31
 
32
  # ── Torch global optimizations ────────────────────────────────────────────────
33
- torch.set_grad_enabled(False) # no autograd overhead on tensor ops
34
- torch.set_num_threads(1) # don't compete with ORT threads
35
- torch.set_num_interop_threads(1) # no inter-op parallelism from torch
36
 
37
  # ── API Key Auth ──────────────────────────────────────────────────────────────
38
  api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
@@ -63,18 +68,21 @@ session = rt.InferenceSession(
63
  input_name = session.get_inputs()[0].name
64
  logger.info("βœ… ONNX model ready")
65
 
 
 
 
66
  # ── Inference ─────────────────────────────────────────────────────────────────
67
  def preprocess(image: Image.Image) -> np.ndarray:
68
  image = image.convert("RGB").resize(IMG_SIZE, Image.BILINEAR)
69
  x = np.ascontiguousarray(image, dtype=np.float32)
70
  x = (x / 255.0 - 0.5) / 0.5
71
- return x.transpose(2, 0, 1)[np.newaxis, :] # [1, 3, H, W]
72
 
73
 
74
  def solve_image(image: Image.Image) -> str:
75
- x = preprocess(image)
76
- logits = session.run(None, {input_name: x})[0]
77
- probs = torch.tensor(logits).softmax(-1)
78
  preds, _ = tokenizer.decode(probs)
79
  return preds[0]
80
 
@@ -117,6 +125,28 @@ app.add_middleware(
117
  )
118
 
119
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  # ── Endpoints ─────────────────────────────────────────────────────────────────
121
  @app.get("/health")
122
  def health():
@@ -127,6 +157,7 @@ def health():
127
  "quantized": True,
128
  "workers": os.getenv("WEB_CONCURRENCY", "1"),
129
  "intra_threads": ORT_INTRA_THREADS,
 
130
  }
131
 
132
 
 
6
  import logging
7
  import numpy as np
8
  from contextlib import asynccontextmanager
9
+ from datetime import datetime, timezone
10
 
11
+ from fastapi import FastAPI, HTTPException, Security, Depends, Request
12
  from fastapi.security.api_key import APIKeyHeader
13
  from fastapi.middleware.cors import CORSMiddleware
14
  from pydantic import BaseModel
 
18
 
19
  from utils.tokenizer_base import Tokenizer
20
 
21
+ logging.basicConfig(
22
+ level=logging.INFO,
23
+ format="%(asctime)s UTC | %(levelname)s | %(message)s",
24
+ datefmt="%Y-%m-%d %H:%M:%S"
25
+ )
26
  logger = logging.getLogger(__name__)
27
 
28
  # ── Config ────────────────────────────────────────────────────────────────────
 
35
  ORT_INTER_THREADS = int(os.getenv("ORT_INTER_THREADS", "1"))
36
 
37
  # ── Torch global optimizations ────────────────────────────────────────────────
38
+ torch.set_grad_enabled(False)
39
+ torch.set_num_threads(1)
40
+ torch.set_num_interop_threads(1)
41
 
42
  # ── API Key Auth ──────────────────────────────────────────────────────────────
43
  api_key_header = APIKeyHeader(name="X-API-Key", auto_error=False)
 
68
  input_name = session.get_inputs()[0].name
69
  logger.info("βœ… ONNX model ready")
70
 
71
+ # ── Request counter (per worker) ──────────────────────────────────────────────
72
+ request_count = 0
73
+
74
  # ── Inference ─────────────────────────────────────────────────────────────────
75
  def preprocess(image: Image.Image) -> np.ndarray:
76
  image = image.convert("RGB").resize(IMG_SIZE, Image.BILINEAR)
77
  x = np.ascontiguousarray(image, dtype=np.float32)
78
  x = (x / 255.0 - 0.5) / 0.5
79
+ return x.transpose(2, 0, 1)[np.newaxis, :]
80
 
81
 
82
  def solve_image(image: Image.Image) -> str:
83
+ x = preprocess(image)
84
+ logits = session.run(None, {input_name: x})[0]
85
+ probs = torch.tensor(logits).softmax(-1)
86
  preds, _ = tokenizer.decode(probs)
87
  return preds[0]
88
 
 
125
  )
126
 
127
 
128
+ # ── Access logging middleware ─────────────────────────────────────────────────
129
+ @app.middleware("http")
130
+ async def log_requests(request: Request, call_next):
131
+ global request_count
132
+ request_count += 1
133
+
134
+ timestamp = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
135
+ ip = request.headers.get("X-Forwarded-For", request.client.host)
136
+ req_num = request_count
137
+
138
+ start = time.time()
139
+ response = await call_next(request)
140
+ elapsed = time.time() - start
141
+
142
+ logger.info(
143
+ f"[#{req_num}] {timestamp} UTC | IP={ip} | "
144
+ f"{request.method} {request.url.path} | {elapsed:.3f}s"
145
+ )
146
+
147
+ return response
148
+
149
+
150
  # ── Endpoints ─────────────────────────────────────────────────────────────────
151
  @app.get("/health")
152
  def health():
 
157
  "quantized": True,
158
  "workers": os.getenv("WEB_CONCURRENCY", "1"),
159
  "intra_threads": ORT_INTRA_THREADS,
160
+ "requests_served": request_count,
161
  }
162
 
163