diff --git a/api/models/teste b/api/models/teste new file mode 100644 index 00000000..3ef55dc2 Binary files /dev/null and b/api/models/teste differ diff --git a/src/App.css b/src/App.css index 4e6b4487..e69de29b 100644 --- a/src/App.css +++ b/src/App.css @@ -1,4 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap"); -.font-roboto { - font-family: "Roboto Mono", monospace; -} diff --git a/src/Shared/apexChartsOptions.ts b/src/Shared/apexChartsOptions.ts index 8e4f6439..37eba799 100644 --- a/src/Shared/apexChartsOptions.ts +++ b/src/Shared/apexChartsOptions.ts @@ -10,13 +10,13 @@ export const ReactApexChartsDefaultOptions = { xaxis: { labels: { style: { - colors: "#ffffff", + colors: "#000", }, }, title: { text: "Epoch", style: { - color: "#ffffff", + color: "#000", }, }, }, @@ -24,13 +24,13 @@ export const ReactApexChartsDefaultOptions = { labels: { formatter: (value: number) => value.toFixed(4), style: { - colors: "#ffffff", + colors: "#000", }, }, title: { text: "Loss", style: { - color: "#ffffff", + color: "#000", }, }, }, @@ -38,18 +38,19 @@ export const ReactApexChartsDefaultOptions = { theme: "dark", }, grid: { - borderColor: "#ffffff", + borderColor: "#777", + strokeDashArray: 1, }, title: { text: "Loss vs Epochs", align: 'center' as 'center', style: { - color: "#ffffff", + color: "#000", }, }, legend: { labels: { - colors: "#ffffff", // Muda a cor das legendas + colors: "#000", // Muda a cor das legendas }, }, }; diff --git a/src/assets/images/tailLogo.svg b/src/assets/images/tailLogo.svg new file mode 100644 index 00000000..7a4fafd4 --- /dev/null +++ b/src/assets/images/tailLogo.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/components/csvTable/csvTable.tsx b/src/components/csvTable/csvTable.tsx index 6c3bd5f8..6c6a855c 100644 --- a/src/components/csvTable/csvTable.tsx +++ b/src/components/csvTable/csvTable.tsx @@ -1,50 +1,37 @@ import React from "react"; -import './csvTable.css'; interface Props { - head: any[]; + head: string[]; data: any[][]; } export default function CsvTable({ data, head }: Props) { return ( -
- - - - {head.map((headTitle, index) => { - return ( - - ); - })} +
+
- {headTitle} -
+ + + {head.map((headTitle, index) => ( + + ))} - {data.map((row, index) => { - return ( - - {row.map((cell, cellIndex) => { - return ( - + { + row.map((cell, cellIndex) => ( + - ); - })} - - ); - })} + + + )) + } + + ))}
+ {headTitle} +
+ {data.map((row, rowIndex) => ( +
+
{cell} -
diff --git a/src/components/menu/menu.tsx b/src/components/menu/menu.tsx index e1007ee2..604a7421 100644 --- a/src/components/menu/menu.tsx +++ b/src/components/menu/menu.tsx @@ -1,20 +1,45 @@ import React, { useState } from "react"; -import { HiOutlineMenu, HiOutlineX } from "react-icons/hi"; // Importando ícones do React Icons -import { Link } from "react-router-dom"; +import { HiOutlineMenu, HiOutlineX } from "react-icons/hi"; +import { Link, useLocation } from "react-router-dom"; import { CSSTransition } from "react-transition-group"; import "./menu.css"; export function Menu() { const [isExpanded, setIsExpanded] = useState(false); + const location = useLocation(); const toggleMenu = () => { setIsExpanded(!isExpanded); }; + const menuItems = [ + { + path: "/", + title: "Classificar", + description: "Utilize modelos pré-treinados ou use os seus próprios modelos para classificar texto", + }, + { + path: "/train", + title: "Treinar Classificador", + description: "Faça upload dos seus dados e treine o seu próprio classificador textual", + }, + { + path: "/about", + title: "Sobre", + description: "Detalhes sobre o projeto", + }, + { + path: "https://forms.gle/Snud46RwuwT16Mrb9", + title: "Feedback", + description: "Envie sua opinião", + external: true, + }, + ]; + return ( - <> +
- + ); } diff --git a/src/components/resultTable/resultTable.tsx b/src/components/resultTable/resultTable.tsx index e9f4a4fe..b54326a4 100644 --- a/src/components/resultTable/resultTable.tsx +++ b/src/components/resultTable/resultTable.tsx @@ -1,4 +1,10 @@ import React from "react"; +import CsvTable from "../csvTable/csvTable"; + +interface TableData { + Coluna: string; + Valor: any; +} interface Props { data: { [key: string]: any }; @@ -6,38 +12,12 @@ interface Props { } export default function ResultTable({ data, classifierName }: Props) { - return ( -
- - - - - + const tableData: TableData[] = Object.entries(data).map(([key, value]) => ({ + Coluna: key, + Valor: value, + })); + + const convertedTableData: any[][] = tableData.slice(0, 4).map((item) => [item.Coluna, item.Valor]); - - - - - {Object.keys(data) - .slice(0, 10) - .map((row: any, index: number) => { - return ( - - - - - - ); - })} - -
{"Index"}{"Input"}{"Output"}
{index}{row} - {data[row]} -
-
- ); + return ; } diff --git a/src/components/selectFileCard/selectFileCard.tsx b/src/components/selectFileCard/selectFileCard.tsx index e1b94c3c..fbd6468c 100644 --- a/src/components/selectFileCard/selectFileCard.tsx +++ b/src/components/selectFileCard/selectFileCard.tsx @@ -2,6 +2,7 @@ import { Icon } from "@iconify/react"; import { ChangeEvent, useState } from "react"; import Papa from "papaparse"; import CsvTable from "../csvTable/csvTable"; +import { Link } from "@mui/material"; interface props { selectedFile: File | null; @@ -52,7 +53,6 @@ export default function SelectFileCard({ } }; - // Arrastar e soltar const handleDrop = (event: React.DragEvent) => { setIsDragging(false); event.preventDefault(); @@ -66,69 +66,66 @@ export default function SelectFileCard({ }; const handleDragOver = (event: React.DragEvent) => { - setIsDragging(true); // Quando o usuário arrasta algo para cima + setIsDragging(true); event.preventDefault(); }; const handleDragLeave = () => { - setIsDragging(false); // Quando o usuário cancela o arrasto + setIsDragging(false); }; - return ( + return !selectedFile ? (
0 ? `w-4/5` : `w-2/5` - } relative mx-auto mt-24 bg-main-dark border-2 border-main-lighter text-white pt-4 px-4 placeholder-gray-300 rounded-3xl min-h-min flex flex-col items-center justify-between ${ - isDragging ? "blur-sm" : "" - }`} + className={`${data.length > 0 ? `w-4/5` : `w-2/5` + } min-h-[170px] relative mx-auto mt-24 bg-gray-100 border-dashed border-2 border-gray-700 text-gray-600 px-4 placeholder-gray-300 rounded-md flex flex-col items-center justify-center gap-4 ${isDragging ? "blur-sm" : "" + }`} onDrop={handleDrop} onDragOver={handleDragOver} onDragLeave={handleDragLeave} > - {isDragging ? ( -

Arrastar e soltar

- ) : ( - <> - - - {selectedFile ? ( // se tiver arquivo selecionado, seu nome é exibido -

{selectedFile.name}

- ) : ( - <> -

Arrastar e soltar

-

Ou

- - )} - - {data.length > 0 && ( - - )} - - - - + + + + +

Arraste e solte ou { + const fileInput = document.getElementById("fileInput"); + if (fileInput) { + fileInput.click(); + } + }} + > + selecione do Computador + +

+
+ ) : ( + +
0 ? `w-4/5` : `w-2/5` + } min-h-[170px] relative mx-auto flex flex-col items-center justify-center ${isDragging ? "blur-sm" : "" + }`} + onDrop={handleDrop} + onDragOver={handleDragOver} + onDragLeave={handleDragLeave} + > + + + {data.length > 0 && ( + )}
- ); + ) } diff --git a/src/index.css b/src/index.css index ae228ce9..bf8caa94 100644 --- a/src/index.css +++ b/src/index.css @@ -2,12 +2,18 @@ @tailwind components; @tailwind utilities; +@layer base { + body { + font-family: Inter, sans-serif; + } + + code, + pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + } +} + * { margin: 0; padding: 0; } - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New", - monospace; -} diff --git a/src/pages/about.tsx b/src/pages/about.tsx index 6f52b7fb..13bb5f42 100644 --- a/src/pages/about.tsx +++ b/src/pages/about.tsx @@ -1,144 +1,8 @@ -import { Menu } from "../components/menu/menu"; -import { FaLinkedin, FaGithub } from "react-icons/fa"; +import Layout from "./layout/layout"; +import AboutView from "./views/aboutView"; export default function About() { - const teamMembers = [ - { - name: "Jonas Gabriel", - linkedin: "https://www.linkedin.com/in/jonas-gabriel-araujo/", - github: "https://github.com/jonasgabriel18", - photo: "../../../assets/jonas.jpg", - }, - { - name: "Luiz Gusttavo", - linkedin: - "https://www.linkedin.com/in/luiz-gusttavo-oliveira-de-souza-7538091b1/", - github: "https://github.com/GusttavoOliveira", - photo: "../../../assets/luiz.jpg", - }, + return ; - { - name: "Bertrand Lira", - linkedin: "https://www.linkedin.com/in/bertrand-lira-veloso-52aa4926a/", - github: "https://github.com/BertrandLira", - photo: "../../../assets/bertrand.jpg", - }, - - { - name: "Cameron Maloney", - linkedin: "https://www.linkedin.com/in/cameronmal/", - github: "https://github.com/cmaloney111", - photo: "../../../assets/cameron.jpg", - }, - - { - name: "Gisele Silva", - linkedin: "https://www.linkedin.com/in/gisele-silva-6692941a4/", - github: "https://github.com/GiseleBr678", - photo: "../../../assets/LINDADEMAIS/gisele.jpg", - }, - - { - name: "Thauã Magalhães", - linkedin: "https://www.linkedin.com/in/thaua-lucas/", - github: "https://github.com/tahaluh", - photo: "../../../assets/thaua.jpg", - }, - - { - name: "Thiago Rodrigues", - linkedin: "https://www.linkedin.com/in/thiago-rodrigues-b8a328249/", - github: "https://github.com/tahaluh", - photo: "../../../assets/thiago.jpg", - }, - ]; - - return ( -
- - -
-

- LinguifAI -

- -

- O LinguifAI é uma aplicação inovadora desenvolvida pela diretoria de - NLP da TAIL, projetada para simplificar e agilizar o treinamento e a - classificação de modelos de Machine Learning em texto. Com essa - ferramenta, é possível experimentar diversos algoritmos e ajustar - parâmetros de forma intuitiva, tornando o processo de desenvolvimento - de modelos NLP mais acessível e eficiente. -

- -

Tecnologias Utilizadas:

- -
- React - - Electron - - Python - -
- Flask -
- - tensorFlow -
- -

Conheça a Equipe:

- -
- {teamMembers.map((member, index) => ( -
- {member.name} -

{member.name}

- -
- ))} -
-
-
- ); } diff --git a/src/pages/home.tsx b/src/pages/home.tsx index 0dcd7ff8..edcda349 100644 --- a/src/pages/home.tsx +++ b/src/pages/home.tsx @@ -1,207 +1,7 @@ -import { useState, useEffect } from "react"; -import SelectFileCard from "../components/selectFileCard/selectFileCard"; -import axios from "axios"; -import ResultTable from "../components/resultTable/resultTable"; -import { Menu } from "../components/menu/menu"; +import Layout from "./layout/layout"; +import HomeView from "./views/homeView"; -export default function Home() { - const [selectedFile, setSelectedFile] = useState(null); - - const [data, setData] = useState([]); - const [header, setHeader] = useState([]); - - const [selectedColumn, setSelectedColumn] = useState(0); - const [selectedClassifier, setSelectedClassifier] = useState(""); - - const [classifiers, setClassifiers] = useState<{ [key: string]: string }>({}); - - const [result, setResult] = useState<{ [key: string]: any }>({}); - - const [isLoading, setIsLoading] = useState(false); - - useEffect(() => { - const fetchClassifiers = async () => { - setTimeout(async () => { - try { - const response = await axios.get( - "http://localhost:5000/get-classifiers" - ); - setClassifiers(response.data); - } catch (error) { - try { - const response = await axios.get( - "http://localhost:5000/get-classifiers" - ); - setClassifiers(response.data); - } catch (error) { - console.error("Error fetching classifiers:", error); - } - } - }, 25000); - }; - - fetchClassifiers(); - }, []); - - - const handleChangeSelectedColumn = (event: any) => { - setSelectedColumn(event.target.value); - }; - - const handleChangeSelectedClassifier = (event: any) => { - setSelectedClassifier(event.target.value); - }; - - const handleSubmit = async () => { - setIsLoading(true); - let selectedData = data.map((row) => row[selectedColumn]); - const response = await axios - .post("http://localhost:5000/classify", { - data: selectedData, - classifier: selectedClassifier, - }) - .catch((error) => { - console.error(error.response.data); - }); - - if (response && response.data) { - const parsedData = JSON.parse(response.data.result); - - const input: any[] = Object.values(parsedData.input_column); - const output: any[] = Object.values(parsedData.output_column).flat(1); - - if (input.length === output.length) { - // cria um dicionário com os valores de input e output - const result = input.reduce((acc, key, index) => { - acc[key] = output[index]; - return acc; - }, {} as { [key: string]: any }); - console.log(result); - setResult(result); - } else { - console.error("Os arrays 'input' e 'output' tem tamanhos diferentes."); - } - } - - setIsLoading(false); - }; - - const handleDownloadOutputCSV = async () => { - // adicionar uma coluna no data - - const finalHeader = header.concat(`${selectedClassifier}_output`); - const finalData = data.map((row) => - row.concat(result[row[selectedColumn]]) - ); - - // gera um csv com os dados - - const csv = finalHeader - .join(",") - .concat("\n") - .concat(finalData.map((row) => row.join(",")).join("\n")); - - // cria um link para download do csv - - const csvFile = new Blob([csv], { type: "text/csv" }); - const csvURL = window.URL.createObjectURL(csvFile); - const tempLink = document.createElement("a"); - tempLink.href = csvURL; - tempLink.setAttribute("download", "output.csv"); - tempLink.click(); - }; - - return ( -
- - -
-

- LinguifAI -

- - { - - } - - {selectedFile && ( - <> -
- -
-
- -
-
- -
- {Object.keys(result).length > 0 && ( -
- -
- -
-
- )} - - )} -
-
- ); +export default function Home() { + return ; } diff --git a/src/pages/layout/header.tsx b/src/pages/layout/header.tsx new file mode 100644 index 00000000..d1a90c7a --- /dev/null +++ b/src/pages/layout/header.tsx @@ -0,0 +1,23 @@ +import React from "react"; +import { Menu } from "../../components/menu/menu"; +import logo from "../../assets/images/tailLogo.svg"; + +interface HeaderProps { + title: string; +} + +const Header: React.FC = ({ title }) => { + return ( +
+ +
+ Logo da LinguifAI +

+ LinguifAI +

+
+
+ ); +}; + +export default Header; diff --git a/src/pages/layout/layout.tsx b/src/pages/layout/layout.tsx new file mode 100644 index 00000000..bb51eeb3 --- /dev/null +++ b/src/pages/layout/layout.tsx @@ -0,0 +1,17 @@ +import React, { ReactNode } from "react"; +import { Menu } from "../../components/menu/menu"; +import logo from "../../assets/images/tailLogo.svg"; +import Header from "./header"; + +interface LayoutProps { + children: ReactNode; +} + +export default function Layout({ children }: LayoutProps) { + return ( +
+
+
{children}
+
+ ); +} diff --git a/src/pages/train.tsx b/src/pages/train.tsx index ea3c67f9..c20d55bf 100644 --- a/src/pages/train.tsx +++ b/src/pages/train.tsx @@ -4,393 +4,12 @@ import axios from "axios"; import ResultTable from "../components/resultTable/resultTable"; import { Menu } from "../components/menu/menu"; import { ReactApexChartsDefaultOptions } from "../Shared/apexChartsOptions"; +import Layout from "./layout/layout"; +import TrainView from "./views/trainView"; export default function Train() { - const [selectedFile, setSelectedFile] = useState(null); - - const [data, setData] = useState([]); - const [header, setHeader] = useState([]); - - const [selectedColumn, setSelectedColumn] = useState(0); - const [selectedLabel, setSelectedLabel] = useState(0); - - const [isLoading, setIsLoading] = useState(false); - const [hasTrained, setHasTrained] = useState(false); - const [isCancelling, setIsCancelling] = useState(false); - - const handleChangeSelectedColumn = (event: any) => { - setSelectedColumn(event.target.value); - }; - - const handleChangeSelectedLabel = (event: any) => { - setSelectedLabel(event.target.value); - }; - - const handleRnnSubmit = async () => { - setIsLoading(true); - setHasTrained(true); - setLoadingProgress(0); - setTrainLosses([]); - setValidLosses([]); - - let selectedData = data.map((row) => ({ - value: row[selectedColumn], - label: row[selectedLabel], - })); - - let selectedLabels = data.map((row) => row[selectedLabel]); - let selectedValues = data.map((row) => row[selectedColumn]); - - const sendData = { - data: selectedValues, - label: selectedLabels, - batch_size: batchSize || 16, - epochs: epochs || 50, - learning_rate: learningRate || 0.001, - name: modelName || "trained-model", - }; - - console.log(sendData); - - const url = "http://localhost:5000/neural-network-rnn"; - - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch((error) => { - throw new Error(error); - }); - }); - }); - }); - - setIsLoading(false); - }; - - const handleNbSubmit = async () => { - setIsLoading(true); - setLoadingProgress(0); - - let selectedData = data.map((row) => ({ - value: row[selectedColumn], - label: row[selectedLabel], - })); - - let selectedLabels = data.map((row) => row[selectedLabel]); - let selectedValues = data.map((row) => row[selectedColumn]); - - const sendData = { - data: selectedValues, - label: selectedLabels, - batch_size: batchSize || 16, - epochs: epochs || 50, - learning_rate: learningRate || 0.001, - name: modelName || "trained-model", - }; - - console.log(sendData); - - const url = "http://localhost:5000/neural-network-nb"; - - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch(async (error) => { - await axios.post(url, sendData).catch((error) => { - throw new Error(error); - }); - }); - }); - }); - - setIsLoading(false); - }; - - const [batchSize, setBatchSize] = useState(16); - const [epochs, setEpochs] = useState(50); - const [learningRate, setLearningRate] = useState(0.001); - const [modelName, setModelName] = useState(""); - - const handleBatchSizeChange = ( - event: React.ChangeEvent - ) => { - const value = parseInt(event.target.value); - setBatchSize(value); - }; - - const handleEpochsChange = (event: React.ChangeEvent) => { - const value = parseInt(event.target.value); - setEpochs(value); - }; - - const handleLearningRateChange = ( - event: React.ChangeEvent - ) => { - const value = parseFloat(event.target.value); - setLearningRate(value); - }; - - const handleModelNameChange = ( - event: React.ChangeEvent - ) => { - const value = event.target.value; - setModelName(value); - }; - - const [advancedOptionsVisible, setAdvancedOptionsVisible] = useState(false); - - const toggleAdvancedOptions = () => { - setAdvancedOptionsVisible(!advancedOptionsVisible); - }; - - // carregamento - - const [loadingProgress, setLoadingProgress] = useState(0); - const [train_losses, setTrainLosses] = useState([]); - const [valid_losses, setValidLosses] = useState([]); - const prevLoadingProgressRef = useRef(0); // Explicitly type prevLoadingProgressRef - - useEffect(() => { - const fetchData = async () => { - try { - const response = await axios.get( - "http://localhost:5000/training-status" - ); - const { training_progress, training_in_progress } = response.data; - const newProgress: number = - training_in_progress || training_progress === 100 - ? training_progress - : 0; // Explicitly type newProgress - updateLoadingProgress(newProgress); - - setTrainLosses(train_losses); - setValidLosses(valid_losses); - } catch (error) { - console.error("Error fetching progress:", error); - } - }; - - const updateLoadingProgress = (newProgress: number) => { - // Explicitly type newProgress parameter - const duration = 1000; // Duration in milliseconds for the transition - const startTime = Date.now(); - const startProgress = prevLoadingProgressRef.current; - - const updateProgress = () => { - const elapsedTime = Date.now() - startTime; - const progress = Math.min(1, elapsedTime / duration); // Ensure progress doesn't exceed 1 - const interpolatedProgress = - startProgress + (newProgress - startProgress) * progress; - setLoadingProgress(interpolatedProgress); - - if (progress < 1) { - requestAnimationFrame(updateProgress); - } else { - prevLoadingProgressRef.current = newProgress; - } - }; - - updateProgress(); - }; - - const interval = setInterval(fetchData, 1050); - - return () => clearInterval(interval); - }, []); return ( -
- - -
-

- LinguifAI -

- - { - - } - - {selectedFile && ( - <> -
- - -
- -
- - -
- -
- - -
- - - - {advancedOptionsVisible && ( -
-
- - -
- -
- - -
- -
- - -
-
- )} - -
-
- {isLoading && ( -
-
-
-
- {`Treinamento em ${loadingProgress.toFixed(2)}%`} -
-
- )} - - - -
-
- - )} -
-
+ ); } diff --git a/src/pages/views/aboutView.tsx b/src/pages/views/aboutView.tsx new file mode 100644 index 00000000..9c619475 --- /dev/null +++ b/src/pages/views/aboutView.tsx @@ -0,0 +1,128 @@ +import React from "react"; +import { Menu } from "../../components/menu/menu"; +import { FaGithub, FaLinkedin } from "react-icons/fa"; + +export default function AboutView() { + const teamMembers = [ + { + name: "Jonas Gabriel", + linkedin: "https://www.linkedin.com/in/jonas-gabriel-araujo/", + github: "https://github.com/jonasgabriel18", + photo: "../../../assets/jonas.jpg", + }, + { + name: "Luiz Gusttavo", + linkedin: "https://www.linkedin.com/in/luiz-gusttavo-oliveira-de-souza-7538091b1/", + github: "https://github.com/GusttavoOliveira", + photo: "../../../assets/luiz.jpg", + }, + { + name: "Bertrand Lira", + linkedin: "https://www.linkedin.com/in/bertrand-lira-veloso-52aa4926a/", + github: "https://github.com/BertrandLira", + photo: "../../../assets/bertrand.jpg", + }, + { + name: "Cameron Maloney", + linkedin: "https://www.linkedin.com/in/cameronmal/", + github: "https://github.com/cmaloney111", + photo: "../../../assets/cameron.jpg", + }, + { + name: "Gisele Silva", + linkedin: "https://www.linkedin.com/in/gisele-silva-6692941a4/", + github: "https://github.com/GiseleBr678", + photo: "../../../assets/LINDADEMAIS/gisele.jpg", + }, + { + name: "Thauã Magalhães", + linkedin: "https://www.linkedin.com/in/thaua-lucas/", + github: "https://github.com/tahaluh", + photo: "../../../assets/thaua.jpg", + }, + { + name: "Thiago Rodrigues", + linkedin: "https://www.linkedin.com/in/thiago-rodrigues-b8a328249/", + github: "https://github.com/tahaluh", + photo: "../../../assets/thiago.jpg", + }, + ]; + + return ( +
+ + +
+

+ O LinguifAI é uma aplicação inovadora desenvolvida pela diretoria de NLP da TAIL, projetada para simplificar e agilizar o treinamento e a classificação de modelos de Machine Learning em texto. Com essa ferramenta, é possível experimentar diversos algoritmos e ajustar parâmetros de forma intuitiva, tornando o processo de desenvolvimento de modelos NLP mais acessível e eficiente. +

+ +

Tecnologias Utilizadas:

+ +
+ React + Electron + Python +
+ Flask +
+ TensorFlow +
+ +

Conheça nossa equipe:

+ +
+ {teamMembers.map((member, index) => ( +
+ {member.name} +

{member.name}

+ +
+ ))} +
+
+
+ ); +} diff --git a/src/pages/views/homeView.tsx b/src/pages/views/homeView.tsx new file mode 100644 index 00000000..f14fa2c6 --- /dev/null +++ b/src/pages/views/homeView.tsx @@ -0,0 +1,185 @@ +import React, { useState, useEffect } from "react"; +import axios from "axios"; +import SelectFileCard from "../../components/selectFileCard/selectFileCard"; +import ResultTable from "../../components/resultTable/resultTable"; + +export default function HomeView() { + const [selectedFile, setSelectedFile] = useState(null); + const [data, setData] = useState([]); + const [header, setHeader] = useState([]); + const [selectedColumn, setSelectedColumn] = useState(0); + const [selectedClassifier, setSelectedClassifier] = useState(""); + const [classifiers, setClassifiers] = useState<{ [key: string]: string }>({}); + const [result, setResult] = useState<{ [key: string]: any }>({}); + const [isLoading, setIsLoading] = useState(false); + + useEffect(() => { + const fetchClassifiers = async () => { + while (true) { + try { + const response = await axios.get( + "http://localhost:5000/get-classifiers" + ); + setClassifiers(response.data); + break; + } catch (error) { + console.error("Error fetching classifiers, retrying...", error); + await new Promise((resolve) => setTimeout(resolve, 3000)); + } + } + }; + + fetchClassifiers(); + }, []); + + const handleChangeSelectedColumn = (event: React.ChangeEvent) => { + setSelectedColumn(Number(event.target.value)); + }; + + const handleChangeSelectedClassifier = (event: React.ChangeEvent) => { + setSelectedClassifier(event.target.value); + }; + + const handleSubmit = async () => { + setIsLoading(true); + let selectedData = data.map((row) => row[selectedColumn]); + const response = await axios + .post("http://localhost:5000/classify", { + data: selectedData, + classifier: selectedClassifier, + }) + .catch((error) => { + console.error(error.response.data); + }); + + if (response && response.data) { + const parsedData = JSON.parse(response.data.result); + const input: any[] = Object.values(parsedData.input_column); + const output: any[] = Object.values(parsedData.output_column).flat(1); + + if (input.length === output.length) { + const result = input.reduce((acc, key, index) => { + acc[key] = output[index]; + return acc; + }, {} as { [key: string]: any }); + + console.log(result); + setResult(result); + } else { + console.error("Os arrays 'input' e 'output' tem tamanhos diferentes."); + } + } + + setIsLoading(false); + }; + + const handleDownloadOutputCSV = async () => { + const finalHeader = header.concat(`${selectedClassifier}_output`); + const finalData = data.map((row) => + row.concat(result[row[selectedColumn]]) + ); + + const csv = finalHeader + .join(",") + .concat("\n") + .concat(finalData.map((row) => row.join(",")).join("\n")); + + const csvFile = new Blob([csv], { type: "text/csv" }); + const csvURL = window.URL.createObjectURL(csvFile); + const tempLink = document.createElement("a"); + tempLink.href = csvURL; + tempLink.setAttribute("download", "output.csv"); + tempLink.click(); + }; + + return ( +
+ + + {selectedFile && ( + <> +
+ + +
+
+ + +
+
+ +
+ {Object.keys(result).length > 0 && ( +
+ +
+ +
+
+ )} + + )} +
+ ); +} diff --git a/src/pages/views/trainView.tsx b/src/pages/views/trainView.tsx new file mode 100644 index 00000000..5836b8a2 --- /dev/null +++ b/src/pages/views/trainView.tsx @@ -0,0 +1,374 @@ +import React, { useState, useEffect, useRef } from "react"; +import axios from "axios"; +import ReactApexChart from "react-apexcharts"; +import SelectFileCard from "../../components/selectFileCard/selectFileCard"; +import { ReactApexChartsDefaultOptions } from "../../Shared/apexChartsOptions"; + +export default function TrainView() { + const [selectedFile, setSelectedFile] = useState(null); + + const [data, setData] = useState([]); + const [header, setHeader] = useState([]); + + const [selectedColumn, setSelectedColumn] = useState(0); + const [selectedLabel, setSelectedLabel] = useState(0); + + const [isLoading, setIsLoading] = useState(false); + const [hasTrained, setHasTrained] = useState(false); + const [isCancelling, setIsCancelling] = useState(false); + + const handleChangeSelectedColumn = (event: React.ChangeEvent) => { + setSelectedColumn(Number(event.target.value)); + }; + + const handleChangeSelectedLabel = (event: React.ChangeEvent) => { + setSelectedLabel(Number(event.target.value)); + }; + + const handleCancelTraining = async () => { + setIsCancelling(true); + try { + await axios.post('http://localhost:5000/cancel-training'); + alert('Treinamento cancelado com sucesso!'); + } catch (error) { + console.error('Erro ao cancelar o treinamento:', error); + alert('Falha ao cancelar o treinamento.'); + } + setIsCancelling(false); + }; + + const handleRnnSubmit = async () => { + setIsLoading(true); + setHasTrained(true); + setLoadingProgress(0); + setTrainLosses([]); + setValidLosses([]); + + let selectedData = data.map((row) => ({ + value: row[selectedColumn], + label: row[selectedLabel], + })); + + let selectedLabels = data.map((row) => row[selectedLabel]); + let selectedValues = data.map((row) => row[selectedColumn]); + + const sendData = { + data: selectedValues, + label: selectedLabels, + batch_size: batchSize || 16, + epochs: epochs || 50, + learning_rate: learningRate || 0.001, + name: modelName || "trained-model", + }; + + console.log(sendData); + + const url = "http://localhost:5000/neural-network-rnn"; + + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch((error) => { + throw new Error(error); + }); + }); + }); + }); + + setIsLoading(false); + }; + + const handleNbSubmit = async () => { + setIsLoading(true); + setLoadingProgress(0); + + let selectedData = data.map((row) => ({ + value: row[selectedColumn], + label: row[selectedLabel], + })); + + let selectedLabels = data.map((row) => row[selectedLabel]); + let selectedValues = data.map((row) => row[selectedColumn]); + + const sendData = { + data: selectedValues, + label: selectedLabels, + batch_size: batchSize || 16, + epochs: epochs || 50, + learning_rate: learningRate || 0.001, + name: modelName || "trained-model", + }; + + console.log(sendData); + + const url = "http://localhost:5000/neural-network-nb"; + + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch(async (error) => { + await axios.post(url, sendData).catch((error) => { + throw new Error(error); + }); + }); + }); + }); + + setIsLoading(false); + }; + + const [batchSize, setBatchSize] = useState(16); + const [epochs, setEpochs] = useState(50); + const [learningRate, setLearningRate] = useState(0.001); + const [modelName, setModelName] = useState(""); + + const handleBatchSizeChange = ( + event: React.ChangeEvent + ) => { + const value = parseInt(event.target.value); + setBatchSize(value); + }; + + const handleEpochsChange = (event: React.ChangeEvent) => { + const value = parseInt(event.target.value); + setEpochs(value); + }; + + const handleLearningRateChange = ( + event: React.ChangeEvent + ) => { + const value = parseFloat(event.target.value); + setLearningRate(value); + }; + + const handleModelNameChange = ( + event: React.ChangeEvent + ) => { + const value = event.target.value; + setModelName(value); + }; + + const [advancedOptionsVisible, setAdvancedOptionsVisible] = useState(false); + + const toggleAdvancedOptions = () => { + setAdvancedOptionsVisible(!advancedOptionsVisible); + }; + + const [loadingProgress, setLoadingProgress] = useState(0); + const [train_losses, setTrainLosses] = useState([]); + const [valid_losses, setValidLosses] = useState([]); + const prevLoadingProgressRef = useRef(0); + + useEffect(() => { + const fetchData = async () => { + try { + const response = await axios.get( + "http://localhost:5000/training-status" + ); + const { training_progress, training_in_progress, train_losses, valid_losses } = response.data; + const newProgress: number = + training_in_progress || training_progress === 100 + ? training_progress + : 0; // Explicitly type newProgress + updateLoadingProgress(newProgress); + + setTrainLosses(train_losses); + setValidLosses(valid_losses); + } catch (error) { + console.error("Error fetching progress:", error); + } + }; + + const updateLoadingProgress = (newProgress: number) => { + // Explicitly type newProgress parameter + const duration = 1000; + const startTime = Date.now(); + const startProgress = prevLoadingProgressRef.current; + + const updateProgress = () => { + const elapsedTime = Date.now() - startTime; + const progress = Math.min(1, elapsedTime / duration); + const interpolatedProgress = + startProgress + (newProgress - startProgress) * progress; + setLoadingProgress(interpolatedProgress); + + if (progress < 1) { + requestAnimationFrame(updateProgress); + } else { + prevLoadingProgressRef.current = newProgress; + } + }; + + updateProgress(); + }; + + const interval = setInterval(fetchData, 1050); + + return () => clearInterval(interval); + }, []); + + return ( +
+ + + {selectedFile && ( + <> +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+
+ {isLoading && ( +
+
+
+
+ {`Treinamento em ${loadingProgress.toFixed(2)}%`} +
+
+ )} + + {!isLoading && } + + {hasTrained && train_losses.length > 0 && ( +
+ +
+ )} + + {isLoading && ( + + )} +
+
+ + )} +
+ ); +} +