|
|
import os |
|
|
import streamlit as st |
|
|
import pandas as pd |
|
|
import joblib |
|
|
import optuna |
|
|
import numpy as np |
|
|
import openai |
|
|
from catboost import CatBoostClassifier |
|
|
|
|
|
|
|
|
from google import genai |
|
|
from google.genai import types |
|
|
|
|
|
|
|
|
|
|
|
_original_number_input = st.number_input |
|
|
|
|
|
def safe_number_input(label, **kwargs): |
|
|
""" |
|
|
Clamp `value` into [min_value, max_value] and warn if we had to adjust. |
|
|
Then call the real st.number_input with the clamped default. |
|
|
""" |
|
|
min_value = kwargs.get("min_value", float("-inf")) |
|
|
max_value = kwargs.get("max_value", float("inf")) |
|
|
value = kwargs.get("value", min_value) |
|
|
clamped = min(max(value, min_value), max_value) |
|
|
if clamped != value: |
|
|
st.warning( |
|
|
f"⚠️ Default for “{label}” ({value}) was outside " |
|
|
f"[{min_value}, {max_value}]; using {clamped} instead." |
|
|
) |
|
|
kwargs["value"] = clamped |
|
|
return _original_number_input(label, **kwargs) |
|
|
|
|
|
st.number_input = safe_number_input |
|
|
|
|
|
|
|
|
|
|
|
gemini_key = os.getenv("GEMINI_API_KEY") |
|
|
if not gemini_key: |
|
|
st.error("Gemini API key not found. Please set GEMINI_API_KEY in your Space settings.") |
|
|
st.stop() |
|
|
|
|
|
client = genai.Client(api_key=gemini_key) |
|
|
|
|
|
|
|
|
def scaffold_quality_combined(printability, cell_response, |
|
|
weight_printability=0.3, weight_cell_response=0.7): |
|
|
if printability == 0: |
|
|
return 0.0 |
|
|
if cell_response == 1: |
|
|
return 100 * (printability / 3.0) |
|
|
norm_p = printability / 3.0 |
|
|
norm_c = (cell_response - 1) / 4.0 |
|
|
hm = (weight_printability + weight_cell_response) / ( |
|
|
(weight_printability / norm_p) + |
|
|
(weight_cell_response / norm_c) |
|
|
) |
|
|
mc = (norm_p**weight_printability) * (norm_c**weight_cell_response) |
|
|
return 100 * ((hm + mc) / 2.0) |
|
|
|
|
|
BIOMATERIAL_OPTIONS = [ |
|
|
"Alginate (%w/v)", |
|
|
"PVA-HA (%w/v)", |
|
|
"CaSO4 (%w/v)", |
|
|
"Na2HPO4 (%w/v)", |
|
|
"Gelatin (%w/v)", |
|
|
"GelMA (%w/v)", |
|
|
"laponite (%w/v)", |
|
|
"graphene oxide (%w/v)", |
|
|
"hydroxyapatite (%w/v)", |
|
|
"Hyaluronic_Acid (%w/v)", |
|
|
"hyaluronan metacrylate (%w/v)", |
|
|
"NorHA (%w/v)", |
|
|
"Fibroin/Fibrinogen (%w/v)", |
|
|
"Pluronic P-123 (%w/v)", |
|
|
"Collagen (%w/v)", |
|
|
"Chitosan (%w/v)", |
|
|
"CS-AEMA (%w/v)", |
|
|
"RGD (mM)", |
|
|
"TCP (%w/v)", |
|
|
"Gellan (%w/v)", |
|
|
"bioactive glass (%w/v)", |
|
|
"Nano/Methycellulose (%w/v)", |
|
|
"PEGTA (%w/v)", |
|
|
"PEGMA (%w/v)", |
|
|
"PEGDA (%w/v)", |
|
|
"Agarose (%w/v)", |
|
|
" hyaluronic acid+ Ph moieties (%w/v)", |
|
|
"matrigel (%w/v)", |
|
|
"CaCl2(mM)", |
|
|
"NaCl(mM)", |
|
|
"BaCl2(mM)", |
|
|
"SrCl2(mM)", |
|
|
"CaCO3 (mM)", |
|
|
"Genipin (%w/v)", |
|
|
"PVA (%wt)", |
|
|
"trans-glutaminase (%w/v)", |
|
|
"alginate lyase (U/ml)", |
|
|
"D-glucose (%w/v)", |
|
|
"PLGA (%w/v)", |
|
|
"vascular tissued-derived dECM (%w/v)", |
|
|
"PEG-8-SH (mM)", |
|
|
"Alginate dialdehyde (%w/v)", |
|
|
"Alginate sulfate (%w/v)", |
|
|
"RGD-modified alginate (%w/v)", |
|
|
"poly(N-isopropylacrylamide) grafted hyaluronan (%w/v)", |
|
|
"chondroitin sulfate methacrylate (%w/v)", |
|
|
"PCL (%w/v)", |
|
|
"alginate methacrylate (%w/v)", |
|
|
"HRP (U/ml)", |
|
|
"Pluronic F127 (%w/v)/Lutrol F127 (%w/v)", |
|
|
"Irgacure 2959 (%w/v)", |
|
|
"Eosin Y (%w/v)", |
|
|
"Ruthenium (mM)", |
|
|
"sodium persulfate (SPS) (mM)", |
|
|
"HEPES (mM)", |
|
|
"LAP (%w/v)", |
|
|
"glutaraldehyde (%w/v)", |
|
|
"PBS (M)", |
|
|
"glycerol (%w/v)", |
|
|
"cECM (%w/v)", |
|
|
"gel-fu(%w/v)", |
|
|
"Rose Bengal (%w/v)", |
|
|
"Vitamin B2(%w/v)", |
|
|
"VEGF(%w/v)", |
|
|
"Polypyrrole:PSS(%w/v)", |
|
|
"boratebioactiveglass(%w/v)", |
|
|
"astaxanthin(%w/v)", |
|
|
"PRP (%v/v)", |
|
|
"methacrylated collagen (%w/v)", |
|
|
"α-Toc (µM)", |
|
|
"ascorbic acid (mM)", |
|
|
"Liver dECM(%w/v)", |
|
|
"galactosylated alginate (%w/v)", |
|
|
"SC-PEG(%w/v)", |
|
|
"SFMA-L(%w/v)", |
|
|
"SFMA-M(%w/v)", |
|
|
"SFMA-H(%w/v)", |
|
|
"KdECMMA(%w/v)", |
|
|
"BA silk fibronin (%w/v)", |
|
|
"Carrageenan(%v)", |
|
|
"Carbopol ETD 2020 NF (%w/v)", |
|
|
"Carbopol Ultrez 10 NF(%w/v)", |
|
|
"Carbopol NF-980(%w/v)", |
|
|
"FBS (%v/v)", |
|
|
"MeTro (%w/v)", |
|
|
"Triethanolamine (%v/v)", |
|
|
"PEG-Fibrinogen (%w/v)", |
|
|
"polyethylene glycol dimethacrylate (%w/v)", |
|
|
"aprotinin (µg/ml)", |
|
|
"gold nanorod (mg/mL)", |
|
|
"egg white (w/v)", |
|
|
"1-Vinyl-2-Pyrrolidione (v/v)", |
|
|
"carboxyl functionalized carbon nanotubes (%w/v)", |
|
|
"polyHIPE (%w/v)", |
|
|
"β-D galactose (mM)", |
|
|
"hydrogen peroxide (H2O2) (%v/v)", |
|
|
"lactic acid v/v", |
|
|
"NorCol (%w/v)", |
|
|
"DDT (%w/v)", |
|
|
"ammonium persulfate (mM)", |
|
|
"diTyr-RGD (mM)", |
|
|
"PHEG-Tyr (%w/v)", |
|
|
"MMP2-degradable peptide (%w/v)", |
|
|
"KdECM (%w/v)", |
|
|
"EDC (mg)", |
|
|
"NHS (mg)", |
|
|
"VA086 (%w/v)", |
|
|
"PGS (%w/v)", |
|
|
"thiolated HA (%w/v)", |
|
|
"boron nitride nanotubes (%w/v)", |
|
|
"PEDOT:PSS (ul)", |
|
|
"KCl (mM)", |
|
|
"skeletal muscle ECM methacrylate (%w/v)", |
|
|
"PEO (%w/v)", |
|
|
"Carbon dots (mg/ml)", |
|
|
"Laminin (ug/ml)", |
|
|
"DF-PEG (%w/v)", |
|
|
"omenta ECM (%w/v)", |
|
|
"thrombin (unit/ml)", |
|
|
"Carbon nanotube (CNT) (w/v)", |
|
|
"Phytagel(%v)", |
|
|
"Laponite-XLG (%w/w)" |
|
|
] |
|
|
|
|
|
CELL_LINE_OPTIONS = [ |
|
|
"chondrocyteyte", |
|
|
"HepG2", |
|
|
"bMSCs", |
|
|
"HUVECs", |
|
|
"NIH3T3", |
|
|
"MESCs", |
|
|
"hiPSC-CMs /ATCCs", |
|
|
"CPCs", |
|
|
"L929", |
|
|
"Myoblast cells", |
|
|
"hiPSCs", |
|
|
"HepaRG", |
|
|
"hESCs", |
|
|
"10T1/2", |
|
|
"Cardiac progenitor cells", |
|
|
"NSCLC PDX", |
|
|
"RAMECs", |
|
|
"hASCs", |
|
|
"HAVIC", |
|
|
"Primary mouse hepatocyte", |
|
|
"PTECs", |
|
|
"human nasoseptal chondrocytes", |
|
|
"PDX", |
|
|
"HPFs", |
|
|
"U87-MG", |
|
|
"ESCs", |
|
|
"HASSMC", |
|
|
"dermal fibroblasts", |
|
|
"MC3T3-E1", |
|
|
"Schwann cells", |
|
|
"hiPSC-CMs and HS-27A", |
|
|
"Saos-2 ", |
|
|
"SU3", |
|
|
"hTMSCs", |
|
|
"HACs", |
|
|
"HADMSCs", |
|
|
"HeLa", |
|
|
"human primary kidney cells", |
|
|
"myoblasts", |
|
|
"MSCs", |
|
|
"human primary kidneycells", |
|
|
"293FT", |
|
|
"HEK 293FT", |
|
|
"Wnt3a-293FT", |
|
|
"RSC96/HUVECs", |
|
|
"human adipogenic mesenchymal stem cells", |
|
|
"HEPG2/ECs", |
|
|
"HUVECs/MSCs", |
|
|
"RHECs", |
|
|
"Human non-small cell lung cancer line Calu-3 (Calu-3)", |
|
|
"HL-1", |
|
|
"mouse cardiac cells", |
|
|
"IMR-90", |
|
|
"EPCs", |
|
|
"MRC5", |
|
|
"rMSC", |
|
|
"basil plant cell", |
|
|
"hNCs", |
|
|
"A549", |
|
|
"human induced pluripotent stem cell-derived cardiomyocytes", |
|
|
"bMSCs/hACs", |
|
|
"EA.hy 926 cells", |
|
|
"HepG2/C3A", |
|
|
"human epithelial lung carcinoma cells", |
|
|
"Human cardiac fibroblasts", |
|
|
"hTERT-MSC", |
|
|
"cardiomyocytes", |
|
|
"Huh7", |
|
|
"NRCMs", |
|
|
"HCF", |
|
|
"Wnt reporter-293FT", |
|
|
"neonatal rat ventricular CFs", |
|
|
"human coronary artery endothelial cells", |
|
|
"hiPSC-CM / fibroblasts", |
|
|
"primary mouse hepatocyte", |
|
|
"NIH3T3/ HUVECs", |
|
|
"murine macrophage-like cell line", |
|
|
"Endothelial cells", |
|
|
"Human aortic VIC", |
|
|
"sADSC", |
|
|
"HUVECs/H9C2", |
|
|
"neonatal rat ventricular cardiomyocytes", |
|
|
"MG-63", |
|
|
"Neonatal mouse cardiomyocytes (NMVCMs)", |
|
|
"human hepatic stellate cell line", |
|
|
"HEK-293", |
|
|
"aHSC", |
|
|
"MFCs", |
|
|
"fibroblasts", |
|
|
"HNDF", |
|
|
"cardiomyocyte/MSCs", |
|
|
"ADSCs", |
|
|
"HCASMCs", |
|
|
"cardiomyocyte", |
|
|
"hCPCs", |
|
|
"Human CM /adult human fibroblasts ", |
|
|
"primary rat hepatocyte", |
|
|
"human cardiac progenitor cells", |
|
|
"SMC", |
|
|
"Human MSCs", |
|
|
"ACPCs", |
|
|
"Huh7/HepaRG", |
|
|
"Human umbilical vein endothelial cells", |
|
|
"ATDC5", |
|
|
"hESC-derived HLCs", |
|
|
"NIH 3T3", |
|
|
"n neonatal mouse ventricular cardiomyocytes", |
|
|
"CFs/CMs/HUVECs", |
|
|
"MRC-5", |
|
|
"VIC", |
|
|
"eHep", |
|
|
"hUVECs/NIH3T3", |
|
|
"MC3T3", |
|
|
"HLC", |
|
|
"hepatoma", |
|
|
"FB", |
|
|
"A549 GFP+", |
|
|
"HPAAF", |
|
|
"PMHs", |
|
|
"HUVSMCs", |
|
|
"Human CPCs", |
|
|
"Fibroblasts/THP-1", |
|
|
"rat ventricular cardiomyocytes", |
|
|
"iCMs/iCFs/iECs", |
|
|
"HUVEC/HHSC", |
|
|
"Human CPCs / MSCs", |
|
|
"HepaRG/LX-2 ", |
|
|
"iCMs/iCFs/iECs/iCMFs", |
|
|
"LX-2 ", |
|
|
"SMMC-7721", |
|
|
"Hepatoblast- single cell/iESC/iMSC", |
|
|
"iCMFs", |
|
|
"Hepatoblast- spheroid/iESC/iMSC", |
|
|
"hBM-MSCs", |
|
|
"BMSCs", |
|
|
"HUVECs and HHSCs", |
|
|
"Intrahepatic cholangiocarcinoma (ICC)", |
|
|
"VICs", |
|
|
"CMs/CFs", |
|
|
"human neonatal dermal fi broblasts", |
|
|
"10T1/2 fibroblast-laden cells", |
|
|
"human cardiac fibroblasts", |
|
|
"neonatal rat ventricular CMs", |
|
|
"HUVECs and hiPSC-CS", |
|
|
"iPSC-derived CM", |
|
|
"Human Umbilical Vein Endothelial Cells + iPSC-derived CM", |
|
|
"rabbit bone marrow mesenchymal stem cells", |
|
|
"Neonatal rat cardiomyocytes", |
|
|
"NIH 3T3 mouse fibroblasts", |
|
|
"Human CPCs & MSCs", |
|
|
"NSCLC PDX/CAFs", |
|
|
"hiPSCs-derived HLCs", |
|
|
"U87", |
|
|
"75% hepatoblast cells, 20% iEC and 5% iMSC", |
|
|
"SMCs", |
|
|
"A549/95-D cells", |
|
|
"NCI-H441", |
|
|
"pancreatic cancer cell", |
|
|
"prostate cancer stem cell", |
|
|
"human primary parathyroid cells ", |
|
|
"primary human hepatocytes", |
|
|
"CPCs / MSCs", |
|
|
"CPCs ", |
|
|
"cardiac fibroblasts", |
|
|
"iPSCs-derived cardiomyocytes", |
|
|
"cardiomyocytes/ fibroblasts", |
|
|
"hiPSC-CM", |
|
|
"iPSCs/HUVECs", |
|
|
"iPSC-CMs", |
|
|
"iPSCs", |
|
|
"H1395", |
|
|
"PC9", |
|
|
"H1650", |
|
|
"HULEC-5a", |
|
|
"NCI-H1703" |
|
|
] |
|
|
|
|
|
PRINT_PARAM_NAMES = [ |
|
|
"Physical Crosslinking Duration (s)", |
|
|
"Photo Crosslinking Duration (s)", |
|
|
"Extrusion Pressure (kPa)", |
|
|
"Nozzle Movement Speed (mm/s)", |
|
|
"Nozzle Diameter (µm)", |
|
|
"Syringe Temperature (°C)", |
|
|
"Substrate Temperature (°C)", |
|
|
] |
|
|
|
|
|
@st.cache_resource |
|
|
def load_encoder(): |
|
|
return joblib.load('cell_line_encoder.joblib') |
|
|
|
|
|
@st.cache_resource |
|
|
def load_scalers(): |
|
|
return ( |
|
|
joblib.load('scaler_printability.joblib'), |
|
|
joblib.load('scaler_cell_response.joblib') |
|
|
) |
|
|
|
|
|
@st.cache_resource |
|
|
def load_models(): |
|
|
m_p = CatBoostClassifier(); m_p.load_model('catboost_printability.cbm') |
|
|
m_c = CatBoostClassifier(); m_c.load_model('catboost_cell_response.cbm') |
|
|
return m_p, m_c |
|
|
|
|
|
encoder = load_encoder() |
|
|
scaler_print, scaler_cell = load_scalers() |
|
|
model_print, model_cell = load_models() |
|
|
|
|
|
feature_order_print = list(scaler_print.feature_names_in_) |
|
|
feature_order_cell = list(scaler_cell.feature_names_in_) |
|
|
|
|
|
if 'bio_rows' not in st.session_state: |
|
|
st.session_state.bio_rows = [{ |
|
|
'mat': BIOMATERIAL_OPTIONS[0], |
|
|
'min': 0.0, 'max': 10.0, 'step': 0.1 |
|
|
}] |
|
|
|
|
|
if 'density_range' not in st.session_state: |
|
|
st.session_state.density_range = {'min': 0.0, 'max': 10.0, 'step': 0.1} |
|
|
|
|
|
if 'pp_ranges' not in st.session_state: |
|
|
st.session_state.pp_ranges = { |
|
|
name: {'min': 0.0, 'max': 10.0, 'step': 1.0} |
|
|
for name in PRINT_PARAM_NAMES |
|
|
} |
|
|
|
|
|
st.title("🧬 MLATE: Machine Learning Applications in Tissue Engieering") |
|
|
st.markdown( |
|
|
"<p style='font-size:1.2em; color:grey;'>" |
|
|
"A fully integrated Multi-Tissue, machine learning platform for prediction, optimization and generating procedures for fabricating 3D-(bio)printing scaffolds for tissue engineering. " |
|
|
"For more details, please refer to and cite our paper: " |
|
|
"<a href='https://doi.org/xxx' target='_blank'>https://doi.org/xxx</a>" |
|
|
"</p>", |
|
|
unsafe_allow_html=True |
|
|
) |
|
|
|
|
|
st.subheader("Biomaterials (enter range for each)") |
|
|
if st.button("➕ Add Biomaterial"): |
|
|
used = {r['mat'] for r in st.session_state.bio_rows} |
|
|
available = [m for m in BIOMATERIAL_OPTIONS if m not in used] |
|
|
if available: |
|
|
st.session_state.bio_rows.append({ |
|
|
'mat': available[0], 'min': 0.0, 'max': 10.0, 'step': 0.1 |
|
|
}) |
|
|
st.rerun() |
|
|
|
|
|
for i, row in enumerate(st.session_state.bio_rows): |
|
|
used_except_current = { |
|
|
r['mat'] for idx, r in enumerate(st.session_state.bio_rows) if idx != i |
|
|
} |
|
|
options = [m for m in BIOMATERIAL_OPTIONS if m not in used_except_current] |
|
|
|
|
|
c1, c2, c3, c4, c5 = st.columns([2, 1, 1, 1, 0.3]) |
|
|
mat = c1.selectbox( |
|
|
"", options, |
|
|
index=options.index(row['mat']) if row['mat'] in options else 0, |
|
|
key=f"bio_mat_{i}" |
|
|
) |
|
|
st.session_state.bio_rows[i]['mat'] = mat |
|
|
|
|
|
mn = c2.number_input( |
|
|
"Min", min_value=0.0, max_value=row['max'], |
|
|
value=row['min'], step=row['step'], key=f"bio_min_{i}" |
|
|
) |
|
|
mx = c3.number_input( |
|
|
"Max", min_value=row['step'], max_value=100.0, |
|
|
value=max(row['max'], row['step']), step=row['step'], |
|
|
key=f"bio_max_{i}" |
|
|
) |
|
|
st.session_state.bio_rows[i].update(min=mn, max=mx) |
|
|
|
|
|
st.session_state.bio_rows[i]['step'] = c4.number_input( |
|
|
"Step", min_value=0.0, |
|
|
max_value=(mx - mn) if mx > mn else 0.1, |
|
|
value=row['step'], step=0.1, key=f"bio_step_{i}" |
|
|
) |
|
|
|
|
|
if c5.button("❌", key=f"rem_{i}"): |
|
|
st.session_state.bio_rows.pop(i) |
|
|
st.rerun() |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
st.subheader("Cell Line & Density (10^6 cells/ml)") |
|
|
col1, col2, col3, col4 = st.columns([2,1,1,1]) |
|
|
cell_line = col1.selectbox("Cell Line", CELL_LINE_OPTIONS) |
|
|
|
|
|
dr = st.session_state.density_range |
|
|
dmin = col2.number_input( |
|
|
"Min Density", min_value=0.0, max_value=dr['max'], |
|
|
value=dr['min'], step=dr['step'], key="cd_min" |
|
|
) |
|
|
dmax = col3.number_input( |
|
|
"Max Density", min_value=dr['step'], max_value=1000.0, |
|
|
value=max(dr['max'], dr['step']), step=dr['step'], key="cd_max" |
|
|
) |
|
|
dr.update(min=dmin, max=dmax) |
|
|
|
|
|
dr['step'] = col4.number_input( |
|
|
"Step", min_value=0.0, |
|
|
max_value=(dmax - dmin) if dmax > dmin else 0.1, |
|
|
value=dr['step'], step=0.1, key="cd_step" |
|
|
) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
st.subheader("Printing Parameters (enter range)") |
|
|
for name in PRINT_PARAM_NAMES: |
|
|
pmin = st.session_state.pp_ranges[name]['min'] |
|
|
pmax = st.session_state.pp_ranges[name]['max'] |
|
|
pstep = st.session_state.pp_ranges[name]['step'] |
|
|
|
|
|
c1, c2, c3, c4 = st.columns([2,1,1,1]) |
|
|
c1.write(name) |
|
|
pmin = c2.number_input( |
|
|
"Min", min_value=0.0, max_value=pmax, |
|
|
value=pmin, step=pstep, key=f"pp_min_{name}" |
|
|
) |
|
|
pmax = c3.number_input( |
|
|
"Max", min_value=pstep, max_value=10000.0, |
|
|
value=max(pmax, pstep), step=pstep, key=f"pp_max_{name}" |
|
|
) |
|
|
pstep = c4.number_input( |
|
|
"Step", min_value=0.0, |
|
|
max_value=(pmax - pmin) if pmax > pmin else 1.0, |
|
|
value=pstep, step=max(1e-3, pstep/10), |
|
|
key=f"pp_step_{name}" |
|
|
) |
|
|
st.session_state.pp_ranges[name].update(min=pmin, max=pmax, step=pstep) |
|
|
|
|
|
st.markdown("---") |
|
|
|
|
|
if st.button("🛠️ Optimize WSSQ"): |
|
|
with st.spinner("Running Optuna…"): |
|
|
def objective(trial): |
|
|
bi_vals = { |
|
|
r['mat']: trial.suggest_float( |
|
|
f"bio__{r['mat']}", r['min'], r['max'], step=r['step'] |
|
|
) |
|
|
for r in st.session_state.bio_rows |
|
|
} |
|
|
for m in BIOMATERIAL_OPTIONS: |
|
|
bi_vals.setdefault(m, 0.0) |
|
|
|
|
|
cd = 0.0 if cell_line=="NoCellCultured" else trial.suggest_float( |
|
|
"cell_density", dr['min'], dr['max'], step=dr['step'] |
|
|
) |
|
|
|
|
|
pp_vals = { |
|
|
name: trial.suggest_float( |
|
|
f"pp__{name}", |
|
|
st.session_state.pp_ranges[name]['min'], |
|
|
st.session_state.pp_ranges[name]['max'], |
|
|
step=st.session_state.pp_ranges[name]['step'] |
|
|
) |
|
|
for name in PRINT_PARAM_NAMES |
|
|
} |
|
|
|
|
|
feat = {**bi_vals, **pp_vals} |
|
|
feat["Cell Density (cells/mL)"] = cd |
|
|
feat.update( |
|
|
encoder.transform(pd.DataFrame({"Cell Line":[cell_line]})) |
|
|
.iloc[0].to_dict() |
|
|
) |
|
|
|
|
|
X = pd.DataFrame([feat]) |
|
|
Xp = X.reindex(columns=feature_order_print, fill_value=0.0) |
|
|
Xc = X.reindex(columns=feature_order_cell, fill_value=0.0) |
|
|
|
|
|
p_proba = model_print.predict_proba(scaler_print.transform(Xp))[0] |
|
|
c_proba = model_cell .predict_proba(scaler_cell .transform(Xc))[0] |
|
|
exp_p = float(np.dot(p_proba, model_print.classes_.astype(float))) |
|
|
exp_c = float(np.dot(c_proba, model_cell .classes_.astype(float))) |
|
|
|
|
|
return scaffold_quality_combined(exp_p, exp_c) |
|
|
|
|
|
study = optuna.create_study(direction="maximize") |
|
|
study.optimize(objective, n_trials=50) |
|
|
best = study.best_trial |
|
|
|
|
|
st.success(f"🏆 Best WSSQ: **{best.value:.3f}**") |
|
|
|
|
|
best_df = pd.Series(best.params, name="value") \ |
|
|
.rename_axis("parameter") \ |
|
|
.to_frame() |
|
|
st.table(best_df) |
|
|
|
|
|
st.markdown("## 🧪 Fabrication Procedure") |
|
|
with st.spinner("Generating fabrication procedure…"): |
|
|
density = best.params.get("cell_density", 0.0) |
|
|
prompt = ( |
|
|
"Based on the following optimized scaffold parameters AND your selected cell line:\n\n" |
|
|
f"• Cell line: {cell_line}\n" |
|
|
"Optimized scaffold parameters:\n" |
|
|
f"{best.params}\n\n" |
|
|
"Write a detailed, step-by-step fabrication procedure for 3D (bio)printing " |
|
|
"this scaffold — including materials, equipment, printing settings, and post‑processing." |
|
|
) |
|
|
|
|
|
resp = client.models.generate_content( |
|
|
model="gemini-2.0-flash-001", |
|
|
contents=prompt, |
|
|
config=types.GenerateContentConfig( |
|
|
system_instruction=( |
|
|
"You are a biomedical engineering professor with tissue engineering experties. " |
|
|
"you know how to print 3d (bio)printed scaffolds in labs." |
|
|
) |
|
|
) |
|
|
) |
|
|
|
|
|
procedure = resp.text |
|
|
st.markdown(procedure) |