This is an automated email from the ASF dual-hosted git repository. sergeykamov pushed a commit to branch NLPCRAFT-490 in repository https://gitbox.apache.org/repos/asf/incubator-nlpcraft.git
The following commit(s) were added to refs/heads/NLPCRAFT-490 by this push: new 9aa5a2e WIP. 9aa5a2e is described below commit 9aa5a2e4bed2fdcf2822e909d0d13aa0dfeca979 Author: Sergey Kamov <skhdlem...@gmail.com> AuthorDate: Wed Mar 30 13:12:19 2022 +0300 WIP. --- .../internal/conversation/NCConversationData.scala | 17 +++++- .../conversation/NCConversationManager.scala | 2 +- .../conversation/NCConversationManagerSpec.scala | 8 +-- .../conversation/NCConversationTimeoutSpec.scala | 70 ++++++++++++++++++++++ 4 files changed, 88 insertions(+), 9 deletions(-) diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationData.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationData.scala index 472dc6a..d2a2231 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationData.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationData.scala @@ -36,7 +36,7 @@ case class NCConversationData( mdlId: String, timeoutMs: Long, maxDepth: Int -) extends LazyLogging { +) extends LazyLogging: private final val data = new NCPropertyMapAdapter() case class EntityHolder(entity: NCEntity, var entityTypeUsageTime: Long = 0) @@ -47,6 +47,12 @@ case class NCConversationData( private val lastEnts = mutable.ArrayBuffer.empty[Iterable[NCEntity]] private val ctx = mutable.ArrayBuffer.empty[NCEntity] + /** + * + */ + val getUserData: NCPropertyMap = data + + @volatile private var lastUpdateTstamp = NCUtils.nowUtcMs() @volatile private var depth = 0 @@ -204,5 +210,10 @@ case class NCConversationData( /** * */ - val getUserData: NCPropertyMap = data -} \ No newline at end of file + def clear(): Unit = + stm.synchronized { + ctx.clear() + stm.clear() + lastEnts.clear() + data.clear() + } diff --git a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala index bc7c557..ce9d66c 100644 --- a/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala +++ b/nlpcraft/src/main/scala/org/apache/nlpcraft/internal/conversation/NCConversationManager.scala @@ -61,7 +61,7 @@ class NCConversationManager(cfg: NCModelConfig) extends LazyLogging: for ((key, value) <- convs) if value.tstamp < now - cfg.getConversationTimeout then - value.conv.getUserData.clear() + value.conv.clear() delKeys += key convs --= delKeys diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationManagerSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationManagerSpec.scala index 113b538..1b6d6dc 100644 --- a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationManagerSpec.scala +++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationManagerSpec.scala @@ -65,22 +65,20 @@ class NCConversationManagerSpec: val t = NCTestToken() val reqId = "req1" - // TODO: important (error in code) - drop method and use saved conversation instead - error is thrown. - def getConversation: NCConversationData = mgr.getConversation("user1") + val conv = mgr.getConversation("user1") def checkSize(size: Int): Unit = - val conv = getConversation require(conv.getEntities.sizeIs == size, s"Unexpected entities size: ${conv.getEntities.size}, expected: $size") // Initial empty. checkSize(0) // Added. Still empty. - getConversation.addEntities(reqId, Seq(NCTestEntity("e1", reqId, tokens = t), NCTestEntity("e2", reqId, tokens = t))) + conv.addEntities(reqId, Seq(NCTestEntity("e1", reqId, tokens = t), NCTestEntity("e2", reqId, tokens = t))) checkSize(0) // Updated. Not empty. - getConversation.updateEntities() + conv.updateEntities() checkSize(2) // Cleared by timeout. diff --git a/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationTimeoutSpec.scala b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationTimeoutSpec.scala new file mode 100644 index 0000000..72282ee --- /dev/null +++ b/nlpcraft/src/test/scala/org/apache/nlpcraft/internal/conversation/NCConversationTimeoutSpec.scala @@ -0,0 +1,70 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.nlpcraft.internal.conversation + +import org.apache.nlpcraft.* +import org.apache.nlpcraft.nlp.entity.parser.semantic.NCSemanticTestElement +import org.apache.nlpcraft.nlp.util.* +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +import scala.jdk.CollectionConverters.* +import scala.util.Using + +class NCConversationTimeoutSpec: + private val TIMEOUT = 200 + private val VALUE = "value" + private val EMPTY = "empty" + + @Test + def test(): Unit = + val mdl: NCModel = + new NCTestModelAdapter: + override val getConfig: NCModelConfig = + val cfg = new NCModelConfig("testId", "test", "1.0", "Test description", "Test origin") + cfg.setConversationTimeout(TIMEOUT) + cfg + + override val getPipeline: NCPipeline = + val pl = mkEnPipeline + import NCSemanticTestElement as TE + pl.getEntityParsers.add(NCTestUtils.mkENSemanticParser(TE("test"))) + pl + + @NCIntent("intent=i term(e)~{# == 'test'}") + def onMatch(im: NCIntentMatch, @NCIntentTerm("e") e: NCEntity): NCResult = + val conv = im.getContext.getConversation + val res = new NCResult(conv.getData.getOpt("key").orElse(EMPTY), NCResultType.ASK_RESULT) + + // For next calls. + conv.getData.put("key", VALUE) + + res + + Using.resource(new NCModelClient(mdl)) { cli => + def check(hasValue: Boolean): Unit = + require(cli.ask("test", null, "userId").getBody.toString == (if hasValue then VALUE else EMPTY)) + + check(false) + check(true) + + Thread.sleep(TIMEOUT * 2) + + check(false) + check(true) + }