diff --git a/api/DataProcesser.py b/api/DataProcesser.py index 7c82fff2..646f5d5c 100644 --- a/api/DataProcesser.py +++ b/api/DataProcesser.py @@ -21,6 +21,17 @@ def handle_classify(self, df, classifier): return classifier_switcher.get(classifier, lambda: "Invalid Classifier")(df) + def generate_statistics(self, df): + unique_labels = df['output_column'].unique() + + statistics = { + 'total_rows': len(df), + 'unique_labels': list(unique_labels), + 'label_counts': df['output_column'].value_counts().to_dict() + } + + return statistics + def preprocess_text(self, texto): if self.input_column is not None: # Verifique se a coluna foi definida # tiro tudo que não for texto e espaço @@ -36,23 +47,15 @@ def preprocess_text(self, texto): return "Coluna não escolhida. Escolha a coluna primeiro." def classify_emotions(self, df): - df['output_column'] = df['input_column'].apply( - self.preprocess_text).apply(make_prediction) - - result_csv = df # converte o df pra csv - return result_csv + df['output_column'] = df['input_column'].apply(make_prediction) + return df def lin_regression_model(self, df): - df['output_column'] = df['input_column'].apply( - self.preprocess_text).apply(make_prediction_nblin) - - result_csv = df # converte o df pra csv - return result_csv + df['output_column'] = df['input_column'].apply(make_prediction_nblin) + return df def nb_news_application(self, df): df['output_column'] = df['input_column'].apply(news_prediction) - - result_csv = df - return result_csv + return df ##TODO métodos com o processamento de classificação diff --git a/api/NbEmotionsModel.py b/api/NbEmotionsModel.py index 40c744f6..07c68c3d 100644 --- a/api/NbEmotionsModel.py +++ b/api/NbEmotionsModel.py @@ -15,4 +15,4 @@ def make_prediction(my_sentence): new_sentence = tfidf_vectorizer.transform([my_sentence]) prediction = model.predict(new_sentence) - return prediction \ No newline at end of file + return prediction[0] \ No newline at end of file diff --git a/api/app.py b/api/app.py index 2006869d..11ffcb86 100644 --- a/api/app.py +++ b/api/app.py @@ -1,22 +1,31 @@ from flask import Flask, jsonify, request from flask_cors import CORS from DataProcesser import DataProcesser +from available_classifiers import get_available_classifiers import os +import atexit +import threading import pandas as pd import nltk import json nltk.download('wordnet') app = Flask(__name__) +server_thread = None CORS(app) # Permite todas as origens por padrão (não recomendado para produção) -UPLOAD_FOLDER = './uploads' -app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER app.config['JSONIFY_PRETTYPRINT_REGULAR'] = True data_processer = DataProcesser() +def run_flask_app(): + global server_thread + app.run(host='0.0.0.0', port=5000, debug=True, use_reloader=False) + +def shutdown_server(): + print("Server shutting down...") + os.kill(os.getpid(), 9) @app.route('/', methods=['GET']) def hello_world(): @@ -29,29 +38,23 @@ def upload_file(): selected_data = received_data.get('data') selected_classifier = int(received_data.get('classifier')) - #print("selected data: ", selected_data) - #print("selected classifier: ", selected_classifier) - df = pd.DataFrame(selected_data, columns=['input_column']) result = data_processer.handle_classify(df, selected_classifier) + stats = data_processer.generate_statistics(result) - return jsonify({'result': result.to_json()}) - -@app.route('/nb-news-model', methods=["POST"]) -def news_model(): - result = data_processer.nb_news_application() - result_json = result.to_json() - return jsonify({"result": result_json}) + return jsonify({'result': result.to_json(), 'stats': stats}) -@app.route('/nb-emotions-model', methods=["POST"]) -def emotions_model(): - result = data_processer.classify_emotions() - return jsonify({"result": result.to_json()}) +@app.route('/get-classifiers', methods=["GET"]) +def get_classifiers(): + classifiers = get_available_classifiers() + return jsonify(classifiers) -@app.route('/lin-regression-model', methods=["POST"]) -def lin_regression_model(): - result = data_processer.lin_regression_model() - return jsonify({"result": result.to_json()}) +@app.get('/shutdown') +def shutdown(): + shutdown_server() + return 'Server shutting down...' if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000, debug=True) + server_thread = threading.Thread(target=run_flask_app) + server_thread.start() + atexit.register(shutdown_server) diff --git a/api/available_classifiers.py b/api/available_classifiers.py new file mode 100644 index 00000000..b42bcaac --- /dev/null +++ b/api/available_classifiers.py @@ -0,0 +1,6 @@ +def get_available_classifiers(): + return [ + {'id': 0, 'name': 'Naive-Bayes Emotions'}, + {'id': 1, 'name': 'Naive-Bayes News Topics'}, + {'id': 2, 'name': 'Linear Regression Emotions'} + ] \ No newline at end of file diff --git a/main.js b/main.js index 22071684..72c867f0 100644 --- a/main.js +++ b/main.js @@ -1,17 +1,19 @@ const { app, BrowserWindow } = require("electron"); const childProcess = require("child_process"); const path = require("path"); +const axios = require("axios"); const url = require("url"); var processes = []; +/* const child = childProcess.spawn("python", ["./api/app.py"], { detached: false, stdio: "ignore", }); processes.push(child); - +*/ function createWindow() { // cria a janela const win = new BrowserWindow({ @@ -56,12 +58,15 @@ app.on("before-quit", () => {}); app.on("window-all-closed", () => { if (process.platform !== "darwin") { - /* - // TENTA fechar o processo do python - processes.forEach(function (proc) { - proc.kill(); - }); */ + //console.log("Fechando") + axios.get("http://127.0.0.1:5000/shutdown").then(response => { + + }).catch(error => { + + }) + setTimeout(() => { + app.quit(); + }, 2000); - app.quit(); } }); diff --git a/src/components/csvTable/csvTable.css b/src/components/csvTable/csvTable.css new file mode 100644 index 00000000..8cd6b21b --- /dev/null +++ b/src/components/csvTable/csvTable.css @@ -0,0 +1,30 @@ +.csv-table th, .csv-table td { + max-width: 500px; + height: 100px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.csv-table td { + text-align: left; +} + +.csv-div { + margin-top: 1.25rem; + width: 90%; + height: 80%; + max-height: 1500px; + max-width: 1200px; + margin-left: 1.25rem; + overflow-x: auto; + overflow-y: auto; + border-radius: 1rem; + border-width: 0.125rem; + border-color: #ccc; + } + + .csv-div th, .csv-div td { + border: 0.0625rem solid #ccc; + padding: 0.625rem; + } \ No newline at end of file diff --git a/src/components/csvTable/csvTable.tsx b/src/components/csvTable/csvTable.tsx index bbb4fe90..74243dc4 100644 --- a/src/components/csvTable/csvTable.tsx +++ b/src/components/csvTable/csvTable.tsx @@ -1,4 +1,5 @@ import React from "react"; +import './csvTable.css'; interface Props { head: any[]; @@ -7,8 +8,8 @@ interface Props { export default function CsvTable({ data, head }: Props) { return ( -
- +
+
{head.map((headTitle, index) => { diff --git a/src/components/resultTable/resultTable.tsx b/src/components/resultTable/resultTable.tsx index d1260703..e9f4a4fe 100644 --- a/src/components/resultTable/resultTable.tsx +++ b/src/components/resultTable/resultTable.tsx @@ -23,7 +23,7 @@ export default function ResultTable({ data, classifierName }: Props) { .map((row: any, index: number) => { return ( ({}); + const [isLoading, setIsLoading] = useState(false); + const handleChangeSelectedColumn = (event: any) => { setSelectedColumn(event.target.value); }; @@ -23,6 +25,7 @@ export default function Home() { }; const handleSubmit = async () => { + setIsLoading(true); let selectedData = data.map((row) => row[selectedColumn]); console.log(selectedData) console.log(selectedClassifier); @@ -55,6 +58,8 @@ export default function Home() { console.error("Os arrays 'input' e 'output' têm tamanhos diferentes."); } } + + setIsLoading(false); }; const handleDownloadOutputCSV = async () => { @@ -134,7 +139,7 @@ export default function Home() { className="w-full bg-main-dark text-white py-2 px-4 hover:bg-main-darker focus:outline-none border-2 border-main-lighter rounded-3xl h-14" onClick={handleSubmit} > - Enviar + {isLoading ? "Carregando..." : "Classificar"}