diff --git a/src/web/backend/app.py b/src/web/backend/app.py index d9559ab5..f0fc8675 100644 --- a/src/web/backend/app.py +++ b/src/web/backend/app.py @@ -2,13 +2,12 @@ import random import csv from flask_cors import CORS -from flask import request, jsonify, make_response +from flask import request, jsonify from flask import Flask import sys import os import argparse -import torch # needs to be before importing Review and Lda sys.path.append(os.path.abspath(os.path.join( @@ -21,6 +20,7 @@ from aml.rnd import Rnd from aml.bert import BERT +model_names = ['lda', 'bert', 'btm', 'rnd', 'ctm'] __dirname = os.path.dirname(__file__) @@ -92,5 +92,21 @@ def get_random_row_from_csv(): return jsonify({'error': '[Server]: reviews.csv not found'}), 500 +@app.route('/get_models', methods=['GET']) +def get_models(): + path = os.path.join(__dirname, 'models') + models = os.listdir(path) + result = {} + + for lang in models: + model_path = os.path.join(path, lang) + models = os.listdir(model_path) + lang_ = lang.split('.')[-1] if '.' in lang else 'eng' + + result[lang_] = list(filter(lambda x: x in model_names, models)) + + return jsonify(result) + + if __name__ == '__main__': app.run(debug=True) diff --git a/src/web/frontend/.eslintrc.js b/src/web/frontend/.eslintrc.js new file mode 100644 index 00000000..a72662a1 --- /dev/null +++ b/src/web/frontend/.eslintrc.js @@ -0,0 +1,36 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react/recommended" + ], + "overrides": [ + { + "env": { + "node": true + }, + "files": [ + ".eslintrc.{js,cjs}" + ], + "parserOptions": { + "sourceType": "script" + } + } + ], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": [ + "@typescript-eslint", + "react" + ], + "rules": { + "no-namespace": 0 + } +} diff --git a/src/web/frontend/Components/Chart.jsx b/src/web/frontend/Components/Chart.tsx similarity index 64% rename from src/web/frontend/Components/Chart.jsx rename to src/web/frontend/Components/Chart.tsx index a25bcb9a..7686f9c9 100644 --- a/src/web/frontend/Components/Chart.jsx +++ b/src/web/frontend/Components/Chart.tsx @@ -7,8 +7,10 @@ import { Tooltip, Legend, } from "chart.js"; + import { Bar } from "react-chartjs-2"; -import React, { useState, useEffect } from "react"; +import React from "react"; + ChartJS.register( CategoryScale, LinearScale, @@ -19,7 +21,7 @@ ChartJS.register( ); export const options = { - indexAxis: "y", + indexAxis: "y" as const, elements: { bar: { borderWidth: 2, @@ -28,7 +30,7 @@ export const options = { responsive: true, plugins: { legend: { - position: "right", + position: "right" as const, }, title: { display: true, @@ -37,9 +39,7 @@ export const options = { }, }; -export default function Example(props) { - console.log("output", props.output); - // setChartData(props.output); - - return ; -} +export const Chart = (props: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + output: any; +}) => ; diff --git a/src/web/frontend/Components/Footer.jsx b/src/web/frontend/Components/Footer.tsx similarity index 100% rename from src/web/frontend/Components/Footer.jsx rename to src/web/frontend/Components/Footer.tsx diff --git a/src/web/frontend/hooks/useFetch.tsx b/src/web/frontend/hooks/useFetch.tsx new file mode 100644 index 00000000..79dd64ae --- /dev/null +++ b/src/web/frontend/hooks/useFetch.tsx @@ -0,0 +1,25 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import axios from "axios"; +import { RD } from "prelude"; +import React from "react"; + +export const useFetch = = object>({ + params, + url, +}: { + url: string; + params?: Params; +}) => { + const [data, setData] = React.useState>(RD.Init); + + React.useEffect(() => { + setData(RD.Loading); + + axios + .get(url, { params }) + .then((x) => setData(RD.Data({ data: x.data }))) + .catch((x) => setData(RD.Error({ error: x }))); + }, [params, url]); + + return data; +}; diff --git a/src/web/frontend/next-env.d.ts b/src/web/frontend/next-env.d.ts new file mode 100644 index 00000000..4f11a03d --- /dev/null +++ b/src/web/frontend/next-env.d.ts @@ -0,0 +1,5 @@ +/// +/// + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/basic-features/typescript for more information. diff --git a/src/web/frontend/package.json b/src/web/frontend/package.json index 130252b2..013d32a9 100644 --- a/src/web/frontend/package.json +++ b/src/web/frontend/package.json @@ -14,15 +14,26 @@ "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@next/font": "13.3.0", + "axios": "^1.6.2", + "chart.js": "^4.4.1", "csv-loader": "^3.0.5", "csvtojson": "^2.0.10", + "fp-ts": "^2.16.1", "framer-motion": "^10.12.2", "next": "13.3.0", "react": "18.2.0", "react-chartjs-2": "^5.2.0", - "react-dom": "18.2.0" + "react-dom": "18.2.0", + "ts-pattern": "^5.0.6" }, "devDependencies": { - "faker": "^5.5.3" + "@types/node": "20.10.3", + "@types/react": "^18.2.42", + "@typescript-eslint/eslint-plugin": "^6.13.2", + "@typescript-eslint/parser": "^6.13.2", + "eslint": "^8.55.0", + "eslint-plugin-react": "^7.33.2", + "faker": "^5.5.3", + "typescript": "^5.3.3" } } diff --git a/src/web/frontend/pages/_app.js b/src/web/frontend/pages/_app.tsx similarity index 55% rename from src/web/frontend/pages/_app.js rename to src/web/frontend/pages/_app.tsx index 479b39df..e91d73ee 100644 --- a/src/web/frontend/pages/_app.js +++ b/src/web/frontend/pages/_app.tsx @@ -1,8 +1,8 @@ +import React from "react"; import "@/styles/globals.css"; import { ChakraProvider } from "@chakra-ui/react"; -import { useEffect, useState } from "react"; -import { Spinner } from "@chakra-ui/react"; -export default function App({ Component, pageProps }) { +import { AppProps } from "next/app"; +export default function App({ Component, pageProps }: AppProps) { return ( diff --git a/src/web/frontend/pages/_document.js b/src/web/frontend/pages/_document.tsx similarity index 63% rename from src/web/frontend/pages/_document.js rename to src/web/frontend/pages/_document.tsx index 54e8bf3e..25aa9125 100644 --- a/src/web/frontend/pages/_document.js +++ b/src/web/frontend/pages/_document.tsx @@ -1,4 +1,5 @@ -import { Html, Head, Main, NextScript } from 'next/document' +import React from "react"; +import { Html, Head, Main, NextScript } from "next/document"; export default function Document() { return ( @@ -9,5 +10,5 @@ export default function Document() { - ) + ); } diff --git a/src/web/frontend/pages/api/hello.js b/src/web/frontend/pages/api/hello.ts similarity index 100% rename from src/web/frontend/pages/api/hello.js rename to src/web/frontend/pages/api/hello.ts diff --git a/src/web/frontend/pages/index.js b/src/web/frontend/pages/index.js deleted file mode 100644 index ce76ed09..00000000 --- a/src/web/frontend/pages/index.js +++ /dev/null @@ -1,237 +0,0 @@ -import Head from "next/head"; -import React from "react" -import { Inter } from "@next/font/google"; -import { Center, Container, HStack, Heading } from "@chakra-ui/layout"; -import { Textarea } from "@chakra-ui/textarea"; -import { RepeatIcon } from "@chakra-ui/icons"; - -import Footer from "../Components/Footer"; -import { useState, useEffect } from "react"; -import { Button } from "@chakra-ui/button"; -import Chart from "../Components/Chart"; -import { - Select, - FormControl, - FormLabel, - Spinner, - useToast, -} from "@chakra-ui/react"; -const inter = Inter({ subsets: ["latin"] }); - -const Languages = [ - ['' , "None"], - ['pes-Arab', 'Persian'], - ['zho_Hans', "Chinese"], - ['deu_Latn', 'German'], - ['arb_Arab', 'Arabic'], - ['fra_Latn', 'French'], - ['spa_Latn', 'Spanish'] -] - -const ASPECT_MODELS = [ - 'bert', - 'btm', - 'ctm', - 'random', - 'lda' -] - -const API_LINKS = { - 'staging': 'http://localhost:5000', - 'production': 'https://lady.onrender.com' -} - -const ENV = 'staging' - -//use state to store textarea value -export default function Home() { - const toast = useToast(); - const [formval, setformval] = useState( - "The food was fresh and delicious, and the best part was that the chef sent us a dessert they had created that day." - ); - const [selectedModel, setSelectedModel] = useState("lda"); - const [selectedLang, setSelectedLang] = useState("arb_Arab"); - const [naspects, setnaspects] = useState(5); - - const [data, setData] = useState(""); - const [isLoad, setIsLoading] = useState(true); - - let apilink = API_LINKS[ENV]; - - useEffect(() => { - const fetchData = async () => { - // get the data from the api - const data = await fetch(`${apilink}/random`); - // convert the data to json - const json = await data.json(); - - // set state with the result - console.log("data", data); - setIsLoading(false); - }; - - // call the function - fetchData() - // make sure to catch any error - .catch(console.error); - }, []); - - const getRandomReview = async () => { - const response = await fetch(`${apilink}/random`); - const json = await response.json(); - - setformval(json[0]); - }; - - const handleSubmit = React.useCallback(async (e) => { - e.preventDefault(); - setIsLoading(!isLoad); - - const requestOptions = { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ - text: formval, - model: selectedModel, - lang: selectedLang, - naspects: naspects, - }), - }; - - const response = await fetch(`${apilink}/api`, requestOptions); - const json = await response.json(); - setIsLoading(false); - - if (Object.keys(json).length === 0) { - toast({ - title: "Model not found", - status: "error", - isClosable: true, - position: "top", - }); - } - - setData(json); - }, [isLoad, selectedLang, selectedModel, naspects]); - - let handleInputChange = (e) => { - let inputValue = e.target.value; - setformval(inputValue); - }; - - const isError = React.useMemo(() => formval === "", [formval]); - - const values = React.useMemo(() => Object.entries(data).sort(([, a], [, b]) => b - a), [data]); - - const output = React.useMemo(() => ({ - labels: values.map(([label]) => label), - datasets: [ - { - label: "Score", - data: values.map(([, value]) => value), - borderColor: "rgb(53, 162, 235)", - backgroundColor: "#38B2AC", - } /* - { - label: "Dataset 2", - data: [20, 30, 20, 10, 10, 5, 0], - borderColor: "rgb(53, 162, 235)", - backgroundColor: "rgba(53, 162, 235, 0.5)", - },*/, - ], - }), [values]); - - return ( - <> - - Latent Aspect Detection - - - - - {!isLoad ? ( - - Latent Aspect Detection - - - {/*} - {" "} */} - - Model: - - Language - - - {/* Number of aspects */} - - {/* setnaspects(value)} - min={5} - max={25} - step={5} - maxW={24} - > - - - - - - */} - - -