sohug commited on
Commit
3c07b8f
·
1 Parent(s): 4322841

Bengali and less jargon

Browse files
Files changed (3) hide show
  1. app.py +69 -29
  2. assets/skin.jpg +0 -0
  3. requirements.txt +0 -1
app.py CHANGED
@@ -15,16 +15,23 @@ MAX_RETRIES = 3
15
  GEMINI_ENV_KEY = "GEMINI_API_KEY"
16
 
17
  SYSTEM_INSTRUCTION = (
18
- "You are a specialized, cautious dermatological AI assistant. "
19
- "Your analysis must be based strictly on the visual information and established dermatological knowledge. "
20
- "You are an expert in visual diagnosis. No need to give any disclaimers about not being a doctor. "
21
- "Keep your answers concise and focused on the dermatological aspects of the image."
 
 
 
 
22
  )
23
 
24
  USER_QUERY = (
25
- "Analyze this image of a skin lesion. "
26
- "Provide a brief description of the findings, the most likely primary diagnosis, "
27
- "and a confidence level (High, Medium, or Low)."
 
 
 
28
  )
29
 
30
 
@@ -41,13 +48,41 @@ def pil_to_base64(image: Image.Image) -> str:
41
 
42
 
43
  def generate_gemini_analysis(image: Image.Image, max_output_tokens=2048, temperature=0.0):
44
- """Send image to Gemini API and return dermatological analysis."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
45
  api_key = os.environ.get(GEMINI_ENV_KEY)
46
  if not api_key:
47
- return "⚠️ **Missing API key.** Set GEMINI_API_KEY as an environment variable."
 
 
48
 
49
  if not image:
50
- return "⚠️ Please upload an image."
 
 
 
51
 
52
  image_b64 = pil_to_base64(image)
53
 
@@ -67,9 +102,13 @@ def generate_gemini_analysis(image: Image.Image, max_output_tokens=2048, tempera
67
 
68
  headers = {"Content-Type": "application/json"}
69
 
 
 
 
70
  # Retry logic
71
  for attempt in range(MAX_RETRIES):
72
  try:
 
73
  response = requests.post(
74
  f"{API_URL}?key={api_key}",
75
  headers=headers,
@@ -81,9 +120,13 @@ def generate_gemini_analysis(image: Image.Image, max_output_tokens=2048, tempera
81
  break
82
  except requests.exceptions.RequestException as e:
83
  if attempt < MAX_RETRIES - 1:
 
84
  time.sleep(2 ** attempt)
85
  continue
86
- return f"❌ Request failed: {e}"
 
 
 
87
 
88
  candidate = data.get("candidates", [{}])[0]
89
  parts = candidate.get("content", {}).get("parts", [])
@@ -91,9 +134,13 @@ def generate_gemini_analysis(image: Image.Image, max_output_tokens=2048, tempera
91
 
92
  if not generated_text:
93
  finish_reason = candidate.get("finishReason", "")
94
- return f"⚠️ No text output from model. Finish reason: `{finish_reason}`"
 
95
 
96
- return f"### 🩺 Gemini Dermatological Analysis\n\n{generated_text.strip()}"
 
 
 
97
 
98
 
99
  # ==========================
@@ -139,8 +186,8 @@ with gr.Blocks(css=css, title="Skin Disease Analyzer") as demo:
139
  with gr.Column(elem_id="container"):
140
  gr.Markdown(
141
  """
142
- # 🧠 Skin Disease Analyzer
143
- Upload an image of a skin lesion to receive an **AI-powered dermatological analysis**.
144
  """
145
  )
146
 
@@ -153,28 +200,21 @@ Upload an image of a skin lesion to receive an **AI-powered dermatological analy
153
 
154
  # Centered analyze button (smaller)
155
  with gr.Row(elem_id="analyze-button"):
156
- analyze_btn = gr.Button("🚀 Analyze", variant="primary")
157
 
 
 
158
  output_md = gr.Markdown(label="Result")
159
 
160
- # Working sample image (direct link)
161
- gr.HTML(
162
- """
163
- <div class="sample-img">
164
- <p>📸 Sample Image:</p>
165
- <img src="https://en.wikipedia.org/wiki/Skin_cancer#/media/File:Melanoma.jpg"
166
- alt="Sample Skin Lesion"
167
- onerror="this.style.display='none'">
168
- <p style="font-size: 0.9em; margin-top: 5px;">Sample Skin Lesion</p>
169
- </div>
170
- """
171
- )
172
 
173
  # Event binding
174
  analyze_btn.click(
175
  fn=generate_gemini_analysis,
176
  inputs=[image_input],
177
- outputs=output_md,
178
  )
179
 
180
  demo.launch()
 
15
  GEMINI_ENV_KEY = "GEMINI_API_KEY"
16
 
17
  SYSTEM_INSTRUCTION = (
18
+ """
19
+ You are an AI dermatology assistant designed to help patients understand possible skin conditions from images.
20
+ Your goal is to offer an informative, empathetic explanation in clear, simple language.
21
+ Avoid technical jargon.
22
+ keep your answer brief and concise.
23
+ No need to give any disclaimer or introduction.
24
+ Your response should be in Bengali.
25
+ """
26
  )
27
 
28
  USER_QUERY = (
29
+ """
30
+ Analyze this image of a skin lesion and provide:
31
+ 1. The most likely diagnosis as Disease Name.
32
+ 2. A brief explanation of the condition for the patient — including typical symptoms, possible causes, and general self-care advice.
33
+ 3. A brief description of what you observed in the image that supports your conclusion.
34
+ """
35
  )
36
 
37
 
 
48
 
49
 
50
  def generate_gemini_analysis(image: Image.Image, max_output_tokens=2048, temperature=0.0):
51
+ """Send image to Gemini API and return dermatological analysis with a live spinner and status updates."""
52
+ def build_spinner_html(status: str = "Working...", hidden: bool = False) -> str:
53
+ display = "none" if hidden else "flex"
54
+ return f"""
55
+ <div style="display:{display};align-items:center;gap:12px;justify-content:center;">
56
+ <div style="display:flex;flex-direction:column;align-items:center;gap:8px;">
57
+ <div style="
58
+ width:48px;height:48px;
59
+ border:6px solid rgba(255,255,255,0.12);
60
+ border-top-color:#06b6d4;
61
+ border-radius:50%;
62
+ animation: spin 1s linear infinite;
63
+ "></div>
64
+ <div style="color:#ddd;font-size:0.95em;min-width:180px;text-align:center;">{status}</div>
65
+ </div>
66
+ </div>
67
+ <style>
68
+ @keyframes spin {{ from {{ transform: rotate(0deg); }} to {{ transform: rotate(360deg); }} }}
69
+ </style>
70
+ """
71
+
72
+ # initial spinner
73
+ yield build_spinner_html("Initializing..."), ""
74
+
75
  api_key = os.environ.get(GEMINI_ENV_KEY)
76
  if not api_key:
77
+ # hide spinner when showing error/result
78
+ yield build_spinner_html("Missing API key", hidden=True), "⚠️ **Missing API key.** Set GEMINI_API_KEY as an environment variable."
79
+ return
80
 
81
  if not image:
82
+ yield build_spinner_html("No image provided", hidden=True), "⚠️ Please upload an image."
83
+ return
84
+
85
+ yield build_spinner_html("Preparing image..."), ""
86
 
87
  image_b64 = pil_to_base64(image)
88
 
 
102
 
103
  headers = {"Content-Type": "application/json"}
104
 
105
+ # before sending
106
+ yield build_spinner_html("Sending to Gemini..."), ""
107
+
108
  # Retry logic
109
  for attempt in range(MAX_RETRIES):
110
  try:
111
+ yield build_spinner_html("Processing..."), ""
112
  response = requests.post(
113
  f"{API_URL}?key={api_key}",
114
  headers=headers,
 
120
  break
121
  except requests.exceptions.RequestException as e:
122
  if attempt < MAX_RETRIES - 1:
123
+ yield build_spinner_html("Network error — retrying..."), ""
124
  time.sleep(2 ** attempt)
125
  continue
126
+ yield build_spinner_html("Request failed", hidden=True), f"❌ Request failed: {e}"
127
+ return
128
+
129
+ yield build_spinner_html("Parsing response..."), ""
130
 
131
  candidate = data.get("candidates", [{}])[0]
132
  parts = candidate.get("content", {}).get("parts", [])
 
134
 
135
  if not generated_text:
136
  finish_reason = candidate.get("finishReason", "")
137
+ yield build_spinner_html("No output", hidden=True), f"⚠️ No text output from model. Finish reason: `{finish_reason}`"
138
+ return
139
 
140
+ final_md = f"### 🩺 Dermatological Result \n\n{generated_text.strip()}"
141
+
142
+ # hide spinner, show final result
143
+ yield build_spinner_html("Completed", hidden=True), final_md
144
 
145
 
146
  # ==========================
 
186
  with gr.Column(elem_id="container"):
187
  gr.Markdown(
188
  """
189
+ # Skin Disease Test
190
+ Upload an image of a skin lesion to receive an **AI-powered dermatological result**.
191
  """
192
  )
193
 
 
200
 
201
  # Centered analyze button (smaller)
202
  with gr.Row(elem_id="analyze-button"):
203
+ analyze_btn = gr.Button("Test", variant="primary")
204
 
205
+ # Progress HTML + Result Markdown
206
+ progress_html = gr.HTML()
207
  output_md = gr.Markdown(label="Result")
208
 
209
+ # Working sample image (local file)
210
+ gr.Markdown('<p style="font-size:0.9em;margin-top:50px;">📸 Sample Skin Lesion</p>')
211
+ gr.Image(value="assets/skin.jpg", show_label=False, interactive=False, height=300)
 
 
 
 
 
 
 
 
 
212
 
213
  # Event binding
214
  analyze_btn.click(
215
  fn=generate_gemini_analysis,
216
  inputs=[image_input],
217
+ outputs=[progress_html, output_md],
218
  )
219
 
220
  demo.launch()
assets/skin.jpg ADDED
requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
  gradio
2
  requests
3
 
4
- # add a sample image and analyze button bellow the image and middle position
 
1
  gradio
2
  requests
3