HDDprediciton / mobile_app.py
Sompote's picture
Upload 15 files
80f87f8 verified
import streamlit as st
import numpy as np
import joblib
# Page configuration
st.set_page_config(
page_title="HDD Predictor",
page_icon="πŸ”§",
layout="centered",
initial_sidebar_state="collapsed"
)
# Ultra-minimal Canva-style CSS
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;600;700&display=swap');
/* Hide Streamlit elements */
#MainMenu {visibility: hidden;}
footer {visibility: hidden;}
header {visibility: hidden;}
.stDeployButton {visibility: hidden;}
/* Main background */
.main {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
padding: 1rem 0;
}
/* Container */
.container {
background: white;
border-radius: 25px;
padding: 2rem 1.5rem;
margin: 1rem auto;
max-width: 400px;
box-shadow: 0 25px 50px rgba(0,0,0,0.15);
text-align: center;
}
/* Typography */
.title {
font-family: 'Poppins', sans-serif;
font-size: 1.8rem;
font-weight: 700;
color: #2d3748;
margin-bottom: 0.5rem;
}
.subtitle {
font-family: 'Poppins', sans-serif;
font-size: 0.9rem;
color: #718096;
margin-bottom: 2rem;
font-weight: 400;
}
/* Inputs */
.stSelectbox label, .stSlider label {
font-family: 'Poppins', sans-serif;
font-weight: 600;
color: #4a5568;
font-size: 0.95rem;
}
.stSelectbox > div > div {
border-radius: 15px;
border: 2px solid #e2e8f0;
font-family: 'Poppins', sans-serif;
}
.stSlider > div > div {
border-radius: 15px;
padding: 1rem;
background: #f7fafc;
}
/* Button */
.stButton > button {
background: linear-gradient(135deg, #667eea, #764ba2);
color: white;
border: none;
border-radius: 20px;
padding: 1rem 2rem;
font-family: 'Poppins', sans-serif;
font-weight: 600;
font-size: 1rem;
width: 100%;
margin: 1.5rem 0;
box-shadow: 0 10px 25px rgba(102, 126, 234, 0.3);
transition: all 0.3s ease;
}
.stButton > button:hover {
transform: translateY(-3px);
box-shadow: 0 15px 35px rgba(102, 126, 234, 0.4);
}
/* Result */
.result {
margin: 2rem 0;
padding: 2rem;
border-radius: 20px;
text-align: center;
}
.solution-icon {
font-size: 4rem;
margin-bottom: 1rem;
display: block;
}
.solution-title {
font-family: 'Poppins', sans-serif;
font-size: 1.5rem;
font-weight: 700;
color: white;
margin-bottom: 0.5rem;
}
.solution-desc {
font-family: 'Poppins', sans-serif;
font-size: 1rem;
color: rgba(255,255,255,0.9);
font-weight: 400;
}
/* Solution colors */
.sol-a { background: linear-gradient(135deg, #48bb78, #38a169); }
.sol-b { background: linear-gradient(135deg, #ed8936, #dd6b20); }
.sol-c { background: linear-gradient(135deg, #ed64a6, #d53f8c); }
.sol-d { background: linear-gradient(135deg, #9f7aea, #805ad5); }
.sol-e { background: linear-gradient(135deg, #68d391, #48bb78); }
/* Mobile logo styling */
.mobile-logo {
text-align: center;
margin-bottom: 1rem;
padding: 0.5rem;
background: rgba(255,255,255,0.1);
border-radius: 15px;
backdrop-filter: blur(10px);
}
.mobile-logo img {
filter: drop-shadow(0 2px 4px rgba(0,0,0,0.1));
margin: 0 0.5rem;
}
</style>
""", unsafe_allow_html=True)
# Load model
@st.cache_resource
def load_model():
try:
model = joblib.load('decision_tree_model.pkl')
le_soil = joblib.load('dt_soil_encoder.pkl')
le_water = joblib.load('dt_water_encoder.pkl')
le_solution = joblib.load('dt_solution_encoder.pkl')
return model, le_soil, le_water, le_solution
except FileNotFoundError:
st.error("Model files not found!")
return None, None, None, None
def predict_solution(diameter, soil_type, high_water, model, le_soil, le_water, le_solution):
try:
soil_encoded = le_soil.transform([soil_type])[0]
water_encoded = le_water.transform([high_water])[0]
features = np.array([[diameter, soil_encoded, water_encoded]])
prediction_encoded = model.predict(features)[0]
prediction = le_solution.inverse_transform([prediction_encoded])[0]
return prediction
except Exception as e:
return f"Error: {str(e)}"
def main():
# Logo section
st.markdown('<div class="mobile-logo">', unsafe_allow_html=True)
try:
# Center the single MEA logo
st.image('logo2.e8c5ff97.png', width=100)
except FileNotFoundError:
st.markdown("""
<div style="text-align: center; color: rgba(255,255,255,0.7); font-size: 0.8rem;">
πŸ“ MEA Logo not found
</div>
""", unsafe_allow_html=True)
st.markdown('</div>', unsafe_allow_html=True)
# Container start
st.markdown('<div class="container">', unsafe_allow_html=True)
# Header
st.markdown('<div class="title">πŸ”§ HDD Predictor</div>', unsafe_allow_html=True)
st.markdown('<div class="subtitle">Quick drilling solution recommendation</div>', unsafe_allow_html=True)
# Load model
model_data = load_model()
if model_data[0] is None:
st.stop()
model, le_soil, le_water, le_solution = model_data
# Inputs
diameter = st.slider("Diameter (m)", 0.5, 2.0, 1.2, 0.1)
soil_type = st.selectbox("Soil", ['clay', 'sand'])
high_water = st.selectbox("High Water", ['no', 'yes'])
# Predict
if st.button("Get Solution"):
prediction = predict_solution(diameter, soil_type, high_water, model, le_soil, le_water, le_solution)
solutions = {
'A': {'icon': 'πŸ›‘οΈ', 'title': 'Enhanced Protection', 'desc': 'Sheetpile + Trench + Grouting', 'class': 'sol-a'},
'B': {'icon': '🏰', 'title': 'Maximum Protection', 'desc': 'Full System + Casing', 'class': 'sol-b'},
'C': {'icon': 'πŸ”¨', 'title': 'Moderate Protection', 'desc': 'Sheetpile + Trench', 'class': 'sol-c'},
'D': {'icon': 'πŸ’§', 'title': 'Basic Protection', 'desc': 'Grouting Only', 'class': 'sol-d'},
'E': {'icon': 'βœ…', 'title': 'Minimal Action', 'desc': 'No Additional Measures', 'class': 'sol-e'}
}
if prediction in solutions:
sol = solutions[prediction]
st.markdown(f'''
<div class="result {sol['class']}">
<div class="solution-icon">{sol['icon']}</div>
<div class="solution-title">Solution {prediction}</div>
<div class="solution-title">{sol['title']}</div>
<div class="solution-desc">{sol['desc']}</div>
</div>
''', unsafe_allow_html=True)
# Container end
st.markdown('</div>', unsafe_allow_html=True)
if __name__ == "__main__":
main()