package perfectfit; import java.io.IOException; import java.io.InputStream; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Collectors; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import com.fasterxml.jackson.core.JsonParseException; import com.fasterxml.jackson.core.exc.StreamReadException; import com.fasterxml.jackson.databind.DatabindException; import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import tudelft.dialogmanager.DialogPhase; import tudelft.dialogmanager.DialogState; import tudelft.dialogmanager.answertypes.InvalidAnswerException; import tudelft.dialogmanager.parameters.DoubleValue; import tudelft.dialogmanager.parameters.Parameters; import tudelft.dialogmanager.stimuli.Stimulus; import tudelft.dialogmanager.stimuli.Textual; import tudelft.mentalhealth.perfectfit.updatefuncs.CheckDeadline; import tudelft.mentalhealth.perfectfit.updatefuncs.DateString; import tudelft.mentalhealth.perfectfit.updatefuncs.Example; import tudelft.mentalhealth.perfectfit.updatefuncs.StringLength; import tudelft.mentalhealth.perfectfit.updatefuncs.Time; import tudelft.mentalhealth.perfectfit.updatefuncs.TimeDifference; /** * Servlet to handle user actions and reply with bot response. */ @SuppressWarnings("serial") public class ChatServlet extends HttpServlet { private final static ObjectMapper jackson = new ObjectMapper(); static { jackson.registerSubtypes(Example.class, Time.class, CheckDeadline.class, TimeDifference.class, StringLength.class, DateString.class); } InputStream stream = getClass().getClassLoader() .getResourceAsStream("dialog.json"); /** * This service gets the current stimulation serialized as json. replies * NOT_ACCEPTABLE if chat was finished already. Replies BAD_REQUEST if the * given text answer is not acceptable in current state. Replies OK if text * answer was processed succesfully. */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DialogState state = getState(request.getSession()); if (state.isFinal()) { response.sendError(HttpServletResponse.SC_NOT_ACCEPTABLE, "Chat is finished. Try starting a new session"); return; } String usertext = request.getReader().lines() .collect(Collectors.joining(System.lineSeparator())); try { state = state.with(usertext); } catch (InvalidAnswerException e) { e.printStackTrace(); response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage()); } // run evaluation and then prepare the next state immediately. state = state.withUpdate(false); if (!state.isFinal()) { state = state.withUpdate(true); } request.getSession().setAttribute("state", state); response.setStatus(HttpServletResponse.SC_OK); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { DialogState state = getState(request.getSession()); if (state == null) { response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED, "Please enter the chat through the form"); return; } if (state.isFinal()) { response.sendError(400, "Chat is finished. Try starting a new session"); return; } DialogPhase phase = state.getCurrentPhase(); Stimulus stimulus = phase.getStimulation() .substitute(state.getParameters()); StimAnswer reply = new StimAnswer(stimulus, phase.getAnswer()); if (!(stimulus instanceof Textual)) { throw new IllegalStateException( "The Demo App only supports Textual."); } response.setContentType("text/json;charset=UTF-8"); response.getWriter().append(jackson.writeValueAsString(reply)); } /** * A OPTIONS command resets the state, using the query string in request. * This can be used to restart a session, and must be used to load query * arguments into the state. CONNECT seems not available , otherwise that * would have been better */ @Override protected void doOptions(HttpServletRequest request, HttpServletResponse response) throws StreamReadException, DatabindException, IOException { System.out.println("Initializing session"); InputStream stream = getClass().getClassLoader() .getResourceAsStream("dialog.json"); DialogState state = jackson.readValue(stream, DialogState.class); state = addVariables(state, request.getParameterMap()); // initialize the preparation so that we have the text ready. state = state.withUpdate(true); request.getSession().setAttribute("state", state); } /** * @param state the current state. * @param map a querystring eg 'age=25&weight=96' * @return DialogState with the parameters added. * */ private DialogState addVariables(DialogState state, Map map) { Parameters params = state.getParameters(); for (Entry entry : map.entrySet()) { params = params.with(entry.getKey(), new DoubleValue(Double.valueOf(entry.getValue()[0]))); } return state.with(params); } /** * * @param httpSession the current session * @return current {@link DialogState} for this session * @throws Exception if error occurs reading the initial state. Should not * happen */ private DialogState getState(HttpSession httpSession) throws JsonParseException, JsonMappingException, IOException { return (DialogState) httpSession.getAttribute("state"); } }