Geonomic commited on
Commit
922a589
Β·
verified Β·
1 Parent(s): d0439af

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +54 -35
app.py CHANGED
@@ -140,7 +140,7 @@ def run_deep_learning_cascade(dna_sequence):
140
 
141
  validation = "High Confidence Regulatory Element" if p_promoter >= 0.50 else "Weak Regulatory Signal"
142
  final_label += f" | Validation: {validation}"
143
- raw_scores[" Promoter Signal"] = p_promoter
144
 
145
  return final_label, confidence, raw_scores
146
 
@@ -150,13 +150,13 @@ def run_deep_learning_cascade(dna_sequence):
150
  def get_genomic_context(sequence, is_coding):
151
  feature_type = "CODING" if is_coding else "PROMOTER"
152
  try:
153
- # THE BLAST FIX: Added 'biomol_genomic[PROP]' back to force chromosomal coordinates!
154
  result_handle = NCBIWWW.qblast(
155
  "blastn",
156
  "nt",
157
  sequence,
158
  entrez_query="Homo sapiens[Organism] AND biomol_genomic[PROP]",
159
- hitlist_size=1
160
  )
161
  blast_record = NCBIXML.read(result_handle)
162
  except Exception as e:
@@ -165,10 +165,17 @@ def get_genomic_context(sequence, is_coding):
165
  if not blast_record.alignments:
166
  return {"error": "No human genome match found for this sequence."}
167
 
168
- alignment = blast_record.alignments[0]
 
 
 
 
 
 
 
 
 
169
  hsp = alignment.hsps[0]
170
- chrom_match = re.search(r"chromosome\s([0-9XYMT]+)", alignment.title, re.IGNORECASE)
171
- chrom = chrom_match.group(1) if chrom_match else None
172
  location_string = f"Chromosome {chrom}" if chrom else f"Accession {alignment.accession}"
173
 
174
  start, end = hsp.sbjct_start, hsp.sbjct_end
@@ -182,7 +189,6 @@ def get_genomic_context(sequence, is_coding):
182
  search_end = max(start, end) if feature_type == "CODING" else (end + 15000 if is_forward else end)
183
 
184
  try:
185
- # THE ENSEMBL FIX: Changed 'Content-Type' to 'Accept' for proper JSON retrieval!
186
  response = requests.get(
187
  f"https://rest.ensembl.org/overlap/region/human/{chrom}:{search_start}-{search_end}?feature=gene",
188
  headers={"Accept": "application/json"}
@@ -210,7 +216,9 @@ def get_genomic_context(sequence, is_coding):
210
  # ==============================
211
  def gradio_inference(dna_sequence, run_mapping):
212
  if len(dna_sequence.strip()) < 10:
213
- return ("❌ Sequence too short!", "", "", "⚠️ Please enter at least 10 base pairs.")
 
 
214
 
215
  # Run AI Models (GPU)
216
  label, conf, raw_scores = run_deep_learning_cascade(dna_sequence)
@@ -223,34 +231,38 @@ def gradio_inference(dna_sequence, run_mapping):
223
  else:
224
  stats_lines.append(f"- {key}: {val}")
225
 
226
- # Run Context Mapping (CPU / Network)
227
- context_output = ""
228
- if run_mapping:
229
- is_coding = "GENE" in label
230
- context = get_genomic_context(dna_sequence, is_coding)
231
-
232
- if "error" in context:
233
- context_output = f"❌ Mapping failed: {context['error']}"
234
- elif "location" in context:
235
- context_lines = [
236
- f" Location: {context['location']}",
237
- f" Strand: {context['strand']}",
238
- f" Coordinates: {context['start']:,} – {context['end']:,}",
239
- f" Notes: {context['metadata']}"
240
- ]
241
- context_output = "\n".join(context_lines)
242
- else:
243
- context_output = "⚠️ Could not map sequence."
244
- else:
245
- context_output = "πŸ—ΊοΈ Spatial mapping skipped (Enable checkbox to query NCBI)."
246
-
247
  summary = (
248
  f"βœ… Deep Scan Complete\n\n"
249
- f" Final Classification: {label}\n\n"
250
- f" Confidence Score: {conf:.2%}"
251
  )
252
 
253
- return summary, "\n".join(stats_lines), context_output, ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
  # --- CUSTOM CSS ---
256
  custom_css = """
@@ -302,14 +314,21 @@ with gr.Blocks(theme=gr.themes.Soft(), title="🧬 The Genomic Oracle 🧬", css
302
  submit_btn = gr.Button("πŸš€ Initialize Deep Scan", elem_id="scan_btn")
303
 
304
  with gr.Column(scale=1):
305
- output_summary = gr.Textbox(label=" Classification Summary", lines=4)
306
- stats_panel = gr.Textbox(label=" Internal Pipeline Statistics", lines=4)
307
- mapping_section = gr.Accordion(" Genomic Context (BLAST/Ensembl)", open=False)
308
  with mapping_section:
309
  context_output = gr.Textbox(label="Mapping Results", lines=5, placeholder="Results will appear here...")
310
 
311
  info_box = gr.Markdown("", elem_id="info_box")
312
 
 
 
 
 
 
 
 
313
  submit_btn.click(
314
  fn=lambda seq, map_flag: (
315
  *gradio_inference(seq, map_flag)[:3],
 
140
 
141
  validation = "High Confidence Regulatory Element" if p_promoter >= 0.50 else "Weak Regulatory Signal"
142
  final_label += f" | Validation: {validation}"
143
+ raw_scores["Promoter Signal"] = p_promoter
144
 
145
  return final_label, confidence, raw_scores
146
 
 
150
  def get_genomic_context(sequence, is_coding):
151
  feature_type = "CODING" if is_coding else "PROMOTER"
152
  try:
153
+ # ask blast for 5 hits instead of 1 so we can hunt for the true chromosome
154
  result_handle = NCBIWWW.qblast(
155
  "blastn",
156
  "nt",
157
  sequence,
158
  entrez_query="Homo sapiens[Organism] AND biomol_genomic[PROP]",
159
+ hitlist_size=5
160
  )
161
  blast_record = NCBIXML.read(result_handle)
162
  except Exception as e:
 
165
  if not blast_record.alignments:
166
  return {"error": "No human genome match found for this sequence."}
167
 
168
+ # Loop through the top hits and grab the first one that is an actual Chromosome
169
+ alignment = blast_record.alignments[0] # Default to the top hit
170
+ chrom = None
171
+ for aln in blast_record.alignments:
172
+ chrom_match = re.search(r"chromosome\s([0-9XYMT]+)", aln.title, re.IGNORECASE)
173
+ if chrom_match:
174
+ alignment = aln
175
+ chrom = chrom_match.group(1)
176
+ break # We found the chromosome, stop searching!
177
+
178
  hsp = alignment.hsps[0]
 
 
179
  location_string = f"Chromosome {chrom}" if chrom else f"Accession {alignment.accession}"
180
 
181
  start, end = hsp.sbjct_start, hsp.sbjct_end
 
189
  search_end = max(start, end) if feature_type == "CODING" else (end + 15000 if is_forward else end)
190
 
191
  try:
 
192
  response = requests.get(
193
  f"https://rest.ensembl.org/overlap/region/human/{chrom}:{search_start}-{search_end}?feature=gene",
194
  headers={"Accept": "application/json"}
 
216
  # ==============================
217
  def gradio_inference(dna_sequence, run_mapping):
218
  if len(dna_sequence.strip()) < 10:
219
+ # Using 'yield' to instantly push updates to the UI
220
+ yield ("❌ Sequence too short!", "", "", "⚠️ Please enter at least 10 base pairs.")
221
+ return
222
 
223
  # Run AI Models (GPU)
224
  label, conf, raw_scores = run_deep_learning_cascade(dna_sequence)
 
231
  else:
232
  stats_lines.append(f"- {key}: {val}")
233
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
234
  summary = (
235
  f"βœ… Deep Scan Complete\n\n"
236
+ f"Final Classification: {label}\n"
237
+ f"Confidence Score: {conf:.2%}"
238
  )
239
 
240
+ if not run_mapping:
241
+ yield (summary, "\n".join(stats_lines), "Spatial mapping skipped (Enable checkbox to run BLAST).", "")
242
+ return
243
+
244
+ # 🚨 STREAMING UPDATE: Pushes AI results instantly while showing a loading message for BLAST!
245
+ yield (summary, "\n".join(stats_lines), "⏳ Querying NCBI BLAST... (This takes 1-3 minutes. Please wait.)", "")
246
+
247
+ # Run Context Mapping (CPU / Network)
248
+ is_coding = "GENE" in label
249
+ context = get_genomic_context(dna_sequence, is_coding)
250
+
251
+ if "error" in context:
252
+ context_output = f"❌ Mapping failed: {context['error']}"
253
+ elif "location" in context:
254
+ context_lines = [
255
+ f"Location: {context['location']}",
256
+ f"Strand: {context['strand']}",
257
+ f"Coordinates: {context['start']:,} – {context['end']:,}",
258
+ f"Notes: {context['metadata']}"
259
+ ]
260
+ context_output = "\n".join(context_lines)
261
+ else:
262
+ context_output = "⚠️ Could not map sequence."
263
+
264
+ # 🚨 FINAL UPDATE: Pushes the finished BLAST results!
265
+ yield (summary, "\n".join(stats_lines), context_output, "")
266
 
267
  # --- CUSTOM CSS ---
268
  custom_css = """
 
314
  submit_btn = gr.Button("πŸš€ Initialize Deep Scan", elem_id="scan_btn")
315
 
316
  with gr.Column(scale=1):
317
+ output_summary = gr.Textbox(label="Classification Summary", lines=4)
318
+ stats_panel = gr.Textbox(label="Internal Pipeline Statistics", lines=4)
319
+ mapping_section = gr.Accordion("Genomic Context (BLAST/Ensembl)", open=False)
320
  with mapping_section:
321
  context_output = gr.Textbox(label="Mapping Results", lines=5, placeholder="Results will appear here...")
322
 
323
  info_box = gr.Markdown("", elem_id="info_box")
324
 
325
+ # 🚨 NEW UX FEATURE: Auto-open the accordion when the user checks the BLAST box!
326
+ run_mapping_cb.change(
327
+ fn=lambda is_checked: gr.Accordion(open=is_checked),
328
+ inputs=[run_mapping_cb],
329
+ outputs=[mapping_section]
330
+ )
331
+
332
  submit_btn.click(
333
  fn=lambda seq, map_flag: (
334
  *gradio_inference(seq, map_flag)[:3],