Spaces:
Sleeping
Sleeping
File size: 5,912 Bytes
7c50e6c 9d2a066 c752748 9d2a066 7c50e6c 9d2a066 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
import streamlit as st
import pandas as pd
import numpy as np
import smtplib
import re
import os
from dotenv import load_dotenv # <--- Import this
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
# --- Configuration ---
load_dotenv() # <--- This loads the variables from .env
# Now we read the secrets using os.getenv
SENDER_EMAIL = os.getenv("SENDER_EMAIL")
SENDER_PASSWORD = os.getenv("SENDER_PASSWORD")
if not SENDER_EMAIL or not SENDER_PASSWORD:
st.error("Error: Email credentials not found. Please check your .env file.")
st.stop()
# --- Helper Functions ---
def validate_email(email):
pattern = r'^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$'
return re.match(pattern, email)
def send_email(receiver_email, result_df, filename="result.csv"):
try:
msg = MIMEMultipart()
msg['From'] = SENDER_EMAIL
msg['To'] = receiver_email
msg['Subject'] = "Your TOPSIS Result is Ready"
body = "Hello,\n\nPlease find the attached result file for your TOPSIS calculation.\n\nBest,\nTOPSIS Web Service"
msg.attach(MIMEText(body, 'plain'))
# Convert DataFrame to CSV string
csv_data = result_df.to_csv(index=False)
# Attachment
part = MIMEBase('application', 'octet-stream')
part.set_payload(csv_data)
encoders.encode_base64(part)
part.add_header('Content-Disposition', f"attachment; filename= {filename}")
msg.attach(part)
# SMTP Server Setup (For Gmail) - USING SSL PORT 465
# Note: SMTP_SSL does not need server.starttls()
server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
server.login(SENDER_EMAIL, SENDER_PASSWORD)
text = msg.as_string()
server.sendmail(SENDER_EMAIL, receiver_email, text)
server.quit()
return True, "Email sent successfully!"
except Exception as e:
return False, str(e)
def calculate_topsis(df, weights, impacts):
# This logic is adapted from your CLI package
try:
# Preprocessing: Drop first column (Object Names) and convert to float
data = df.iloc[:, 1:].values.astype(float)
# Normalization
rss = np.sqrt(np.sum(data**2, axis=0))
normalized_data = data / rss
# Weighting
weighted_data = normalized_data * weights
# Ideal Best and Worst
ideal_best = []
ideal_worst = []
for i in range(len(impacts)):
if impacts[i] == '+':
ideal_best.append(np.max(weighted_data[:, i]))
ideal_worst.append(np.min(weighted_data[:, i]))
else:
ideal_best.append(np.min(weighted_data[:, i]))
ideal_worst.append(np.max(weighted_data[:, i]))
# Euclidean Distance
s_best = np.sqrt(np.sum((weighted_data - ideal_best)**2, axis=1))
s_worst = np.sqrt(np.sum((weighted_data - ideal_worst)**2, axis=1))
# Topsis Score
topsis_score = s_worst / (s_best + s_worst)
# Add to DF
df['Topsis Score'] = topsis_score
df['Rank'] = df['Topsis Score'].rank(ascending=False).astype(int)
return df
except Exception as e:
st.error(f"Error in calculation: {e}")
return None
# --- Main App UI ---
st.title("Topsis Web Service")
st.write("Upload your data, define weights/impacts, and get results via email.")
# 1. Inputs
email_id = st.text_input("Email ID (to receive results)", placeholder="name@example.com")
uploaded_file = st.file_uploader("Upload Input File (CSV)", type=["csv"])
weights_input = st.text_input("Weights (comma-separated)", placeholder="1,1,1,2")
impacts_input = st.text_input("Impacts (comma-separated, + or -)", placeholder="+,+,-,+")
# 2. Submit Button
if st.button("Submit"):
# --- Validations ---
if not uploaded_file:
st.error("Please upload a CSV file.")
elif not email_id or not validate_email(email_id):
st.error("Please enter a valid email address.")
elif not weights_input:
st.error("Please enter weights.")
elif not impacts_input:
st.error("Please enter impacts.")
else:
# Process Inputs
try:
df = pd.read_csv(uploaded_file)
# Parse Weights
weights = [float(w) for w in weights_input.split(',')]
# Parse Impacts
impacts = impacts_input.split(',')
# Validation: Column Count
num_cols = df.shape[1] - 1 # Exclude first column
if len(weights) != num_cols or len(impacts) != num_cols:
st.error(f"Count Mismatch! Input file has {num_cols} numerical columns, but you provided {len(weights)} weights and {len(impacts)} impacts.")
elif not all(i in ['+', '-'] for i in impacts):
st.error("Impacts must be either '+' or '-'.")
else:
# --- Run Logic ---
st.info("Calculating TOPSIS Score...")
result_df = calculate_topsis(df, weights, impacts)
if result_df is not None:
# --- Send Email ---
st.info(f"Sending result to {email_id}...")
success, message = send_email(email_id, result_df)
if success:
st.success("Success! Result file has been sent to your email.")
st.dataframe(result_df) # Show preview
else:
st.error(f"Failed to send email: {message}")
except ValueError:
st.error("Weights must be numeric values separated by commas.")
except Exception as e:
st.error(f"An unexpected error occurred: {e}") |