From c6f73cafdf5c5944d89c447c11eec5c39049ac97 Mon Sep 17 00:00:00 2001 From: tedoaba Date: Sat, 26 Oct 2024 11:09:43 +0300 Subject: [PATCH] model for deep learning and tailwind css modified --- .gitignore | 2 + Dockerfile | 43 ++---- app/__init__.py | 4 +- app/dashboard.py | 4 +- app/data.py | 73 +-------- app/model.xgb | Bin 183426 -> 0 bytes app/models.py | 2 +- app/predict.py | 36 ----- app/schema.sql | 44 ++++-- app/static/css/main.css | 110 ++++++++----- app/templates/_footer.html | 2 +- app/templates/_navigation.html | 44 +++--- app/templates/base.html | 3 +- app/xgb_model.py | 126 ++++++++++++--- dashboard/app.py | 43 ------ dashboard/dash_app.py | 73 --------- dashboard/requirements.txt | 4 - docker-compose.yml | 27 ++-- models/xgb_model.pkl | Bin 0 -> 393614 bytes notebooks/kaim2-week-8-9-task-3.ipynb | 2 +- package-lock.json | 215 ++++++++++++++++++++++++++ package.json | 6 + requirements.txt | 1 + 23 files changed, 479 insertions(+), 385 deletions(-) delete mode 100644 app/model.xgb delete mode 100644 app/predict.py delete mode 100644 dashboard/app.py delete mode 100644 dashboard/dash_app.py delete mode 100644 dashboard/requirements.txt create mode 100644 models/xgb_model.pkl create mode 100644 package-lock.json create mode 100644 package.json diff --git a/.gitignore b/.gitignore index 2b2e393..8597d3a 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,8 @@ mlruns mlartifacts/ mlruns/ +node_modules/ + # Distribution / packaging .Python diff --git a/Dockerfile b/Dockerfile index 76625ad..50d7b1e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,43 +1,24 @@ -# Use official Python image as the base image +# Use the official Python image as a base image FROM python:3.10 -# Set environment variables -ENV PYTHONDONTWRITEBYTECODE 1 -ENV PYTHONUNBUFFERED 1 -ENV FLASK_APP=app - -# Copy and install system dependencies -RUN apt-get update && apt-get install -y \ - build-essential \ - libpq-dev \ - curl \ - && rm -rf /var/lib/apt/lists/* - -# Install Node.js and npm for TailwindCSS -RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - && \ - apt-get install -y nodejs && \ - apt-get clean && rm -rf /var/lib/apt/lists/* - -# Set the working directory +# Set the working directory in the container WORKDIR /app -# Copy project dependencies first to improve caching +# Copy the requirements file into the container COPY requirements.txt . -RUN pip install --no-cache-dir --upgrade pip && \ - pip install --no-cache-dir -r requirements.txt -# Copy Node dependencies and install them -COPY app/package.json . -RUN npm install +# Install the dependencies +RUN pip install --no-cache-dir -r requirements.txt -# Copy the rest of the project files -COPY app/. . +# Copy the entire application into the container +COPY . . -# Build CSS with Tailwind -RUN npm run create-css +# Set environment variables +ENV FLASK_APP=app +ENV FLASK_ENV=development -# Expose port 5000 for the Flask app +# Expose the port the app runs on EXPOSE 5000 -# Run the Flask app +# Command to run the application CMD ["flask", "run", "--host=0.0.0.0"] diff --git a/app/__init__.py b/app/__init__.py index de0472e..c703a71 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -2,7 +2,7 @@ from dotenv import load_dotenv from flask import Flask -from app import pages, transactions, data, predict +from app import pages, transactions, data, xgb_model from app.models import db from app.database import init_db_command from app.dashboard import ( @@ -35,7 +35,7 @@ def create_app(): app.register_blueprint(pages.bp) app.register_blueprint(transactions.bp) app.register_blueprint(data.bp) - app.register_blueprint(predict.bp) + app.register_blueprint(xgb_model.bp) # Initialize Dash apps and pass the `db` object for querying the database create_summary_dash_app(app, db) diff --git a/app/dashboard.py b/app/dashboard.py index f399765..0f5420b 100644 --- a/app/dashboard.py +++ b/app/dashboard.py @@ -1,7 +1,7 @@ import pandas as pd import plotly.express as px from dash import Dash, dcc, html, Input, Output -from sqlalchemy import create_engine, func +from sqlalchemy import func from app.models import Features def create_summary_dash_app(flask_app, db): @@ -101,7 +101,7 @@ def update_device_browser_analysis(_): ) device_browser_df = pd.DataFrame(device_browser_data, columns=['device_id', 'browser', 'fraud_cases']) - fig = px.bar(device_browser_df, x='device_id', y='fraud_cases', color='browser', title='Fraud by Device and Browser') + fig = px.bar(device_browser_df, x='fraud_cases', y='device_id', color='browser', title='Fraud by Device and Browser') return fig return dash_app diff --git a/app/data.py b/app/data.py index 5741ea4..5834462 100644 --- a/app/data.py +++ b/app/data.py @@ -3,31 +3,13 @@ import pandas as pd import matplotlib.pyplot as plt from dotenv import load_dotenv -from flask import Blueprint, render_template, jsonify +from flask import Blueprint, render_template from sqlalchemy import create_engine -from sklearn.model_selection import train_test_split -from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix -from sklearn.preprocessing import LabelEncoder -from imblearn.over_sampling import SMOTE -from xgboost import XGBClassifier -from sklearn import preprocessing -import mlflow -from mlflow import pyfunc -import xgboost as xgb -from dash import Dash, dcc, html, Input, Output -from flask import Blueprint -from dash import Dash -import dash_core_components as dcc -import dash_html_components as html load_dotenv() bp = Blueprint("data", __name__) -# Load the model -model = xgb.Booster() -model = model.load_model("model.xgb") - @bp.route("/data") def data(): # Retrieve database URL from environment variables @@ -59,56 +41,3 @@ def data(): features = df.to_dict(orient='records') return render_template('data/data.html', features=features) - -@bp.route('/result') -def result(): - database_url = os.getenv('DATABASE_URL') - if not database_url: - raise RuntimeError("DATABASE_URL environment variable not set.") - - engine = create_engine(database_url) - - # Fetch data from database - data = pd.read_sql("SELECT * FROM transactions ORDER BY ctid DESC LIMIT 1", engine) - - ID = data['user_id'] - - df = data - - # Initialize a LabelEncoder object - label_encoder = LabelEncoder() - - # Iterate through each column in the dataframe - for column in df.columns: - # Check if the column datatype is not numeric - if df[column].dtype not in ['int64', 'float64']: - # Fit label encoder and transform values - df[column] = label_encoder.fit_transform(df[column]) - - # Get the numeric columns - numeric_columns = df.select_dtypes(include=['number']).columns - - # Create the StandardScaler - transform = preprocessing.StandardScaler() - - # Fit the scaler on the data (calculate mean and standard deviation) - transform.fit(df[numeric_columns]) - - # Transform the data using the fitted transform and reassign it to X - df[numeric_columns] = transform.transform(df[numeric_columns]) - - df = xgb.DMatrix(df) - - prediction = None - - if model is None: - print("Model is not loaded. Please check the loading process.") - else: - prediction = model.predict(df) - - - # Make prediction - #prediction = model.predict(df) - print("Prediction: ", prediction) - - return render_template('data/result.html', prediction=prediction, ID=ID) diff --git a/app/model.xgb b/app/model.xgb deleted file mode 100644 index cb1d13e40b881538cc44e04c916b4c3d92883a19..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 183426 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 z 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 Bycqxh diff --git a/app/models.py b/app/models.py index 7530800..8de6ad7 100644 --- a/app/models.py +++ b/app/models.py @@ -33,7 +33,7 @@ class Features(db.Model): sex = db.Column(db.String) age = db.Column(db.Integer) ip_address = db.Column(db.String) - class_ = db.Column('class', db.Integer) # Fraud class: 0 = non-fraud, 1 = fraud + class_ = db.Column('class', db.Integer) lower_bound_ip_address = db.Column(db.BigInteger) upper_bound_ip_address = db.Column(db.BigInteger) country = db.Column(db.String) diff --git a/app/predict.py b/app/predict.py deleted file mode 100644 index 80bcf85..0000000 --- a/app/predict.py +++ /dev/null @@ -1,36 +0,0 @@ -from flask import Blueprint, render_template, send_file, request, jsonify -import matplotlib.pyplot as plt -from app.models import db, Transaction -import io -import pandas as pd -import pickle - -from datetime import datetime, timezone -import pickle -from sklearn.preprocessing import LabelEncoder -import pandas as pd - - -bp = Blueprint("predict", __name__) - - -@bp.route('/plot.png') -def plot_png(): - fig = create_figure() - output = io.BytesIO() - fig.savefig(output, format='png') - output.seek(0) - return send_file(output, mimetype='image/png') - -def create_figure(): - # Sample data - categories = ['TransactionID', 'Category', 'Amount', 'AnomalyScore', 'Timestamp'] - values = [30, 30, 15, 10, 20] - - fig, ax = plt.subplots() - ax.bar(categories, values) - ax.set_xlabel('Features') - ax.set_ylabel('Importance (%)') - ax.set_title('Feature Importance Visualization') - - return fig diff --git a/app/schema.sql b/app/schema.sql index c753413..edfcbea 100644 --- a/app/schema.sql +++ b/app/schema.sql @@ -1,17 +1,35 @@ DROP TABLE IF EXISTS transactions; CREATE TABLE transactions ( - user_id INT PRIMARY KEY, -- user_id as the unique identifier - signup_time TIMESTAMP NOT NULL, -- Signup time as timestamp - purchase_time TIMESTAMP NOT NULL, -- Purchase time as timestamp - purchase_value FLOAT NOT NULL, -- Purchase value as a float - device_id VARCHAR NOT NULL, -- Device ID as a string - source VARCHAR NOT NULL, -- Source as a string (e.g., app, web) - browser VARCHAR NOT NULL, -- Browser as a string - sex VARCHAR NOT NULL, -- Sex as a string - age INT NOT NULL, -- Age as integer - ip_address FLOAT NOT NULL, -- IP address as a float - lower_bound_ip_address FLOAT NOT NULL, -- Lower bound of IP address - upper_bound_ip_address FLOAT NOT NULL, -- Upper bound of IP address - country VARCHAR NOT NULL -- Country as a string + user_id INT PRIMARY KEY, + signup_time TIMESTAMP NOT NULL, + purchase_time TIMESTAMP NOT NULL, + purchase_value FLOAT NOT NULL, + device_id VARCHAR NOT NULL, + source VARCHAR NOT NULL, + browser VARCHAR NOT NULL, + sex VARCHAR NOT NULL, + age INT NOT NULL, + ip_address FLOAT NOT NULL, + lower_bound_ip_address FLOAT NOT NULL, + upper_bound_ip_address FLOAT NOT NULL, + country VARCHAR NOT NULL + +DROP TABLE IF EXISTS features; + +CREATE TABLE features ( + user_id SERIAL PRIMARY KEY, + signup_time TIMESTAMP, + purchase_time TIMESTAMP, + purchase_value FLOAT, + device_id VARCHAR, + source VARCHAR, + browser VARCHAR, + sex VARCHAR, + age INTEGER, + ip_address VARCHAR, + class INTEGER, + lower_bound_ip_address BIGINT, + upper_bound_ip_address BIGINT, + country VARCHAR ); diff --git a/app/static/css/main.css b/app/static/css/main.css index a55d0b6..1354ed0 100644 --- a/app/static/css/main.css +++ b/app/static/css/main.css @@ -616,6 +616,11 @@ video { position: relative; } +.inset-x-0 { + left: 0px; + right: 0px; +} + .start-0 { inset-inline-start: 0px; } @@ -628,6 +633,14 @@ video { top: 0.75rem; } +.bottom-0 { + bottom: 0px; +} + +.end-0 { + inset-inline-end: 0px; +} + .-z-10 { z-index: -10; } @@ -636,6 +649,10 @@ video { z-index: 0; } +.z-10 { + z-index: 10; +} + .z-20 { z-index: 20; } @@ -670,6 +687,10 @@ video { margin-bottom: 1.5rem; } +.ms-3 { + margin-inline-start: 0.75rem; +} + .mt-4 { margin-top: 1rem; } @@ -702,36 +723,40 @@ video { height: 2.5rem; } +.h-2\.5 { + height: 0.625rem; +} + .h-5 { height: 1.25rem; } -.h-32 { - height: 8rem; +.h-full { + height: 100%; } -.h-8 { - height: 2rem; +.h-screen { + height: 100vh; } .w-10 { width: 2.5rem; } -.w-5 { - width: 1.25rem; +.w-2\.5 { + width: 0.625rem; } -.w-full { - width: 100%; +.w-44 { + width: 11rem; } -.w-32 { - width: 8rem; +.w-5 { + width: 1.25rem; } -.w-8 { - width: 2rem; +.w-full { + width: 100%; } .min-w-full { @@ -815,6 +840,11 @@ video { border-bottom-width: calc(1px * var(--tw-divide-y-reverse)); } +.divide-gray-100 > :not([hidden]) ~ :not([hidden]) { + --tw-divide-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-divide-opacity)); +} + .divide-gray-200 > :not([hidden]) ~ :not([hidden]) { --tw-divide-opacity: 1; border-color: rgb(229 231 235 / var(--tw-divide-opacity)); @@ -825,10 +855,6 @@ video { border-color: rgb(55 65 81 / var(--tw-divide-opacity)); } -.self-center { - align-self: center; -} - .overflow-hidden { overflow: hidden; } @@ -837,10 +863,6 @@ video { overflow-x: auto; } -.whitespace-nowrap { - white-space: nowrap; -} - .rounded { border-radius: 0.25rem; } @@ -913,6 +935,11 @@ video { background-color: rgb(17 45 50 / var(--tw-bg-opacity)); } +.bg-dg-dark-grey { + --tw-bg-opacity: 1; + background-color: rgb(79 74 65 / var(--tw-bg-opacity)); +} + .bg-dg-light-blue { --tw-bg-opacity: 1; background-color: rgb(37 78 88 / var(--tw-bg-opacity)); @@ -937,11 +964,6 @@ video { background-color: rgb(255 255 255 / var(--tw-bg-opacity)); } -.bg-dg-dark-grey { - --tw-bg-opacity: 1; - background-color: rgb(79 74 65 / var(--tw-bg-opacity)); -} - .p-10 { padding: 2.5rem; } @@ -979,6 +1001,11 @@ video { padding-right: 12rem; } +.px-5 { + padding-left: 1.25rem; + padding-right: 1.25rem; +} + .py-2 { padding-top: 0.5rem; padding-bottom: 0.5rem; @@ -1028,11 +1055,6 @@ video { font-family: Montserrat, sans-serif; } -.text-2xl { - font-size: 1.5rem; - line-height: 2rem; -} - .text-4xl { font-size: 2.25rem; line-height: 2.5rem; @@ -1069,10 +1091,6 @@ video { font-weight: 400; } -.font-semibold { - font-weight: 600; -} - .leading-none { line-height: 1; } @@ -1081,9 +1099,9 @@ video { letter-spacing: -0.025em; } -.text-blue-400 { +.text-gray-100 { --tw-text-opacity: 1; - color: rgb(96 165 250 / var(--tw-text-opacity)); + color: rgb(243 244 246 / var(--tw-text-opacity)); } .text-gray-500 { @@ -1101,11 +1119,6 @@ video { color: rgb(255 255 255 / var(--tw-text-opacity)); } -.text-gray-100 { - --tw-text-opacity: 1; - color: rgb(243 244 246 / var(--tw-text-opacity)); -} - .shadow { --tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1); --tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color); @@ -1143,11 +1156,26 @@ video { background-color: rgb(29 78 216 / var(--tw-bg-opacity)); } +.hover\:bg-blue-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(30 64 175 / var(--tw-bg-opacity)); +} + +.hover\:bg-dg-light-blue:hover { + --tw-bg-opacity: 1; + background-color: rgb(37 78 88 / var(--tw-bg-opacity)); +} + .hover\:bg-gray-100:hover { --tw-bg-opacity: 1; background-color: rgb(243 244 246 / var(--tw-bg-opacity)); } +.hover\:bg-dg-dark-grey:hover { + --tw-bg-opacity: 1; + background-color: rgb(79 74 65 / var(--tw-bg-opacity)); +} + .hover\:underline:hover { text-decoration-line: underline; } diff --git a/app/templates/_footer.html b/app/templates/_footer.html index 51fb527..56ec08c 100644 --- a/app/templates/_footer.html +++ b/app/templates/_footer.html @@ -1,6 +1,6 @@ -