App - Py Code
App - Py Code
import numpy as np
import plotly.graph_objects as go
import joblib
import json
import os
import pandas as pd
import time
st.set_page_config(
layout="wide",
page_icon="🌸",
initial_sidebar_state="expanded"
st.markdown("""
<style>
@import url('https://fonts.googleapis.com/css2?
family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
:root {
--primary: #6366f1;
--primary-dark: #4f46e5;
--secondary: #10b981;
--dark: #0f172a;
--darker: #020617;
--light: #f8fafc;
--text-primary: #e2e8f0;
--text-secondary: #94a3b8;
--success: #10b981;
--warning: #f59e0b;
--danger: #ef4444;
color: var(--text-primary);
background-color: var(--dark);
line-height: 1.6;
font-weight: 600;
color: var(--light);
margin-top: 0;
.stMarkdown p, .stMarkdown li {
.stApp {
color: white;
border: none;
border-radius: 6px;
font-weight: 500;
transform: translateY(-2px);
.glass-panel {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.08);
padding: 1.5rem;
margin-bottom: 1.5rem;
.metric-value {
font-size: 1.2rem;
font-weight: 600;
color: var(--light);
.metric-label {
font-size: 0.9rem;
color: var(--text-secondary);
.block-container {
.confidence-bar {
height: 8px;
border-radius: 4px;
margin-top: 4px;
overflow: hidden;
.confidence-fill {
height: 100%;
border-radius: 4px;
/* Custom scrollbar */
::-webkit-scrollbar {
width: 8px;
height: 8px;
::-webkit-scrollbar-track {
background: rgba(255,255,255,0.05);
::-webkit-scrollbar-thumb {
background: var(--primary);
border-radius: 4px;
/* Responsive adjustments */
.block-container {
.stMarkdown h1 {
.stSlider {
</style>
""", unsafe_allow_html=True)
@st.cache_resource
def load_resources():
try:
label_encoder = joblib.load("models/label_encoder.pkl")
# Load models
models = {}
model_files = {
"SVM": "models/svm_model.pkl",
try:
model = joblib.load(file_path)
# Test prediction
prediction = model.predict(dummy_input)
if prediction.shape[1] != len(label_encoder.classes_):
continue
else:
prediction = model.predict(dummy_input)
models[model_name] = model
except Exception as e:
if not models:
scaler = joblib.load("models/minmax_scaler.pkl")
metrics = json.load(f)
conf_matrices = {}
matrix_files = {
"SVM": "conf_matrix_svm.npy",
if os.path.exists(file_path):
matrix = np.load(file_path)
if matrix.shape[0] == len(label_encoder.classes_):
conf_matrices[model_name] = matrix
except Exception as e:
def render_3d_flower(species):
colors = {
"setosa": "var(--primary)",
"versicolor": "var(--secondary)",
"virginica": "var(--warning)"
try:
r = 1 + 0.3 * np.cos(5 * u)
x = r * np.sin(v) * np.cos(u)
y = r * np.sin(v) * np.sin(u)
z = r * np.cos(v)
fig = go.Figure(data=[
go.Surface(
showscale=False,
opacity=0.9,
lighting=dict(
ambient=0.7,
diffuse=0.7,
roughness=0.1,
specular=0.2
])
fig.update_layout(
scene=dict(
xaxis=dict(visible=False),
yaxis=dict(visible=False),
zaxis=dict(visible=False),
bgcolor='rgba(0,0,0,0)',
camera=dict(
),
margin=dict(l=0, r=0, b=0, t=0),
height=350,
paper_bgcolor='rgba(0,0,0,0)'
except Exception as e:
try:
importance = model.feature_importances_
else:
return
fig = go.Figure(go.Bar(
x=importance,
y=features,
orientation='h',
marker_color='#6366f1'
))
fig.update_layout(
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font=dict(color='white'),
height=300,
st.plotly_chart(fig, use_container_width=True)
except Exception as e:
def render_confusion_matrix(model_name):
try:
if model_name in conf_matrices:
cm = conf_matrices[model_name]
plt.style.use('dark_background')
sns.heatmap(cm,
annot=True,
fmt='d',
cmap=cmap,
cbar=False,
ax=ax,
annot_kws={
"size": 14,
"color": "black"
},
linewidths=0.5,
linecolor='#475569',
xticklabels=labels,
yticklabels=labels,
square=True)
pad=20,
color='white',
fontsize=14,
fontweight='bold')
ax.set_xlabel('Predicted Label',
color='white',
labelpad=10,
fontweight='bold')
ax.set_ylabel('True Label',
color='white',
labelpad=10,
fontweight='bold')
ax.tick_params(axis='both',
colors='white',
labelsize=12,
rotation=0)
fig.patch.set_facecolor('#0f172a')
ax.set_facecolor('#1e293b')
st.pyplot(fig, clear_figure=True)
else:
except Exception as e:
def render_performance(metrics):
try:
model_names = list(metrics.keys())
metric_data = {
metric_data[metric]['values'].append(metrics[model].get(metric, 0))
fig = go.Figure()
fig.add_trace(go.Bar(
x=model_names,
y=data['values'],
name=metric,
marker_color=data['color'],
hovertemplate='%{x}<br>%{y:.3f}<extra></extra>'
))
fig.update_layout(
barmode='group',
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font=dict(color='white'),
legend=dict(
orientation="h",
yanchor="bottom",
y=1.02,
xanchor="right",
x=1,
font=dict(size=12)
),
height=400,
hovermode="x unified"
fig.update_xaxes(tickangle=-30)
st.plotly_chart(fig, use_container_width=True)
except Exception as e:
try:
if probabilities is None:
return
fig = go.Figure(go.Bar(
x=probabilities * 100,
y=classes,
orientation='h',
marker_color=colors,
textposition='auto',
textfont=dict(color='white')
))
fig.update_layout(
plot_bgcolor='rgba(0,0,0,0)',
paper_bgcolor='rgba(0,0,0,0)',
font=dict(color='white'),
height=250,
xaxis=dict(
range=[0, 100],
title='Confidence (%)',
ticksuffix='%'
),
yaxis=dict(
autorange="reversed"
st.plotly_chart(fig, use_container_width=True)
except Exception as e:
output = StringIO()
output.write("="*40 + "\n\n")
predicted_idx = np.argmax(probabilities)
output.write("\nInput Features:\n")
output.write("Class Probabilities:\n")
output.write(f"{cls.split('-')[-1].capitalize()}: {prob*100:.1f}%\n")
return output.getvalue()
try:
probabilities = model.predict(input_data)[0]
predicted_class_idx = np.argmax(probabilities)
predicted_class = label_encoder.inverse_transform([predicted_class_idx])[0]
except Exception as e:
def main():
st.title("FloraSpec AI")
st.markdown(
unsafe_allow_html=True
st.session_state.predict_clicked = False
st.session_state.prediction_data = None
with st.container():
# Input sliders
sepal_length = st.slider(
min_value=4.0,
max_value=8.0,
value=5.1,
step=0.1
sepal_width = st.slider(
min_value=2.0,
max_value=4.5,
value=3.5,
step=0.1
petal_length = st.slider(
min_value=1.0,
max_value=7.0,
value=1.4,
step=0.1
petal_width = st.slider(
min_value=0.1,
max_value=2.5,
value=0.2,
step=0.1
# Model selection
model_choice = st.selectbox(
"Model Selection",
options=list(models.keys()),
st.session_state.predict_clicked = True
try:
scaled_input = scaler.transform(input_data)
model = models[model_choice]
else:
prediction = model.predict(scaled_input)
predicted_class = label_encoder.inverse_transform(prediction.reshape(-1))[0]
st.session_state.prediction_data = {
'input_data': input_data,
'scaled_input': scaled_input,
'model_choice': model_choice,
'predicted_class': predicted_class,
'probabilities': probabilities,
'predicted_idx': predicted_idx
except Exception as e:
st.session_state.predict_clicked = False
st.markdown("</div>", unsafe_allow_html=True)
with col2:
prediction_data = st.session_state.prediction_data
display_class = prediction_data['predicted_class'].split('-')[-1].capitalize()
with st.container():
# Prediction Header
st.markdown(f"""
<div>
</div>
</div>
</div>
""", unsafe_allow_html=True)
render_confidence_scores(prediction_data["probabilities"],
prediction_data["predicted_idx"])
render_3d_flower(display_class)
st.download_button(
data=get_prediction_download(
display_class,
prediction_data["probabilities"],
prediction_data["model_choice"],
prediction_data["input_data"]
),
file_name=f"floraspec_prediction_{display_class.lower()}.txt",
mime="text/plain",
use_container_width=True
st.markdown("</div>", unsafe_allow_html=True)
with st.container():
render_feature_importance(models[prediction_data["model_choice"]],
prediction_data["model_choice"])
with tab2:
render_confusion_matrix(prediction_data["model_choice"])
st.markdown("</div>", unsafe_allow_html=True)
with st.container():
render_performance(evaluation_metrics)
tabs = st.tabs(list(models.keys()))
with tabs[i]:
render_confusion_matrix(model_name)
st.markdown("</div>", unsafe_allow_html=True)
if __name__ == "__main__":
main()