diff --git a/project.scala b/project.scala index 8cb132e..81dfca1 100644 --- a/project.scala +++ b/project.scala @@ -17,9 +17,9 @@ //> using dep dev.profunktor::redis4cats-log4cats:1.5.2 //> using dep com.softwaremill.sttp.client4::core:4.0.0-M6 -//> using dep com.softwaremill.sttp.client3::core:3.9.0 -//> using dep com.softwaremill.sttp.client3::circe:3.9.0 -//> using dep com.softwaremill.sttp.client3::async-http-client-backend-cats:3.9.0 +//> using dep com.softwaremill.sttp.client3::core:3.9.1 +//> using dep com.softwaremill.sttp.client3::circe:3.9.1 +//> using dep com.softwaremill.sttp.client3::async-http-client-backend-cats:3.9.1 //> using dep de.brendamour:jpasskit:0.3.3 //> using dep com.outr::scribe:3.12.2 diff --git a/src/xyz/didx/ConversationPollingHandler.scala b/src/xyz/didx/ConversationPollingHandler.scala index a2cf9f0..dfaa6a0 100644 --- a/src/xyz/didx/ConversationPollingHandler.scala +++ b/src/xyz/didx/ConversationPollingHandler.scala @@ -143,50 +143,37 @@ class ConversationPollingHandler(using logger: Logger[IO]): userMessages: List[SignalSimpleMessage], signalBot: SignalBot ): EitherT[IO, Exception, List[String]] = - userMessages.traverse(getResponseFromUserMessage(_, signalBot)) + userMessages.traverse(msg => EitherT(getResponseFromUserMessage(msg, signalBot))) private def getResponseFromUserMessage( message: SignalSimpleMessage, signalBot: SignalBot - ): EitherT[IO, Exception, String] = + ): IO[Either[Exception, String]] = val userPhone = message.phone // Retrieve the current state of the user, defaulting to Onboarding if not present val currentState = userStates.getOrElse(userPhone, ChatState.Onboarding) - val (response, nextState) = AiHandler.getAiResponse( - input = message.text, - conversationId = userPhone, - state = currentState, - telNo = Some(userPhone) - ) - - // Update the state map with the new state for this user - userStates.update(userPhone, nextState) - - val signalMessage: SignalSimpleMessage = SignalSimpleMessage(userPhone, message.name, response) - for { - sendResult: String <- processAndRespond(signalMessage, signalBot) - } yield sendResult - - private def processAndRespond( - k: SignalSimpleMessage, - signalBot: SignalBot - ): EitherT[IO, Exception, String] = - k match { - case m: SignalSimpleMessage if m.text.toLowerCase().contains("https://maps.google.com") => - EitherT.fromEither[IO](Left(new Exception("Not implemented yet"))) - - case _ => - EitherT( - signalBot.send( - SignalSendMessage( - List[String](), - k.text, - signalConf.signalPhone, - List(k.phone) - ) - ) - ) + _ <- signalBot.startTyping(userPhone) + (response, nextState) = AiHandler.getAiResponse( + input = message.text, + conversationId = userPhone, + state = currentState, + telNo = Some(userPhone) + ) + signalMessage = SignalSimpleMessage(userPhone, message.name, response) + _ <- signalBot.stopTyping(userPhone) + sendResult <- signalBot.send( + SignalSendMessage( + List[String](), + signalMessage.text, + signalConf.signalPhone, + List(message.phone) + ) + ) + } yield { + // Update the state map with the new state for this user + userStates.update(userPhone, nextState) + sendResult } diff --git a/src/xyz/didx/SignalBot.scala b/src/xyz/didx/SignalBot.scala index ff9d7db..12beca5 100644 --- a/src/xyz/didx/SignalBot.scala +++ b/src/xyz/didx/SignalBot.scala @@ -59,7 +59,7 @@ case class SignalBot(backend: SttpBackend[IO, Any]): def verify(pin: String): IO[Either[Exception, String]] = val request = basicRequest .contentType("application/json") - .body(s"""{"pin": $pin""") + .body(s"""{"pin": $pin}""") .post(uri"${signalConf.signalUrl}/verify/${signalConf.signalPhone}") val response = request.send(backend) response.map(c => @@ -115,3 +115,37 @@ case class SignalBot(backend: SttpBackend[IO, Any]): .flatten .sequence ) + + def startTyping(userNumber: String): IO[ + Either[String, Unit] + ] = + val request = basicRequest + .contentType("application/json") + .body(s"""{"recipient": $userNumber}""") + .put( + uri"${signalConf.signalUrl}/v1/typing-indicator/${signalConf.signalPhone}" + ) + + val response = request.send(backend) + response map (r => + r.body match + case Left(error) => Left(error) + case Right(_) => Right(IO.unit) + ) + + def stopTyping(userNumber: String): IO[ + Either[String, Unit] + ] = + val request = basicRequest + .contentType("application/json") + .body(s"""{"recipient": $userNumber}""") + .delete( + uri"${signalConf.signalUrl}/v1/typing-indicator/${signalConf.signalPhone}" + ) + + val response = request.send(backend) + response map (r => + r.body match + case Left(error) => Left(error) + case Right(_) => Right(IO.unit) + )