Update app.py
Browse files
app.py
CHANGED
|
@@ -17,8 +17,11 @@ matplotlib.use('Agg') # 修复后台线程问题
|
|
| 17 |
from rdkit import Chem
|
| 18 |
from rdkit.Chem import Draw
|
| 19 |
from rdkit.Chem import AllChem
|
|
|
|
| 20 |
from io import BytesIO
|
| 21 |
import traceback
|
|
|
|
|
|
|
| 22 |
|
| 23 |
# 配置日志
|
| 24 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
@@ -198,47 +201,37 @@ def predict_all(smiles):
|
|
| 198 |
return error_msg, None, error_msg, None, error_msg, None
|
| 199 |
|
| 200 |
# 新增函数:将绘制的分子结构转换为SMILES
|
| 201 |
-
def draw_to_smiles(
|
| 202 |
"""
|
| 203 |
-
将绘制的分子
|
| 204 |
-
:param
|
| 205 |
:return: (SMILES字符串, 分子图像)
|
| 206 |
"""
|
| 207 |
-
|
| 208 |
-
|
| 209 |
-
molfile = mol_data["mol"]
|
| 210 |
-
|
| 211 |
-
# 将molfile转换为RDKit分子对象
|
| 212 |
-
mol = Chem.MolFromMolBlock(molfile)
|
| 213 |
-
|
| 214 |
-
if mol is None:
|
| 215 |
-
# 如果直接解析失败,尝试添加氢原子
|
| 216 |
-
mol = Chem.MolFromMolBlock(molfile, sanitize=False)
|
| 217 |
-
if mol:
|
| 218 |
-
try:
|
| 219 |
-
# 尝试修复分子
|
| 220 |
-
mol.UpdatePropertyCache()
|
| 221 |
-
Chem.SanitizeMol(mol)
|
| 222 |
-
except:
|
| 223 |
-
pass
|
| 224 |
|
| 225 |
-
|
| 226 |
-
|
|
|
|
|
|
|
| 227 |
|
| 228 |
-
#
|
| 229 |
-
|
|
|
|
|
|
|
| 230 |
|
| 231 |
-
#
|
| 232 |
-
|
|
|
|
|
|
|
| 233 |
|
| 234 |
# 创建分子图像
|
| 235 |
-
img = Draw.MolToImage(mol)
|
| 236 |
img_buffer = BytesIO()
|
| 237 |
-
|
| 238 |
img_buffer.seek(0)
|
| 239 |
|
| 240 |
-
|
| 241 |
-
return
|
| 242 |
|
| 243 |
except Exception as e:
|
| 244 |
error_msg = f"分子转换失败: {str(e)}"
|
|
@@ -246,19 +239,12 @@ def draw_to_smiles(mol_data):
|
|
| 246 |
return None, None
|
| 247 |
|
| 248 |
# 新增函数:处理绘制输入的预测流程
|
| 249 |
-
def predict_from_drawing(
|
| 250 |
"""
|
| 251 |
处理用户绘制的分子结构
|
| 252 |
-
:param
|
| 253 |
:return: 预测结果 (6个输出组件)
|
| 254 |
"""
|
| 255 |
-
# 将绘制的结构转换为SMILES
|
| 256 |
-
smiles, img = draw_to_smiles(mol_data)
|
| 257 |
-
|
| 258 |
-
if not smiles:
|
| 259 |
-
error_msg = "无法解析绘制的分子结构"
|
| 260 |
-
return error_msg, None, error_msg, None, error_msg, None
|
| 261 |
-
|
| 262 |
# 使用预测函数
|
| 263 |
return predict_all(smiles)
|
| 264 |
|
|
@@ -287,17 +273,24 @@ with gr.Blocks(title="CrystalGAT") as demo:
|
|
| 287 |
|
| 288 |
with gr.Tab("绘制分子"):
|
| 289 |
gr.Markdown("### 绘制分子结构")
|
| 290 |
-
gr.Markdown("使用下方的绘图工具绘制分子结构,然后
|
| 291 |
|
| 292 |
-
# 使用
|
| 293 |
-
drawing_input = gr.
|
| 294 |
label="绘制分子结构",
|
| 295 |
-
type="
|
| 296 |
-
|
| 297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
)
|
|
|
|
| 299 |
drawing_display = gr.Image(label="分子结构预览", interactive=False)
|
| 300 |
-
drawing_output = gr.Text(label="生成的SMILES")
|
| 301 |
submit_btn2 = gr.Button("预测", variant="primary")
|
| 302 |
|
| 303 |
# 输出区域 (两种输入方式共享)
|
|
@@ -322,14 +315,14 @@ with gr.Blocks(title="CrystalGAT") as demo:
|
|
| 322 |
|
| 323 |
# 绘图输入路径
|
| 324 |
drawing_input.change(
|
| 325 |
-
fn=
|
| 326 |
inputs=drawing_input,
|
| 327 |
-
outputs=[
|
| 328 |
)
|
| 329 |
|
| 330 |
submit_btn2.click(
|
| 331 |
fn=predict_from_drawing,
|
| 332 |
-
inputs=
|
| 333 |
outputs=[elastic_text, elastic_img, plastic_text, plastic_img, brittle_text, brittle_img]
|
| 334 |
)
|
| 335 |
|
|
|
|
| 17 |
from rdkit import Chem
|
| 18 |
from rdkit.Chem import Draw
|
| 19 |
from rdkit.Chem import AllChem
|
| 20 |
+
from rdkit.Chem import MolFromSmiles
|
| 21 |
from io import BytesIO
|
| 22 |
import traceback
|
| 23 |
+
import tempfile
|
| 24 |
+
import base64
|
| 25 |
|
| 26 |
# 配置日志
|
| 27 |
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
|
|
|
|
| 201 |
return error_msg, None, error_msg, None, error_msg, None
|
| 202 |
|
| 203 |
# 新增函数:将绘制的分子结构转换为SMILES
|
| 204 |
+
def draw_to_smiles(image_data):
|
| 205 |
"""
|
| 206 |
+
将绘制的分子图像转换为SMILES字符串
|
| 207 |
+
:param image_data: 包含分子图像数据的base64字符串
|
| 208 |
:return: (SMILES字符串, 分子图像)
|
| 209 |
"""
|
| 210 |
+
if not image_data:
|
| 211 |
+
return None, None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 212 |
|
| 213 |
+
try:
|
| 214 |
+
# 将base64图像数据转换为PIL图像
|
| 215 |
+
image_bytes = base64.b64decode(image_data.split(",")[1])
|
| 216 |
+
image = Image.open(BytesIO(image_bytes))
|
| 217 |
|
| 218 |
+
# 保存临时文件
|
| 219 |
+
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp:
|
| 220 |
+
image.save(tmp.name)
|
| 221 |
+
tmp_path = tmp.name
|
| 222 |
|
| 223 |
+
# 使用RDKit从图像读取分子
|
| 224 |
+
mol = MolFromSmiles("") # 创建一个空分子
|
| 225 |
+
# 注意:实际应用中这里应该使用OCR或图像识别技术
|
| 226 |
+
# 这里简化处理,提示用户输入SMILES
|
| 227 |
|
| 228 |
# 创建分子图像
|
|
|
|
| 229 |
img_buffer = BytesIO()
|
| 230 |
+
image.save(img_buffer, format="PNG")
|
| 231 |
img_buffer.seek(0)
|
| 232 |
|
| 233 |
+
# 提示用户输入SMILES
|
| 234 |
+
return None, img_buffer
|
| 235 |
|
| 236 |
except Exception as e:
|
| 237 |
error_msg = f"分子转换失败: {str(e)}"
|
|
|
|
| 239 |
return None, None
|
| 240 |
|
| 241 |
# 新增函数:处理绘制输入的预测流程
|
| 242 |
+
def predict_from_drawing(smiles):
|
| 243 |
"""
|
| 244 |
处理用户绘制的分子结构
|
| 245 |
+
:param smiles: 用户输入的SMILES字符串
|
| 246 |
:return: 预测结果 (6个输出组件)
|
| 247 |
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 248 |
# 使用预测函数
|
| 249 |
return predict_all(smiles)
|
| 250 |
|
|
|
|
| 273 |
|
| 274 |
with gr.Tab("绘制分子"):
|
| 275 |
gr.Markdown("### 绘制分子结构")
|
| 276 |
+
gr.Markdown("使用下方的绘图工具绘制分子结构,然后在SMILES框中输入对应的SMILES字符串")
|
| 277 |
|
| 278 |
+
# 使用标准绘图组件
|
| 279 |
+
drawing_input = gr.ImageEditor(
|
| 280 |
label="绘制分子结构",
|
| 281 |
+
type="pil",
|
| 282 |
+
interactive=True,
|
| 283 |
+
height=300
|
| 284 |
+
)
|
| 285 |
+
|
| 286 |
+
gr.Markdown("### 输入绘制的分子对应的SMILES")
|
| 287 |
+
drawing_smiles = gr.Textbox(
|
| 288 |
+
label="SMILES",
|
| 289 |
+
placeholder="输入绘制的分子对应的SMILES字符串",
|
| 290 |
+
interactive=True
|
| 291 |
)
|
| 292 |
+
|
| 293 |
drawing_display = gr.Image(label="分子结构预览", interactive=False)
|
|
|
|
| 294 |
submit_btn2 = gr.Button("预测", variant="primary")
|
| 295 |
|
| 296 |
# 输出区域 (两种输入方式共享)
|
|
|
|
| 315 |
|
| 316 |
# 绘图输入路径
|
| 317 |
drawing_input.change(
|
| 318 |
+
fn=draw_to_smiles,
|
| 319 |
inputs=drawing_input,
|
| 320 |
+
outputs=[drawing_smiles, drawing_display]
|
| 321 |
)
|
| 322 |
|
| 323 |
submit_btn2.click(
|
| 324 |
fn=predict_from_drawing,
|
| 325 |
+
inputs=drawing_smiles,
|
| 326 |
outputs=[elastic_text, elastic_img, plastic_text, plastic_img, brittle_text, brittle_img]
|
| 327 |
)
|
| 328 |
|