Inquisiter07 commited on
Commit
98fed04
Β·
1 Parent(s): 07da06b

Fix: Set FLASK_APP=app:app for Hugging Face

Browse files
Files changed (2) hide show
  1. Dockerfile +3 -6
  2. app.py +132 -0
Dockerfile CHANGED
@@ -1,19 +1,16 @@
1
  FROM python:3.11
2
 
3
  WORKDIR /app
4
-
5
- # Copy all code
6
  COPY . .
7
 
8
- # Install dependencies
9
  RUN pip install --upgrade pip && pip install -r requirements.txt
10
 
11
- # Expose port for Hugging Face
12
  EXPOSE 7860
13
 
14
- # Run Flask
15
- ENV FLASK_APP=app.py
16
  ENV FLASK_RUN_HOST=0.0.0.0
17
  ENV FLASK_RUN_PORT=7860
 
18
  CMD ["flask", "run"]
19
 
 
1
  FROM python:3.11
2
 
3
  WORKDIR /app
 
 
4
  COPY . .
5
 
 
6
  RUN pip install --upgrade pip && pip install -r requirements.txt
7
 
 
8
  EXPOSE 7860
9
 
10
+ # Fix here πŸ‘‡
11
+ ENV FLASK_APP=app:app
12
  ENV FLASK_RUN_HOST=0.0.0.0
13
  ENV FLASK_RUN_PORT=7860
14
+
15
  CMD ["flask", "run"]
16
 
app.py ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, request, jsonify, render_template, send_from_directory
2
+ from transformers import AutoModelForImageClassification, AutoImageProcessor
3
+ from huggingface_hub import InferenceClient
4
+ from PIL import Image
5
+ import torch
6
+ import os
7
+
8
+ app = Flask(__name__)
9
+
10
+ # =======================================
11
+ # πŸ” Hugging Face LLM Token + InferenceClient
12
+ # =======================================
13
+ HUGGINGFACE_TOKEN = os.environ.get("HUGGINGFACE_TOKEN")
14
+
15
+ client = InferenceClient(
16
+ model="mistralai/Mistral-7B-Instruct-v0.1",
17
+ token=HUGGINGFACE_TOKEN
18
+ )
19
+
20
+ # =======================================
21
+ # 🧠 Load Skin Disease Model
22
+ # =======================================
23
+ print("Loading skin condition classifier...")
24
+ model_name = "Jayanth2002/dinov2-base-finetuned-SkinDisease"
25
+ image_model = AutoModelForImageClassification.from_pretrained(model_name)
26
+ processor = AutoImageProcessor.from_pretrained(model_name)
27
+
28
+ # Class labels
29
+ class_names = [
30
+ 'Basal Cell Carcinoma', 'Darier_s Disease', 'Epidermolysis Bullosa Pruriginosa',
31
+ 'Hailey-Hailey Disease', 'Herpes Simplex', 'Impetigo', 'Larva Migrans',
32
+ 'Leprosy Borderline', 'Leprosy Lepromatous', 'Leprosy Tuberculoid', 'Lichen Planus',
33
+ 'Lupus Erythematosus Chronicus Discoides', 'Melanoma', 'Molluscum Contagiosum',
34
+ 'Mycosis Fungoides', 'Neurofibromatosis', 'Papilomatosis Confluentes And Reticulate',
35
+ 'Pediculosis Capitis', 'Pityriasis Rosea', 'Porokeratosis Actinic', 'Psoriasis',
36
+ 'Tinea Corporis', 'Tinea Nigra', 'Tungiasis', 'actinic keratosis', 'dermatofibroma',
37
+ 'nevus', 'pigmented benign keratosis', 'seborrheic keratosis', 'squamous cell carcinoma',
38
+ 'vascular lesion'
39
+ ]
40
+
41
+ # =======================================
42
+ # 🌐 Frontend Routes
43
+ # =======================================
44
+ @app.route("/")
45
+ def index():
46
+ return render_template("index.html")
47
+
48
+ @app.route("/upload")
49
+ def upload():
50
+ return render_template("upload.html")
51
+
52
+ @app.route("/result")
53
+ def result():
54
+ return render_template("result.html") # Notice: matches the filename "results.html" instead of "result.html"
55
+
56
+ # =======================================
57
+ # πŸ“Έ /analyze Route
58
+ # =======================================
59
+ @app.route('/analyze', methods=['POST'])
60
+ def analyze():
61
+ if 'image' not in request.files:
62
+ return jsonify({"error": "No image uploaded"}), 400
63
+
64
+ image_file = request.files['image']
65
+ image = Image.open(image_file.stream).convert("RGB")
66
+ inputs = processor(images=image, return_tensors="pt")
67
+
68
+ with torch.no_grad():
69
+ logits = image_model(**inputs).logits
70
+ probs = torch.softmax(logits, dim=-1)[0]
71
+
72
+ top_idx = torch.argmax(probs).item()
73
+ top_conf = probs[top_idx].item()
74
+ prediction = class_names[top_idx]
75
+
76
+ top_conditions = sorted(
77
+ zip(class_names, probs.tolist()),
78
+ key=lambda x: x[1],
79
+ reverse=True
80
+ )[:5]
81
+
82
+ return jsonify({
83
+ "prediction": prediction,
84
+ "confidence": round(top_conf, 4),
85
+ "topConditions": [(name, round(prob, 4)) for name, prob in top_conditions],
86
+ "description": f"{prediction} is a skin condition. Please consult a medical professional.",
87
+ "recommendations": [
88
+ "Take a clearer image if unsure.",
89
+ "Consider visiting a dermatologist.",
90
+ "Avoid self-diagnosis or self-treatment."
91
+ ]
92
+ })
93
+
94
+ # =======================================
95
+ # πŸ’¬ /ask Route
96
+ # =======================================
97
+ @app.route('/ask', methods=['POST'])
98
+ def ask():
99
+ data = request.json
100
+ question = data.get("question", "")
101
+ condition = data.get("condition", "")
102
+
103
+ if not question:
104
+ return jsonify({"answer": "Please ask a valid question."}), 400
105
+
106
+ messages = [
107
+ {
108
+ "role": "user",
109
+ "content": f"A user may have {condition}. They asked: '{question}'. Respond like a helpful AI medical assistant."
110
+ }
111
+ ]
112
+
113
+ try:
114
+ response = client.chat_completion(
115
+ messages=messages,
116
+ max_tokens=200
117
+ )
118
+ answer = response.choices[0]["message"]["content"]
119
+ return jsonify({"answer": answer.strip()})
120
+ except Exception as e:
121
+ return jsonify({"answer": f"Error communicating with Hugging Face: {e}"}), 500
122
+
123
+ # Add route for placeholder images if needed
124
+ @app.route('/api/placeholder/<width>/<height>')
125
+ def placeholder(width, height):
126
+ # This is a simple implementation - you might want to generate an actual placeholder image
127
+ # For now, we'll just serve a static placeholder
128
+ return send_from_directory('static/images', 'placeholder.jpg')
129
+
130
+
131
+ if __name__ == '__main__':
132
+ app.run(debug=True)