Vaishnav14220 commited on
Commit
0a24ce6
·
1 Parent(s): 4946745

Add RDKit reaction SVG rendering tab

Browse files
Files changed (1) hide show
  1. app.py +58 -0
app.py CHANGED
@@ -10,6 +10,7 @@ import gradio as gr
10
  import plotly.graph_objects as go
11
  from fastapi import FastAPI, HTTPException, Query
12
  from fastapi.middleware.cors import CORSMiddleware
 
13
 
14
  from nist_kinetics_api import (
15
  Category,
@@ -325,6 +326,43 @@ def _build_dataset_plot(detail: ReactionDetail) -> go.Figure | None:
325
  return fig
326
 
327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
328
  def fetch_detail(selected_url: str, manual_url: str):
329
  detail_url = (manual_url or "").strip() or (selected_url or "").strip()
330
  if not detail_url:
@@ -517,6 +555,26 @@ def build_interface() -> gr.Blocks:
517
  outputs=[detail_markdown, dataset_table, reaction_plot],
518
  )
519
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
520
  return demo
521
 
522
 
 
10
  import plotly.graph_objects as go
11
  from fastapi import FastAPI, HTTPException, Query
12
  from fastapi.middleware.cors import CORSMiddleware
13
+ from rdkit.Chem import Draw, rdChemReactions
14
 
15
  from nist_kinetics_api import (
16
  Category,
 
326
  return fig
327
 
328
 
329
+ def render_reaction_svg(reaction_text: str):
330
+ reaction_text = (reaction_text or "").strip()
331
+ if not reaction_text:
332
+ return gr.update(value=""), "⚠️ Enter a reaction SMILES/SMARTS string (e.g. CH4.O>>CO2)."
333
+ if ">>" not in reaction_text:
334
+ return gr.update(value=""), "⚠️ Reaction input must include '>>' separating reactants and products."
335
+
336
+ try:
337
+ reaction = rdChemReactions.ReactionFromSmarts(reaction_text, useSmiles=True)
338
+ except Exception as exc: # pragma: no cover - RDKit parsing issues
339
+ return gr.update(value=""), f"🚨 Could not parse reaction: {exc}"
340
+
341
+ if reaction is None or (reaction.GetNumReactantTemplates() == 0 and reaction.GetNumProductTemplates() == 0):
342
+ return gr.update(value=""), "⚠️ RDKit returned an empty reaction."
343
+
344
+ try:
345
+ svg = Draw.ReactionToImage(reaction, subImgSize=(220, 220), useSVG=True)
346
+ except Exception as exc: # pragma: no cover - RDKit drawing issues
347
+ return gr.update(value=""), f"🚨 Failed to render reaction: {exc}"
348
+
349
+ if isinstance(svg, tuple): # Some RDKit versions return (svg, legend)
350
+ svg = svg[0]
351
+ if hasattr(svg, "data"):
352
+ svg = svg.data
353
+ if isinstance(svg, bytes):
354
+ svg = svg.decode("utf-8", errors="ignore")
355
+
356
+ if not isinstance(svg, str) or "<svg" not in svg:
357
+ svg = f"<pre>{svg}</pre>"
358
+
359
+ status = (
360
+ f"Rendered reaction with {reaction.GetNumReactantTemplates()} reactant templates "
361
+ f"and {reaction.GetNumProductTemplates()} product templates."
362
+ )
363
+ return svg, status
364
+
365
+
366
  def fetch_detail(selected_url: str, manual_url: str):
367
  detail_url = (manual_url or "").strip() or (selected_url or "").strip()
368
  if not detail_url:
 
555
  outputs=[detail_markdown, dataset_table, reaction_plot],
556
  )
557
 
558
+ with gr.Tab("Reaction SVG"):
559
+ gr.Markdown(
560
+ "Render an RDKit reaction sketch from reaction SMILES/SMARTS. "
561
+ "Example: `CCO.O=C=O>>CC(=O)O` or `[CH3:1].[Cl:2][C@@H](F)[Br]>>[CH3:1][C@@H](F)[Cl]`."
562
+ )
563
+ reaction_input = gr.Textbox(
564
+ label="Reaction SMILES/SMARTS",
565
+ placeholder="Reactant1.Reactant2>>Product1.Product2",
566
+ lines=2,
567
+ )
568
+ render_button = gr.Button("Render Reaction", variant="secondary")
569
+ reaction_svg = gr.HTML()
570
+ render_status = gr.Markdown()
571
+
572
+ render_button.click(
573
+ fn=render_reaction_svg,
574
+ inputs=reaction_input,
575
+ outputs=[reaction_svg, render_status],
576
+ )
577
+
578
  return demo
579
 
580