Gaston895 commited on
Commit
8d6d2d7
·
1 Parent(s): c716f57

fix: batch inference to prevent OOM + add /ping for UptimeRobot

Browse files
Files changed (1) hide show
  1. app.py +39 -13
app.py CHANGED
@@ -4,15 +4,25 @@ import torch
4
 
5
  app = Flask(__name__)
6
 
7
- # Load your specific SciBERT model from HF
8
  MODEL_PATH = "gsstec/aegis-scibert-technical"
9
  tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
10
  model = AutoModelForSequenceClassification.from_pretrained(MODEL_PATH)
 
 
 
 
 
11
 
12
  @app.route('/')
13
  def index():
14
  return render_template('index.html')
15
 
 
 
 
 
 
16
  @app.route('/predict', methods=['POST'])
17
  def predict():
18
  data = request.json
@@ -124,20 +134,36 @@ def predict():
124
  "Consciousness Transfer", "Digital Immortality", "Synthetic Life", "Artificial Evolution"
125
  ]
126
  tech_scores = {}
127
-
128
- for category in categories:
129
- # Create category-specific input text
130
- input_text = f"Scientific and technological advancements in {category} emergent in the year {year}."
131
-
132
- # Tokenization
133
- inputs = tokenizer(input_text, return_tensors="pt", truncation=True, max_length=512)
134
-
135
- # Prediction
 
 
 
 
 
 
 
 
 
 
 
 
136
  with torch.no_grad():
137
  outputs = model(**inputs)
138
- # Get the first prediction score for this category
139
- prediction = torch.softmax(outputs.logits, dim=1).tolist()[0]
140
- tech_scores[category] = prediction[0]
 
 
 
 
141
 
142
  return jsonify({
143
  "year": year,
 
4
 
5
  app = Flask(__name__)
6
 
7
+ # Load model once at startup
8
  MODEL_PATH = "gsstec/aegis-scibert-technical"
9
  tokenizer = AutoTokenizer.from_pretrained(MODEL_PATH)
10
  model = AutoModelForSequenceClassification.from_pretrained(MODEL_PATH)
11
+ model.eval() # disable dropout — reduces memory and is correct for inference
12
+
13
+ # Process this many categories per forward pass.
14
+ # 16 keeps peak RAM well under the free-tier limit while still being fast.
15
+ BATCH_SIZE = 16
16
 
17
  @app.route('/')
18
  def index():
19
  return render_template('index.html')
20
 
21
+ @app.route('/ping', methods=['GET'])
22
+ def ping():
23
+ """UptimeRobot keep-alive endpoint — returns 200 immediately, no model inference."""
24
+ return jsonify({"status": "ok", "message": "TEC App is alive"}), 200
25
+
26
  @app.route('/predict', methods=['POST'])
27
  def predict():
28
  data = request.json
 
134
  "Consciousness Transfer", "Digital Immortality", "Synthetic Life", "Artificial Evolution"
135
  ]
136
  tech_scores = {}
137
+
138
+ # Build all input texts upfront
139
+ texts = [
140
+ f"Scientific and technological advancements in {cat} emergent in the year {year}."
141
+ for cat in categories
142
+ ]
143
+
144
+ # Process in batches to avoid OOM on CPU-only free tier
145
+ for i in range(0, len(categories), BATCH_SIZE):
146
+ batch_cats = categories[i : i + BATCH_SIZE]
147
+ batch_texts = texts[i : i + BATCH_SIZE]
148
+
149
+ # max_length=64 is plenty for these short sentences; saves ~8x memory vs 512
150
+ inputs = tokenizer(
151
+ batch_texts,
152
+ return_tensors="pt",
153
+ truncation=True,
154
+ max_length=64,
155
+ padding=True,
156
+ )
157
+
158
  with torch.no_grad():
159
  outputs = model(**inputs)
160
+ probs = torch.softmax(outputs.logits, dim=1) # shape: (batch, num_labels)
161
+
162
+ for j, cat in enumerate(batch_cats):
163
+ tech_scores[cat] = float(probs[j][0])
164
+
165
+ # Free batch tensors immediately to keep peak RAM low
166
+ del inputs, outputs, probs
167
 
168
  return jsonify({
169
  "year": year,