Spaces:
Build error
Build error
| # -*- coding: utf-8 -*- | |
| """chem-sim.ipynb | |
| Automatically generated by Colab. | |
| Original file is located at | |
| https://colab.research.google.com/drive/1GgGC-fVnA0fSxU859NjSi_jH8yiWUKOu | |
| """ | |
| # !pip install tensorflow==2.15 | |
| """# Chem simulation using scipy""" | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| import pandas as pd | |
| from scipy.integrate import solve_ivp | |
| import random | |
| import tensorflow as tf | |
| """# Dataset | |
| $$ | |
| \displaystyle | |
| k = A \cdot e^{-\frac{E_a}{RT}} | |
| $$ | |
| k : Rate constant (what weβre solving for) | |
| A : Pre-exponential factor (frequency factor) | |
| Ea : Activation energy (J/mol) | |
| R : Gas constant 8.314 J/molΒ·K | |
| T : Temperature (in Kelvin) | |
| | temp: Kelvin | pH: 0β14 scale | Ea: in kJ/mol | A_factor: 1/s | | |
| ## Zero order | |
| """ | |
| def zero(t, y, k): | |
| A, B, C = y | |
| dA_dt = -k | |
| dB_dt = 0 | |
| dC_dt = k | |
| return [dA_dt, dB_dt, dC_dt] | |
| """## First Order""" | |
| def first(t, y, k): | |
| A, B, C = y | |
| dA_dt = -k * A | |
| dB_dt = 0 | |
| dC_dt = +k * A | |
| return [dA_dt, dB_dt, dC_dt] | |
| def decay_first(t, y, k): | |
| A, B, C = y | |
| dA_dt = -k * A | |
| dB_dt = 0 | |
| dC_dt = 0 | |
| return [dA_dt, dB_dt, dC_dt] | |
| def reversible_first(t, y, k, k_1): | |
| A, B, C = y | |
| dA_dt = -k * A + k_1 * C | |
| dB_dt = 0 | |
| dC_dt = k * A - k_1 * C | |
| return [dA_dt, dB_dt, dC_dt] | |
| """## Second Order""" | |
| def second1(t, y, k): | |
| A, B, C = y | |
| dA_dt = -k * A * B | |
| dB_dt = -k * A * B | |
| dC_dt = +k * A * B | |
| return [dA_dt, dB_dt, dC_dt] | |
| def second2(t, y, k): | |
| A, B, C = y | |
| dA_dt = -2 * k * A**2 | |
| dB_dt = 0 | |
| dC_dt = +k * A**2 | |
| return [dA_dt, dB_dt, dC_dt] | |
| def reversible_second1(t, y, k, k_1): | |
| A, B, C = y | |
| dA_dt = -k * A * B + k_1 * C | |
| dB_dt = -k * A * B + k_1 * C | |
| dC_dt = +k * A * B - k_1 * C | |
| return [dA_dt, dB_dt, dC_dt] | |
| def reversible_second2(t, y, k, k_1): | |
| A, B, C = y | |
| dA_dt = -2 * k * A**2 + 2 * k_1 * C | |
| dB_dt = 0 | |
| dC_dt = +k * A**2 - k_1 * C | |
| return [dA_dt, dB_dt, dC_dt] | |
| """## Third order""" | |
| def third1(t, y, k): | |
| A, B, C = y | |
| dA_dt = -3 * k * A**3 | |
| dB_dt = 0 | |
| dC_dt = +k * A**3 | |
| return [dA_dt, dB_dt, dC_dt] | |
| def third2(t, y, k): | |
| A, B, C = y | |
| dA_dt = -2 * k * A**2 * B | |
| dB_dt = -1 * k * A**2 * B | |
| dC_dt = +k * A**2 * B | |
| return [dA_dt, dB_dt, dC_dt] | |
| def reversible_third1(t, y, k, k_1): | |
| A, B, C = y | |
| dA_dt = -3 * k * A**3 + 3 * k_1 * C | |
| dB_dt = 0 | |
| dC_dt = +k * A**3 - k_1 * C | |
| return [dA_dt, dB_dt, dC_dt] | |
| def reversible_third2(t, y, k, k_1): | |
| A, B, C = y | |
| dA_dt = -2 * k * A**2 * B + 2 * k_1 * C | |
| dB_dt = -1 * k * A**2 * B + 1 * k_1 * C | |
| dC_dt = +k * A**2 * B - k_1 * C | |
| return [dA_dt, dB_dt, dC_dt] | |
| """## functions""" | |
| def compute_k(temp, Ea, A_factor): | |
| R = 8.314 | |
| Ea_J = Ea * 1000 # Convert Ea from kJ/mol to J/mol | |
| k = A_factor * np.exp(-Ea_J / (R * temp)) | |
| return k | |
| def ode1(A0, B0, C0, temp, Ea, A_factor): | |
| y0 = [A0, B0, C0] | |
| k = compute_k(temp, Ea, A_factor) | |
| k_1 = k * random.uniform(0.5, 0.9) | |
| t_span = (0, 8) # From time 0 to 10 seconds | |
| t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution | |
| num = random.randint(0, 11) # For choosing between first or decay if not reversible | |
| match num: | |
| case 0: | |
| func_name = zero | |
| is_reversible = 0 | |
| order = 'zero' | |
| case 1: | |
| func_name = first | |
| is_reversible = 0 | |
| order = 'first' | |
| case 2: | |
| func_name = decay_first | |
| is_reversible = 0 | |
| order = 'first' | |
| case 3: | |
| func_name = reversible_first | |
| is_reversible = 1 | |
| order = 'first' | |
| case 4: | |
| func_name = second1 | |
| is_reversible = 0 | |
| order = 'second' | |
| case 5: | |
| func_name = second2 | |
| is_reversible = 0 | |
| order = 'second' | |
| case 6: | |
| func_name = reversible_second1 | |
| is_reversible = 1 | |
| order = 'second' | |
| case 7: | |
| func_name = reversible_second2 | |
| is_reversible = 1 | |
| order = 'second' | |
| case 8: | |
| func_name = third1 | |
| is_reversible = 0 | |
| order = 'third' | |
| case 9: | |
| func_name = third2 | |
| is_reversible = 0 | |
| order = 'third' | |
| case 10: | |
| func_name = reversible_third1 | |
| is_reversible = 1 | |
| order = 'third' | |
| case 11: | |
| func_name = reversible_third2 | |
| is_reversible = 1 | |
| order = 'third' | |
| if is_reversible == 1: | |
| solution = solve_ivp( | |
| func_name, | |
| t_span, | |
| y0, | |
| args=(k, k_1), | |
| t_eval=t_eval | |
| ) | |
| elif is_reversible == 0: | |
| solution = solve_ivp( | |
| func_name, | |
| t_span, | |
| y0, | |
| args=(k,), | |
| t_eval=t_eval | |
| ) | |
| return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1, is_reversible, order | |
| """## dataframe""" | |
| results = [] | |
| counter = 0 | |
| while counter < 6000: | |
| counter += 1 | |
| A0 = round(random.uniform(1.0, 10.0), 2) | |
| B0 = round(random.uniform(0.0, 5.0), 2) | |
| C0 = round(random.uniform(0.0, 5.0), 2) | |
| temp = random.randint(270, 280) | |
| pH = round(random.uniform(1.0, 14.0), 2) | |
| Ea = random.randint(90, 100) | |
| A_factor = round(random.uniform(2e16, 5e17), 2) | |
| pressure = round(random.uniform(0.5, 5.0), 2) | |
| weight = round(random.uniform(20, 200), 1) | |
| structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown']) | |
| catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base']) | |
| time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor) | |
| row = { | |
| 'order' : order, | |
| 'temp': temp, | |
| 'pH': pH, | |
| 'Ea': Ea, | |
| 'A_factor': A_factor, | |
| 'pressure': pressure, | |
| 'log_pressure' : np.log(pressure), | |
| 'weight': weight, | |
| 'structure': structure, | |
| 'catalyst': catalyst, | |
| 'is_reversible': is_reversible, | |
| 'k' : k, | |
| 'k_1' : k_1, | |
| 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4], | |
| 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10], | |
| 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4], | |
| 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10], | |
| 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4], | |
| 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10] | |
| } | |
| results.append(row) | |
| df = pd.DataFrame(results) | |
| df_original = df.copy() | |
| # df | |
| """# Machine learning | |
| ## Data preparation | |
| - removing 'structure' and 'catalyst' from dataframe | |
| - mapping 0 to zero , 1 to first, 2 to second and 3 to third in order column | |
| - mapping structure and catalyst | |
| """ | |
| structure_map = {'Linear': 0, 'Ring': 1, 'Branched': 2, 'Unknown': 3} | |
| catalyst_map = {'None': 0, 'Enzyme': 1, 'Acid': 2, 'Base': 3} | |
| order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3} | |
| df['structure'] = df['structure'].map(structure_map) | |
| df['catalyst'] = df['catalyst'].map(catalyst_map) | |
| df['order'] = df['order'].map(order_map) | |
| # df | |
| """## Models | |
| ## DNN (Deep Neural Networks) | |
| - saving file as csv | |
| """ | |
| df_X = df_original.drop(['order'], axis=1) | |
| df_y = df_original['order'] | |
| train_df = df_X.copy() | |
| train_df['order'] = df_y | |
| train_df.to_csv('chem_data_train.csv', index=False) | |
| train_df.to_csv('chem_data_test.csv', index=False) | |
| """- DNNs""" | |
| csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1'] | |
| classes = ['First_Order','Second_Order','Third_Order'] | |
| train_path = './chem_data_train.csv' | |
| test_path = './chem_data_train.csv' | |
| train = pd.read_csv(train_path) | |
| test = pd.read_csv(test_path) | |
| # train.head() | |
| if 'order' in train.columns: | |
| train_y = train.pop('order') | |
| if 'order' in test.columns: | |
| test_y = test.pop('order') | |
| # Fill missing values in the 'catalyst' column | |
| train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none | |
| test['catalyst'] = test['catalyst'].fillna('None') | |
| # train.head() #the species column is now gone | |
| # Define categorical and numerical feature columns | |
| CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings | |
| NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', | |
| 'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', | |
| 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', | |
| 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10'] #columns that have numerical values | |
| feature_columns = [] | |
| for feature_name in CATEGORICAL_COLUMNS: | |
| vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english | |
| cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary) | |
| indicator_column = tf.feature_column.indicator_column(cat_column) #it creates binary coolumns that will be mapped in to feature columns and it will be steamlined to our DNN model | |
| feature_columns.append(indicator_column) | |
| for feature_name in NUMERIC_COLUMNS: | |
| feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32)) | |
| print(feature_columns) | |
| import logging | |
| tf.get_logger().setLevel(logging.INFO) | |
| #setting up input function | |
| def input_fn(features,labels,training=True,batch_size=500): | |
| #convert the inputs to a dataset | |
| dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object | |
| if training: | |
| dataset = dataset.shuffle(1000).repeat() | |
| return dataset.batch(batch_size) | |
| from sklearn.preprocessing import StandardScaler | |
| # Normalize the numerical features in the training data | |
| scaler = StandardScaler() | |
| train_normalized = train.copy() | |
| train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS]) | |
| test_normalized = test.copy() | |
| test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS]) | |
| from sklearn.preprocessing import LabelEncoder | |
| # Convert the 'order' labels to numerical values | |
| le = LabelEncoder() | |
| train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values | |
| classifier = tf.estimator.DNNClassifier( | |
| feature_columns=feature_columns, | |
| hidden_units=[50, 40], | |
| n_classes=4, # We have 4 classes: zero, first, second, third | |
| optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=0.001)) | |
| classifier.train( | |
| input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True), | |
| steps=600 | |
| ) | |
| test_y_encoded = le.fit_transform(test_y) #we used sckit label encoder to encode the values better than 1 2 3 4 5 blah blah | |
| classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False)) | |
| """- accuracy = 0.99983335 | |
| # Interactive/sliders | |
| - TODO: be able to change chemical-initial-conc, temp, ea, A_factor, pH, molecular-weight using sliders/input | |
| - best ml model predicts the order of the differential equation from that | |
| """ | |
| def predict_order(inputs): | |
| try: | |
| # Create a pandas DataFrame from the input dictionary | |
| input_df = pd.DataFrame(inputs, index=[0]) | |
| # Normalize the numerical features | |
| input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS]) | |
| # Make a prediction | |
| predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False)) | |
| # Get the predicted class and probability | |
| for pred_dict in predictions: | |
| class_id = pred_dict['class_ids'][0] | |
| probability = pred_dict['probabilities'][class_id] | |
| # Get the class name from the label encoder | |
| class_name = le.inverse_transform([class_id])[0] | |
| print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability)) | |
| return class_name | |
| except Exception as e: | |
| print(f"An error occurred: {e}") | |
| return None | |
| def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order): | |
| y0 = [A0, B0, C0] | |
| k = compute_k(temp, Ea, A_factor) | |
| k_1 = k * 0.7 | |
| t_span = (0, 8) | |
| t_eval = np.linspace(0, 8, 11) | |
| if order == 'zero': | |
| solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| elif is_reversible == 0 and order == 'first': | |
| solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| elif is_reversible == 1 and order == 'first': | |
| solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| elif is_reversible == 0 and order == 'second': | |
| solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| elif is_reversible == 1 and order == 'second': | |
| solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| elif is_reversible == 0 and order == 'third': | |
| solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| elif is_reversible == 1 and order == 'third': | |
| solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1 | |
| """## gradio""" | |
| # !pip install gradio | |
| import gradio as gr | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| def run_simulation_and_plot(temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0): | |
| #Data Preparation for Predictio | |
| # Simullatqae the reaction using ode1 to get concentrations over time for prediction features | |
| time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred, is_reversible_simulated, order_simulated = ode1(A0, B0, C0, temp, Ea, A_factor) | |
| # Create a dictionary with all the necessary inputs for the model | |
| inputs = { | |
| 'temp': temp, | |
| 'pH': pH, | |
| 'Ea': Ea, | |
| 'A_factor': A_factor, | |
| 'pressure': pressure, | |
| 'log_pressure': np.log(pressure), | |
| 'weight': 150, # Using a placeholder value as it's not a user input | |
| 'structure': structure, | |
| 'catalyst': catalyst, | |
| 'is_reversible': int(is_reversible), | |
| 'k': k_pred, # Use simulated k | |
| 'k_1': k_1_pred, # Use simulated k_1 | |
| 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4], | |
| 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10], | |
| 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4], | |
| 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10], | |
| 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4], | |
| 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10] | |
| } | |
| # --- 2. Prediction --- | |
| predicted_order = predict_order(inputs) | |
| # --- 3. Simulation with ode2 and Predicted Order --- | |
| # Use ode2 for the final simulation and plotting | |
| time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order) | |
| # --- 4. Plotting --- | |
| plt.figure() | |
| plt.plot(time_sim, A_sim, label='A') | |
| plt.plot(time_sim, B_sim, label='B') | |
| plt.plot(time_sim, C_sim, label='C') | |
| plt.xlabel('Time') | |
| plt.ylabel('Concentration') | |
| plt.title(f'Concentration vs. Time (Predicted Order: {predicted_order})') | |
| plt.legend() | |
| plt.grid(True) | |
| return predicted_order, plt | |
| # --- 5. Gradio Interface --- | |
| with gr.Blocks() as iface: | |
| gr.Markdown("# Chemical Reaction Order Prediction and Simulation") | |
| gr.Markdown("Use the sliders and options to see the predicted reaction order and a plot of the concentrations over time.") | |
| with gr.Row(): | |
| with gr.Column(): | |
| gr.Markdown("### Reaction Conditions") | |
| temp = gr.Slider(270, 280, value=277, label="Temperature (K)") | |
| Ea = gr.Slider(90, 100, value=93, label="Activation Energy (Ea, kJ/mol)") | |
| A_factor = gr.Slider(2e16, 5e17, value=4.2e17, label="Pre-exponential Factor (A_factor)") | |
| pH = gr.Slider(1.0, 14.0, value=6.5, label="pH") | |
| pressure = gr.Slider(0.5, 5.0, value=3.0, label="Pressure") | |
| is_reversible = gr.Checkbox(label="Is Reversible?") | |
| structure = gr.Dropdown(['Linear', 'Ring', 'Branched', 'Unknown'], label="Structure") | |
| catalyst = gr.Dropdown(['None', 'Enzyme', 'Acid', 'Base'], label="Catalyst") | |
| with gr.Column(): | |
| gr.Markdown("### Initial Concentrations") | |
| A0 = gr.Slider(0.0, 10.0, value=5.0, label="A0") | |
| B0 = gr.Slider(0.0, 10.0, value=2.0, label="B0") | |
| C0 = gr.Slider(0.0, 10.0, value=1.0, label="C0") | |
| with gr.Row(): | |
| predict_button = gr.Button("Predict and Plot") | |
| with gr.Row(): | |
| with gr.Column(): | |
| order_output = gr.Textbox(label="Predicted Order") | |
| with gr.Column(): | |
| plot_output = gr.Plot() | |
| predict_button.click( | |
| fn=run_simulation_and_plot, | |
| inputs=[temp, Ea, A_factor, pH, pressure, is_reversible, structure, catalyst, A0, B0, C0], | |
| outputs=[order_output, plot_output] | |
| ) | |
| iface.launch() | |
| """## Streamlit Stuff""" | |
| !pip install -q streamlit | |
| import streamlit as st | |
| import pandas as pd | |
| import numpy as np | |
| import matplotlib.pyplot as plt | |
| # Assuming the functions compute_k, ode1, ode2, predict_order, and the classifier, scaler, and le objects are already defined and available in the notebook's global scope from previous cells. | |
| st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title | |
| st.title("π§ͺ Chemical Reaction Order Prediction and Simulation β¨") | |
| st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. π") | |
| # Use columns for a better layout of inputs | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.header("βοΈ Reaction Conditions") | |
| temp = st.slider("Temperature (K) π‘οΈ", 270.0, 280.0, value=277.0) | |
| Ea = st.slider("Activation Energy (Ea, kJ/mol) π₯", 90.0, 100.0, value=93.0) | |
| A_factor = st.slider("Pre-exponential Factor (A_factor) π", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format | |
| pH = st.slider("pH π§ͺ", 1.0, 14.0, value=6.5) | |
| pressure = st.slider("Pressure π«οΈ", 0.5, 5.0, value=3.0) | |
| is_reversible = st.checkbox("Is Reversible? π", value=False) | |
| structure = st.selectbox("Structure βοΈ", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1) | |
| catalyst = st.selectbox("Catalyst β¨", ['None', 'Enzyme', 'Acid', 'Base'], index=2) | |
| with col2: | |
| st.header("π Initial Concentrations") | |
| A0 = st.slider("Initial Concentration of A (Aβ)", 0.0, 10.0, value=5.0) | |
| B0 = st.slider("Initial Concentration of B (Bβ)", 0.0, 10.0, value=2.0) | |
| C0 = st.slider("Initial Concentration of C (Cβ)", 0.0, 10.0, value=1.0) | |
| st.markdown("---") # Add a horizontal rule for separation | |
| if st.button("π Predict and Plot Reaction"): | |
| # Data Preparation for Prediction | |
| # Simulate the reaction using ode1 to get concentrations over time for prediction features | |
| time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred, is_reversible_simulated, order_simulated = ode1(A0, B0, C0, temp, Ea, A_factor) | |
| # Create a dictionary with all the necessary inputs for the model | |
| inputs = { | |
| 'temp': temp, | |
| 'pH': pH, | |
| 'Ea': Ea, | |
| 'A_factor': A_factor, | |
| 'pressure': pressure, | |
| 'log_pressure': np.log(pressure), | |
| 'weight': 150, # Using a placeholder value as it's not a user input | |
| 'structure': structure, | |
| 'catalyst': catalyst, | |
| 'is_reversible': int(is_reversible), | |
| 'k': k_pred, # Use simulated k | |
| 'k_1': k_1_pred, # Use simulated k_1 | |
| 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4], | |
| 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10], | |
| 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4], | |
| 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10], | |
| 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4], | |
| 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10] | |
| } | |
| # --- 2. Prediction --- | |
| with st.spinner('Predicting reaction order...'): | |
| predicted_order = predict_order(inputs) | |
| st.success(f"β Predicted Order: **{predicted_order}**") | |
| # --- 3. Simulation with ode2 and Predicted Order --- | |
| with st.spinner('Simulating reaction...'): | |
| time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order) | |
| # --- 4. Plotting --- | |
| st.header("π Concentration vs. Time Plot") | |
| fig, ax = plt.subplots() | |
| ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points | |
| ax.plot(time_sim, B_sim, label='B', marker='x') | |
| ax.plot(time_sim, C_sim, label='C', marker='s') | |
| ax.set_xlabel('Time') | |
| ax.set_ylabel('Concentration') | |
| ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})') | |
| ax.legend() | |
| ax.grid(True) | |
| st.pyplot(fig) | |
| st.markdown("---") | |
| st.markdown("App created with β€οΈ using Streamlit") | |
| """Main code for Steamlit pipeline | |
| first copy this code and then create a file named app.py and save it | |
| """ | |
| # import numpy as np | |
| # import matplotlib.pyplot as plt | |
| # import pandas as pd | |
| # from scipy.integrate import solve_ivp | |
| # import random | |
| # import tensorflow as tf | |
| # def compute_k(temp, Ea, A_factor): | |
| # R = 8.314 | |
| # Ea_J = Ea * 1000 # Convert Ea from kJ/mol to J/mol | |
| # k = A_factor * np.exp(-Ea_J / (R * temp)) | |
| # return k | |
| # def zero(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -k | |
| # dB_dt = 0 | |
| # dC_dt = k | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def first(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -k * A | |
| # dB_dt = 0 | |
| # dC_dt = +k * A | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def decay_first(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -k * A | |
| # dB_dt = 0 | |
| # dC_dt = 0 | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def reversible_first(t, y, k, k_1): | |
| # A, B, C = y | |
| # dA_dt = -k * A + k_1 * C | |
| # dB_dt = 0 | |
| # dC_dt = k * A - k_1 * C | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def second1(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -k * A * B | |
| # dB_dt = -k * A * B | |
| # dC_dt = +k * A * B | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def second2(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -2 * k * A**2 | |
| # dB_dt = 0 | |
| # dC_dt = +k * A**2 | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def reversible_second1(t, y, k, k_1): | |
| # A, B, C = y | |
| # dA_dt = -k * A * B + k_1 * C | |
| # dB_dt = -k * A * B + k_1 * C | |
| # dC_dt = +k * A * B - k_1 * C | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def reversible_second2(t, y, k, k_1): | |
| # A, B, C = y | |
| # dA_dt = -2 * k * A**2 + 2 * k_1 * C | |
| # dB_dt = 0 | |
| # dC_dt = +k * A**2 - k_1 * C | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def third1(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -3 * k * A**3 | |
| # dB_dt = 0 | |
| # dC_dt = +k * A**3 | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def third2(t, y, k): | |
| # A, B, C = y | |
| # dA_dt = -2 * k * A**2 * B | |
| # dB_dt = -1 * k * A**2 * B | |
| # dC_dt = +k * A**2 * B | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def reversible_third1(t, y, k, k_1): | |
| # A, B, C = y | |
| # dA_dt = -3 * k * A**3 + 3 * k_1 * C | |
| # dB_dt = 0 | |
| # dC_dt = +k * A**3 - k_1 * C | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def reversible_third2(t, y, k, k_1): | |
| # A, B, C = y | |
| # dA_dt = -2 * k * A**2 * B + 2 * k_1 * C | |
| # dB_dt = -1 * k * A**2 * B + 1 * k_1 * C | |
| # dC_dt = +k * A**2 * B - k_1 * C | |
| # return [dA_dt, dB_dt, dC_dt] | |
| # def ode1(A0, B0, C0, temp, Ea, A_factor): | |
| # y0 = [A0, B0, C0] | |
| # k = compute_k(temp, Ea, A_factor) | |
| # k_1 = k * random.uniform(0.5, 0.9) | |
| # t_span = (0, 8) # From time 0 to 10 seconds | |
| # t_eval = np.linspace(0, 8, 11) # 11 points where you want the solution | |
| # num = random.randint(0, 11) # For choosing between first or decay if not reversible | |
| # match num: | |
| # case 0: | |
| # func_name = zero | |
| # is_reversible = 0 | |
| # order = 'zero' | |
| # case 1: | |
| # func_name = first | |
| # is_reversible = 0 | |
| # order = 'first' | |
| # case 2: | |
| # func_name = decay_first | |
| # is_reversible = 0 | |
| # order = 'first' | |
| # case 3: | |
| # func_name = reversible_first | |
| # is_reversible = 1 | |
| # order = 'first' | |
| # case 4: | |
| # func_name = second1 | |
| # is_reversible = 0 | |
| # order = 'second' | |
| # case 5: | |
| # func_name = second2 | |
| # is_reversible = 0 | |
| # order = 'second' | |
| # case 6: | |
| # func_name = reversible_second1 | |
| # is_reversible = 1 | |
| # order = 'second' | |
| # case 7: | |
| # func_name = reversible_second2 | |
| # is_reversible = 1 | |
| # order = 'second' | |
| # case 8: | |
| # func_name = third1 | |
| # is_reversible = 0 | |
| # order = 'third' | |
| # case 9: | |
| # func_name = third2 | |
| # is_reversible = 0 | |
| # order = 'third' | |
| # case 10: | |
| # func_name = reversible_third1 | |
| # is_reversible = 1 | |
| # order = 'third' | |
| # case 11: | |
| # func_name = reversible_third2 | |
| # is_reversible = 1 | |
| # order = 'third' | |
| # if is_reversible == 1: | |
| # solution = solve_ivp( | |
| # func_name, | |
| # t_span, | |
| # y0, | |
| # args=(k, k_1), | |
| # t_eval=t_eval | |
| # ) | |
| # elif is_reversible == 0: | |
| # solution = solve_ivp( | |
| # func_name, | |
| # t_span, | |
| # y0, | |
| # args=(k,), | |
| # t_eval=t_eval | |
| # ) | |
| # return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1, is_reversible, order | |
| # results = [] | |
| # counter = 0 | |
| # while counter < 6000: | |
| # counter += 1 | |
| # A0 = round(random.uniform(1.0, 10.0), 2) | |
| # B0 = round(random.uniform(0.0, 5.0), 2) | |
| # C0 = round(random.uniform(0.0, 5.0), 2) | |
| # temp = random.randint(270, 280) | |
| # pH = round(random.uniform(1.0, 14.0), 2) | |
| # Ea = random.randint(90, 100) | |
| # A_factor = round(random.uniform(2e16, 5e17), 2) | |
| # pressure = round(random.uniform(0.5, 5.0), 2) | |
| # weight = round(random.uniform(20, 200), 1) | |
| # structure = random.choice(['Linear', 'Ring', 'Branched', 'Unknown']) | |
| # catalyst = random.choice(['None', 'Enzyme', 'Acid', 'Base']) | |
| # time, A, B, C, k, k_1, is_reversible, order = ode1(A0, B0, C0, temp, Ea, A_factor) | |
| # row = { | |
| # 'order' : order, | |
| # 'temp': temp, | |
| # 'pH': pH, | |
| # 'Ea': Ea, | |
| # 'A_factor': A_factor, | |
| # 'pressure': pressure, | |
| # 'log_pressure' : np.log(pressure), | |
| # 'weight': weight, | |
| # 'structure': structure, | |
| # 'catalyst': catalyst, | |
| # 'is_reversible': is_reversible, | |
| # 'k' : k, | |
| # 'k_1' : k_1, | |
| # 'A0': A[0], 'A1': A[1], 'A2': A[2], 'A3': A[3], 'A4': A[4], | |
| # 'A5': A[5], 'A6': A[6], 'A7': A[7], 'A8': A[8], 'A9': A[9], 'A10': A[10], | |
| # 'B0': B[0], 'B1': B[1], 'B2': B[2], 'B3': B[3], 'B4': B[4], | |
| # 'B5': B[5], 'B6': B[6], 'B7': B[7], 'B8': B[8], 'B9': B[9], 'B10': B[10], | |
| # 'C0': C[0], 'C1': C[1], 'C2': C[2], 'C3': C[3], 'C4': C[4], | |
| # 'C5': C[5], 'C6': C[6], 'C7': C[7], 'C8': C[8], 'C9': C[9], 'C10': C[10] | |
| # } | |
| # results.append(row) | |
| # df = pd.DataFrame(results) | |
| # df_original = df.copy() | |
| # # display(df) | |
| # structure_map = {'Linear': 0, 'Ring': 1, 'Branched': 2, 'Unknown': 3} | |
| # catalyst_map = {'None': 0, 'Enzyme': 1, 'Acid': 2, 'Base': 3} | |
| # order_map = {'zero': 0, 'first': 1, 'second': 2, 'third' : 3} | |
| # df['structure'] = df['structure'].map(structure_map) | |
| # df['catalyst'] = df['catalyst'].map(catalyst_map) | |
| # df['order'] = df['order'].map(order_map) | |
| # # display(df) | |
| # csv_columns = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', 'structure', 'catalyst', 'is_reversible', 'k', 'k_1'] | |
| # classes = ['First_Order','Second_Order','Third_Order'] | |
| # train_path = './chem_data_train.csv' | |
| # test_path = './chem_data_train.csv' | |
| # train = pd.read_csv(train_path) | |
| # test = pd.read_csv(test_path) | |
| # # display(train.head()) | |
| # if 'order' in train.columns: | |
| # train_y = train.pop('order') | |
| # if 'order' in test.columns: | |
| # test_y = test.pop('order') | |
| # # Fill missing values in the 'catalyst' column | |
| # train['catalyst'] = train['catalyst'].fillna('None') #NaN values arenot accepted by classifier thats why convert every Nan values to none | |
| # test['catalyst'] = test['catalyst'].fillna('None') | |
| # # display(train.head()) #the species column is now gone | |
| # # Define categorical and numerical feature columns | |
| # CATEGORICAL_COLUMNS = ['structure', 'catalyst'] #columns that have strings | |
| # NUMERIC_COLUMNS = ['temp', 'pH', 'Ea', 'A_factor', 'pressure', 'log_pressure', 'weight', | |
| # 'is_reversible', 'k', 'k_1', 'A0', 'A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7', 'A8', 'A9', 'A10', | |
| # 'B0', 'B1', 'B2', 'B3', 'B4', 'B5', 'B6', 'B7', 'B8', 'B9', 'B10', | |
| # 'C0', 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'C8', 'C9', 'C10'] #columns that have numerical values | |
| # feature_columns = [] | |
| # for feature_name in CATEGORICAL_COLUMNS: | |
| # vocabulary = train[feature_name].unique() #Assining each string a numerical uinque value because our dumb ahh model canot understand english | |
| # cat_column = tf.feature_column.categorical_column_with_vocabulary_list(feature_name, vocabulary) | |
| # indicator_column = tf.feature_column.indicator_column(cat_column) #it creates binary coolumns that will be mapped in to feature columns and it will be steamlined to our DNN model | |
| # feature_columns.append(indicator_column) | |
| # for feature_name in NUMERIC_COLUMNS: | |
| # feature_columns.append(tf.feature_column.numeric_column(feature_name, dtype=tf.float32)) | |
| # # print(feature_columns) | |
| # import logging | |
| # tf.get_logger().setLevel(logging.INFO) | |
| # #setting up input function | |
| # def input_fn(features,labels,training=True,batch_size=500): | |
| # #convert the inputs to a dataset | |
| # dataset = tf.data.Dataset.from_tensor_slices((dict(features), labels)) #this cnonverts the dataset into tensorflow object | |
| # if training: | |
| # dataset = dataset.shuffle(1000).repeat() | |
| # return dataset.batch(batch_size) | |
| # from sklearn.preprocessing import StandardScaler | |
| # # Normalize the numerical features in the training data | |
| # scaler = StandardScaler() | |
| # train_normalized = train.copy() | |
| # train_normalized[NUMERIC_COLUMNS] = scaler.fit_transform(train[NUMERIC_COLUMNS]) | |
| # test_normalized = test.copy() | |
| # test_normalized[NUMERIC_COLUMNS] = scaler.transform(test[NUMERIC_COLUMNS]) | |
| # from sklearn.preprocessing import LabelEncoder | |
| # # Convert the 'order' labels to numerical values | |
| # le = LabelEncoder() | |
| # train_y_encoded = le.fit_transform(train_y) #we used sckit label encoder to encode the values | |
| # classifier = tf.estimator.DNNClassifier( | |
| # feature_columns=feature_columns, | |
| # hidden_units=[50, 40], | |
| # n_classes=4, # We have 4 classes: zero, first, second, third | |
| # optimizer=tf.keras.optimizers.legacy.RMSprop(learning_rate=0.001)) | |
| # classifier.train( | |
| # input_fn=lambda: input_fn(train_normalized, train_y_encoded, training=True), | |
| # steps=300 | |
| # ) | |
| # test_y_encoded = le.fit_transform(test_y) #we used sckit label encoder to encode the values better than 1 2 3 4 5 blah blah | |
| # classifier.evaluate(input_fn=lambda: input_fn(test_normalized,test_y_encoded,training=False)) | |
| # def predict_order(inputs): | |
| # try: | |
| # # Create a pandas DataFrame from the input dictionary | |
| # input_df = pd.DataFrame(inputs, index=[0]) | |
| # # Normalize the numerical features | |
| # input_df[NUMERIC_COLUMNS] = scaler.transform(input_df[NUMERIC_COLUMNS]) | |
| # # Make a prediction | |
| # predictions = classifier.predict(input_fn=lambda: input_fn(input_df, labels=None, training=False)) | |
| # # Get the predicted class and probability | |
| # for pred_dict in predictions: | |
| # class_id = pred_dict['class_ids'][0] | |
| # probability = pred_dict['probabilities'][class_id] | |
| # # Get the class name from the label encoder | |
| # class_name = le.inverse_transform([class_id])[0] | |
| # print('Order is "{}" ({:.1f}%)'.format(class_name, 100 * probability)) | |
| # return class_name | |
| # except Exception as e: | |
| # print(f"An error occurred: {e}") | |
| # return None | |
| # def ode2(A0, B0, C0, temp, Ea, A_factor, is_reversible, order): | |
| # y0 = [A0, B0, C0] | |
| # k = compute_k(temp, Ea, A_factor) | |
| # k_1 = k * 0.7 | |
| # t_span = (0, 8) | |
| # t_eval = np.linspace(0, 8, 11) | |
| # if order == 'zero': | |
| # solution = solve_ivp(zero, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| # elif is_reversible == 0 and order == 'first': | |
| # solution = solve_ivp(first, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| # elif is_reversible == 1 and order == 'first': | |
| # solution = solve_ivp(reversible_first, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| # elif is_reversible == 0 and order == 'second': | |
| # solution = solve_ivp(second1, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| # elif is_reversible == 1 and order == 'second': | |
| # solution = solve_ivp(reversible_second1, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| # elif is_reversible == 0 and order == 'third': | |
| # solution = solve_ivp(third2, t_span, y0, args=(k,) ,t_eval=t_eval) | |
| # elif is_reversible == 1 and order == 'third': | |
| # solution = solve_ivp(reversible_third2, t_span, y0, args=(k, k_1) ,t_eval=t_eval) | |
| # return solution.t, solution.y[0], solution.y[1], solution.y[2], k, k_1 | |
| # import streamlit as st | |
| # import pandas as pd | |
| # import numpy as np | |
| # import matplotlib.pyplot as plt | |
| # # Assuming the functions compute_k, ode1, ode2, predict_order, and the classifier, scaler, and le objects are already defined and available in the notebook's global scope from previous cells. | |
| # st.set_page_config(layout="wide", page_title="Chemical Reaction Simulator") # Set page layout to wide and add a page title | |
| # st.title("π§ͺ Project E-11") | |
| # st.markdown("π§ͺ Chemical Reaction Order Prediction and Simulation β¨") | |
| # st.markdown("Adjust the parameters below to predict the reaction order and visualize the concentration changes over time. π") | |
| # # Use columns for a better layout of inputs | |
| # col1, col2 = st.columns(2) | |
| # with col1: | |
| # st.header("βοΈ Reaction Conditions") | |
| # temp = st.slider("Temperature (K) π‘οΈ", 270.0, 280.0, value=277.0) | |
| # Ea = st.slider("Activation Energy (Ea, kJ/mol) π₯", 90.0, 100.0, value=93.0) | |
| # A_factor = st.slider("Pre-exponential Factor (A_factor) π", 2e16, 5e17, value=4.2e17, format="%e") # Use scientific notation format | |
| # pH = st.slider("pH π§ͺ", 1.0, 14.0, value=6.5) | |
| # pressure = st.slider("Pressure π«οΈ", 0.5, 5.0, value=3.0) | |
| # is_reversible = st.checkbox("Is Reversible? π", value=False) | |
| # structure = st.selectbox("Structure βοΈ", ['Linear', 'Ring', 'Branched', 'Unknown'], index=1) | |
| # catalyst = st.selectbox("Catalyst β¨", ['None', 'Enzyme', 'Acid', 'Base'], index=2) | |
| # with col2: | |
| # st.header("π Initial Concentrations") | |
| # A0 = st.slider("Initial Concentration of A (Aβ)", 0.0, 10.0, value=5.0) | |
| # B0 = st.slider("Initial Concentration of B (Bβ)", 0.0, 10.0, value=2.0) | |
| # C0 = st.slider("Initial Concentration of C (Cβ)", 0.0, 10.0, value=1.0) | |
| # st.markdown("---") # Add a horizontal rule for separation | |
| # if st.button("π Predict and Plot Reaction"): | |
| # # Data Preparation for Prediction | |
| # # Simulate the reaction using ode1 to get concentrations over time for prediction features | |
| # time_pred, A_pred, B_pred, C_pred, k_pred, k_1_pred, is_reversible_simulated, order_simulated = ode1(A0, B0, C0, temp, Ea, A_factor) | |
| # # Create a dictionary with all the necessary inputs for the model | |
| # inputs = { | |
| # 'temp': temp, | |
| # 'pH': pH, | |
| # 'Ea': Ea, | |
| # 'A_factor': A_factor, | |
| # 'pressure': pressure, | |
| # 'log_pressure': np.log(pressure), | |
| # 'weight': 150, # Using a placeholder value as it's not a user input | |
| # 'structure': structure, | |
| # 'catalyst': catalyst, | |
| # 'is_reversible': int(is_reversible), | |
| # 'k': k_pred, # Use simulated k | |
| # 'k_1': k_1_pred, # Use simulated k_1 | |
| # 'A0': A_pred[0], 'A1': A_pred[1], 'A2': A_pred[2], 'A3': A_pred[3], 'A4': A_pred[4], | |
| # 'A5': A_pred[5], 'A6': A_pred[6], 'A7': A_pred[7], 'A8': A_pred[8], 'A9': A_pred[9], 'A10': A_pred[10], | |
| # 'B0': B_pred[0], 'B1': B_pred[1], 'B2': B_pred[2], 'B3': B_pred[3], 'B4': B_pred[4], | |
| # 'B5': B_pred[5], 'B6': B_pred[6], 'B7': B_pred[7], 'B8': B_pred[8], 'B9': B_pred[9], 'B10': B_pred[10], | |
| # 'C0': C_pred[0], 'C1': C_pred[1], 'C2': C_pred[2], 'C3': C_pred[3], 'C4': C_pred[4], | |
| # 'C5': C_pred[5], 'C6': C_pred[6], 'C7': C_pred[7], 'C8': C_pred[8], 'C9': C_pred[9], 'C10': C_pred[10] | |
| # } | |
| # # --- 2. Prediction --- | |
| # with st.spinner('Predicting reaction order...'): | |
| # predicted_order = predict_order(inputs) | |
| # st.success(f"β Predicted Order: **{predicted_order}**") | |
| # # --- 3. Simulation with ode2 and Predicted Order --- | |
| # with st.spinner('Simulating reaction...'): | |
| # time_sim, A_sim, B_sim, C_sim, k_sim, k_1_sim = ode2(A0, B0, C0, temp, Ea, A_factor, int(is_reversible), predicted_order) | |
| # # --- 4. Plotting --- | |
| # st.header("π Concentration vs. Time Plot") | |
| # fig, ax = plt.subplots() | |
| # ax.plot(time_sim, A_sim, label='A', marker='o') # Add markers to plot points | |
| # ax.plot(time_sim, B_sim, label='B', marker='x') | |
| # ax.plot(time_sim, C_sim, label='C', marker='s') | |
| # ax.set_xlabel('Time') | |
| # ax.set_ylabel('Concentration') | |
| # ax.set_title(f'Concentration vs. Time (Predicted Order: {predicted_order})') | |
| # ax.legend() | |
| # ax.grid(True) | |
| # st.pyplot(fig) | |
| # st.markdown("---") | |
| # st.markdown("App created with β€οΈ by Mujtaba , Muzammil , Taha and Ali Zain.") | |
| # !streamlit run /content/app.py &>/content/logs.txt & #this starts the loca server | |
| # !npx localtunnel --port 8501 #the tunnel | |
| # get_ipython().run_line_magic('shell', 'curl https://loca.lt/mytunnelpassword') #getting ur home ip adress :cold: | |
| # %%writefile requirements.txt | |
| # gradio | |
| # pandas | |
| # numpy | |
| # matplotlib | |
| # scipy | |
| # tensorflow==2.15 | |
| # scikit-learn |