LLM-Compatibilty-Advisor / src /streamlit_app.py
qwerty45-uiop's picture
Update src/streamlit_app.py
5cc3290 verified
raw
history blame
9.97 kB
#!/usr/bin/env python3
"""
LLM Compatibility Advisor - Streamlined Version
Author: Assistant
Description: Provides device-based LLM recommendations with popular models
Requirements: streamlit, pandas, plotly, openpyxl
"""
import streamlit as st
import pandas as pd
import re
import plotly.graph_objects as go
from typing import Optional, Tuple, Dict, List
# Must be first Streamlit command
st.set_page_config(
page_title="LLM Compatibility Advisor",
layout="wide",
page_icon="🧠"
)
@st.cache_data
def load_data():
try:
df = pd.read_excel("src/BITS_INTERNS.xlsx", sheet_name="Form Responses 1")
df.columns = df.columns.str.strip()
return df, None
except FileNotFoundError:
return None, "Excel file 'BITS_INTERNS.xlsx' not found. Please upload the file."
except Exception as e:
return None, f"Error loading data: {str(e)}"
def extract_numeric_ram(ram) -> Optional[int]:
if pd.isna(ram):
return None
ram_str = str(ram).lower().replace(" ", "")
# Handle GB format
gb_match = re.search(r"(\d+(?:\.\d+)?)(?:gb|g)", ram_str)
if gb_match:
return int(float(gb_match.group(1)))
# Handle MB format
mb_match = re.search(r"(\d+)(?:mb|m)", ram_str)
if mb_match:
return max(1, int(int(mb_match.group(1)) / 1024))
# Handle plain numbers
plain_match = re.search(r"(\d+)", ram_str)
if plain_match:
return int(plain_match.group(1))
return None
# Simplified LLM database
LLM_DATABASE = {
"ultra_low": { # ≀2GB
"general": [
{"name": "TinyLlama-1.1B-Chat", "size": "637MB", "description": "Compact chat model"},
{"name": "all-MiniLM-L6-v2", "size": "91MB", "description": "Sentence embeddings"}
],
"code": [
{"name": "CodeT5-small", "size": "242MB", "description": "Code generation"}
]
},
"low": { # 3-4GB
"general": [
{"name": "Phi-1.5", "size": "2.8GB", "description": "Microsoft's efficient model"},
{"name": "Gemma-2B", "size": "1.4GB", "description": "Google's compact model"}
],
"code": [
{"name": "CodeGen-2B", "size": "1.8GB", "description": "Salesforce code model"}
]
},
"moderate": { # 5-8GB
"general": [
{"name": "Llama-2-7B-Chat", "size": "3.5GB", "description": "Meta's popular chat model"},
{"name": "Mistral-7B-Instruct-v0.2", "size": "4.1GB", "description": "Latest Mistral instruct"}
],
"code": [
{"name": "CodeLlama-7B-Instruct", "size": "3.8GB", "description": "Instruction-tuned CodeLlama"}
]
},
"good": { # 9-16GB
"general": [
{"name": "Llama-2-13B-Chat", "size": "7.3GB", "description": "Larger Llama variant"},
{"name": "OpenChat-3.5", "size": "7.1GB", "description": "High-quality chat model"}
],
"code": [
{"name": "CodeLlama-13B-Instruct", "size": "7.3GB", "description": "Larger code model"}
]
},
"high": { # 17-32GB
"general": [
{"name": "Mixtral-8x7B-Instruct-v0.1", "size": "26.9GB", "description": "Mixture of experts"},
{"name": "Yi-34B-Chat", "size": "19.5GB", "description": "01.AI's large model"}
],
"code": [
{"name": "CodeLlama-34B-Instruct", "size": "19.0GB", "description": "Large code specialist"}
]
},
"ultra_high": { # >32GB
"general": [
{"name": "Llama-2-70B", "size": "130GB", "description": "Full precision"},
{"name": "Mixtral-8x22B", "size": "176GB", "description": "Latest mixture model"}
]
}
}
def recommend_llm(ram_str) -> Tuple[str, str, Dict[str, List[Dict]]]:
"""Returns (recommendation, performance_tier, detailed_models)"""
ram = extract_numeric_ram(ram_str)
if ram is None:
return "βšͺ Check exact specs", "Unknown", {}
if ram <= 2:
return "πŸ”Έ Ultra-lightweight models", "Ultra Low", LLM_DATABASE["ultra_low"]
elif ram <= 4:
return "πŸ”Έ Small language models", "Low", LLM_DATABASE["low"]
elif ram <= 8:
return "🟠 7B models - excellent capabilities", "Moderate", LLM_DATABASE["moderate"]
elif ram <= 16:
return "🟒 High-quality models", "Good", LLM_DATABASE["good"]
elif ram <= 32:
return "πŸ”΅ Premium models", "High", LLM_DATABASE["high"]
else:
return "πŸ”΅ Top-tier models", "Ultra High", LLM_DATABASE["ultra_high"]
def get_os_info(os_name) -> Tuple[str, str]:
"""Returns (icon, clean_name)"""
if pd.isna(os_name):
return "πŸ’»", "Not specified"
os = str(os_name).lower()
if "windows" in os:
return "πŸͺŸ", os_name
elif "mac" in os:
return "🍎", os_name
elif "linux" in os or "ubuntu" in os:
return "🐧", os_name
elif "android" in os:
return "πŸ€–", os_name
elif "ios" in os:
return "πŸ“±", os_name
else:
return "πŸ’»", os_name
def create_performance_chart(df):
"""Create RAM distribution chart"""
laptop_rams = df["Laptop RAM"].apply(extract_numeric_ram).dropna()
mobile_rams = df["Mobile RAM"].apply(extract_numeric_ram).dropna()
fig = go.Figure()
fig.add_trace(go.Histogram(x=laptop_rams, name="Laptop RAM", opacity=0.7))
fig.add_trace(go.Histogram(x=mobile_rams, name="Mobile RAM", opacity=0.7))
fig.update_layout(
title="RAM Distribution",
xaxis_title="RAM (GB)",
yaxis_title="Students",
barmode='overlay',
height=400
)
return fig
def display_models(models_dict: Dict[str, List[Dict]]):
"""Display models by category"""
if not models_dict:
return
for category, model_list in models_dict.items():
if model_list:
st.markdown(f"**{category.title()} Models:**")
for model in model_list[:5]: # Limit to 5 per category
st.write(f"β€’ {model['name']} ({model['size']}) - {model['description']}")
# Main App
st.title("🧠 LLM Compatibility Advisor")
st.markdown("Get personalized AI model recommendations with download sizes!")
# Load data
df, error = load_data()
if error:
st.error(error)
st.stop()
if df is None or df.empty:
st.error("No data found.")
st.stop()
# Sidebar
with st.sidebar:
st.header("πŸ“Š Quick Stats")
st.metric("Total Students", len(df))
avg_laptop_ram = df["Laptop RAM"].apply(extract_numeric_ram).mean()
avg_mobile_ram = df["Mobile RAM"].apply(extract_numeric_ram).mean()
if not pd.isna(avg_laptop_ram):
st.metric("Avg Laptop RAM", f"{avg_laptop_ram:.1f} GB")
if not pd.isna(avg_mobile_ram):
st.metric("Avg Mobile RAM", f"{avg_mobile_ram:.1f} GB")
# Individual Analysis
st.subheader("πŸ‘€ Individual Student Analysis")
selected_user = st.selectbox(
"Choose a student:",
options=[""] + list(df["Full Name"].unique()),
format_func=lambda x: "Select a student..." if x == "" else x
)
if selected_user:
user_data = df[df["Full Name"] == selected_user].iloc[0]
col1, col2 = st.columns(2)
with col1:
st.markdown("### πŸ’» Laptop")
laptop_os_icon, laptop_os_name = get_os_info(user_data.get('Laptop Operating System'))
laptop_ram = user_data.get('Laptop RAM', 'Not specified')
laptop_rec, laptop_tier, laptop_models = recommend_llm(laptop_ram)
st.markdown(f"**OS:** {laptop_os_icon} {laptop_os_name}")
st.markdown(f"**RAM:** {laptop_ram}")
st.success(f"**Recommendation:** {laptop_rec}")
display_models(laptop_models)
with col2:
st.markdown("### πŸ“± Mobile")
mobile_os_icon, mobile_os_name = get_os_info(user_data.get('Mobile Operating System'))
mobile_ram = user_data.get('Mobile RAM', 'Not specified')
mobile_rec, mobile_tier, mobile_models = recommend_llm(mobile_ram)
st.markdown(f"**OS:** {mobile_os_icon} {mobile_os_name}")
st.markdown(f"**RAM:** {mobile_ram}")
st.success(f"**Recommendation:** {mobile_rec}")
display_models(mobile_models)
# Batch Analysis
st.markdown("---")
st.header("πŸ“Š Batch Analysis")
# Create summary table
df_display = df[["Full Name", "Laptop RAM", "Mobile RAM"]].copy()
df_display["Laptop Recommendation"] = df["Laptop RAM"].apply(lambda x: recommend_llm(x)[0])
df_display["Mobile Recommendation"] = df["Mobile RAM"].apply(lambda x: recommend_llm(x)[0])
st.dataframe(df_display, use_container_width=True)
# Performance chart
if len(df) > 1:
st.subheader("πŸ“ˆ RAM Distribution")
fig = create_performance_chart(df)
st.plotly_chart(fig, use_container_width=True)
# Model Explorer
st.markdown("---")
st.header("πŸ” Model Explorer")
selected_ram_range = st.selectbox(
"Select RAM range:",
["≀2GB (Ultra Low)", "3-4GB (Low)", "5-8GB (Moderate)",
"9-16GB (Good)", "17-32GB (High)", ">32GB (Ultra High)"]
)
# Map selection to database
ram_mapping = {
"≀2GB (Ultra Low)": "ultra_low",
"3-4GB (Low)": "low",
"5-8GB (Moderate)": "moderate",
"9-16GB (Good)": "good",
"17-32GB (High)": "high",
">32GB (Ultra High)": "ultra_high"
}
selected_key = ram_mapping[selected_ram_range]
if selected_key in LLM_DATABASE:
st.subheader(f"Models for {selected_ram_range}")
display_models(LLM_DATABASE[selected_key])
# Quick reference
with st.expander("πŸ“˜ Quick Reference"):
st.markdown("""
## Popular Models by Category
**General Purpose:**
- Llama-2 Series (7B, 13B, 70B)
- Mistral Series
- Gemma (2B, 7B)
**Code Specialists:**
- CodeLlama
- CodeGen
**Where to Download:**
- πŸ€— Hugging Face Hub
- πŸ¦™ Ollama
- πŸ“¦ LM Studio
""")
st.markdown("---")
st.markdown("*Built for BITS Pilani Interns*")