pravjet commited on
Commit
9fd579f
·
verified ·
1 Parent(s): 324de18

Upload 7 files

Browse files
Files changed (7) hide show
  1. .dockerignore +11 -0
  2. Dockerfile.prod +36 -0
  3. Procfile +1 -0
  4. README.md +60 -0
  5. app.py +73 -0
  6. download_model.py +8 -0
  7. requirements.txt +6 -0
.dockerignore ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ venv
2
+ __pycache__
3
+ *.pyc
4
+ *.pyo
5
+ *.pyd
6
+ .Python
7
+ .env
8
+ .git
9
+ .gitignore
10
+ .huggingface
11
+ .cache
Dockerfile.prod ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Production Dockerfile: pre-download model and run with gunicorn
2
+ FROM python:3.11-slim as builder
3
+
4
+ WORKDIR /app
5
+
6
+ RUN apt-get update && apt-get install -y --no-install-recommends \
7
+ build-essential \
8
+ libxml2-dev libxslt1-dev zlib1g-dev libjpeg-dev libpng-dev git curl && \
9
+ rm -rf /var/lib/apt/lists/*
10
+
11
+ COPY requirements.txt ./
12
+ RUN python -m pip install --upgrade pip
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Pre-download the model into the cache
16
+ COPY download_model.py ./
17
+ RUN python download_model.py
18
+
19
+ # Runtime image
20
+ FROM python:3.11-slim
21
+ WORKDIR /app
22
+
23
+ RUN apt-get update && apt-get install -y --no-install-recommends \
24
+ libxml2-dev libxslt1-dev zlib1g-dev libjpeg-dev libpng-dev && rm -rf /var/lib/apt/lists/*
25
+
26
+ COPY --from=builder /root/.cache /root/.cache
27
+ COPY requirements.txt ./
28
+ RUN python -m pip install --upgrade pip
29
+ RUN pip install --no-cache-dir -r requirements.txt
30
+
31
+ COPY . /app
32
+
33
+ ENV MOCK_MODE=0
34
+ EXPOSE 5000
35
+
36
+ CMD ["gunicorn", "-w", "2", "-b", "0.0.0.0:5000", "app:app"]
Procfile ADDED
@@ -0,0 +1 @@
 
 
1
+ web: gunicorn -w 2 -b 0.0.0.0:$PORT app:app
README.md ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Misinfo Backend (Production-ready)
2
+
3
+ A Flask backend providing `/analyze` to check text or article URLs for possible misinformation.
4
+
5
+ Key improvements for production
6
+
7
+ - Pinned dependencies in `requirements.txt`.
8
+ - `/health` endpoint for readiness checks.
9
+ - Production Dockerfile (`Dockerfile.prod`) that pre-downloads the HF model into the image.
10
+ - Uses `gunicorn` as the WSGI server (configured in `Procfile` for Heroku-like platforms).
11
+
12
+ Quick local dev
13
+
14
+ 1. Create venv and install dev requirements:
15
+ ```powershell
16
+ python -m venv venv
17
+ .\venv\Scripts\Activate.ps1
18
+ python -m pip install -r requirements.txt
19
+ ```
20
+
21
+ 2. Run fast dev/mock mode:
22
+ ```powershell
23
+ $env:MOCK_MODE=1; python app.py
24
+ ```
25
+
26
+ 3. Health check:
27
+ ```powershell
28
+ Invoke-RestMethod -Uri 'http://127.0.0.1:5000/health' -Method Get
29
+ ```
30
+
31
+ Docker (production image)
32
+
33
+ Build production image (this pre-downloads model during image build):
34
+ ```powershell
35
+ docker build -f Dockerfile.prod -t misinfo-backend:prod .
36
+ ```
37
+
38
+ Run:
39
+ ```powershell
40
+ docker run -p 5000:5000 --env MOCK_MODE=0 misinfo-backend:prod
41
+ ```
42
+
43
+ Heroku / Platform.sh / similar
44
+
45
+ - Use the provided `Procfile` and push the repo. Set environment variable `MOCK_MODE=0` to enable real model.
46
+
47
+ Notes
48
+
49
+ - The image pre-downloads the model into `/root/.cache`. For large-scale production, consider hosting the model in a model server or using a smaller / distilled model.
50
+ - Consider using a GPU-equipped instance if you need faster inference.
51
+
52
+ Files added/changed
53
+
54
+ - `requirements.txt` (pinned)
55
+ - `app.py` (health endpoint, prod-friendly)
56
+ - `download_model.py` (pre-download helper)
57
+ - `Dockerfile.prod` (production dockerfile)
58
+ - `.dockerignore`
59
+ - `Procfile`
60
+
app.py ADDED
@@ -0,0 +1,73 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify
2
+ import os
3
+ import sys
4
+ from newspaper import Article
5
+
6
+ app = Flask(__name__)
7
+
8
+ # Configuration from environment
9
+ MOCK_MODE = os.environ.get("MOCK_MODE") == "1" or ("--mock" in sys.argv)
10
+ DEBUG = os.environ.get("DEBUG", "0") == "1"
11
+
12
+ # Load model at import time so Docker build can pre-download using a helper script
13
+ model = None
14
+ if not MOCK_MODE:
15
+ try:
16
+ from transformers import pipeline
17
+ model = pipeline("text-classification", model="mrm8488/bert-tiny-finetuned-fake-news-detection")
18
+ except Exception:
19
+ MOCK_MODE = True
20
+
21
+
22
+ @app.route("/health", methods=["GET"])
23
+ def health():
24
+ return jsonify({"status": "ok", "mock_mode": MOCK_MODE})
25
+
26
+
27
+ @app.route("/analyze", methods=["POST"])
28
+ def analyze():
29
+ data = request.get_json() or {}
30
+ text = data.get("text")
31
+ url = data.get("url")
32
+
33
+ if url:
34
+ try:
35
+ article = Article(url)
36
+ article.download()
37
+ article.parse()
38
+ text = article.text
39
+ except Exception as e:
40
+ return jsonify({"error": "Failed to extract article from URL", "details": str(e)}), 400
41
+
42
+ if not text:
43
+ return jsonify({"error": "No text provided"}), 400
44
+
45
+ if MOCK_MODE:
46
+ lowered = text.lower()
47
+ if "fake" in lowered or "misinform" in lowered or "hoax" in lowered:
48
+ label = "MISINFO"
49
+ score = 0.92
50
+ verdict = "Possibly Misinformation"
51
+ else:
52
+ label = "REAL"
53
+ score = 0.85
54
+ verdict = "Authentic"
55
+ authenticity_score = round(score * 100, 2)
56
+ else:
57
+ result = model(text)[0]
58
+ label = result["label"]
59
+ score = result["score"]
60
+ verdict = "Authentic" if label == "REAL" else "Possibly Misinformation"
61
+ authenticity_score = round(score * 100, 2)
62
+
63
+ return jsonify({
64
+ "verdict": verdict,
65
+ "authenticity_score": authenticity_score,
66
+ "model_label": label,
67
+ })
68
+
69
+
70
+ if __name__ == "__main__":
71
+ port = int(os.environ.get("PORT", "5000"))
72
+ # In production (gunicorn) this block isn't used; it's useful for local dev.
73
+ app.run(debug=DEBUG, host="0.0.0.0", port=port)
download_model.py ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ from transformers import pipeline
2
+
3
+ def download():
4
+ # instantiate pipeline to force model download into cache
5
+ pipeline("text-classification", model="mrm8488/bert-tiny-finetuned-fake-news-detection")
6
+
7
+ if __name__ == '__main__':
8
+ download()
requirements.txt ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ flask==2.3.3
2
+ transformers==4.34.0
3
+ newspaper3k==0.2.8
4
+ lxml_html_clean==0.3.0
5
+ gunicorn==20.1.0
6
+ torch