Vaishnav14220 commited on
Commit
7ac4139
Β·
1 Parent(s): d474c53

Enhance Reaction SVG tab: AI processing happens FIRST before rendering - DeepSeek analyzes and completes reactions before RDKit SVG generation, ensuring all reactions are properly enhanced/validated/completed

Browse files
Files changed (1) hide show
  1. app.py +124 -99
app.py CHANGED
@@ -222,8 +222,8 @@ def fetch_specific_db(db_name, formula):
222
 
223
  # Generic table extraction
224
  tables = soup.find_all('table')
225
- df = None
226
- if tables:
227
  df = pd.read_html(StringIO(str(tables[0])))[0]
228
 
229
  # Fallback: Links for spectra/structures
@@ -900,7 +900,7 @@ def render_reaction_svg(reaction_text: str, api_key: str = "", auto_complete: bo
900
 
901
  # Check if it's already SMILES format (contains >>)
902
  if ">>" in reaction_text:
903
- svg = _render_smiles_to_svg(reaction_text)
904
  if svg:
905
  status = "βœ… Reaction rendered successfully from SMILES."
906
  return svg, status
@@ -917,7 +917,7 @@ def render_reaction_svg(reaction_text: str, api_key: str = "", auto_complete: bo
917
  svg = _render_reaction_from_nist(completed_reaction)
918
  if svg:
919
  status = f"βœ… Reaction completed and rendered using DeepSeek AI.\nOriginal: {reaction_text}\nCompleted: {completed_reaction}"
920
- return svg, status
921
  else:
922
  return "", f"🚨 DeepSeek completed reaction but rendering failed: {completed_reaction}"
923
  else:
@@ -1065,13 +1065,13 @@ def fetch_detail(selected_url: str, manual_url: str, auto_fetch_thermo: bool = T
1065
  return markdown, table, None, "", {}, ""
1066
 
1067
  plot_fig = _build_dataset_plot(detail)
1068
-
1069
  # Try to render the reaction title as SVG
1070
  reaction_svg = ""
1071
  if detail.title:
1072
  title = detail.title.strip()
1073
  smiles_attempt = None
1074
-
1075
  # Try different reaction format conversions
1076
  if " β†’ " in title:
1077
  # Format: "A + B β†’ C"
@@ -1090,12 +1090,12 @@ def fetch_detail(selected_url: str, manual_url: str, auto_fetch_thermo: bool = T
1090
  reactants = parts[0].replace(" + ", ".").strip()
1091
  products = parts[1].replace(" + ", ".").strip()
1092
  smiles_attempt = f"{reactants}>>{products}"
1093
-
1094
  if smiles_attempt:
1095
  svg = _render_smiles_to_svg(smiles_attempt)
1096
  if svg:
1097
  reaction_svg = svg
1098
-
1099
  # Auto-fetch thermodynamic data for compounds in the reaction
1100
  thermo_data = {}
1101
  thermo_summary = ""
@@ -1265,24 +1265,24 @@ def build_interface() -> gr.Blocks:
1265
  value=True,
1266
  info="Automatically fetch thermodynamic data for searched compounds"
1267
  )
1268
-
1269
- with gr.Row():
1270
- decomp = gr.Checkbox(label="Only decomposition reactions", value=False)
1271
- category = gr.Dropdown(label="Result type filter", choices=CATEGORY_CHOICES, value=str(Category.any.value))
1272
- units = gr.Textbox(
1273
- label="Optional Units token",
1274
- placeholder="Leave blank to use NIST account defaults",
1275
- )
1276
 
1277
  search_button = gr.Button("πŸ” Search NIST", variant="primary")
1278
- search_status = gr.Markdown()
1279
 
1280
- result_table = gr.Dataframe(
1281
- headers=["#", "Records", "Reaction", "Detail URL"],
1282
- datatype=["number", "number", "str", "str"],
1283
- interactive=False,
1284
- wrap=True,
1285
- )
1286
 
1287
  # Search results thermodynamic data
1288
  search_thermo_accordion = gr.Accordion(label="πŸ”¬ Search Query Thermodynamic Data", open=False)
@@ -1293,15 +1293,15 @@ def build_interface() -> gr.Blocks:
1293
  with gr.TabItem("Reaction Detail"):
1294
  with gr.Row():
1295
  with gr.Column(scale=2):
1296
- selection = gr.Dropdown(
1297
- label="Select a reaction from the latest search",
1298
- choices=[],
1299
- interactive=False,
1300
- )
1301
- manual_url = gr.Textbox(
1302
- label="Or paste a NIST detail URL",
1303
- placeholder="https://kinetics.nist.gov/kinetics/ReactionSearch?....",
1304
- )
1305
  with gr.Column(scale=1):
1306
  auto_fetch_thermo = gr.Checkbox(
1307
  label="πŸ”¬ Auto-fetch thermodynamics",
@@ -1315,31 +1315,31 @@ def build_interface() -> gr.Blocks:
1315
  )
1316
 
1317
  detail_button = gr.Button("Fetch Reaction Detail", variant="primary")
1318
-
1319
- # Reaction metadata and details
1320
- detail_markdown = gr.Markdown()
1321
-
1322
  with gr.Row():
1323
- # Kinetics data table
1324
  with gr.Column():
1325
  gr.Markdown("### Kinetics Data")
1326
- dataset_table = gr.Dataframe(
1327
- headers=["Section", "Squib", "Temp [K]", "A", "n", "Ea [J/mole]", "k(298 K)", "Order", "Squib URL"],
1328
- datatype=["str"] * 9,
1329
- interactive=False,
1330
- wrap=True,
1331
- )
1332
-
1333
  # Arrhenius plot
1334
  with gr.Column():
1335
  gr.Markdown("### Arrhenius Plot")
1336
  reaction_plot = gr.Plot()
1337
 
1338
- # Reaction SVG visualization
1339
- with gr.Row():
1340
- gr.Markdown("### Reaction Structure")
1341
- reaction_svg = gr.HTML()
1342
-
1343
  # Auto-fetched thermodynamic data
1344
  thermo_summary = gr.Markdown()
1345
  thermo_accordion = gr.Accordion(label="πŸ”¬ Thermodynamic Data", open=False)
@@ -1350,13 +1350,18 @@ def build_interface() -> gr.Blocks:
1350
  # Tab 3: Reaction SVG (Enhanced with NIST reactions and AI completion)
1351
  with gr.TabItem("Reaction SVG"):
1352
  gr.Markdown(
1353
- "🎨 **Render chemical reactions as SVG using RDKit + AI Completion**\n\n"
1354
- "Choose from NIST database reactions, enter custom reactions, or let AI complete partial reactions!\n\n"
 
 
 
 
1355
  "**Features:**\n"
1356
  "- πŸ§ͺ 200+ NIST database reactions\n"
1357
- "- πŸ€– AI-powered reaction completion (DeepSeek)\n"
1358
- "- πŸ”¬ Multiple input formats (NIST, SMILES, SMARTS)\n"
1359
- "- ⚑ Automatic format detection and conversion"
 
1360
  )
1361
 
1362
  # API Key Configuration
@@ -1367,7 +1372,7 @@ def build_interface() -> gr.Blocks:
1367
  type="password",
1368
  info="Get your API key from https://platform.deepseek.com/"
1369
  )
1370
- gr.Markdown(
1371
  "**How to get API key:**\n"
1372
  "1. Visit https://platform.deepseek.com/\n"
1373
  "2. Sign up/Login to your account\n"
@@ -1379,8 +1384,8 @@ def build_interface() -> gr.Blocks:
1379
  # NIST reactions dropdown
1380
  nist_reactions = _fetch_all_nist_reactions(limit=200)
1381
  nist_reaction_options = [("", "")] + nist_reactions if nist_reactions else []
1382
-
1383
- with gr.Row():
1384
  with gr.Column():
1385
  nist_reaction_dropdown = gr.Dropdown(
1386
  label="πŸ§ͺ NIST Database Reactions",
@@ -1389,8 +1394,8 @@ def build_interface() -> gr.Blocks:
1389
  interactive=True,
1390
  info=f"Select from {len(nist_reactions)} reactions in NIST kinetics database"
1391
  )
1392
-
1393
- reaction_input = gr.Textbox(
1394
  label="Custom Reaction Input",
1395
  placeholder="Enter reaction in any format:\nNIST: CH4 + O2 β†’ CO2 + H2O\nSMILES: CH4.O2>>CO2.H2O\nPartial: CH4 + O2 β†’ (AI will complete)",
1396
  lines=4,
@@ -1406,17 +1411,20 @@ def build_interface() -> gr.Blocks:
1406
  )
1407
 
1408
  ai_options = gr.CheckboxGroup(
1409
- label="πŸ€– AI Enhancement",
1410
- choices=["Enable AI completion", "High quality rendering", "Show completion reasoning"],
1411
- value=["Enable AI completion"],
1412
- info="Use DeepSeek AI to complete partial reactions"
1413
  )
1414
 
1415
  # Buttons
1416
  with gr.Row():
1417
- render_auto_btn = gr.Button("πŸš€ Smart Render (Auto-detect)", variant="primary")
1418
- render_nist_btn = gr.Button("πŸ§ͺ Render NIST Format", variant="secondary")
1419
- render_smiles_btn = gr.Button("πŸ”¬ Render SMILES/SMARTS", variant="secondary")
 
 
 
1420
  clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="stop")
1421
 
1422
  # Output
@@ -1428,14 +1436,14 @@ def build_interface() -> gr.Blocks:
1428
  def populate_from_nist_dropdown(selected_label):
1429
  if selected_label and selected_label in nist_dict:
1430
  return nist_dict[selected_label]
1431
- return ""
1432
-
1433
  nist_reaction_dropdown.change(
1434
  fn=populate_from_nist_dropdown,
1435
  inputs=nist_reaction_dropdown,
1436
- outputs=reaction_input,
1437
- )
1438
-
1439
  # Smart auto-render function
1440
  def render_auto_reaction(reaction_text, api_key, ai_options, render_mode):
1441
  if not reaction_text:
@@ -1444,35 +1452,52 @@ def build_interface() -> gr.Blocks:
1444
  status_prefix = ""
1445
  final_reaction = reaction_text
1446
 
1447
- # Check if AI completion is enabled and reaction might be incomplete
1448
- if "Enable AI completion" in (ai_options or []) and api_key:
1449
- analysis = _analyze_reaction_completeness(reaction_text)
1450
- if not analysis["complete"]:
1451
- completed_reaction = _complete_reaction_with_deepseek(reaction_text, api_key)
1452
- if completed_reaction:
1453
- final_reaction = completed_reaction
1454
- status_prefix = f"πŸ€– **AI Completed Reaction**\nOriginal: {reaction_text}\nCompleted: {final_reaction}\n\n"
1455
-
1456
- # Render based on detected format or forced mode
1457
- if render_mode == "Force SMILES/SMARTS" or (render_mode == "Auto (detect format)" and ">>" in final_reaction):
 
 
 
 
 
 
 
 
 
1458
  svg = _render_smiles_to_svg(final_reaction)
1459
  render_type = "SMILES/SMARTS"
1460
- elif render_mode == "Force NIST format" or render_mode == "Auto (detect format)":
1461
  svg = _render_reaction_from_nist(final_reaction)
1462
  render_type = "NIST format"
1463
- else:
1464
- # Try both formats
1465
- svg = _render_reaction_from_nist(final_reaction)
1466
- if not svg:
1467
  svg = _render_smiles_to_svg(final_reaction)
1468
- render_type = "auto-detected"
 
 
 
 
 
 
 
 
1469
 
1470
  if svg:
1471
  quality_note = " (High quality)" if "High quality rendering" in (ai_options or []) else ""
1472
- status = f"{status_prefix}βœ… Successfully rendered as {render_type}{quality_note}"
 
1473
  return svg, status
1474
  else:
1475
- return "", f"{status_prefix}❌ Could not render reaction. Try a different format or check syntax: {final_reaction[:100]}..."
1476
 
1477
  # Legacy render functions (kept for compatibility)
1478
  def render_nist_reaction(reaction_text, options):
@@ -1482,7 +1507,7 @@ def build_interface() -> gr.Blocks:
1482
  svg = _render_reaction_from_nist(reaction_text)
1483
  if svg:
1484
  status = f"βœ… Successfully rendered NIST reaction: {reaction_text[:100]}..."
1485
- if "High quality" in (options or []):
1486
  status += " (High quality mode)"
1487
  return svg, status
1488
  else:
@@ -1495,7 +1520,7 @@ def build_interface() -> gr.Blocks:
1495
  svg = _render_smiles_to_svg(reaction_text)
1496
  if svg:
1497
  status = f"βœ… Successfully rendered SMILES reaction: {reaction_text[:100]}..."
1498
- if "High quality" in (options or []):
1499
  status += " (High quality mode)"
1500
  return svg, status
1501
  else:
@@ -1509,8 +1534,8 @@ def build_interface() -> gr.Blocks:
1509
  render_auto_btn.click(
1510
  fn=render_auto_reaction,
1511
  inputs=[reaction_input, deepseek_api_key, ai_options, render_mode],
1512
- outputs=[reaction_svg_output, render_status],
1513
- )
1514
 
1515
  render_nist_btn.click(
1516
  fn=render_nist_reaction,
@@ -1532,8 +1557,8 @@ def build_interface() -> gr.Blocks:
1532
 
1533
  # Tab 4: Kinetics Plotter
1534
  with gr.TabItem("Kinetics Plotter"):
1535
- with gr.Row():
1536
- with gr.Column():
1537
  A_input = gr.Number(value=1.3e-9, label="A (cmΒ³/moleculeΒ·s)")
1538
  n_input = gr.Number(value=-0.495, label="n (power)")
1539
  Ea_input = gr.Number(value=1150, label="Ea (J/mol)")
@@ -1571,8 +1596,8 @@ def build_interface() -> gr.Blocks:
1571
 
1572
  fetch_btn = gr.Button("Fetch Data")
1573
 
1574
- with gr.Column():
1575
- output_md = gr.Markdown()
1576
  output_df = gr.Dataframe(label="Tabular Data")
1577
  output_plot = gr.Plot(visible=False, label="Spectrum Preview") # For IR/UV/THz later
1578
 
@@ -1613,7 +1638,7 @@ def build_interface() -> gr.Blocks:
1613
  ["CH3"], ["benzene"], ["C6H5OH"]
1614
  ],
1615
  inputs=[formula_input] # Note: This is placeholder; make per-tab if needed
1616
- )
1617
 
1618
  return demo
1619
 
 
222
 
223
  # Generic table extraction
224
  tables = soup.find_all('table')
225
+ df = None
226
+ if tables:
227
  df = pd.read_html(StringIO(str(tables[0])))[0]
228
 
229
  # Fallback: Links for spectra/structures
 
900
 
901
  # Check if it's already SMILES format (contains >>)
902
  if ">>" in reaction_text:
903
+ svg = _render_smiles_to_svg(reaction_text)
904
  if svg:
905
  status = "βœ… Reaction rendered successfully from SMILES."
906
  return svg, status
 
917
  svg = _render_reaction_from_nist(completed_reaction)
918
  if svg:
919
  status = f"βœ… Reaction completed and rendered using DeepSeek AI.\nOriginal: {reaction_text}\nCompleted: {completed_reaction}"
920
+ return svg, status
921
  else:
922
  return "", f"🚨 DeepSeek completed reaction but rendering failed: {completed_reaction}"
923
  else:
 
1065
  return markdown, table, None, "", {}, ""
1066
 
1067
  plot_fig = _build_dataset_plot(detail)
1068
+
1069
  # Try to render the reaction title as SVG
1070
  reaction_svg = ""
1071
  if detail.title:
1072
  title = detail.title.strip()
1073
  smiles_attempt = None
1074
+
1075
  # Try different reaction format conversions
1076
  if " β†’ " in title:
1077
  # Format: "A + B β†’ C"
 
1090
  reactants = parts[0].replace(" + ", ".").strip()
1091
  products = parts[1].replace(" + ", ".").strip()
1092
  smiles_attempt = f"{reactants}>>{products}"
1093
+
1094
  if smiles_attempt:
1095
  svg = _render_smiles_to_svg(smiles_attempt)
1096
  if svg:
1097
  reaction_svg = svg
1098
+
1099
  # Auto-fetch thermodynamic data for compounds in the reaction
1100
  thermo_data = {}
1101
  thermo_summary = ""
 
1265
  value=True,
1266
  info="Automatically fetch thermodynamic data for searched compounds"
1267
  )
1268
+
1269
+ with gr.Row():
1270
+ decomp = gr.Checkbox(label="Only decomposition reactions", value=False)
1271
+ category = gr.Dropdown(label="Result type filter", choices=CATEGORY_CHOICES, value=str(Category.any.value))
1272
+ units = gr.Textbox(
1273
+ label="Optional Units token",
1274
+ placeholder="Leave blank to use NIST account defaults",
1275
+ )
1276
 
1277
  search_button = gr.Button("πŸ” Search NIST", variant="primary")
1278
+ search_status = gr.Markdown()
1279
 
1280
+ result_table = gr.Dataframe(
1281
+ headers=["#", "Records", "Reaction", "Detail URL"],
1282
+ datatype=["number", "number", "str", "str"],
1283
+ interactive=False,
1284
+ wrap=True,
1285
+ )
1286
 
1287
  # Search results thermodynamic data
1288
  search_thermo_accordion = gr.Accordion(label="πŸ”¬ Search Query Thermodynamic Data", open=False)
 
1293
  with gr.TabItem("Reaction Detail"):
1294
  with gr.Row():
1295
  with gr.Column(scale=2):
1296
+ selection = gr.Dropdown(
1297
+ label="Select a reaction from the latest search",
1298
+ choices=[],
1299
+ interactive=False,
1300
+ )
1301
+ manual_url = gr.Textbox(
1302
+ label="Or paste a NIST detail URL",
1303
+ placeholder="https://kinetics.nist.gov/kinetics/ReactionSearch?....",
1304
+ )
1305
  with gr.Column(scale=1):
1306
  auto_fetch_thermo = gr.Checkbox(
1307
  label="πŸ”¬ Auto-fetch thermodynamics",
 
1315
  )
1316
 
1317
  detail_button = gr.Button("Fetch Reaction Detail", variant="primary")
1318
+
1319
+ # Reaction metadata and details
1320
+ detail_markdown = gr.Markdown()
1321
+
1322
  with gr.Row():
1323
+ # Kinetics data table
1324
  with gr.Column():
1325
  gr.Markdown("### Kinetics Data")
1326
+ dataset_table = gr.Dataframe(
1327
+ headers=["Section", "Squib", "Temp [K]", "A", "n", "Ea [J/mole]", "k(298 K)", "Order", "Squib URL"],
1328
+ datatype=["str"] * 9,
1329
+ interactive=False,
1330
+ wrap=True,
1331
+ )
1332
+
1333
  # Arrhenius plot
1334
  with gr.Column():
1335
  gr.Markdown("### Arrhenius Plot")
1336
  reaction_plot = gr.Plot()
1337
 
1338
+ # Reaction SVG visualization
1339
+ with gr.Row():
1340
+ gr.Markdown("### Reaction Structure")
1341
+ reaction_svg = gr.HTML()
1342
+
1343
  # Auto-fetched thermodynamic data
1344
  thermo_summary = gr.Markdown()
1345
  thermo_accordion = gr.Accordion(label="πŸ”¬ Thermodynamic Data", open=False)
 
1350
  # Tab 3: Reaction SVG (Enhanced with NIST reactions and AI completion)
1351
  with gr.TabItem("Reaction SVG"):
1352
  gr.Markdown(
1353
+ "🎨 **Render chemical reactions as SVG using RDKit + AI Enhancement**\n\n"
1354
+ "Choose from NIST database reactions, enter custom reactions, or let AI enhance/validate/complete your reactions!\n\n"
1355
+ "**Workflow:**\n"
1356
+ "1. πŸ€– **AI Enhancement First**: DeepSeek AI analyzes and enhances your reaction\n"
1357
+ "2. 🎨 **RDKit Rendering**: Complete reaction rendered as beautiful SVG\n"
1358
+ "3. βœ… **Validation**: AI confirms reaction balance and plausibility\n\n"
1359
  "**Features:**\n"
1360
  "- πŸ§ͺ 200+ NIST database reactions\n"
1361
+ "- πŸ€– AI-powered reaction enhancement (DeepSeek-V3.2-Exp)\n"
1362
+ "- πŸ”¬ Multiple input formats (NIST, SMILES, SMARTS, partial)\n"
1363
+ "- ⚑ Automatic format detection and intelligent conversion\n"
1364
+ "- βœ… Reaction validation and balancing"
1365
  )
1366
 
1367
  # API Key Configuration
 
1372
  type="password",
1373
  info="Get your API key from https://platform.deepseek.com/"
1374
  )
1375
+ gr.Markdown(
1376
  "**How to get API key:**\n"
1377
  "1. Visit https://platform.deepseek.com/\n"
1378
  "2. Sign up/Login to your account\n"
 
1384
  # NIST reactions dropdown
1385
  nist_reactions = _fetch_all_nist_reactions(limit=200)
1386
  nist_reaction_options = [("", "")] + nist_reactions if nist_reactions else []
1387
+
1388
+ with gr.Row():
1389
  with gr.Column():
1390
  nist_reaction_dropdown = gr.Dropdown(
1391
  label="πŸ§ͺ NIST Database Reactions",
 
1394
  interactive=True,
1395
  info=f"Select from {len(nist_reactions)} reactions in NIST kinetics database"
1396
  )
1397
+
1398
+ reaction_input = gr.Textbox(
1399
  label="Custom Reaction Input",
1400
  placeholder="Enter reaction in any format:\nNIST: CH4 + O2 β†’ CO2 + H2O\nSMILES: CH4.O2>>CO2.H2O\nPartial: CH4 + O2 β†’ (AI will complete)",
1401
  lines=4,
 
1411
  )
1412
 
1413
  ai_options = gr.CheckboxGroup(
1414
+ label="πŸ€– AI Enhancement Options",
1415
+ choices=["Enable AI enhancement (recommended)", "High quality rendering", "Show AI reasoning"],
1416
+ value=["Enable AI enhancement (recommended)"],
1417
+ info="DeepSeek AI analyzes, validates, and enhances reactions before rendering"
1418
  )
1419
 
1420
  # Buttons
1421
  with gr.Row():
1422
+ render_auto_btn = gr.Button("πŸš€ AI First β†’ Render (Recommended)", variant="primary",
1423
+ info="DeepSeek AI enhances/completes reaction first, then renders SVG")
1424
+ render_nist_btn = gr.Button("πŸ§ͺ Direct NIST Render", variant="secondary",
1425
+ info="Render directly without AI enhancement")
1426
+ render_smiles_btn = gr.Button("πŸ”¬ Direct SMILES Render", variant="secondary",
1427
+ info="Render SMILES/SMARTS directly without AI enhancement")
1428
  clear_btn = gr.Button("πŸ—‘οΈ Clear", variant="stop")
1429
 
1430
  # Output
 
1436
  def populate_from_nist_dropdown(selected_label):
1437
  if selected_label and selected_label in nist_dict:
1438
  return nist_dict[selected_label]
1439
+ return ""
1440
+
1441
  nist_reaction_dropdown.change(
1442
  fn=populate_from_nist_dropdown,
1443
  inputs=nist_reaction_dropdown,
1444
+ outputs=reaction_input,
1445
+ )
1446
+
1447
  # Smart auto-render function
1448
  def render_auto_reaction(reaction_text, api_key, ai_options, render_mode):
1449
  if not reaction_text:
 
1452
  status_prefix = ""
1453
  final_reaction = reaction_text
1454
 
1455
+ # Always try AI enhancement first if enabled and API key provided
1456
+ if "Enable AI enhancement (recommended)" in (ai_options or []) and api_key:
1457
+ # Try to complete/enhance the reaction using DeepSeek
1458
+ completed_reaction = _complete_reaction_with_deepseek(reaction_text, api_key)
1459
+ if completed_reaction and completed_reaction != reaction_text:
1460
+ final_reaction = completed_reaction
1461
+ status_prefix = f"πŸ€– **AI Enhanced Reaction**\nOriginal: {reaction_text}\nAI Completed: {final_reaction}\n\n"
1462
+ elif completed_reaction == reaction_text:
1463
+ # AI validated the reaction as complete
1464
+ status_prefix = f"πŸ€– **AI Validated Reaction**\nReaction confirmed as complete and balanced.\n\n"
1465
+ else:
1466
+ # AI failed, try direct rendering
1467
+ status_prefix = f"⚠️ **AI Enhancement Failed**\nProceeding with original reaction.\n\n"
1468
+
1469
+ # Render the final reaction (AI-enhanced or original)
1470
+ svg = None
1471
+ render_type = "unknown"
1472
+
1473
+ # Try different rendering approaches based on mode
1474
+ if render_mode == "Force SMILES/SMARTS":
1475
  svg = _render_smiles_to_svg(final_reaction)
1476
  render_type = "SMILES/SMARTS"
1477
+ elif render_mode == "Force NIST format":
1478
  svg = _render_reaction_from_nist(final_reaction)
1479
  render_type = "NIST format"
1480
+ else: # Auto (detect format)
1481
+ # First try SMILES if it contains >>
1482
+ if ">>" in final_reaction:
 
1483
  svg = _render_smiles_to_svg(final_reaction)
1484
+ render_type = "SMILES/SMARTS (detected)"
1485
+ else:
1486
+ # Try NIST format first, then SMILES
1487
+ svg = _render_reaction_from_nist(final_reaction)
1488
+ if svg:
1489
+ render_type = "NIST format (detected)"
1490
+ else:
1491
+ svg = _render_smiles_to_svg(final_reaction)
1492
+ render_type = "SMILES/SMARTS (fallback)"
1493
 
1494
  if svg:
1495
  quality_note = " (High quality)" if "High quality rendering" in (ai_options or []) else ""
1496
+ reasoning_note = " (with AI reasoning)" if "Show AI reasoning" in (ai_options or []) else ""
1497
+ status = f"{status_prefix}βœ… Successfully rendered as {render_type}{quality_note}{reasoning_note}"
1498
  return svg, status
1499
  else:
1500
+ return "", f"{status_prefix}❌ Could not render reaction. The reaction format may not be supported: {final_reaction[:100]}...\n\nTry adjusting the render mode or checking your reaction syntax."
1501
 
1502
  # Legacy render functions (kept for compatibility)
1503
  def render_nist_reaction(reaction_text, options):
 
1507
  svg = _render_reaction_from_nist(reaction_text)
1508
  if svg:
1509
  status = f"βœ… Successfully rendered NIST reaction: {reaction_text[:100]}..."
1510
+ if "High quality rendering" in (options or []):
1511
  status += " (High quality mode)"
1512
  return svg, status
1513
  else:
 
1520
  svg = _render_smiles_to_svg(reaction_text)
1521
  if svg:
1522
  status = f"βœ… Successfully rendered SMILES reaction: {reaction_text[:100]}..."
1523
+ if "High quality rendering" in (options or []):
1524
  status += " (High quality mode)"
1525
  return svg, status
1526
  else:
 
1534
  render_auto_btn.click(
1535
  fn=render_auto_reaction,
1536
  inputs=[reaction_input, deepseek_api_key, ai_options, render_mode],
1537
+ outputs=[reaction_svg_output, render_status],
1538
+ )
1539
 
1540
  render_nist_btn.click(
1541
  fn=render_nist_reaction,
 
1557
 
1558
  # Tab 4: Kinetics Plotter
1559
  with gr.TabItem("Kinetics Plotter"):
1560
+ with gr.Row():
1561
+ with gr.Column():
1562
  A_input = gr.Number(value=1.3e-9, label="A (cmΒ³/moleculeΒ·s)")
1563
  n_input = gr.Number(value=-0.495, label="n (power)")
1564
  Ea_input = gr.Number(value=1150, label="Ea (J/mol)")
 
1596
 
1597
  fetch_btn = gr.Button("Fetch Data")
1598
 
1599
+ with gr.Column():
1600
+ output_md = gr.Markdown()
1601
  output_df = gr.Dataframe(label="Tabular Data")
1602
  output_plot = gr.Plot(visible=False, label="Spectrum Preview") # For IR/UV/THz later
1603
 
 
1638
  ["CH3"], ["benzene"], ["C6H5OH"]
1639
  ],
1640
  inputs=[formula_input] # Note: This is placeholder; make per-tab if needed
1641
+ )
1642
 
1643
  return demo
1644