Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -117,15 +117,7 @@ def load_ensemble_models():
|
|
| 117 |
|
| 118 |
model = PredictModel(num_layers=6, d_model=256, dff=512, num_heads=8, vocab_size=18, a=1, dense_dropout=0.4)
|
| 119 |
# Dummy call to build graph
|
| 120 |
-
# We use dummy tensors to initialize the weights
|
| 121 |
dummy_x = tf.zeros((1, 512), dtype=tf.int64)
|
| 122 |
-
# ... (simplified init) ...
|
| 123 |
-
# Actually, simpler to just load weights if we build input correctly.
|
| 124 |
-
# But Safe way: Just return the fresh model and load weights during loop if needed?
|
| 125 |
-
# No, that's slow. We load weights NOW.
|
| 126 |
-
|
| 127 |
-
# NOTE: To load weights, we need to build the model first.
|
| 128 |
-
# We will do lazy-loading inside the loop but KEEP the model in memory.
|
| 129 |
models.append((model, weight_file))
|
| 130 |
|
| 131 |
return models
|
|
@@ -162,16 +154,13 @@ def predict_single(payload, linker, peptide):
|
|
| 162 |
if not payload or not linker or not peptide:
|
| 163 |
return "β οΈ Please fill in all fields."
|
| 164 |
|
| 165 |
-
# For single prediction, we accept the small slowness of loading
|
| 166 |
-
# to avoid keeping models in memory forever if not needed.
|
| 167 |
-
# OR reuse the logic. Let's reuse logic for consistency.
|
| 168 |
models = load_ensemble_models()
|
| 169 |
data = preprocess_input(payload, linker, peptide)
|
| 170 |
|
| 171 |
if data is None: return "Error processing input."
|
| 172 |
|
| 173 |
score = predict_with_loaded_models(models, data)
|
| 174 |
-
keras.backend.clear_session()
|
| 175 |
|
| 176 |
label = "Active PDC β
" if score > 0.5 else "Inactive β"
|
| 177 |
return f"{label}\nConfidence: {score:.2%}"
|
|
@@ -197,7 +186,7 @@ def predict_batch(file_obj, progress=gr.Progress()):
|
|
| 197 |
if missing:
|
| 198 |
return None, pd.DataFrame({"Error": [f"Missing columns: {missing}"]})
|
| 199 |
|
| 200 |
-
# 3. LOAD MODELS ONCE
|
| 201 |
print("π Loading Ensemble Models for Batch Processing...")
|
| 202 |
models = load_ensemble_models()
|
| 203 |
|
|
@@ -209,36 +198,52 @@ def predict_batch(file_obj, progress=gr.Progress()):
|
|
| 209 |
l_smiles = row[col_map['Linker SMILES']]
|
| 210 |
peptide = row[col_map['Peptide Sequence']]
|
| 211 |
|
| 212 |
-
# Preprocess
|
| 213 |
data = preprocess_input(p_smiles, l_smiles, peptide)
|
| 214 |
|
| 215 |
if data is None:
|
| 216 |
pred, conf = "Error", 0.0
|
| 217 |
else:
|
| 218 |
-
# Predict using the ALREADY LOADED models
|
| 219 |
score = predict_with_loaded_models(models, data)
|
| 220 |
pred = "Active" if score > 0.5 else "Inactive"
|
| 221 |
conf = score
|
| 222 |
|
| 223 |
-
|
|
|
|
| 224 |
|
| 225 |
# 5. Cleanup
|
| 226 |
keras.backend.clear_session()
|
| 227 |
|
| 228 |
# 6. Format Outputs
|
| 229 |
-
|
|
|
|
| 230 |
output_file = "predictions.csv"
|
| 231 |
res_df.to_csv(output_file, index=False)
|
| 232 |
|
| 233 |
return output_file, res_df
|
| 234 |
|
| 235 |
# --- 7. GRADIO INTERFACE ---
|
| 236 |
-
|
| 237 |
-
|
| 238 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 239 |
|
| 240 |
with gr.Tabs():
|
| 241 |
with gr.TabItem("Single Prediction"):
|
|
|
|
| 242 |
with gr.Row():
|
| 243 |
with gr.Column():
|
| 244 |
in_payload = gr.Textbox(label="Payload SMILES", placeholder="e.g. COc1cc2c...", lines=2)
|
|
@@ -250,19 +255,20 @@ with gr.Blocks(title="PDCNet Ensemble Demo") as demo:
|
|
| 250 |
btn_predict.click(predict_single, inputs=[in_payload, in_linker, in_peptide], outputs=out_result)
|
| 251 |
|
| 252 |
with gr.TabItem("Batch Prediction (File)"):
|
| 253 |
-
gr.Markdown("Upload a CSV or Excel file.")
|
| 254 |
-
|
| 255 |
-
|
| 256 |
-
|
|
|
|
| 257 |
|
| 258 |
-
# OUTPUTS
|
| 259 |
out_dataframe = gr.Dataframe(label="Results Preview", interactive=False)
|
| 260 |
file_output = gr.File(label="Download Full Results (.csv)")
|
| 261 |
|
| 262 |
btn_batch.click(
|
| 263 |
predict_batch,
|
| 264 |
inputs=file_input,
|
| 265 |
-
outputs=[file_output, out_dataframe]
|
| 266 |
)
|
| 267 |
|
| 268 |
demo.launch()
|
|
|
|
| 117 |
|
| 118 |
model = PredictModel(num_layers=6, d_model=256, dff=512, num_heads=8, vocab_size=18, a=1, dense_dropout=0.4)
|
| 119 |
# Dummy call to build graph
|
|
|
|
| 120 |
dummy_x = tf.zeros((1, 512), dtype=tf.int64)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
models.append((model, weight_file))
|
| 122 |
|
| 123 |
return models
|
|
|
|
| 154 |
if not payload or not linker or not peptide:
|
| 155 |
return "β οΈ Please fill in all fields."
|
| 156 |
|
|
|
|
|
|
|
|
|
|
| 157 |
models = load_ensemble_models()
|
| 158 |
data = preprocess_input(payload, linker, peptide)
|
| 159 |
|
| 160 |
if data is None: return "Error processing input."
|
| 161 |
|
| 162 |
score = predict_with_loaded_models(models, data)
|
| 163 |
+
keras.backend.clear_session()
|
| 164 |
|
| 165 |
label = "Active PDC β
" if score > 0.5 else "Inactive β"
|
| 166 |
return f"{label}\nConfidence: {score:.2%}"
|
|
|
|
| 186 |
if missing:
|
| 187 |
return None, pd.DataFrame({"Error": [f"Missing columns: {missing}"]})
|
| 188 |
|
| 189 |
+
# 3. LOAD MODELS ONCE
|
| 190 |
print("π Loading Ensemble Models for Batch Processing...")
|
| 191 |
models = load_ensemble_models()
|
| 192 |
|
|
|
|
| 198 |
l_smiles = row[col_map['Linker SMILES']]
|
| 199 |
peptide = row[col_map['Peptide Sequence']]
|
| 200 |
|
|
|
|
| 201 |
data = preprocess_input(p_smiles, l_smiles, peptide)
|
| 202 |
|
| 203 |
if data is None:
|
| 204 |
pred, conf = "Error", 0.0
|
| 205 |
else:
|
|
|
|
| 206 |
score = predict_with_loaded_models(models, data)
|
| 207 |
pred = "Active" if score > 0.5 else "Inactive"
|
| 208 |
conf = score
|
| 209 |
|
| 210 |
+
# UI UPDATE: Put Prediction and Score FIRST
|
| 211 |
+
results.append([pred, f"{conf:.4f}", p_smiles, l_smiles, peptide])
|
| 212 |
|
| 213 |
# 5. Cleanup
|
| 214 |
keras.backend.clear_session()
|
| 215 |
|
| 216 |
# 6. Format Outputs
|
| 217 |
+
# Columns Reordered here for both display and CSV
|
| 218 |
+
res_df = pd.DataFrame(results, columns=['Prediction', 'Score', 'Payload', 'Linker', 'Peptide'])
|
| 219 |
output_file = "predictions.csv"
|
| 220 |
res_df.to_csv(output_file, index=False)
|
| 221 |
|
| 222 |
return output_file, res_df
|
| 223 |
|
| 224 |
# --- 7. GRADIO INTERFACE ---
|
| 225 |
+
# CSS to center the content nicely
|
| 226 |
+
css = """
|
| 227 |
+
.gradio-container {text-align: center;}
|
| 228 |
+
h1 {text-align: center; display: block;}
|
| 229 |
+
p {text-align: center; display: block;}
|
| 230 |
+
"""
|
| 231 |
+
|
| 232 |
+
with gr.Blocks(title="PDCNet Ensemble Demo", css=css) as demo:
|
| 233 |
+
|
| 234 |
+
# CENTERED HEADER
|
| 235 |
+
gr.HTML("""
|
| 236 |
+
<div style="text-align: center; max-width: 800px; margin: 0 auto;">
|
| 237 |
+
<h1>π PDCNet Ensemble Predictor</h1>
|
| 238 |
+
<p style="font-size: 1.1em;">
|
| 239 |
+
Predict Peptide-Drug Conjugate activity using Graph Neural Networks + ESM-2 Protein Language Model.
|
| 240 |
+
</p>
|
| 241 |
+
</div>
|
| 242 |
+
""")
|
| 243 |
|
| 244 |
with gr.Tabs():
|
| 245 |
with gr.TabItem("Single Prediction"):
|
| 246 |
+
# Centering the input area slightly
|
| 247 |
with gr.Row():
|
| 248 |
with gr.Column():
|
| 249 |
in_payload = gr.Textbox(label="Payload SMILES", placeholder="e.g. COc1cc2c...", lines=2)
|
|
|
|
| 255 |
btn_predict.click(predict_single, inputs=[in_payload, in_linker, in_peptide], outputs=out_result)
|
| 256 |
|
| 257 |
with gr.TabItem("Batch Prediction (File)"):
|
| 258 |
+
gr.Markdown("### Upload a CSV or Excel file to process many molecules at once.")
|
| 259 |
+
|
| 260 |
+
# UI UPDATE: Stacked vertically (No gr.Row)
|
| 261 |
+
file_input = gr.File(label="Upload Dataset")
|
| 262 |
+
btn_batch = gr.Button("Run Batch Prediction", variant="primary")
|
| 263 |
|
| 264 |
+
# OUTPUTS
|
| 265 |
out_dataframe = gr.Dataframe(label="Results Preview", interactive=False)
|
| 266 |
file_output = gr.File(label="Download Full Results (.csv)")
|
| 267 |
|
| 268 |
btn_batch.click(
|
| 269 |
predict_batch,
|
| 270 |
inputs=file_input,
|
| 271 |
+
outputs=[file_output, out_dataframe]
|
| 272 |
)
|
| 273 |
|
| 274 |
demo.launch()
|