Bio-CLIP / app.py
hohdavid's picture
fixed variable type
c0618e7 verified
Raw
History Blame Contribute Delete
6.43 kB
import streamlit as st
import torch
import torch.nn as nn
import torch.nn.functional as F
import pickle
import numpy as np
import re
from sklearn.cluster import KMeans
from transformers import T5Tokenizer, T5EncoderModel
import os
from dotenv import load_dotenv
import google.generativeai as genai
from bio_clip_recommender import BioCLIP, ProteinEmbedder, ProtocolRecommender
load_dotenv()
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
if not GEMINI_API_KEY:
st.error("API Key not found! Please check that your .env file exists and is formatted correctly.")
st.stop()
genai.configure(api_key=GEMINI_API_KEY)
sys_instruct = """
You are a Senior Research Biochemist. Your primary role is to design scientifically rigorous, highly cohesive protein purification pipelines based ONLY on provided laboratory data.
Follow these strict guidelines:
1. Tone & Style: Be concise, professional, and direct. Omit conversational filler and pleasantries.
2. Formatting: Use standard Markdown. Create clear headers for each step (e.g., '### Step 1: Lysis'). Bold all specific buffer concentrations, proteins, reagents, and pH values so they are easy to read at the bench.
3. Biochemical Rationale: For every step, explicitly state *why* specific reagents are used based on standard biochemical principles.
4. Chemical Guardrails: Never invent or hallucinate protocols or buffers. If you detect chemical incompatibilities in the user's request or retrieved data (e.g., high DTT concentrations applied to standard Ni-NTA columns, or inappropriate detergents for soluble proteins), explicitly flag them with a bold **WARNING**.
"""
model = genai.GenerativeModel('gemini-3.5-flash',
system_instruction=sys_instruct)
st.set_page_config(
page_title="Bio-CLIP Recommender",
layout="wide",
initial_sidebar_state="expanded"
)
@st.cache_resource(show_spinner=False)
def load_ai_engines():
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
embedder = ProteinEmbedder(device=device)
recommender = ProtocolRecommender(device=device)
return embedder, recommender
st.title("Bio-CLIP: Protein Purification AI")
st.markdown("Zero-shot protocol recommendation directly from 1D amino acid sequences.")
with st.spinner("Booting up ProtT5 and Bio-CLIP Models (this takes a moment)..."):
try:
embedder, recommender = load_ai_engines()
models_loaded = True
except Exception as e:
st.error(f"Failed to load model weights. Ensure `.pth` and `.pkl` files are in the same folder. \n\nError: {e}")
models_loaded = False
if models_loaded:
with st.sidebar:
st.header("About")
st.write("This tool uses **ProtT5** to embed amino acids and a Contrastive Learning (**Bio-CLIP**) model to map them to historical purification protocols.")
st.markdown("---")
st.write("**Top K Results**")
top_k = st.slider("Number of recommendations:", 1, 5, 3)
st.markdown("### Input Sequence")
default_gfp = "MSKGEELFTGVVPILVELDGDVNGHKFSVSGEGEGDATYGKLTLKFICTTGKLPVPWPTLVTTFSYGVQCFSRYPDHMKQHDFFKSAMPEGYVQERTIFFKDDGNYKTRAEVKFEGDTLVNRIELKGIDFKEDGNILGHKLEYNYNSHNVYIMADKQKNGIKVNFKIRHNIEDGSVQLADHYQQNTPIGDGPVLLPDNHYLSTQSALSKDPNEKRDHMVLLEFVTAAGITHGMDELYK"
sequence_input = st.text_area("Paste Amino Acid Sequence here:", value=default_gfp, height=150)
user_goal = st.text_input("Optional: What is your specific purification goal? (e.g., 'Prioritize highest yield', 'Are there temperature concerns?')")
if st.button("Generate Purification Pipeline", type="primary"):
sequence_input = sequence_input.strip()
if len(sequence_input) < 10:
st.warning("Please enter a valid amino acid sequence (at least 10 characters).")
else:
with st.spinner("1/2: Running ProtT5 Sequence Embedding..."):
seq_vector = embedder.embed_raw_sequence(sequence_input)
with st.spinner("2/2: Querying Bio-CLIP Latent Space..."):
results = recommender.search(seq_vector, top_k=top_k)
st.success("Search Complete!")
st.markdown("---")
col1, col2, col3 = st.columns(3)
columns = {'lysis': col1, 'elution': col2, 'desalting': col3}
for step in ['lysis', 'elution', 'desalting']:
with columns[step]:
st.subheader(f"{step.capitalize()}")
for i, res in enumerate(results[step]):
conf = max(0.0, min(1.0, (res['confidence'] + 0.1)))
st.markdown(f"**Option {i+1}**")
st.progress(float(conf), text=f"Confidence: {conf*100:.1f}%")
st.info(res['text'])
st.write("")
st.markdown("---")
st.markdown("### 3. AI Synthesis")
with st.spinner("3/3: Gemini AI analyzing retrieved protocols..."):
try:
retrieved_context = f"""
Lysis Options: {[res['text'] for res in results['lysis']]}
Elution Options: {[res['text'] for res in results['elution']]}
Desalting Options: {[res['text'] for res in results['desalting']]}
"""
has_his_tag = "HHHHHH" in sequence_input
rag_prompt = f"""
User Sequence: {sequence_input}
Contains His-Tag: {has_his_tag}
Synthesize a cohesive, step-by-step protein purification protocol using ONLY the retrieved options below.
If the user provided a specific goal, tailor the synthesis to that goal.
User's specific goal/question: {user_goal if user_goal else "Provide a standard, recommended cohesive pipeline from these options."}
--- RETRIEVED PROTOCOL OPTIONS ---
{retrieved_context}
----------------------------------
"""
response = model.generate_content(rag_prompt)
st.write(response.text)
except Exception as e:
st.error(f"An error occurred while generating the AI summary: {e}")