| |
| import os |
| import gradio as gr |
| from fastapi import FastAPI |
| from fastapi.middleware.cors import CORSMiddleware |
| from pydantic import BaseModel |
| from typing import List |
|
|
| from rdkit import Chem |
| from rdkit.Chem import MolToSmiles |
| from STOUT import translate_forward |
|
|
| app = FastAPI(title="SMILES → IUPAC (STOUT-V2)") |
|
|
| app.add_middleware( |
| CORSMiddleware, |
| allow_origins=["*"], |
| allow_methods=["*"], |
| allow_headers=["*"], |
| ) |
|
|
| def canonicalize_smiles(s: str) -> str: |
| mol = Chem.MolFromSmiles(s) |
| if mol is None: |
| raise ValueError(f"非法SMILES,RDKit无法解析:{s!r}") |
| return MolToSmiles(mol, canonical=True) |
|
|
| class SMILESItem(BaseModel): |
| smiles: str |
| canonicalize: bool = True |
|
|
| class BatchRequest(BaseModel): |
| inputs: List[SMILESItem] |
|
|
| @app.get("/healthz") |
| def healthz(): |
| return {"ok": True} |
|
|
| @app.post("/api/smiles2iupac") |
| def api_smiles2iupac(req: SMILESItem): |
| try: |
| s = (req.smiles or "").strip() |
| if not s: |
| return {"success": False, "error": "输入为空"} |
|
|
| s_norm = canonicalize_smiles(s) if req.canonicalize else s |
| name = translate_forward(s_norm) |
|
|
| return { |
| "success": True, |
| "input": s, |
| "smiles_processed": s_norm, |
| "iupac": name, |
| } |
| except Exception as e: |
| return {"success": False, "error": str(e)} |
|
|
| @app.post("/api/smiles2iupac/batch") |
| def api_smiles2iupac_batch(req: BatchRequest): |
| out = [] |
| for item in req.inputs: |
| try: |
| s = (item.smiles or "").strip() |
| if not s: |
| out.append({"success": False, "error": "输入为空"}) |
| continue |
|
|
| s_norm = canonicalize_smiles(s) if item.canonicalize else s |
| name = translate_forward(s_norm) |
| out.append({ |
| "success": True, |
| "input": s, |
| "smiles_processed": s_norm, |
| "iupac": name, |
| }) |
| except Exception as e: |
| out.append({"success": False, "input": item.smiles, "error": str(e)}) |
| return out |
|
|
| def gradio_fn(s: str, canonicalize: bool): |
| if not (s or "").strip(): |
| return "", "输入为空" |
| try: |
| s_norm = canonicalize_smiles(s) if canonicalize else s |
| name = translate_forward(s_norm) |
| return name, f"输入SMILES: {s}\n规范化SMILES: {s_norm}" |
| except Exception as e: |
| return "", f"Error: {e}" |
|
|
| demo = gr.Interface( |
| fn=gradio_fn, |
| inputs=[ |
| gr.Textbox(label="输入SMILES", placeholder="支持任意合法SMILES写法"), |
| gr.Checkbox(label="自动RDKit规范化", value=True), |
| ], |
| outputs=[ |
| gr.Textbox(label="IUPAC名称", interactive=True), |
| gr.Textbox(label="调试信息"), |
| ], |
| title="SMILES → IUPAC (STOUT-V2)", |
| description="Model: Kohulan/STOUT-V2 | 基于TensorFlow的翻译模型", |
| ) |
|
|
| app = gr.mount_gradio_app(app, demo, path="/") |