diff --git a/src/main/java/controller/ExerciseController.java b/src/main/java/controller/ExerciseController.java index eaa2226..68058dc 100644 --- a/src/main/java/controller/ExerciseController.java +++ b/src/main/java/controller/ExerciseController.java @@ -8,7 +8,6 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; -import java.sql.Date; @WebServlet("/exerciseController") @@ -16,9 +15,9 @@ public class ExerciseController extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { ExerciseManager em = new ExerciseManager(); String id = request.getParameter("exerciseID"); - String insertionDate = request.getParameter("insertionDate"); - request.getSession().setAttribute("insertionDate", Date.valueOf(insertionDate)); - request.getSession().setAttribute("exerciseID", Integer.parseInt(id)); + String insertiondate = request.getParameter("insertionDate"); + request.getSession().setAttribute("insertionDate", insertiondate); + request.getSession().setAttribute("exerciseId", id); ExerciseGlossary ex = em.getExercise(Integer.parseInt(id)); request.getSession().setAttribute("exercise", ex); diff --git a/src/main/java/controller/ExerciseEvaluator.java b/src/main/java/controller/ExerciseEvaluator.java index e69de29..17ce3b7 100644 --- a/src/main/java/controller/ExerciseEvaluator.java +++ b/src/main/java/controller/ExerciseEvaluator.java @@ -0,0 +1,185 @@ +package controller; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import info.debatty.java.stringsimilarity.Levenshtein; +import model.entity.ExerciseGlossary; +import model.service.exercise.ExerciseManager; +import model.service.exercise.SpeechRecognition; + +import javax.servlet.ServletException; +import javax.servlet.annotation.MultipartConfig; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.*; +import java.io.*; +import java.lang.reflect.Type; +import java.sql.Blob; +import java.sql.Date; +import java.sql.SQLException; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ExecutionException; + + +@WebServlet("/exerciseEvaluator") +@MultipartConfig +public class ExerciseEvaluator extends HttpServlet { + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { + HttpSession s = request.getSession(); + String contentType = request.getContentType(); + ExerciseManager em = new ExerciseManager(); + + int exerciseId = (int) s.getAttribute("exerciseID"); + int userId = (int) s.getAttribute("id"); + Date d = (Date) s.getAttribute("insertDate"); + + int score; + + if ("application/json".equals(contentType)) { + score = evaluateNoAudio(exerciseId, userId, d); + } else { + try { + score = evaluateAudio(exerciseId, userId, d); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + } + em.saveEvaluation(userId, exerciseId, d, score); + } + + + private int evaluateNoAudio(int exerciseId, int userId, Date date){ + Gson gson = new Gson(); + + ExerciseGlossary baseExercise = new ExerciseManager().getExercise(exerciseId); + String executionJSON = getJSONfromBlob(exerciseId, userId, date); + String type = baseExercise.getType(); + + int score; + + switch (type) { + case "CROSSWORD" -> { + String[][] solution = gson.fromJson(baseExercise.getSolution(), String[][].class); + String[][] execution = gson.fromJson(executionJSON, String[][].class); + + score = evaluateCrossword(execution, solution); + } + case "IMAGESTOTEXT", "TEXTTOIMAGES" -> { + Type solutionType = new TypeToken>() {}.getType(); + Map solution = gson.fromJson(baseExercise.getSolution(), solutionType); + Map execution = gson.fromJson(executionJSON, solutionType); + + score = evaluateITTnTTI(execution, solution); + } + case "RIGHTTEXT" -> { + Type solutionType = new TypeToken>(){}.getType(); + Set solution = gson.fromJson(baseExercise.getSolution(), solutionType); + Set execution = gson.fromJson(executionJSON, solutionType); + + score = evaluateRightText(execution, solution); + } + default -> throw new IllegalStateException("Unexpected value: " + type); + } + + return score; + } + + private String getJSONfromBlob(int exerciseId, int userId, Date d){ + Blob executionBlob = new ExerciseManager().getExecution(exerciseId, userId, d); + StringBuilder stringBuilder = new StringBuilder(); + + try (InputStream binaryStream = executionBlob.getBinaryStream(); + InputStreamReader inputStreamReader = new InputStreamReader(binaryStream); + BufferedReader bufferedReader = new BufferedReader(inputStreamReader)) { + + String line; + while ((line = bufferedReader.readLine()) != null) { + stringBuilder.append(line); + } + + } catch (SQLException | IOException e) { + e.printStackTrace(); + } + + return stringBuilder.toString(); + } + + private int evaluateRightText(Set execution, Set solution) { + double right = 0; + int total = solution.size(); + for (String s : solution) { + if (execution.contains(s.toUpperCase())){ + right++; + } + } + return (int)((right /total)*100); + } + + private int evaluateITTnTTI(Map execution, Map solution) { + double right = 0; + int total = solution.size(); + + for (Map.Entry entry : execution.entrySet()) { + String k = entry.getKey(); + String executionValue = entry.getValue(); + String solutionValue = solution.get(k); + + if (executionValue != null) { + if (executionValue.equals(solutionValue.toUpperCase())) { + right++; + } + } + } + return (int)((right /total)*100); + } + + private int evaluateCrossword(String[][] execution, String[][] solution) { + double right = 0; + int total = 0; + + for (int i = 0; i < execution.length; i++) { + for (int j = 0; j < execution[0].length; j++) { + if (!execution[i][j].equals("#")){ + if (execution[i][j].equals(solution[i][j].toUpperCase())) { + right++; + } + total++; + } + } + } + return (int)((right /total)*100); + } + + private int evaluateAudio(int exerciseId, int userId, Date d) throws IOException, ExecutionException, InterruptedException { + SpeechRecognition s = new SpeechRecognition(); + Levenshtein l = new Levenshtein(); + Gson g = new Gson(); + ExerciseGlossary baseExercise = new ExerciseManager().getExercise(exerciseId); + String solution = g.fromJson(baseExercise.getInitialState(), String.class); + + InputStream audioExecution = getAudiofromBlob(exerciseId, userId, d); + String audioText = null; + if (audioExecution!=null){ + audioText = s.azureSTT(audioExecution); + } + System.out.println(audioText); + System.out.println("\n"+solution); + + if(audioText != null){ + double distance = l.distance(solution, audioText); + double result = ((solution.length()-distance)/solution.length())*100; + return (int) Math.round(result); + } + + return 0; + } + + private InputStream getAudiofromBlob(int exerciseId, int userId, Date d){ + Blob executionBlob = new ExerciseManager().getExecution(exerciseId, userId, d); + try (InputStream audioInputStream = executionBlob.getBinaryStream()) { + return audioInputStream; + } catch (SQLException | IOException e) { + throw new RuntimeException(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/controller/InvitePatient.java b/src/main/java/controller/InvitePatient.java deleted file mode 100644 index a6a0992..0000000 --- a/src/main/java/controller/InvitePatient.java +++ /dev/null @@ -1,25 +0,0 @@ -package controller; - -import model.service.condition.ConditionManager; -import model.service.registration.Registration; - -import javax.servlet.annotation.WebServlet; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.IOException; - - -@WebServlet("/invitePatient") -public class InvitePatient extends HttpServlet { - - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { - HttpSession session = request.getSession(); - model.service.registration.Registration registration=new Registration(); - registration.invitePatient((Integer) session.getAttribute("id"),(String) request.getParameter("email"),(String) request.getParameter("nome"),(String) request.getParameter("cognome")); - response.sendRedirect("JSP/homeTherapist.jsp"); - - } - -} \ No newline at end of file diff --git a/src/main/java/model/service/exercise/SpeechRecognition.java b/src/main/java/model/service/exercise/SpeechRecognition.java index e69de29..46581bb 100644 --- a/src/main/java/model/service/exercise/SpeechRecognition.java +++ b/src/main/java/model/service/exercise/SpeechRecognition.java @@ -0,0 +1,109 @@ +package model.service.exercise; + +import com.microsoft.cognitiveservices.speech.*; +import com.microsoft.cognitiveservices.speech.audio.AudioConfig; +import java.io.*; +import java.nio.file.*; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + + +public class SpeechRecognition { + private static final String AZURE_PROPERTIES = "/azure.properties"; + private static String speechKey; + private static String speechRegion; + + public SpeechRecognition(){ + Properties azureProps = loadProps(); + speechRegion = azureProps.getProperty("azure.region"); + speechKey = azureProps.getProperty("azure.key"); + } + + + public String azureSTT(InputStream audio) throws InterruptedException, ExecutionException, IOException { + SpeechConfig speechConfig = SpeechConfig.fromSubscription(speechKey, speechRegion); + speechConfig.setSpeechRecognitionLanguage("it-It"); + + AudioConfig audioConfig = AudioConfig.fromWavFileInput(generateFile(audio)); + SpeechRecognizer speechRecognizer = new SpeechRecognizer(speechConfig, audioConfig); + + Future task = speechRecognizer.recognizeOnceAsync(); + SpeechRecognitionResult speechRecognitionResult = task.get(); + + String result = null; + + if (speechRecognitionResult.getReason() == ResultReason.RecognizedSpeech) { + result = ("RECOGNIZED: Text= " + speechRecognitionResult.getText()); + } + else if (speechRecognitionResult.getReason() == ResultReason.NoMatch) { + result = ("NOMATCH: Speech could not be recognized."); + } + return result; + } + + public String generateFile(InputStream inputAudio) throws IOException { + //Crea temporaneamente il file creato dal DB + File tempFile = File.createTempFile("tempAudio", ".opus"); + try (FileOutputStream fos = new FileOutputStream(tempFile)) { + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = inputAudio.read(buffer)) != -1) { + fos.write(buffer, 0, bytesRead); + } + } + //Ottieni il path dell'output basandoti sul file creato + Path outputPath = Paths.get(tempFile.getPath()).getParent(); + String path = outputPath.toString() + "\\outputJava.wav"; + + //Controlla che non esista giĆ  un file + try { + // Use the delete method from Files class to delete the file + Files.delete(Paths.get(path)); + } catch (IOException e) { + System.err.println("Error deleting the file: " + e.getMessage()); + } + + + List command = Arrays.asList( + "ffmpeg", + "-i", tempFile.getPath(), + "-ar", "16000", + "-ac", "1", + "-acodec", "pcm_s16le", + path + ); + + try { + ProcessBuilder processBuilder = new ProcessBuilder(command); + Process process = processBuilder.start(); + + BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + String line; + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + int exitCode = process.waitFor(); + if(exitCode != 0){ + System.err.println("\nExited with error code : " + exitCode); + } + } catch (IOException | InterruptedException e) { + e.printStackTrace(); + } + + return path; + } + + private Properties loadProps() { + Properties props = new Properties(); + try (InputStream input = SpeechRecognition.class.getResourceAsStream(AZURE_PROPERTIES)) { + props.load(input); + } catch (IOException e) { + System.out.println(e.getMessage()); + } + + return props; + } +} \ No newline at end of file diff --git a/src/main/java/model/service/registration/Registration.java b/src/main/java/model/service/registration/Registration.java index 358d95d..9b8dd41 100644 --- a/src/main/java/model/service/registration/Registration.java +++ b/src/main/java/model/service/registration/Registration.java @@ -84,7 +84,7 @@ public boolean invitePatient(int therapistId, String patientEmail, String patien String pin = la.generatePin(therapistId); if(pin!=null){ - String body = "Salve "+ patientSurname+ " " + patientName + "\n. il tuo logopedista ti ha invitato a TalkAID! Ecco il tuo codice per registrarti al sito: "+ pin; + String body = "Salve "+ patientSurname+ " " + patientName + ". Il tuo logopedista ti ha invitato a TalkAid! Ecco il tuo codice per registrarti a TalkAid: "+ pin; tool.sendEmail(patientEmail, "Sei stato invitato a TalkAID!", body); return true; diff --git a/src/main/webapp/CSS/invitePatient.css b/src/main/webapp/CSS/invitePatient.css index e69de29..abfadde 100644 --- a/src/main/webapp/CSS/invitePatient.css +++ b/src/main/webapp/CSS/invitePatient.css @@ -0,0 +1,130 @@ +* { + margin: 0; + padding: 0; + font-family: Georgia, sans-serif; +} + +body { + height: 100%; + width: 100%; + display: flex; + flex-direction: column; +} + +a { + color: #199a8e; + text-decoration: none; + font-size: 13px; +} + +/* Aggiunta di stili per il pop-up */ +#InvitePopupOverlay { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + z-index: 1000; + justify-content: center; + align-items: center; +} + +#InvitePage { + width: 154px; + background-color: #fff; + padding: 80px; + border-radius: 10px; + text-align: center; + position: fixed; + top: 43%; + left: 50%; + transform: translate(-50%, -50%); + z-index: 1001; + border: 2px solid #000; +} + + +.homeTherapistOverlay { + transition: opacity 0.3s ease; +} + +#InvitePopupOverlay.visible .homeTherapistOverlay { + opacity: 0.5; +} + +#InviteTitle{ + margin-top: -16%; + font-size: 20px;; +} + + +#InviteForm{ + margin-top: 5%; + width: 70%; + display: flex; + justify-content: center; + align-items: center; + flex-direction: column; +} + +.inputDiv{ + width: 217%; + display: flex; + flex-direction: row; + justify-content: space-between; + background-color: #f9fafb; + border: 2px solid #e8eaed; + border-radius: 500px; + margin-bottom: -1%; +} + +.icon{ + display: flex; + justify-content: center; + align-items: center; + text-align: center; + width: 10%; +} + +.iconLeft{ + margin-left: 3%; +} + + + +.icon > img{ + width: 50%; +} + +.formInput{ + padding: 5% 7%; + height: 90%; + width: 80%; + border: none; + border-radius: 27px; + background-color: #f9fafb; + font-size: 15px; +} + +.formInput:focus{ + border: none; + outline: none; +} + + +#InviteButton{ + color: white; + width: 100%; + background-color: #199a8e; + border: none; + padding: 5% 10%; + border-radius: 500px; + margin-bottom: 20px; + display: inline-block; + font-size: 21px; +} + + + diff --git a/src/main/webapp/JS/exercise.js b/src/main/webapp/JS/exercise.js index e361eda..3511919 100644 --- a/src/main/webapp/JS/exercise.js +++ b/src/main/webapp/JS/exercise.js @@ -10,9 +10,9 @@ const IMAGESINAROW = 2 const exerciseInfo = $("#exerciseInfo"); const EXERCISETYPE = exerciseInfo.data("type"); -const EXERCISEID = exerciseInfo.data("exerciseid"); -const USERTYPE = exerciseInfo.data("usertype"); -const USERID = exerciseInfo.data("userid"); +const EXERCISEID = exerciseInfo.data("exerciseId"); +const USERTYPE = exerciseInfo.data("userType"); +const USERID = exerciseInfo.data("userId"); const exerciseDiv = $("#exerciseDiv"); @@ -122,13 +122,10 @@ function parseJSON(json) { //Gestione redirect function redirect(where){ if (where === "home"){ - console.log("sono a home"); //TODO rimuovi!! if (USERTYPE === "patient"){ - console.log("sono a patient"); //TODO rimuovi!! window.location.href = "homePagePatient.jsp"; }else if (USERTYPE === "therapist"){ - console.log("sono a therapist"); //TODO rimuovi!! - window.location.href = "homeTherapist.jsp"; + window.location.href = "homepagelogopedist.jsp"; } } else{ diff --git a/src/main/webapp/JS/homeTherapist.js b/src/main/webapp/JS/homeTherapist.js index e69de29..b3373a9 100644 --- a/src/main/webapp/JS/homeTherapist.js +++ b/src/main/webapp/JS/homeTherapist.js @@ -0,0 +1,35 @@ +//search bar for name and surname +$(document).ready(function () { + var tableContainer = document.getElementById('tableContainer'); + + // Aggiungi un gestore di eventi all'input di ricerca + $('#searchInput').on('input', function () { + var searchText = $(this).val().toLowerCase(); + + // Nascondi tutte le righe + tableContainer.getElementsByTagName('tbody')[0].style.marginTop = '0'; + + // Filtra e mostra solo le righe che corrispondono alla ricerca + $('tbody tr').each(function () { + var name = $(this).find('td:eq(1)').text().toLowerCase(); + var lastName = $(this).find('td:eq(2)').text().toLowerCase(); + + if (name.includes(searchText) || lastName.includes(searchText)) { + $(this).show(); + } else { + $(this).hide(); + } + }); + }); +}); +/*POPUP INVITE PATIENT*/ +function openInvitePopup() { + document.getElementById("invitePopup").style.display = "block"; +} +function InvitePatient(){ + window.location.href = "invitePatient.jsp"; +} +/*VIEW PATIENT*/ +function viewPatient(i){ + window.location.href = "view_patient.jsp?patientID="+i; +} diff --git a/src/main/webapp/JSP/invitePatient.jsp b/src/main/webapp/JSP/invitePatient.jsp index e69de29..1b01e0a 100644 --- a/src/main/webapp/JSP/invitePatient.jsp +++ b/src/main/webapp/JSP/invitePatient.jsp @@ -0,0 +1,49 @@ + + + + Invita Paziente + + +<% + if(session.getAttribute("type")!=null && session.getAttribute("type").equals("therapist")){ +%> +
+
+

Invita Paziente

+
+
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ + < Torna alla home +
+
+ +<% + }else { + response.sendRedirect("../errorPage/403.html"); + } +%> + + \ No newline at end of file