Como deixar o sistema abaixo ainda mais robusto, perfeito e extremamente facil de usar via web?

from flask import Flask, render_template, request, jsonify
import pandas as pd
import pickle
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import MinMaxScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestRegressor
from sklearn.metrics import mean_squared_error, r2_score
import instaloader
import os
import json
import random
import string
import sys
import time
import nltk  # For text processing (install if needed: pip install nltk)

app = Flask(__name__)

# --- Configuration ---

# User Agents (add more for better scraping)
useragents = [
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36",
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/118.0",
    # ... add more user agents 
]

# Instagram Credentials (replace with your actual credentials)
INSTAGRAM_USERNAME = "extensaodeciliosnatanyolivatto#"
INSTAGRAM_PASSWORD = "Cauad0812#"

# Model and Scaler Filenames
MODEL_FILENAME = "models/rf_model.pkl"
SCALER_FILENAME = "models/scaler.pkl"

# --- Initialize Instaloader ---
L = instaloader.Instaloader()
try:
    L.login(INSTAGRAM_USERNAME, INSTAGRAM_PASSWORD)  # Log in to your Instagram account
except instaloader.exceptions.ConnectionException as e:
    print(f"Error during Instagram login: {e}")
    sys.exit(1)  # Exit if login fails


# --- Load Pre-trained Model and Scaler (if available) ---
try:
    with open(MODEL_FILENAME, 'rb') as file:
        model = pickle.load(file)
    with open(SCALER_FILENAME, 'rb') as file:
        scaler = pickle.load(file)
    model_loaded = True
except FileNotFoundError:
    model_loaded = False
    print("Pre-trained model and scaler not found. You'll need to train the model first.")

# --- Data Collection Function ---
def collect_data(target_username):
    """Collects Instagram data for a given username."""
    try:
        profile = instaloader.Profile.from_username(L.context, target_username)
    except instaloader.exceptions.ProfileNotExistsException:
        return {"error": f"Profile '{target_username}' not found."}

    posts_data = []
    for post in profile.get_posts():
        post_data = {
            "shortcode": post.shortcode,
            "likes": post.likes,
            "comments": post.comments,
            "caption": post.caption,
            "hashtags": [tag.name for tag in post.hashtags],
            "timestamp": post.date_utc.timestamp(),
            "location": post.location,  # Collect location data
            "typename": post.typename,  # Collect post type (e.g., "GraphImage", "GraphVideo")
            # ... add other relevant post data
        }
        posts_data.append(post_data)

    profile_data = {
        "username": profile.username,
        "followers": profile.followers,
        "following": profile.followees,
        "bio": profile.biography,
        "website": profile.external_url,
        # ... add other relevant profile data
    }

    return {"profile": profile_data, "posts": posts_data}


# --- Data Preprocessing Function ---
def preprocess_data(data):
    """Preprocesses the collected Instagram data."""
    df = pd.DataFrame(data["posts"])

    # --- Feature Engineering ---
    df['likes_per_follower'] = df['likes'] / data["profile"]["followers"]
    df['comments_per_follower'] = df['comments'] / data["profile"]["followers"]
    df['engagement_rate'] = (df['likes'] + df['comments']) / data["profile"]["followers"]

    # --- Text Processing (Caption Length and Sentiment) ---
    nltk.download('vader_lexicon')  # Download VADER lexicon if not already downloaded
    from nltk.sentiment.vader import SentimentIntensityAnalyzer
    sia = SentimentIntensityAnalyzer()

    df['caption_length'] = df['caption'].apply(lambda x: len(str(x)) if x else 0) 
    df['caption_sentiment'] = df['caption'].apply(lambda x: sia.polarity_scores(str(x))['compound'] if x else 0)

    # --- Location Features (if location data is available) ---
    df['has_location'] = df['location'].notnull().astype(int)  

    # --- Post Type Features ---
    df = pd.get_dummies(df, columns=['typename'], prefix='post_type')  

    # --- One-Hot Encoding for Hashtags ---
    ohe = OneHotEncoder(handle_unknown='ignore')
    hashtag_features = ohe.fit_transform(df[['hashtags']]).toarray()
    hashtag_feature_names = ohe.get_feature_names_out(['hashtags'])
    hashtag_df = pd.DataFrame(hashtag_features, columns=hashtag_feature_names)
    df = pd.concat([df, hashtag_df], axis=1)

    # ... Add more preprocessing steps as needed (handling missing values, etc.)

    return df


# --- Model Training Function ---
def train_model(df):
    """Trains the RandomForestRegressor model."""
    # Select features and target variable
    features = [
        'likes', 'comments', 'caption_length', 'caption_sentiment', 'has_location', 
        # ... add other relevant features (including post type and hashtag dummies)
    ]
    target = 'engagement_rate'

    # Split the data
    X_train, X_test, y_train, y_test = train_test_split(df[features], df[target], test_size=0.2, random_state=42)

    # Scale numerical features
    numerical_features = ['likes', 'comments', 'caption_length']  # Add more if needed
    ct = ColumnTransformer([
            ('scaler', MinMaxScaler(), numerical_features)
        ], remainder='passthrough')

    X_train_scaled = ct.fit_transform(X_train)
    X_test_scaled = ct.transform(X_test)

    # Train the model
    model = RandomForestRegressor(n_estimators=100, random_state=42)
    model.fit(X_train_scaled, y_train)

    # Evaluate the model
    y_pred = model.predict(X_test_scaled)
    mse = mean_squared_error(y_test, y_pred)
    r2 = r2_score(y_test, y_pred)
    print(f"Mean Squared Error: {mse}")
    print(f"R-squared: {r2}")

    return model, ct  # Return the ColumnTransformer


# --- Prediction Function ---
def predict_engagement(model, ct, data):
    """Predicts engagement rate for new data using the trained model."""
    df = pd.DataFrame([data])  # Assuming 'data' is a dictionary of features
    scaled_data = ct.transform(df)  # Use the ColumnTransformer to transform the data
    prediction = model.predict(scaled_data)[0]
    return prediction


# --- Flask Routes ---

@app.route('/', methods=['GET', 'POST'])
def index():
    if request.method == 'POST':
        target_username = request.form['username']

        # Collect and preprocess data
        data = collect_data(target_username)

        if "error" in data:
            return render_template('index.html', error=data["error"])

        preprocessed_data = preprocess_data(data)

        if not model_loaded:
            # Train the model if it's not loaded
            model, ct = train_model(preprocessed_data)

            # Save the trained model and scaler
            with open(MODEL_FILENAME, 'wb') as file:
                pickle.dump(model, file)
            with open(SCALER_FILENAME, 'wb') as file:
                pickle.dump(ct, file)

            model_loaded = True  # Update the flag
        else:
            # Use the loaded model and scaler
            pass  # model and scaler are already loaded

        # Make prediction
        prediction = predict_engagement(model, ct, preprocessed_data.iloc[0].to_dict())

        return render_template('index.html', prediction=prediction, username=target_username)

    return render_template('index.html')

# ... (other routes for retraining, features, categories, etc.)


if __name__ == '__main__':
    app.run(debug=True)